1use embassy_hal_internal::Peri;
7
8use crate::{module_stop::ModuleStop, pac::crc::vals::Gps, peripherals::CRC};
9
10#[derive(Default, Copy, Clone, PartialEq)]
12pub enum Polynomial {
13 None,
15
16 Crc8,
18
19 #[default]
21 Crc16,
22
23 CrcCcit,
25
26 Crc32,
28
29 Crc32C,
31}
32
33#[derive(Default)]
35pub struct Config {
36 #[allow(missing_docs)]
37 pub polynomial: Polynomial,
38 pub reverse: bool,
41 pub seed: u32,
43 pub reflect_output: bool,
45}
46
47pub struct Crc<'d> {
49 _peri: Peri<'d, CRC>,
50 config: Config,
51}
52
53impl<'d> Crc<'d> {
54 pub fn new(peri: Peri<'d, CRC>, config: Config) -> Self {
64 CRC::start_module();
65
66 let mut instance = Self {
67 _peri: peri,
68 config,
69 };
70
71 instance.reset();
72 instance
73 }
74
75 pub fn set_config(&mut self, config: Config) {
80 self.config = config;
81 self.reset();
82 }
83
84 pub fn reset(&mut self) {
86 let crc = crate::pac::CRC;
87
88 let gps = match self.config.polynomial {
89 Polynomial::None => Gps::None,
90 Polynomial::Crc8 => Gps::Crc8,
91 Polynomial::Crc16 => Gps::Crc16,
92 Polynomial::CrcCcit => Gps::CrcCcit,
93 Polynomial::Crc32 => Gps::Crc32,
94 Polynomial::Crc32C => Gps::Crc32C,
95 };
96
97 let lms = !self.config.reverse;
98
99 crc.crccr0().write(|w| {
100 w.set_gps(gps);
101 w.set_lms(lms);
102 w.set_dorclr(true);
103 });
104
105 if self.config.seed != 0 {
106 match self.config.polynomial {
107 Polynomial::None => unimplemented!(),
108 Polynomial::Crc8 => {
109 crc.crcdor_by().write_value((self.config.seed & 0xFF) as u8);
110 }
111 Polynomial::Crc16 | Polynomial::CrcCcit => {
112 crc.crcdor_ha()
113 .write_value((self.config.seed & 0xFFFF) as u16);
114 }
115 Polynomial::Crc32 | Polynomial::Crc32C => {
116 crc.crcdor().write_value(self.config.seed);
117 }
118 }
119 }
120 }
121
122 pub fn feed_bytes(&mut self, bytes: &[u8]) {
132 let crc = crate::pac::CRC;
133
134 match self.config.polynomial {
135 Polynomial::Crc8 | Polynomial::Crc16 | Polynomial::CrcCcit => {
136 for byte in bytes.iter() {
137 crc.crcdir_by().write_value(*byte);
138 }
139 }
140 Polynomial::Crc32 | Polynomial::Crc32C => {
141 if !bytes.len().is_multiple_of(4) {
142 unimplemented!("CRC-32 input len must be a multiple of 4");
143 }
144
145 match self.config.reverse {
146 false => {
147 for chunk in bytes.chunks_exact(4) {
148 let word = u32::from_be_bytes(chunk.try_into().unwrap());
149 crc.crcdir().write_value(word);
150 }
151 }
152 true => {
153 for chunk in bytes.chunks_exact(4) {
154 let word = u32::from_ne_bytes(chunk.try_into().unwrap());
155 crc.crcdir().write_value(word);
156 }
157 }
158 }
159 }
160 Polynomial::None => unimplemented!(),
161 };
162 }
163
164 pub fn read(&mut self) -> u32 {
166 let crc = crate::pac::CRC;
167
168 let output = match self.config.polynomial {
169 Polynomial::None => unimplemented!(),
170 Polynomial::Crc8 | Polynomial::Crc16 | Polynomial::CrcCcit => {
171 if self.config.polynomial == Polynomial::Crc8 {
172 crc.crcdor_by().read() as _
173 } else {
174 crc.crcdor_ha().read() as _
175 }
176 }
177 Polynomial::Crc32 | Polynomial::Crc32C => crc.crcdor().read(),
178 };
179
180 if self.config.reflect_output {
181 let mask = match self.config.polynomial {
182 Polynomial::Crc8 => u8::MAX as _,
183 Polynomial::Crc16 | Polynomial::CrcCcit => u16::MAX as _,
184 Polynomial::Crc32 | Polynomial::Crc32C => u32::MAX,
185 _ => unimplemented!(),
186 };
187 (!output) & mask
188 } else {
189 output
190 }
191 }
192}
193
194impl<'d> Drop for Crc<'d> {
195 fn drop(&mut self) {
197 CRC::stop_module();
198 }
199}