1#![cfg_attr(not(test), no_std)]
2
3#![doc = include_str!("../README.md")]
4
5use core::marker::PhantomData;
6
7#[derive(Debug)]
8pub enum ConfigurationError {
9 BusError,
10 SerialisationError,
11 BlankError
12}
13
14impl ConfigurationError {
15 fn can_retry(&self) -> bool {
16 match self {
17 ConfigurationError::BusError => true,
18 ConfigurationError::SerialisationError => false,
19 ConfigurationError::BlankError => false
20 }
21 }
22}
23
24pub trait ConfigurationMarshal<Config>
25{
26 type Error: Into<ConfigurationError>;
27
28 fn write(&mut self, config: &Config) -> Result<(), Self::Error>;
29 fn read(&mut self) -> Result<Config, Self::Error>;
30
31 fn write_with_retry(&mut self, config: &Config, retries: usize) -> Result<(), ConfigurationError> {
32 let mut i = 0;
33
34 while let Err(e) = self.write(&config) {
35 let config_err = e.into();
36 if !config_err.can_retry() {
37 return Err(config_err)
38 }
39
40 i = i + 1;
41 if i >= retries {
42 return Err(config_err)
43 }
44 }
45
46 return Ok(());
47 }
48
49 fn read_with_retry(&mut self, retries: usize) -> Result<Config, ConfigurationError> {
50 let mut i = 0;
51
52 loop {
53 match self.read() {
54 Ok(cfg) => {
55 return Ok(cfg)
56 },
57 Err(e) => {
58 let config_err = e.into();
59 if !config_err.can_retry() {
60 return Err(config_err)
61 }
62
63 i = i + 1;
64 if i >= retries {
65 return Err(config_err)
66 }
67 }
68 }
69 }
70 }
71}
72
73pub trait GenericConfigurationProvider<Config>
74where
75 Config: Clone
76{
77 fn current(&self) -> &Config;
78 fn current_mut(&mut self) -> &mut Config;
79
80 fn commit(&mut self, reload: bool) -> Result<(), ConfigurationError>;
81 fn reload(&mut self) -> Result<(), ConfigurationError>;
82}
83
84pub struct ConfigurationProvider<Config, Marshal> {
85 volatile: Config,
86 marshal: Marshal,
87 max_retries: usize,
88}
89
90impl<Config, Marshal> ConfigurationProvider<Config, Marshal>
91where
92 Config: Default + Clone,
93 Marshal: ConfigurationMarshal<Config>
94{
95 pub fn new(mut marshal: Marshal, max_retries: usize, load_default_if_blank: bool) -> Result<Self, ConfigurationError> {
96 let current = marshal.read_with_retry(5);
97 match current {
98 Ok(c) => Ok(Self { volatile: c, marshal, max_retries }),
99 Err(ConfigurationError::BlankError) if load_default_if_blank => {
100 let c = Config::default();
101 marshal.write_with_retry(&c, max_retries)?;
102 Ok(Self { volatile: c, marshal, max_retries })
103 },
104 Err(e) => Err(e)
105 }
106 }
107
108 pub fn new_or_default(mut marshal: Marshal, max_retries: usize) -> Result<Self, ConfigurationError> {
110 let current = marshal.read_with_retry(5);
111 match current {
112 Ok(c) => Ok(Self { volatile: c, marshal, max_retries }),
113 Err(ConfigurationError::BusError) => {
114 Err(ConfigurationError::BusError)
115 },
116 Err(e) => {
117 let c = Config::default();
118 marshal.write_with_retry(&c, max_retries)?;
119 Ok(Self { volatile: c, marshal, max_retries })
120 },
121 }
122 }
123
124 pub fn set_retries(&mut self, retries: usize) {
125 self.max_retries = retries
126 }
127}
128
129impl<Config, Marshal> GenericConfigurationProvider<Config> for ConfigurationProvider<Config, Marshal>
130where
131 Config: Default + Clone,
132 Marshal: ConfigurationMarshal<Config>
133{
134 fn current(&self) -> &Config {
135 &self.volatile
136 }
137
138 fn current_mut(&mut self) -> &mut Config {
139 &mut self.volatile
140 }
141
142 fn commit(&mut self, reload: bool) -> Result<(), ConfigurationError> {
143 self.marshal.write_with_retry(&self.volatile, self.max_retries)?;
144
145 if reload {
146 self.reload()?;
147 }
148
149 Ok(())
150 }
151
152 fn reload(&mut self) -> Result<(), ConfigurationError> {
153 self.volatile = self.marshal.read_with_retry(self.max_retries)?;
154 Ok(())
155 }
156}
157
158pub struct VolatileMarshal<Config>(PhantomData<Config>);
159
160impl<Config> VolatileMarshal<Config> {
161 pub fn new() -> Self {
162 Self(PhantomData)
163 }
164}
165
166impl<Config> ConfigurationMarshal<Config> for VolatileMarshal<Config>
167where
168 Config: Default
169{
170 type Error = ConfigurationError;
171
172 fn write(&mut self, _config: &Config) -> Result<(), Self::Error> {
173 Ok(())
174 }
175
176 fn read(&mut self) -> Result<Config, Self::Error> {
177 Ok(Config::default())
178 }
179}
180
181#[cfg(feature = "m24c64")]
182pub mod m24c64 {
183 extern crate alloc;
184
185 use core::marker::PhantomData;
186
187 use binmarshal::{DemarshalOwned, Marshal, MarshalError, rw::{BitView, BitWriter, VecBitWriter}};
188 use embedded_hal::blocking::{i2c, delay::DelayMs};
189 use grapple_m24c64::M24C64;
190 use alloc::vec;
191
192 use crate::{ConfigurationError, ConfigurationMarshal};
193
194 pub struct M24C64ConfigurationMarshal<Config, I2C, Delay> {
195 delay: Delay,
196 address_offset: usize,
197 eeprom: M24C64<I2C>,
198 marker: PhantomData<Config>
199 }
200
201 #[derive(Debug)]
202 pub enum M24C64ConfigurationError<E, SErr> {
203 Serialisation(SErr),
204 I2C(E),
205 BlankEeprom
206 }
207
208 impl<E, SErr> Into<ConfigurationError> for M24C64ConfigurationError<E, SErr> {
209 fn into(self) -> ConfigurationError {
210 match self {
211 M24C64ConfigurationError::Serialisation(_) => ConfigurationError::SerialisationError,
212 M24C64ConfigurationError::I2C(_) => ConfigurationError::BusError,
213 M24C64ConfigurationError::BlankEeprom => ConfigurationError::BlankError,
214 }
215 }
216 }
217
218 impl<Config, I2C, Delay> M24C64ConfigurationMarshal<Config, I2C, Delay> {
219 #[allow(unused)]
220 pub fn new(eeprom: M24C64<I2C>, address: usize, delay: Delay) -> Self {
221 Self { delay, address_offset: address, eeprom, marker: PhantomData }
222 }
223 }
224
225 impl<'a, I2C, Delay, Config, E> ConfigurationMarshal<Config> for M24C64ConfigurationMarshal<Config, I2C, Delay>
226 where
227 Config: Marshal<()> + DemarshalOwned + Default + Clone,
228 I2C: i2c::Write<u8, Error = E> + i2c::WriteRead<u8, Error = E>,
229 Delay: DelayMs<u16>
230 {
231 type Error = M24C64ConfigurationError<E, MarshalError>;
232
233 fn write(&mut self, config: &Config) -> Result<(), Self::Error> {
234 let mut writer = VecBitWriter::new();
235 if let Err(e) = config.clone().write(&mut writer, ()) {
236 return Err(Self::Error::Serialisation(e));
237 }
238 self.delay.delay_ms(10u16);
239 let bytes = writer.slice();
240 self.eeprom.write(self.address_offset, &(bytes.len() as u16).to_le_bytes(), &mut self.delay).map_err(|e| Self::Error::I2C(e))?;
241 self.delay.delay_ms(10u16);
242 self.eeprom.write(self.address_offset + 0x02, &bytes[..], &mut self.delay).map_err(|e| Self::Error::I2C(e))?;
243 self.delay.delay_ms(10u16);
244 Ok(())
245 }
246
247 fn read(&mut self) -> Result<Config, Self::Error> {
248 let mut len_buf = [0u8; 2];
249 self.delay.delay_ms(1u16);
250 self.eeprom.read(self.address_offset, &mut len_buf[..]).map_err(|e| Self::Error::I2C(e))?;
251
252 if len_buf[0] == 255 && len_buf[1] == 255 {
253 return Err(Self::Error::BlankEeprom);
254 }
255
256 let mut buf = vec![0u8; u16::from_le_bytes(len_buf) as usize];
257 self.eeprom.read(self.address_offset + 0x02, &mut buf[..]).map_err(|e| Self::Error::I2C(e))?;
258 match Config::read(&mut BitView::new(&buf), ()) {
259 Ok(c) => Ok(c),
260 Err(e) => Err(Self::Error::Serialisation(e)),
261 }
262 }
263 }
264}