1#[cfg(feature = "alloc")]
2use alloc::fmt::{self, Debug, Display, Formatter};
3#[cfg(feature = "alloc")]
4use alloc::vec::Vec;
5
6#[cfg(feature = "heapless")]
7use heapless::Vec as HeaplessVec;
8
9use crate::{constants::crc_u32::*, lookup_table::LookUpTable};
10
11#[allow(clippy::upper_case_acronyms)]
12pub struct CRCu32 {
14 by_table: bool,
15 poly: u32,
16 lookup_table: LookUpTable<u32>,
17 sum: u32,
18 pub(crate) bits: u8,
19 high_bit: u32,
20 mask: u32,
21 initial: u32,
22 final_xor: u32,
23 reflect: bool,
24 reorder: bool,
25}
26
27#[cfg(feature = "alloc")]
28impl Debug for CRCu32 {
29 #[inline]
30 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
31 if self.by_table {
32 debug_helper::impl_debug_for_struct!(CRCu64, f, self, let .lookup_table = self.lookup_table.as_ref(), (.sum, "0x{:08X}", self.sum), .bits, (.initial, "0x{:08X}", self.initial), (.final_xor, "0x{:08X}", self.final_xor), .reflect, .reorder);
33 } else {
34 debug_helper::impl_debug_for_struct!(CRCu64, f, self, (.poly, "0x{:08X}", self.poly), (.sum, "0x{:08X}", self.sum), .bits, (.initial, "0x{:08X}", self.initial), (.final_xor, "0x{:08X}", self.final_xor), .reflect, .reorder);
35 }
36 }
37}
38
39#[cfg(feature = "alloc")]
40impl Display for CRCu32 {
41 #[inline]
42 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
43 f.write_fmt(format_args!("0x{:01$X}", self.get_crc(), (self.bits as usize + 3) >> 2))
44 }
45}
46
47impl CRCu32 {
48 pub fn create_crc(poly: u32, bits: u8, initial: u32, final_xor: u32, reflect: bool) -> CRCu32 {
50 debug_assert!(bits <= 32 && bits > 0);
51
52 if bits % 8 == 0 {
53 let lookup_table = if reflect {
54 LookUpTable::Dynamic(Self::crc_reflect_table(poly))
55 } else {
56 LookUpTable::Dynamic(Self::crc_table(poly, bits))
57 };
58
59 Self::create_crc_with_exists_lookup_table(
60 lookup_table,
61 bits,
62 initial,
63 final_xor,
64 reflect,
65 )
66 } else {
67 Self::create(
68 false,
69 LookUpTable::Static(&[0u32; 256]),
70 poly,
71 bits,
72 initial,
73 final_xor,
74 reflect,
75 )
76 }
77 }
78
79 #[inline]
80 pub(crate) fn create_crc_with_exists_lookup_table(
81 lookup_table: LookUpTable<u32>,
82 bits: u8,
83 initial: u32,
84 final_xor: u32,
85 reflect: bool,
86 ) -> CRCu32 {
87 debug_assert!(bits % 8 == 0);
88
89 Self::create(true, lookup_table, 0, bits, initial, final_xor, reflect)
90 }
91
92 #[inline]
93 fn create(
94 by_table: bool,
95 lookup_table: LookUpTable<u32>,
96 mut poly: u32,
97 bits: u8,
98 initial: u32,
99 final_xor: u32,
100 reflect: bool,
101 ) -> CRCu32 {
102 let high_bit = 1 << u32::from(bits - 1);
103 let mask = ((high_bit - 1) << 1) | 1;
104
105 let sum = if reflect { Self::reflect_function(high_bit, initial) } else { initial };
106
107 if !by_table && reflect {
108 poly = Self::reflect_function(high_bit, poly);
109 }
110
111 CRCu32 {
112 by_table,
113 poly,
114 lookup_table,
115 sum,
116 bits,
117 high_bit,
118 mask,
119 initial,
120 final_xor,
121 reflect,
122 reorder: false,
123 }
124 }
125
126 #[inline]
127 fn reflect_function(high_bit: u32, n: u32) -> u32 {
128 let mut i = high_bit;
129 let mut j = 1;
130 let mut out = 0;
131
132 while i != 0 {
133 if n & i != 0 {
134 out |= j;
135 }
136
137 j <<= 1;
138 i >>= 1;
139 }
140
141 out
142 }
143
144 #[inline]
145 fn reflect_method(&self, n: u32) -> u32 {
146 Self::reflect_function(self.high_bit, n)
147 }
148
149 pub fn digest<T: ?Sized + AsRef<[u8]>>(&mut self, data: &T) {
151 if self.by_table {
152 if self.bits == 8 {
153 for n in data.as_ref().iter().copied() {
154 let index = (self.sum as u8 ^ n) as usize;
155 self.sum = self.lookup_table[index];
156 }
157 } else if self.reflect {
158 for n in data.as_ref().iter().copied() {
159 let index = ((self.sum as u8) ^ n) as usize;
160 self.sum = (self.sum >> 8) ^ self.lookup_table[index];
161 }
162 } else {
163 for n in data.as_ref().iter().copied() {
164 let index = ((self.sum >> u32::from(self.bits - 8)) as u8 ^ n) as usize;
165 self.sum = (self.sum << 8) ^ self.lookup_table[index];
166 }
167 }
168 } else if self.reflect {
169 for n in data.as_ref().iter().copied() {
170 let n = super::crc_u8::CRCu8::reflect_function(0x80, n);
171
172 let mut i = 0x80;
173
174 while i != 0 {
175 let mut bit = self.sum & self.high_bit;
176
177 self.sum <<= 1;
178
179 if n & i != 0 {
180 bit ^= self.high_bit;
181 }
182
183 if bit != 0 {
184 self.sum ^= self.poly;
185 }
186
187 i >>= 1;
188 }
189 }
190 } else {
191 for n in data.as_ref().iter().copied() {
192 let mut i = 0x80;
193
194 while i != 0 {
195 let mut bit = self.sum & self.high_bit;
196
197 self.sum <<= 1;
198
199 if n & i != 0 {
200 bit ^= self.high_bit;
201 }
202
203 if bit != 0 {
204 self.sum ^= self.poly;
205 }
206
207 i >>= 1;
208 }
209 }
210 }
211 }
212
213 pub fn reset(&mut self) {
215 self.sum = self.initial;
216 }
217
218 pub fn get_crc(&self) -> u32 {
220 let sum = if self.by_table || !self.reflect {
221 (self.sum ^ self.final_xor) & self.mask
222 } else {
223 (self.reflect_method(self.sum) ^ self.final_xor) & self.mask
224 };
225
226 if self.reorder {
227 let mut new_sum = 0;
228
229 let e = (self.bits as u32 + 7) >> 3;
230
231 let e_dec = e - 1;
232
233 for i in 0..e {
234 new_sum |= ((sum >> ((e_dec - i) * 8)) & 0xFF) << (i * 8);
235 }
236
237 new_sum
238 } else {
239 sum
240 }
241 }
242
243 fn crc_reflect_table(poly_rev: u32) -> [u32; 256] {
244 let mut lookup_table = [0u32; 256];
245
246 for (i, e) in lookup_table.iter_mut().enumerate() {
247 let mut v = i as u32;
248
249 #[allow(clippy::branches_sharing_code)]
250 for _ in 0..8u8 {
251 if v & 1 != 0 {
252 v >>= 1;
253 v ^= poly_rev;
254 } else {
255 v >>= 1;
256 }
257 }
258
259 *e = v;
260 }
261
262 lookup_table
263 }
264
265 fn crc_table(poly: u32, bits: u8) -> [u32; 256] {
266 let mut lookup_table = [0u32; 256];
267
268 let mask1 = 1u32 << u32::from(bits - 1);
269
270 let mask2 = ((mask1 - 1) << 1) | 1;
271
272 for (i, e) in lookup_table.iter_mut().enumerate() {
273 let mut v = i as u32;
274
275 #[allow(clippy::branches_sharing_code)]
276 for _ in 0..bits {
277 if v & mask1 == 0 {
278 v <<= 1;
279 } else {
280 v <<= 1;
281 v ^= poly;
282 }
283 }
284
285 *e = v & mask2;
286 }
287
288 lookup_table
289 }
290}
291
292#[cfg(feature = "alloc")]
293impl CRCu32 {
294 #[inline]
296 pub fn get_crc_vec_le(&mut self) -> Vec<u8> {
297 let crc = self.get_crc();
298
299 let e = (self.bits as usize + 7) >> 3;
300
301 crc.to_le_bytes()[..e].to_vec()
302 }
303
304 #[inline]
306 pub fn get_crc_vec_be(&mut self) -> Vec<u8> {
307 let crc = self.get_crc();
308
309 let e = (self.bits as usize + 7) >> 3;
310
311 crc.to_be_bytes()[(4 - e)..].to_vec()
312 }
313}
314
315#[cfg(feature = "heapless")]
316impl CRCu32 {
317 #[inline]
319 pub fn get_crc_heapless_vec_le(&mut self) -> HeaplessVec<u8, 4> {
320 let crc = self.get_crc();
321
322 let e = (self.bits as usize + 7) >> 3;
323
324 let mut vec = HeaplessVec::new();
325
326 vec.extend_from_slice(&crc.to_le_bytes()[..e]).unwrap();
327
328 vec
329 }
330
331 #[inline]
333 pub fn get_crc_heapless_vec_be(&mut self) -> HeaplessVec<u8, 4> {
334 let crc = self.get_crc();
335
336 let e = (self.bits as usize + 7) >> 3;
337
338 let mut vec = HeaplessVec::new();
339
340 vec.extend_from_slice(&crc.to_be_bytes()[(4 - e)..]).unwrap();
341
342 vec
343 }
344}
345
346impl CRCu32 {
347 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x04F03\", &crc.to_string());")]
356 pub fn crc17can() -> CRCu32 {
358 Self::create_crc(0x0001685B, 17, 0x00000000, 0x00000000, false)
359 }
360
361 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x0ED841\", &crc.to_string());")]
370 pub fn crc21can() -> CRCu32 {
372 Self::create_crc(0x00102899, 21, 0x00000000, 0x00000000, false)
373 }
374
375 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x21CF02\", &crc.to_string());")]
384 pub fn crc24() -> CRCu32 {
386 let lookup_table = LookUpTable::Static(&NO_REF_24_00864CFB);
389 Self::create_crc_with_exists_lookup_table(lookup_table, 24, 0x00B704CE, 0x00000000, false)
390 }
391
392 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0xC25A56\", &crc.to_string());")]
401 pub fn crc24ble() -> CRCu32 {
403 let lookup_table = LookUpTable::Static(&REF_24_00DA6000);
406 Self::create_crc_with_exists_lookup_table(lookup_table, 24, 0x00555555, 0x00000000, true)
407 }
408
409 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x7979BD\", &crc.to_string());")]
418 pub fn crc24flexray_a() -> CRCu32 {
420 let lookup_table = LookUpTable::Static(&NO_REF_24_005D6DCB);
423 Self::create_crc_with_exists_lookup_table(lookup_table, 24, 0x00FEDCBA, 0x00000000, false)
424 }
425
426 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x1F23B8\", &crc.to_string());")]
435 pub fn crc24flexray_b() -> CRCu32 {
437 let lookup_table = LookUpTable::Static(&NO_REF_24_005D6DCB);
440 Self::create_crc_with_exists_lookup_table(lookup_table, 24, 0x00ABCDEF, 0x00000000, false)
441 }
442
443 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0xCDE703\", &crc.to_string());")]
452 pub fn crc24lte_a() -> CRCu32 {
454 let lookup_table = LookUpTable::Static(&NO_REF_24_00864CFB);
457 Self::create_crc_with_exists_lookup_table(lookup_table, 24, 0x00000000, 0x00000000, false)
458 }
459
460 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x23EF52\", &crc.to_string());")]
469 pub fn crc24lte_b() -> CRCu32 {
471 let lookup_table = LookUpTable::Static(&NO_REF_24_00800063);
474 Self::create_crc_with_exists_lookup_table(lookup_table, 24, 0x00000000, 0x00000000, false)
475 }
476
477 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x200FA5\", &crc.to_string());")]
486 pub fn crc24os9() -> CRCu32 {
488 let lookup_table = LookUpTable::Static(&NO_REF_24_00800063);
491 Self::create_crc_with_exists_lookup_table(lookup_table, 24, 0x00FFFFFF, 0x00FFFFFF, false)
492 }
493
494 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x04C34ABF\", &crc.to_string());")]
503 pub fn crc30cdma() -> CRCu32 {
505 Self::create_crc(0x2030B9C7, 30, 0x3FFFFFFF, 0x3FFFFFFF, false)
506 }
507
508 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0xCBF43926\", &crc.to_string());")]
517 pub fn crc32() -> CRCu32 {
519 let lookup_table = LookUpTable::Static(&REF_32_EDB88320);
522 Self::create_crc_with_exists_lookup_table(lookup_table, 32, 0xFFFFFFFF, 0xFFFFFFFF, true)
523 }
524
525 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x181989FC\", &crc.to_string());")]
536 pub fn crc32mhash() -> CRCu32 {
538 let lookup_table = LookUpTable::Static(&NO_REF_32_04C11DB7);
541
542 let mut crc = Self::create_crc_with_exists_lookup_table(
543 lookup_table,
544 32,
545 0xFFFFFFFF,
546 0xFFFFFFFF,
547 false,
548 );
549
550 crc.reorder = true;
551
552 crc
553 }
554
555 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0xFC891918\", &crc.to_string());")]
564 pub fn crc32bzip2() -> CRCu32 {
566 let lookup_table = LookUpTable::Static(&NO_REF_32_04C11DB7);
569 Self::create_crc_with_exists_lookup_table(lookup_table, 32, 0xFFFFFFFF, 0xFFFFFFFF, false)
570 }
571
572 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0xE3069283\", &crc.to_string());")]
581 pub fn crc32c() -> CRCu32 {
583 let lookup_table = LookUpTable::Static(&REF_32_82F63B78);
586 Self::create_crc_with_exists_lookup_table(lookup_table, 32, 0xFFFFFFFF, 0xFFFFFFFF, true)
587 }
588
589 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x87315576\", &crc.to_string());")]
598 pub fn crc32d() -> CRCu32 {
600 let lookup_table = LookUpTable::Static(&REF_32_D419CC15);
603 Self::create_crc_with_exists_lookup_table(lookup_table, 32, 0xFFFFFFFF, 0xFFFFFFFF, true)
604 }
605
606 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x0376E6E7\", &crc.to_string());")]
615 pub fn crc32mpeg2() -> CRCu32 {
617 let lookup_table = LookUpTable::Static(&NO_REF_32_04C11DB7);
620 Self::create_crc_with_exists_lookup_table(lookup_table, 32, 0xFFFFFFFF, 0x00000000, false)
621 }
622
623 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x765E7680\", &crc.to_string());")]
632 pub fn crc32posix() -> CRCu32 {
634 let lookup_table = LookUpTable::Static(&NO_REF_32_04C11DB7);
637 Self::create_crc_with_exists_lookup_table(lookup_table, 32, 0x00000000, 0xFFFFFFFF, false)
638 }
639
640 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x3010BF7F\", &crc.to_string());")]
649 pub fn crc32q() -> CRCu32 {
651 let lookup_table = LookUpTable::Static(&NO_REF_32_814141AB);
654 Self::create_crc_with_exists_lookup_table(lookup_table, 32, 0x00000000, 0x00000000, false)
655 }
656
657 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0x340BC6D9\", &crc.to_string());")]
666 pub fn crc32jamcrc() -> CRCu32 {
668 let lookup_table = LookUpTable::Static(&REF_32_EDB88320);
671 Self::create_crc_with_exists_lookup_table(lookup_table, 32, 0xFFFFFFFF, 0x00000000, true)
672 }
673
674 #[cfg_attr(feature = "alloc", doc = "assert_eq!(\"0xBD0BE338\", &crc.to_string());")]
683 pub fn crc32xfer() -> CRCu32 {
685 let lookup_table = LookUpTable::Static(&NO_REF_32_000000AF);
688 Self::create_crc_with_exists_lookup_table(lookup_table, 32, 0x00000000, 0x00000000, false)
689 }
690}
691
692#[cfg(all(feature = "development", test))]
693mod tests {
694 use alloc::{fmt::Write, string::String};
695
696 use super::CRCu32;
697
698 #[test]
699 fn print_lookup_table() {
700 let crc = CRCu32::crc24ble();
701
702 let mut s = String::new();
703
704 for n in crc.lookup_table.iter().take(255) {
705 s.write_fmt(format_args!("{}u32, ", n)).unwrap();
706 }
707
708 s.write_fmt(format_args!("{}u32", crc.lookup_table[255])).unwrap();
709
710 println!("let lookup_table = [{}];", s);
711 }
712}