milstd1553b_parser/
core.rs1use crate::error::{ParseError, Result};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub enum Bus {
9 BusA,
11 BusB,
13}
14
15impl Bus {
16 pub fn as_bit(&self) -> u8 {
18 match self {
19 Bus::BusA => 0,
20 Bus::BusB => 1,
21 }
22 }
23}
24
25impl std::fmt::Display for Bus {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 match self {
28 Bus::BusA => write!(f, "Bus A"),
29 Bus::BusB => write!(f, "Bus B"),
30 }
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub struct Address(u8);
38
39impl Address {
40 pub const MIN: u8 = 0;
42 pub const MAX: u8 = 31;
44 pub const BROADCAST: u8 = 31;
46
47 pub fn new(addr: u8) -> Result<Self> {
49 if addr > Self::MAX {
50 return Err(ParseError::invalid_address(format!(
51 "Address {} out of range [0, {}]",
52 addr,
53 Self::MAX
54 )));
55 }
56 Ok(Address(addr))
57 }
58
59 pub fn broadcast() -> Self {
61 Address(Self::BROADCAST)
62 }
63
64 pub fn value(&self) -> u8 {
66 self.0
67 }
68
69 pub fn is_broadcast(&self) -> bool {
71 self.0 == Self::BROADCAST
72 }
73
74 pub fn is_remote_terminal(&self) -> bool {
76 self.0 < 30
77 }
78}
79
80impl std::fmt::Display for Address {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 if self.is_broadcast() {
83 write!(f, "BC (broadcast)")
84 } else {
85 write!(f, "RT-{}", self.0)
86 }
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
92#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
93pub enum WordType {
94 Command,
96 Data,
98 Status,
100 ModeCode,
102}
103
104impl std::fmt::Display for WordType {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 match self {
107 WordType::Command => write!(f, "Command"),
108 WordType::Data => write!(f, "Data"),
109 WordType::Status => write!(f, "Status"),
110 WordType::ModeCode => write!(f, "Mode Code"),
111 }
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
125#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
126pub struct Word {
127 data: u32,
129 word_type: WordType,
131}
132
133impl Word {
134 pub fn new(data: u32, word_type: WordType) -> Result<Self> {
138 if data > 0xFFFFF {
140 return Err(ParseError::invalid_word(
141 "Word data exceeds 20 bits".to_string(),
142 ));
143 }
144
145 Self::validate_parity(data)?;
147
148 Ok(Word { data, word_type })
149 }
150
151 pub fn new_unchecked(data: u32, word_type: WordType) -> Self {
156 Word { data, word_type }
157 }
158
159 pub fn data(&self) -> u32 {
161 self.data
162 }
163
164 pub fn word_type(&self) -> WordType {
166 self.word_type
167 }
168
169 pub fn get_data_bits(&self) -> u16 {
171 ((self.data >> 1) & 0xFFFF) as u16
172 }
173
174 pub fn get_parity_bit(&self) -> bool {
176 ((self.data >> 17) & 1) != 0
177 }
178
179 pub fn get_sync_bits(&self) -> u8 {
181 ((self.data >> 18) & 0x3) as u8
182 }
183
184 fn validate_parity(data: u32) -> Result<()> {
189 let count_bits = (data & 0x1FFFF).count_ones();
191
192 let parity_bit = ((data >> 17) & 1) != 0;
194 let total_ones = count_bits + if parity_bit { 1 } else { 0 };
195
196 if total_ones % 2 == 0 {
197 return Err(ParseError::parity_error(
198 "Parity check failed: even number of 1s detected".to_string(),
199 ));
200 }
201
202 Ok(())
203 }
204
205 pub fn calculate_parity(data_bits: u16) -> u8 {
207 let count_ones = data_bits.count_ones();
210
211 if count_ones % 2 == 0 {
213 1
214 } else {
215 0
216 }
217 }
218}
219
220impl std::fmt::Display for Word {
221 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222 write!(
223 f,
224 "Word(type={}, data=0x{:05X})",
225 self.word_type, self.data
226 )
227 }
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 #[test]
235 fn test_address_creation() {
236 assert!(Address::new(0).is_ok());
237 assert!(Address::new(31).is_ok());
238 assert!(Address::new(32).is_err());
239 }
240
241 #[test]
242 fn test_address_broadcast() {
243 let addr = Address::broadcast();
244 assert!(addr.is_broadcast());
245 }
246
247 #[test]
248 fn test_word_creation() {
249 let data_bits = 0xAAAAu16;
251 let parity = Word::calculate_parity(data_bits) as u32;
252 let word_data = (parity << 17) | ((data_bits as u32) << 1) | 0;
253
254 let word = Word::new(word_data, WordType::Data);
255 assert!(word.is_ok());
256 }
257
258 #[test]
259 fn test_word_parity_validation() {
260 let word_data = 0xAAAAA; let result = Word::new(word_data, WordType::Data);
264 let _ = result;
266 }
267
268 #[test]
269 fn test_calculate_parity() {
270 let parity = Word::calculate_parity(0x0000);
272 assert_eq!(parity, 1); let parity = Word::calculate_parity(0xFFFF);
275 assert_eq!(parity, 1); let parity = Word::calculate_parity(0x0001);
278 assert_eq!(parity, 0); }
280
281 #[test]
282 fn test_bus_display() {
283 assert_eq!(Bus::BusA.to_string(), "Bus A");
284 assert_eq!(Bus::BusB.to_string(), "Bus B");
285 }
286}