1use core::marker::PhantomData;
33
34use super::Nvm;
35use crate::pac::{Nvmctrl, nvmctrl::ctrlb::Cmdselect};
36use crate::typelevel::Sealed;
37
38pub struct SmartEeprom<'a, T: SmartEepromState> {
44    nvm: &'a mut Nvm,
45    virtual_size: usize,
46    __: PhantomData<T>,
47}
48
49pub trait SmartEepromState: Sealed {}
51
52pub enum Locked {}
55impl SmartEepromState for Locked {}
56impl Sealed for Locked {}
57pub enum Unlocked {}
60impl SmartEepromState for Unlocked {}
61impl Sealed for Unlocked {}
62
63#[derive(Debug)]
66pub enum SmartEepromRetrievalFailure {
67    Disabled,
70    DisabledAutomaticPageReallocationNotSupported,
72    BufferedWritesNotSupported,
74    InvalidBlockCount {
79        sblk: u32,
81    },
82}
83
84pub enum SmartEepromMode<'a> {
86    Locked(SmartEeprom<'a, Locked>),
88    Unlocked(SmartEeprom<'a, Unlocked>),
90}
91
92pub type Result<'a> = core::result::Result<SmartEepromMode<'a>, SmartEepromRetrievalFailure>;
94
95#[inline]
96fn wait_if_busy() {
97    let nvmctrl = unsafe { &*Nvmctrl::ptr() };
100    while nvmctrl.seestat().read().busy().bit_is_set() {}
101}
102
103impl<'a> SmartEepromMode<'a> {
104    pub(super) fn retrieve(nvm: &'a mut Nvm) -> Result<'a> {
107        use SmartEepromMode as Mode;
108        use SmartEepromRetrievalFailure::*;
109        if nvm.nvm.seecfg().read().aprdis().bit_is_set() {
110            return Err(DisabledAutomaticPageReallocationNotSupported);
111        }
112        if nvm.nvm.seecfg().read().wmode().is_buffered() {
113            return Err(BufferedWritesNotSupported);
114        }
115        let sblk = nvm.nvm.seestat().read().sblk().bits() as u32;
116        let psz = nvm.nvm.seestat().read().psz().bits() as u32;
117        let virtual_size = match (sblk, psz) {
118            (0, _) => return Err(Disabled),
119            (sblk @ 11..=u32::MAX, _) => return Err(InvalidBlockCount { sblk }),
120            (_, 8..=u32::MAX) => {
121                unreachable!("`Nvmctrl.SEESTAT.PSZ` value is represented with 3 bits in user page")
122            }
123            others => Self::map_sblk_psz_to_virtual_size(others),
124        };
125        if nvm.nvm.seestat().read().lock().bit_is_set() {
126            Ok(Mode::Locked(SmartEeprom {
127                nvm,
128                virtual_size,
129                __: PhantomData::<Locked>,
130            }))
131        } else {
132            Ok(Mode::Unlocked(SmartEeprom {
133                nvm,
134                virtual_size,
135                __: PhantomData::<Unlocked>,
136            }))
137        }
138    }
139
140    fn map_sblk_psz_to_virtual_size(sblk_psz_pair: (u32, u32)) -> usize {
141        match sblk_psz_pair {
142            (_, 0) => 512,
143            (_, 1) => 1024,
144            (_, 2) => 2048,
145            (_, 3) => 4096,
146            (1, _) => 4096,
147            (_, 4) => 8192,
148            (2, _) => 8192,
149            (_, 5) => 16384,
150            (3 | 4, _) => 16384,
151            (_, 6) => 32768,
152            (5..=8, _) => 32768,
153            (_, 7) => 65536,
154            _ => unreachable!(),
155        }
156    }
157}
158
159impl<'a, T: SmartEepromState> SmartEeprom<'a, T> {
160    const SEEPROM_ADDR: *mut usize = 0x44000000 as _;
161
162    pub unsafe fn get_slice<TP: SmartEepromPointableSize>(&self) -> &[TP] {
172        unsafe {
173            core::slice::from_raw_parts_mut(
174                Self::SEEPROM_ADDR as _,
175                self.virtual_size / core::mem::size_of::<TP>(),
176            )
177        }
178    }
179
180    pub fn get<TP: SmartEepromPointableSize>(&self, offset: usize, buffer: &mut [TP]) {
186        let slice = unsafe { self.get_slice() };
187        buffer
188            .iter_mut()
189            .zip(slice.iter().skip(offset))
190            .for_each(|(target, source)| {
191                wait_if_busy();
192                *target = *source
193            });
194    }
195
196    pub fn iter<TP: SmartEepromPointableSize>(&'a self) -> SmartEepromIter<'a, TP> {
198        SmartEepromIter {
199            iter: unsafe { self.get_slice().iter() },
200        }
201    }
202}
203
204pub trait SmartEepromPointableSize: Sealed + Copy {}
207
208impl SmartEepromPointableSize for u8 {}
209impl SmartEepromPointableSize for u16 {}
210impl SmartEepromPointableSize for u32 {}
211
212impl<'a> SmartEeprom<'a, Unlocked> {
213    pub unsafe fn get_mut_slice<TP: SmartEepromPointableSize>(&mut self) -> &mut [TP] {
223        unsafe {
224            core::slice::from_raw_parts_mut(
225                Self::SEEPROM_ADDR as _,
226                self.virtual_size / core::mem::size_of::<TP>(),
227            )
228        }
229    }
230
231    pub fn set<TP: SmartEepromPointableSize>(&mut self, offset: usize, buffer: &[TP]) {
236        let slice = unsafe { self.get_mut_slice() };
237        buffer
238            .iter()
239            .zip(slice.iter_mut().skip(offset))
240            .for_each(|(source, target)| {
241                wait_if_busy();
242                *target = *source
243            });
244    }
245
246    pub fn iter_mut<TP: SmartEepromPointableSize>(&'a mut self) -> SmartEepromIterMut<'a, TP> {
248        SmartEepromIterMut {
249            iter: unsafe { self.get_mut_slice().iter_mut() },
250        }
251    }
252
253    pub fn lock(self) -> SmartEeprom<'a, Locked> {
255        self.nvm
257            .command_sync(Cmdselect::Lsee)
258            .expect("SmartEEPROM locking failed");
259        let Self {
260            nvm, virtual_size, ..
261        } = self;
262        SmartEeprom {
263            nvm,
264            virtual_size,
265            __: PhantomData,
266        }
267    }
268}
269
270impl<'a> SmartEeprom<'a, Locked> {
271    pub fn unlock(self) -> SmartEeprom<'a, Unlocked> {
273        self.nvm
275            .command_sync(Cmdselect::Usee)
276            .expect("SmartEEPROM unlocking failed");
277        let Self {
278            nvm, virtual_size, ..
279        } = self;
280        SmartEeprom {
281            nvm,
282            virtual_size,
283            __: PhantomData,
284        }
285    }
286}
287
288pub struct SmartEepromIter<'a, TP: SmartEepromPointableSize> {
290    iter: core::slice::Iter<'a, TP>,
291}
292
293impl<'a, TP: SmartEepromPointableSize> Iterator for SmartEepromIter<'a, TP> {
294    type Item = &'a TP;
295    fn next(&mut self) -> Option<Self::Item> {
296        wait_if_busy();
297        self.iter.next()
298    }
299}
300
301impl<TP: SmartEepromPointableSize> DoubleEndedIterator for SmartEepromIter<'_, TP> {
302    fn next_back(&mut self) -> Option<Self::Item> {
303        wait_if_busy();
304        self.iter.next_back()
305    }
306}
307
308pub struct SmartEepromIterMut<'a, TP: SmartEepromPointableSize> {
310    iter: core::slice::IterMut<'a, TP>,
311}
312
313impl<'a, TP: SmartEepromPointableSize> Iterator for SmartEepromIterMut<'a, TP> {
314    type Item = &'a mut TP;
315    fn next(&mut self) -> Option<Self::Item> {
316        wait_if_busy();
317        self.iter.next()
318    }
319}
320
321impl<TP: SmartEepromPointableSize> DoubleEndedIterator for SmartEepromIterMut<'_, TP> {
322    fn next_back(&mut self) -> Option<Self::Item> {
323        wait_if_busy();
324        self.iter.next_back()
325    }
326}
327
328#[cfg(test)]
329mod tests {
330    use super::*;
331    #[test]
332    fn test_if_virtual_size_is_mapped_correctly() {
333        fn f(sblk: u32, psz: u32) -> usize {
337            SmartEepromMode::map_sblk_psz_to_virtual_size((sblk, psz))
338        }
339        assert_eq!(f(1, 0), 512);
340        assert_eq!(f(1, 1), 1024);
341        assert_eq!(f(1, 2), 2048);
342        assert_eq!(f(1, 3), 4096);
343        assert_eq!(f(1, 4), 4096);
344        assert_eq!(f(1, 5), 4096);
345        assert_eq!(f(1, 6), 4096);
346        assert_eq!(f(1, 7), 4096);
347        assert_eq!(f(2, 0), 512);
348        assert_eq!(f(2, 1), 1024);
349        assert_eq!(f(2, 2), 2048);
350        assert_eq!(f(2, 3), 4096);
351        assert_eq!(f(2, 4), 8192);
352        assert_eq!(f(2, 5), 8192);
353        assert_eq!(f(2, 6), 8192);
354        assert_eq!(f(2, 7), 8192);
355        assert_eq!(f(3, 0), 512);
356        for i in 3..=4 {
357            assert_eq!(f(i, 1), 1024);
358            assert_eq!(f(i, 2), 2048);
359            assert_eq!(f(i, 3), 4096);
360            assert_eq!(f(i, 4), 8192);
361            assert_eq!(f(i, 5), 16384);
362            assert_eq!(f(i, 6), 16384);
363            assert_eq!(f(i, 7), 16384);
364        }
365        for i in 5..=8 {
366            assert_eq!(f(i, 0), 512);
367            assert_eq!(f(i, 1), 1024);
368            assert_eq!(f(i, 2), 2048);
369            assert_eq!(f(i, 3), 4096);
370            assert_eq!(f(i, 4), 8192);
371            assert_eq!(f(i, 5), 16384);
372            assert_eq!(f(i, 6), 32768);
373            assert_eq!(f(i, 7), 32768);
374        }
375        for i in 9..=10 {
376            assert_eq!(f(i, 0), 512);
377            assert_eq!(f(i, 1), 1024);
378            assert_eq!(f(i, 2), 2048);
379            assert_eq!(f(i, 3), 4096);
380            assert_eq!(f(i, 4), 8192);
381            assert_eq!(f(i, 5), 16384);
382            assert_eq!(f(i, 6), 32768);
383            assert_eq!(f(i, 7), 65536);
384        }
385    }
386}