grapple_config/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3#![doc = include_str!("../README.md")]
4
5use core::{convert::Infallible, marker::PhantomData};
6
7pub trait ConfigurationMarshal<Config>
8{
9  type Error;
10  fn write(&mut self, config: &Config) -> Result<(), Self::Error>;
11  fn read(&mut self) -> Result<Config, Self::Error>;
12}
13
14pub trait GenericConfigurationProvider<Config>
15where
16  Config: Clone
17{
18  fn commit(&mut self) -> bool;
19  fn current(&self) -> &Config;
20  fn current_mut(&mut self) -> &mut Config;
21}
22
23pub struct ConfigurationProvider<Config, Marshal> {
24  volatile: Config,
25  marshal: Marshal,
26  max_retries: usize,
27}
28
29impl<Config, Marshal> ConfigurationProvider<Config, Marshal>
30where
31  Config: Default + Clone,
32  Marshal: ConfigurationMarshal<Config>
33{
34  pub fn new(mut marshal: Marshal) -> Result<Self, Marshal::Error> {
35    let current = marshal.read();
36    match current {
37      Ok(c) => {
38        Ok(Self { marshal, volatile: c, max_retries: 5 })
39      },
40      Err(_) => {
41        let c = Config::default();
42        marshal.write(&c)?;
43        Ok(Self { marshal, volatile: c, max_retries: 5 })
44      },
45    }
46  }
47
48  pub fn set_retries(&mut self, retries: usize) {
49    self.max_retries = retries
50  }
51}
52
53impl<Config, Marshal> GenericConfigurationProvider<Config> for ConfigurationProvider<Config, Marshal>
54where
55  Config: Default + Clone,
56  Marshal: ConfigurationMarshal<Config>
57{
58  fn commit(&mut self) -> bool {
59    let mut i = 0;
60    while self.marshal.write(&self.volatile).is_err() {
61      i = i + 1;
62      if i >= self.max_retries {
63        return false;
64      }
65    }
66    return true;
67  }
68
69  fn current(&self) -> &Config {
70    &self.volatile
71  }
72
73  fn current_mut(&mut self) -> &mut Config {
74    &mut self.volatile
75  }
76}
77
78pub struct VolatileMarshal<Config>(PhantomData<Config>);
79
80impl<Config> VolatileMarshal<Config> {
81  pub fn new() -> Self {
82    Self(PhantomData)
83  }
84}
85
86impl<Config> ConfigurationMarshal<Config> for VolatileMarshal<Config>
87where
88  Config: Default
89{
90  type Error = Infallible;
91
92  fn write(&mut self, _config: &Config) -> Result<(), Self::Error> {
93    Ok(())
94  }
95
96  fn read(&mut self) -> Result<Config, Self::Error> {
97    Ok(Config::default())
98  }
99}
100
101#[cfg(feature = "m24c64")]
102pub mod m24c64 {
103  extern crate alloc;
104
105  use core::marker::PhantomData;
106
107  use binmarshal::{rw::{VecBitWriter, BitWriter, BitView}, Demarshal, DemarshalOwned, Marshal};
108  use embedded_hal::blocking::{i2c, delay::DelayMs};
109  use grapple_m24c64::M24C64;
110  use alloc::vec;
111
112  use crate::ConfigurationMarshal;
113
114  pub struct M24C64ConfigurationMarshal<Config, I2C, Delay> {
115    delay: Delay,
116    address_offset: usize,
117    eeprom: M24C64<I2C>,
118    marker: PhantomData<Config>
119  }
120
121  pub enum M24C64ConfigurationError<E> {
122    Serialisation,
123    I2C(E),
124    BlankEeprom
125  }
126
127  impl<Config, I2C, Delay> M24C64ConfigurationMarshal<Config, I2C, Delay> {
128    #[allow(unused)]
129    pub fn new(eeprom: M24C64<I2C>, address: usize, delay: Delay, marker: PhantomData<Config>) -> Self {
130      Self { delay, address_offset: address, eeprom, marker }
131    }
132  }
133
134  impl<'a, I2C, Delay, Config, E> ConfigurationMarshal<Config> for M24C64ConfigurationMarshal<Config, I2C, Delay>
135  where
136    Config: Marshal<()> + DemarshalOwned + Default + Clone,
137    I2C: i2c::Write<u8, Error = E> + i2c::WriteRead<u8, Error = E>,
138    Delay: DelayMs<u16>
139  {
140    type Error = M24C64ConfigurationError<E>;
141
142    fn write(&mut self, config: &Config) -> Result<(), Self::Error> {
143      // let bytes = config.to_bytes().map_err(|e| Self::Error::Deku(e))?;
144      let mut writer = VecBitWriter::new();
145      if config.clone().write(&mut writer, ()).is_err() {
146        return Err(Self::Error::Serialisation);
147      }
148      self.delay.delay_ms(10u16);
149      let bytes = writer.slice();
150      self.eeprom.write(self.address_offset, &(bytes.len() as u16).to_le_bytes(), &mut self.delay).map_err(|e| Self::Error::I2C(e))?;
151      self.delay.delay_ms(10u16);
152      self.eeprom.write(self.address_offset + 0x02, &bytes[..], &mut self.delay).map_err(|e| Self::Error::I2C(e))?;
153      self.delay.delay_ms(10u16);
154      Ok(())
155    }
156
157    fn read(&mut self) -> Result<Config, Self::Error> {
158      let mut len_buf = [0u8; 2];
159      self.eeprom.read(self.address_offset, &mut len_buf[..]).map_err(|e| Self::Error::I2C(e))?;
160
161      if len_buf[0] == 255 && len_buf[1] == 255 {
162        return Err(Self::Error::BlankEeprom);
163      }
164
165      let mut buf = vec![0u8; u16::from_le_bytes(len_buf) as usize];
166      self.eeprom.read(self.address_offset + 0x02, &mut buf[..]).map_err(|e| Self::Error::I2C(e))?;
167      match Config::read(&mut BitView::new(&buf), ()) {
168        Ok(c) => Ok(c),
169        Err(_) => Err(Self::Error::Serialisation),
170      }
171    }
172  }
173}