1use super::bundle::*;
2
3pub type CrcRawType = u8;
10
11use crc::{Crc, CRC_16_IBM_SDLC, CRC_32_ISCSI};
12
13pub const X25: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_SDLC);
14pub const CASTAGNOLI: Crc<u32> = Crc::<u32>::new(&CRC_32_ISCSI);
15
16#[derive(Debug, Clone, PartialEq, Default)]
17pub enum CrcValue {
18 #[default]
19 CrcNo,
20 Crc16Empty,
21 Crc32Empty,
22 Crc16([u8; 2]),
23 Crc32([u8; 4]),
24 Unknown(CrcRawType),
25}
26
27impl CrcValue {
28 pub fn has_crc(&self) -> bool {
29 *self != CrcValue::CrcNo
31 }
32 pub fn to_code(&self) -> CrcRawType {
33 match self {
34 CrcValue::CrcNo => CRC_NO,
35 CrcValue::Crc16(_) => CRC_16,
36 CrcValue::Crc16Empty => CRC_16,
37 CrcValue::Crc32(_) => CRC_32,
38 CrcValue::Crc32Empty => CRC_32,
39 CrcValue::Unknown(code) => *code,
40 }
41 }
42 pub fn bytes(&self) -> Option<&[u8]> {
43 match self {
44 CrcValue::Unknown(_) => None,
45 CrcValue::CrcNo => None,
46 CrcValue::Crc16(buf) => Some(buf),
47 CrcValue::Crc16Empty => Some(&CRC16_EMPTY),
48 CrcValue::Crc32(buf) => Some(buf),
49 CrcValue::Crc32Empty => Some(&CRC32_EMPTY),
50 }
51 }
52}
53pub(crate) const CRC16_EMPTY: [u8; 2] = [0; 2];
54pub(crate) const CRC32_EMPTY: [u8; 4] = [0; 4];
55
56pub const CRC_NO: CrcRawType = 0;
57pub const CRC_16: CrcRawType = 1;
58pub const CRC_32: CrcRawType = 2;
59
60pub trait CRCFuncations {
61 fn to_string(self) -> String;
62}
63impl CRCFuncations for CrcRawType {
64 fn to_string(self) -> String {
65 match self {
66 CRC_NO => String::from("no"),
67 CRC_16 => String::from("16"),
68 CRC_32 => String::from("32"),
69 _ => String::from("unknown"),
70 }
71 }
72}
73
74pub trait CrcBlock: Block + Clone {
75 fn has_crc(&self) -> bool {
77 self.crc_value().has_crc()
78 }
79 fn update_crc(&mut self) {
81 let new_crc = calculate_crc(self);
82 self.set_crc(new_crc);
83 }
84 fn check_crc(&mut self) -> bool {
86 check_crc(self)
87 }
88 fn reset_crc(&mut self) {
90 if self.has_crc() {
91 match self.crc_value() {
92 CrcValue::Crc16(_) => self.set_crc(CrcValue::Crc16Empty),
93 CrcValue::Crc32(_) => self.set_crc(CrcValue::Crc32Empty),
94 _ => {}
95 }
96 }
97 }
98 fn crc(&self) -> Option<&[u8]> {
100 self.crc_value().bytes()
101 }
102 fn set_crc_type(&mut self, crc_value: CrcRawType) {
105 if crc_value == CRC_NO {
106 self.set_crc(CrcValue::CrcNo);
107 } else if crc_value == CRC_16 {
108 self.set_crc(CrcValue::Crc16Empty);
109 } else if crc_value == CRC_32 {
110 self.set_crc(CrcValue::Crc32Empty);
111 } else {
112 self.set_crc(CrcValue::Unknown(crc_value));
113 }
114 }
115 fn crc_type(&self) -> CrcRawType {
117 self.crc_value().to_code()
118 }
119 fn crc_value(&self) -> &CrcValue;
120 fn set_crc(&mut self, crc: CrcValue);
121}
122
123pub fn calculate_crc<T: CrcBlock + Block>(blck: &mut T) -> CrcValue {
124 match blck.crc_type() {
125 CRC_NO => CrcValue::CrcNo,
126 CRC_16 => {
127 let crc_bak = blck.crc_value().clone(); blck.reset_crc(); let data = blck.to_cbor(); let chksm = X25.checksum(&data);
132 let output_crc = chksm.to_be_bytes();
133 blck.set_crc(crc_bak); CrcValue::Crc16(output_crc)
135 }
136 CRC_32 => {
137 let crc_bak = blck.crc_value().clone(); blck.reset_crc(); let data = blck.to_cbor(); let chksm = CASTAGNOLI.checksum(&data);
142 let output_crc = chksm.to_be_bytes();
143 blck.set_crc(crc_bak); CrcValue::Crc32(output_crc)
145 }
146 _ => {
147 panic!("Unknown crc type");
148 }
149 }
150}
151pub fn check_crc<T: CrcBlock + Block>(blck: &mut T) -> bool {
152 if !blck.has_crc() {
153 return !blck.has_crc();
154 }
155 calculate_crc(blck).bytes() == blck.crc()
156}