1use crate::error::Error;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub struct Address(u8);
13
14impl Address {
15 pub const fn from_raw(byte: u8) -> Self {
18 Self(byte)
19 }
20
21 pub const fn pd(addr: u8) -> Result<Self, Error> {
24 if addr > crate::BROADCAST_ADDR {
25 return Err(Error::BadAddress(addr));
26 }
27 Ok(Self(addr))
28 }
29
30 pub const fn reply(addr: u8) -> Result<Self, Error> {
32 if addr > crate::BROADCAST_ADDR {
33 return Err(Error::BadAddress(addr));
34 }
35 Ok(Self(addr | crate::REPLY_FLAG))
36 }
37
38 pub const fn as_byte(self) -> u8 {
40 self.0
41 }
42
43 pub const fn pd_addr(self) -> u8 {
45 self.0 & !crate::REPLY_FLAG
46 }
47
48 pub const fn is_reply(self) -> bool {
50 (self.0 & crate::REPLY_FLAG) != 0
51 }
52
53 pub const fn is_broadcast(self) -> bool {
55 self.pd_addr() == crate::BROADCAST_ADDR
56 }
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub struct Sqn(u8);
68
69impl Sqn {
70 pub const ZERO: Self = Self(0);
72
73 pub const fn new(n: u8) -> Result<Self, Error> {
75 if n > 3 {
76 Err(Error::BadSqn(n))
77 } else {
78 Ok(Self(n))
79 }
80 }
81
82 pub const fn value(self) -> u8 {
84 self.0
85 }
86
87 pub const fn next(self) -> Self {
89 Self(match self.0 {
90 0 | 3 => 1,
91 n => n + 1,
92 })
93 }
94}
95
96bitflags::bitflags! {
97 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
109 pub struct CtrlFlags: u8 {
110 const USE_CRC = 0x04;
112 const HAS_SCB = 0x08;
114 }
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119pub struct ControlByte {
120 pub sqn: Sqn,
122 pub flags: CtrlFlags,
124}
125
126impl ControlByte {
127 pub const fn new(sqn: Sqn, flags: CtrlFlags) -> Self {
129 Self { sqn, flags }
130 }
131
132 pub const fn encode(self) -> u8 {
134 self.sqn.value() | self.flags.bits()
135 }
136
137 pub const fn decode(byte: u8) -> Result<Self, Error> {
139 if (byte & 0xF0) != 0 {
140 return Err(Error::BadControlByte(byte));
141 }
142 let sqn = match Sqn::new(byte & 0x03) {
143 Ok(s) => s,
144 Err(e) => return Err(e),
145 };
146 let flags = match CtrlFlags::from_bits(byte & 0x0C) {
147 Some(f) => f,
148 None => return Err(Error::BadControlByte(byte)),
149 };
150 Ok(Self { sqn, flags })
151 }
152
153 pub const fn use_crc(self) -> bool {
155 self.flags.contains(CtrlFlags::USE_CRC)
156 }
157
158 pub const fn has_scb(self) -> bool {
160 self.flags.contains(CtrlFlags::HAS_SCB)
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn ctrl_byte_roundtrip() {
170 for raw in 0u8..=0x0F {
171 let cb = ControlByte::decode(raw).unwrap();
172 assert_eq!(cb.encode(), raw);
173 }
174 }
175
176 #[test]
177 fn ctrl_byte_rejects_reserved() {
178 for raw in 0x10..=0xFFu8 {
179 assert!(ControlByte::decode(raw).is_err());
180 }
181 }
182
183 #[test]
184 fn sqn_cycles_skipping_zero() {
185 let mut s = Sqn::new(1).unwrap();
186 for _ in 0..10 {
187 s = s.next();
188 assert_ne!(s.value(), 0);
189 }
190 }
191
192 #[test]
193 fn address_reply_flag() {
194 let pd = Address::pd(0x05).unwrap();
195 assert!(!pd.is_reply());
196 assert_eq!(pd.as_byte(), 0x05);
197
198 let reply = Address::reply(0x05).unwrap();
199 assert!(reply.is_reply());
200 assert_eq!(reply.as_byte(), 0x85);
201 assert_eq!(reply.pd_addr(), 0x05);
202
203 let bcast = Address::pd(0x7F).unwrap();
204 assert!(bcast.is_broadcast());
205 }
206}