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 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}