1use crate::{dfu, metadata::ApplicationMetadata};
26use embassy_futures::block_on;
27use embedded_io::{Read as EioRead, ReadReady, Write as EioWrite, WriteReady};
28use embedded_storage_async::nor_flash::NorFlash;
29use heapless::{String, Vec};
30use miniconf::{
31 Path, TreeDeserializeOwned, TreeSchema, TreeSerialize, postcard,
32};
33use sequential_storage::{
34 cache::NoCache,
35 map::{SerializationError, fetch_item, store_item},
36};
37use serial_settings::{BestEffortInterface, Platform, Settings};
38
39#[derive(
40 Default, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq,
41)]
42pub struct SettingsKey(Vec<u8, 128>);
43
44impl sequential_storage::map::Key for SettingsKey {
45 fn serialize_into(
46 &self,
47 buffer: &mut [u8],
48 ) -> Result<usize, SerializationError> {
49 Ok(::postcard::to_slice(self, buffer)
50 .map_err(|_| SerializationError::BufferTooSmall)?
51 .len())
52 }
53
54 fn deserialize_from(
55 buffer: &[u8],
56 ) -> Result<(Self, usize), SerializationError> {
57 let original_length = buffer.len();
58 let (result, remainder) = ::postcard::take_from_bytes(buffer)
59 .map_err(|_| SerializationError::BufferTooSmall)?;
60 Ok((result, original_length - remainder.len()))
61 }
62}
63
64pub struct SerialSettingsPlatform<C, F, S> {
65 pub interface: BestEffortInterface<S>,
67
68 pub _settings_marker: core::marker::PhantomData<C>,
69
70 pub storage: F,
72
73 pub metadata: &'static ApplicationMetadata,
75}
76
77impl<C, F, S> SerialSettingsPlatform<C, F, S>
78where
79 C: TreeDeserializeOwned + TreeSerialize + TreeSchema,
80 F: NorFlash,
81{
82 pub fn load(structure: &mut C, storage: &mut F) {
83 let mut buffer = [0u8; 512];
85 for path in C::SCHEMA
86 .nodes::<Path<String<128>, '/'>, { serial_settings::MAX_DEPTH }>()
87 {
88 let path = path.unwrap();
89
90 let value: &[u8] = match block_on(fetch_item(
92 storage,
93 0..storage.capacity() as _,
94 &mut NoCache::new(),
95 &mut buffer,
96 &SettingsKey(path.clone().into_inner().into_bytes()),
97 )) {
98 Err(e) => {
99 log::warn!(
100 "Failed to fetch `{}` from flash: {e:?}",
101 path.0.as_str()
102 );
103 continue;
104 }
105 Ok(Some(value)) => value,
106 Ok(None) => continue,
107 };
108
109 if value.is_empty() {
112 continue;
113 }
114
115 log::info!("Loading initial `{}` from flash", path.0.as_str());
116
117 let flavor = ::postcard::de_flavors::Slice::new(value);
118 if let Err(e) = postcard::set_by_key(structure, &path, flavor) {
119 log::warn!(
120 "Failed to deserialize `{}` from flash: {e:?}",
121 path.0.as_str()
122 );
123 }
124 }
125 }
126}
127
128impl<C, F, S> Platform for SerialSettingsPlatform<C, F, S>
129where
130 C: Settings,
131 F: NorFlash,
132 S: EioWrite + WriteReady + ReadReady + EioRead,
133{
134 type Interface = BestEffortInterface<S>;
135 type Settings = C;
136 type Error = sequential_storage::Error<F::Error>;
137
138 fn fetch<'a>(
139 &mut self,
140 buf: &'a mut [u8],
141 key: &[u8],
142 ) -> Result<Option<&'a [u8]>, Self::Error> {
143 let range = 0..self.storage.capacity() as _;
144 block_on(fetch_item(
145 &mut self.storage,
146 range,
147 &mut NoCache::new(),
148 buf,
149 &SettingsKey(Vec::try_from(key).unwrap()),
150 ))
151 .map(|v| v.filter(|v: &&[u8]| !v.is_empty()))
152 }
153
154 fn store(
155 &mut self,
156 buf: &mut [u8],
157 key: &[u8],
158 value: &[u8],
159 ) -> Result<(), Self::Error> {
160 let range = 0..self.storage.capacity() as _;
161 block_on(store_item(
162 &mut self.storage,
163 range,
164 &mut NoCache::new(),
165 buf,
166 &SettingsKey(Vec::try_from(key).unwrap()),
167 &value,
168 ))
169 }
170
171 fn clear(&mut self, buf: &mut [u8], key: &[u8]) -> Result<(), Self::Error> {
172 self.store(buf, key, b"")
173 }
174
175 fn cmd(&mut self, cmd: &str) {
176 match cmd {
177 "reboot" => cortex_m::peripheral::SCB::sys_reset(),
178 "dfu" => dfu::dfu_reboot(),
179 "service" => {
180 write!(&mut self.interface, "{}", &self.metadata).unwrap();
181 }
182 _ => {
183 writeln!(
184 self.interface_mut(),
185 "Invalid platform command: `{cmd}` not in [`dfu`, `reboot`, `service`]"
186 )
187 .ok();
188 }
189 }
190 }
191
192 fn interface_mut(&mut self) -> &mut Self::Interface {
193 &mut self.interface
194 }
195}