embedded_wg_display/storage/
mod.rs1use crate::util::hasher::Hasher;
7use common::models::{SystemConfiguration, WidgetInstallationData};
8use defmt::info;
9use esp_bootloader_esp_idf::partitions;
10use esp_hal::peripherals::FLASH;
11use esp_hal::peripherals::SHA;
12use esp_nvs::{Key, Nvs, error::Error as NvsError};
13use esp_storage::{FlashStorage, FlashStorageError};
14
15pub struct Storage<'d> {
16 nvs: Nvs<FlashStorage<'d>>,
17 hasher: Hasher<'d>,
18 config_updated: bool,
19}
20
21#[derive(Debug, defmt::Format)]
23pub enum StorageError {
24 Flash(esp_storage::FlashStorageError),
26 Partition(partitions::Error),
28 PartitionNotFound,
30 Nvs(NvsError),
32}
33
34impl From<FlashStorageError> for StorageError {
35 fn from(e: FlashStorageError) -> Self {
36 StorageError::Flash(e)
37 }
38}
39
40impl From<partitions::Error> for StorageError {
41 fn from(e: partitions::Error) -> Self {
42 StorageError::Partition(e)
43 }
44}
45
46impl From<NvsError> for StorageError {
47 fn from(e: NvsError) -> Self {
48 StorageError::Nvs(e)
49 }
50}
51
52impl<'d> Storage<'d> {
53 fn wasm_key_from_name(&mut self, name: &str) -> Key {
54 let digest = self.hasher.hash(name);
56 let mut key_bytes = [b'0'; 15];
57 const HEX: &[u8; 16] = b"0123456789abcdef";
58
59 for i in 0..7 {
60 key_bytes[2 * i] = HEX[(digest[i] >> 4) as usize];
61 key_bytes[2 * i + 1] = HEX[(digest[i] & 0x0f) as usize];
62 }
63 key_bytes[14] = HEX[(digest[7] >> 4) as usize];
64
65 Key::from_array(&key_bytes)
66 }
67
68 pub fn new(flash: FLASH<'d>, sha_peripherals: SHA<'d>) -> Result<Self, StorageError> {
71 let mut flash_storage = FlashStorage::new(flash).multicore_auto_park();
72
73 let mut partition_table_buffer =
76 alloc::boxed::Box::new([0u8; partitions::PARTITION_TABLE_MAX_LEN]);
77 let partition_table =
78 partitions::read_partition_table(&mut flash_storage, &mut *partition_table_buffer)?;
79
80 defmt::info!("Partition table:");
82 for partition in partition_table.iter() {
83 defmt::info!(
84 " {}: offset=0x{:x}, size=0x{:x}",
85 partition.label_as_str(),
86 partition.offset(),
87 partition.len()
88 );
89 }
90
91 let storage = partition_table
93 .iter()
94 .find(|p| p.label_as_str() == "storage")
95 .ok_or(StorageError::PartitionNotFound)?;
96
97 let nvs = Nvs::new(
98 storage.offset() as usize,
99 storage.len() as usize,
100 flash_storage,
101 )?;
102
103 Ok(Self {
104 nvs,
105 hasher: Hasher::new(sha_peripherals),
106 config_updated: false,
107 })
108 }
109
110 pub fn save_system_config(
114 &mut self,
115 system_config: &SystemConfiguration,
116 ) -> Result<(), StorageError> {
117 if let Ok(current_config) = self.get_system_config()
119 && current_config == *system_config
120 {
121 info!("System config unchanged, not saving to flash");
122 return Ok(());
123 }
124
125 let value = serde_json::to_string(system_config)
126 .map_err(|_| StorageError::Nvs(NvsError::FlashError))?;
127 self.config_set("system_config", &value)?;
128 self.config_updated = true;
129 Ok(())
130 }
131
132 pub fn get_system_config(&mut self) -> Result<SystemConfiguration, StorageError> {
134 let value: alloc::string::String = self.config_get("system_config")?;
135 let config: SystemConfiguration =
136 serde_json::from_str(&value).map_err(|_| StorageError::Nvs(NvsError::FlashError))?;
137 Ok(config)
138 }
139
140 pub fn get_system_config_change(&mut self) -> Option<SystemConfiguration> {
143 if self.config_updated {
144 self.config_updated = false;
145 match self.get_system_config() {
146 Ok(config) => Some(config),
147 Err(err) => {
148 info!("Error getting updated config: {:?}", err);
149 None
150 }
151 }
152 } else {
153 None
154 }
155 }
156
157 pub fn save_compiled_widget(
159 &mut self,
160 widget_metadata: WidgetInstallationData,
161 data: &[u8],
162 ) -> Result<(), StorageError> {
163 self.wasm_write(&widget_metadata.name, data)?;
164 let mut config = self.get_system_config()?;
165 config.widgets.push(widget_metadata);
166 self.save_system_config(&config)?;
167 Ok(())
168 }
169
170 pub fn deinstall_widget(&mut self, name: &str) -> Result<(), StorageError> {
172 self.wasm_delete(name)?; let mut config = self.get_system_config()?;
175 config.widgets.retain(|w| w.name != name);
176 self.save_system_config(&config)?;
177 Ok(())
178 }
179
180 pub fn config_set(&mut self, key: &str, value: &str) -> Result<(), StorageError> {
182 info!("Setting config for key '{}'", key);
183 let ns = Key::from_str("config");
184 let k = Key::from_str(key);
185 self.nvs.set(&ns, &k, value)?;
186 Ok(())
187 }
188
189 pub fn config_get(&mut self, key: &str) -> Result<alloc::string::String, StorageError> {
191 info!("Getting config for key '{}'", key);
192 let ns = Key::from_str("config");
193 let k = Key::from_str(key);
194 Ok(self.nvs.get(&ns, &k)?)
195 }
196
197 pub fn wasm_write(&mut self, name: &str, data: &[u8]) -> Result<(), StorageError> {
199 let key = self.wasm_key_from_name(name);
200 let ns = Key::from_str("wasm");
201 info!(
202 "Writing WASM binary with name: '{}' and key: {:?}",
203 name, key
204 );
205 self.nvs.set(&ns, &key, data)?;
206 Ok(())
207 }
208
209 pub fn wasm_read(&mut self, name: &str) -> Result<alloc::vec::Vec<u8>, StorageError> {
211 let key = self.wasm_key_from_name(name);
212 let ns = Key::from_str("wasm");
213 info!(
214 "Reading WASM binary with name: '{}' and key: {:?}",
215 name, key
216 );
217 Ok(self.nvs.get(&ns, &key)?)
218 }
219
220 pub fn wasm_delete(&mut self, name: &str) -> Result<(), StorageError> {
222 let key = self.wasm_key_from_name(name);
223 let ns = Key::from_str("wasm");
224 info!(
225 "Deleting WASM binary with name: '{}' and key: {:?}",
226 name, key
227 );
228 self.nvs.delete(&ns, &key)?;
229 Ok(())
230 }
231
232 #[allow(dead_code)]
234 pub fn list_widgets(&mut self) -> Result<alloc::vec::Vec<alloc::string::String>, StorageError> {
235 let config = self.get_system_config()?;
236 Ok(config.widgets.iter().map(|w| w.name.clone()).collect())
237 }
238}