leodos_protocols/datalink/reliability/cop1/
clcw.rs1use crate::ids::Vcid;
25use zerocopy::FromBytes;
26use zerocopy::Immutable;
27use zerocopy::IntoBytes;
28use zerocopy::KnownLayout;
29use zerocopy::Unaligned;
30use zerocopy::byteorder::network_endian::U32;
31
32#[repr(C)]
34#[derive(
35 FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable,
36 Debug, Copy, Clone, Eq, PartialEq,
37)]
38pub struct Clcw {
39 word: U32,
40}
41
42#[rustfmt::skip]
43mod bitmask {
44 pub const TYPE_MASK: u32 = 0b_1000_0000_0000_0000_0000_0000_0000_0000;
45 pub const VERSION_MASK: u32 = 0b_0110_0000_0000_0000_0000_0000_0000_0000;
46 pub const STATUS_MASK: u32 = 0b_0001_1100_0000_0000_0000_0000_0000_0000;
47 pub const COP_MASK: u32 = 0b_0000_0011_0000_0000_0000_0000_0000_0000;
48 pub const VCID_MASK: u32 = 0b_0000_0000_1111_1100_0000_0000_0000_0000;
49 pub const NO_RF_MASK: u32 = 0b_0000_0000_0000_0000_1000_0000_0000_0000;
50 pub const NO_BIT_LOCK_MASK: u32 = 0b_0000_0000_0000_0000_0100_0000_0000_0000;
51 pub const LOCKOUT_MASK: u32 = 0b_0000_0000_0000_0000_0010_0000_0000_0000;
52 pub const WAIT_MASK: u32 = 0b_0000_0000_0000_0000_0001_0000_0000_0000;
53 pub const RETRANSMIT_MASK: u32 = 0b_0000_0000_0000_0000_0000_1000_0000_0000;
54 pub const FARM_B_MASK: u32 = 0b_0000_0000_0000_0000_0000_0110_0000_0000;
55 pub const REPORT_MASK: u32 = 0b_0000_0000_0000_0000_0000_0000_1111_1111;
56}
57
58use bitmask::*;
59
60fn get(word: U32, mask: u32) -> u32 {
61 (word.get() & mask) >> mask.trailing_zeros()
62}
63
64fn set(word: &mut U32, mask: u32, value: u32) {
65 word.set((word.get() & !mask) | (value << mask.trailing_zeros()));
66}
67
68impl Clcw {
69 pub const SIZE: usize = 4;
71
72 pub fn new() -> Self {
74 Self { word: U32::ZERO }
75 }
76
77 pub fn parse(bytes: &[u8]) -> Option<&Self> {
79 Self::ref_from_bytes(bytes).ok()
80 }
81
82 pub fn control_word_type(&self) -> u8 {
84 get(self.word, TYPE_MASK) as u8
85 }
86
87 pub fn version(&self) -> u8 {
89 get(self.word, VERSION_MASK) as u8
90 }
91 pub fn set_version(&mut self, v: u8) {
93 set(&mut self.word, VERSION_MASK, v as u32);
94 }
95
96 pub fn status(&self) -> u8 {
98 get(self.word, STATUS_MASK) as u8
99 }
100 pub fn set_status(&mut self, v: u8) {
102 set(&mut self.word, STATUS_MASK, v as u32);
103 }
104
105 pub fn cop_in_effect(&self) -> u8 {
107 get(self.word, COP_MASK) as u8
108 }
109 pub fn set_cop_in_effect(&mut self, v: u8) {
111 set(&mut self.word, COP_MASK, v as u32);
112 }
113
114 pub fn vcid(&self) -> Vcid {
116 Vcid::new(get(self.word, VCID_MASK) as u32)
117 }
118 pub fn set_vcid(&mut self, v: Vcid) {
120 set(&mut self.word, VCID_MASK, v.get());
121 }
122
123 pub fn no_rf_available(&self) -> bool {
125 get(self.word, NO_RF_MASK) != 0
126 }
127 pub fn set_no_rf_available(&mut self, v: bool) {
129 set(&mut self.word, NO_RF_MASK, v as u32);
130 }
131
132 pub fn no_bit_lock(&self) -> bool {
134 get(self.word, NO_BIT_LOCK_MASK) != 0
135 }
136 pub fn set_no_bit_lock(&mut self, v: bool) {
138 set(&mut self.word, NO_BIT_LOCK_MASK, v as u32);
139 }
140
141 pub fn lockout(&self) -> bool {
143 get(self.word, LOCKOUT_MASK) != 0
144 }
145 pub fn set_lockout(&mut self, v: bool) {
147 set(&mut self.word, LOCKOUT_MASK, v as u32);
148 }
149
150 pub fn wait(&self) -> bool {
152 get(self.word, WAIT_MASK) != 0
153 }
154 pub fn set_wait(&mut self, v: bool) {
156 set(&mut self.word, WAIT_MASK, v as u32);
157 }
158
159 pub fn retransmit(&self) -> bool {
161 get(self.word, RETRANSMIT_MASK) != 0
162 }
163 pub fn set_retransmit(&mut self, v: bool) {
165 set(&mut self.word, RETRANSMIT_MASK, v as u32);
166 }
167
168 pub fn farm_b_counter(&self) -> u8 {
170 get(self.word, FARM_B_MASK) as u8
171 }
172 pub fn set_farm_b_counter(&mut self, v: u8) {
174 set(&mut self.word, FARM_B_MASK, (v & 0x03) as u32);
175 }
176
177 pub fn report_value(&self) -> u8 {
179 get(self.word, REPORT_MASK) as u8
180 }
181 pub fn set_report_value(&mut self, v: u8) {
183 set(&mut self.word, REPORT_MASK, v as u32);
184 }
185}
186
187impl Default for Clcw {
188 fn default() -> Self {
189 Self::new()
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196 use crate::ids::Vcid;
197
198 #[test]
199 fn roundtrip_fields() {
200 let mut clcw = Clcw::new();
201
202 clcw.set_cop_in_effect(1);
203 clcw.set_vcid(Vcid::new(42));
204 clcw.set_lockout(true);
205 clcw.set_wait(false);
206 clcw.set_retransmit(true);
207 clcw.set_farm_b_counter(3);
208 clcw.set_report_value(0xAB);
209
210 assert_eq!(clcw.control_word_type(), 0);
211 assert_eq!(clcw.cop_in_effect(), 1);
212 assert_eq!(clcw.vcid(), Vcid::new(42));
213 assert!(clcw.lockout());
214 assert!(!clcw.wait());
215 assert!(clcw.retransmit());
216 assert_eq!(clcw.farm_b_counter(), 3);
217 assert_eq!(clcw.report_value(), 0xAB);
218 }
219
220 #[test]
221 fn size_is_4_bytes() {
222 assert_eq!(core::mem::size_of::<Clcw>(), 4);
223 }
224
225 #[test]
226 fn parse_from_bytes() {
227 let mut clcw = Clcw::new();
228 clcw.set_report_value(99);
229 let bytes = zerocopy::IntoBytes::as_bytes(&clcw);
230 let parsed = Clcw::parse(bytes).unwrap();
231 assert_eq!(parsed.report_value(), 99);
232 }
233}