stackforge_core/layer/modbus/
crc.rs1#[must_use]
14pub fn modbus_crc16(data: &[u8]) -> u16 {
15 let mut crc: u16 = 0xFFFF;
16 for &byte in data {
17 crc ^= u16::from(byte);
18 for _ in 0..8 {
19 if crc & 0x0001 != 0 {
20 crc = (crc >> 1) ^ 0xA001;
21 } else {
22 crc >>= 1;
23 }
24 }
25 }
26 crc
27}
28
29#[must_use]
34pub fn verify_crc16(frame: &[u8]) -> bool {
35 if frame.len() < 3 {
36 return false;
37 }
38 let data = &frame[..frame.len() - 2];
39 let expected = u16::from_le_bytes([frame[frame.len() - 2], frame[frame.len() - 1]]);
40 modbus_crc16(data) == expected
41}
42
43#[must_use]
48pub fn modbus_lrc(data: &[u8]) -> u8 {
49 let sum: u8 = data.iter().fold(0u8, |acc, &b| acc.wrapping_add(b));
50 sum.wrapping_neg()
51}
52
53#[must_use]
57pub fn verify_lrc(data: &[u8]) -> bool {
58 if data.is_empty() {
59 return false;
60 }
61 let sum: u8 = data.iter().fold(0u8, |acc, &b| acc.wrapping_add(b));
62 sum == 0
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn test_crc16_check_value() {
71 assert_eq!(modbus_crc16(b"123456789"), 0x4B37);
73 }
74
75 #[test]
76 fn test_crc16_known_vector() {
77 let data = [0x01, 0x03, 0x00, 0x00, 0x00, 0x0A];
80 let crc = modbus_crc16(&data);
81 let mut frame = data.to_vec();
82 frame.push((crc & 0xFF) as u8);
83 frame.push((crc >> 8) as u8);
84 assert!(verify_crc16(&frame));
85 }
86
87 #[test]
88 fn test_crc16_empty() {
89 assert_eq!(modbus_crc16(&[]), 0xFFFF);
90 }
91
92 #[test]
93 fn test_crc16_single_byte() {
94 let crc = modbus_crc16(&[0x00]);
96 let mut frame = vec![0x00u8];
98 frame.push((crc & 0xFF) as u8);
99 frame.push((crc >> 8) as u8);
100 assert!(verify_crc16(&frame));
101 }
102
103 #[test]
104 fn test_verify_crc16_valid() {
105 let data = [0x01, 0x03, 0x00, 0x00, 0x00, 0x0A];
106 let crc = modbus_crc16(&data);
107 let mut frame = data.to_vec();
108 frame.push((crc & 0xFF) as u8); frame.push((crc >> 8) as u8); assert!(verify_crc16(&frame));
111 }
112
113 #[test]
114 fn test_verify_crc16_corrupted() {
115 let data = [0x01, 0x03, 0x00, 0x00, 0x00, 0x0A];
116 let crc = modbus_crc16(&data);
117 let mut frame = data.to_vec();
118 frame.push((crc & 0xFF) as u8);
119 frame.push(((crc >> 8) as u8) ^ 0xFF); assert!(!verify_crc16(&frame));
121 }
122
123 #[test]
124 fn test_verify_crc16_too_short() {
125 assert!(!verify_crc16(&[0x01, 0x02]));
126 assert!(!verify_crc16(&[]));
127 }
128
129 #[test]
130 fn test_lrc_known_vector() {
131 let data = [0x01, 0x03, 0x00, 0x00, 0x00, 0x0A];
135 assert_eq!(modbus_lrc(&data), 0xF2);
136 }
137
138 #[test]
139 fn test_lrc_empty() {
140 assert_eq!(modbus_lrc(&[]), 0x00);
141 }
142
143 #[test]
144 fn test_lrc_self_check() {
145 let data = [0x01, 0x03, 0x00, 0x00, 0x00, 0x0A];
147 let lrc = modbus_lrc(&data);
148 let mut with_lrc = data.to_vec();
149 with_lrc.push(lrc);
150 assert!(verify_lrc(&with_lrc));
151 }
152
153 #[test]
154 fn test_verify_lrc_valid() {
155 let data = [0x01, 0x03, 0x00, 0x00, 0x00, 0x0A, 0xF2];
156 assert!(verify_lrc(&data));
157 }
158
159 #[test]
160 fn test_verify_lrc_invalid() {
161 let data = [0x01, 0x03, 0x00, 0x00, 0x00, 0x0A, 0xFF];
162 assert!(!verify_lrc(&data));
163 }
164
165 #[test]
166 fn test_verify_lrc_empty() {
167 assert!(!verify_lrc(&[]));
168 }
169}