1#![no_std]
40
41use core::ops::Range;
42
43use embassy_sync::blocking_mutex::raw::RawMutex;
44use embassy_sync::mutex::Mutex;
45use embedded_storage_async::nor_flash::MultiwriteNorFlash;
46use heapless::Vec;
47use sequential_storage::cache::NoCache;
48use sequential_storage::map::{MapConfig, MapStorage};
49
50pub const MAX_KEY_LEN: usize = 64;
54
55pub const SCRATCH_LEN: usize = 512;
60
61type StoreKey = Vec<u8, MAX_KEY_LEN>;
64
65pub const MAX_PEERS: usize = 8;
68
69pub const MAX_ALIAS_LEN: usize = 16;
71
72pub const ALIAS_HEADER_LEN: usize = 1 + MAX_ALIAS_LEN; pub const MAX_PEER_RECORD_LEN: usize = 256;
87
88#[derive(Debug)]
91pub enum Error<E> {
92 KeyTooLong,
94 ValueTooLong,
96 PeerIndexFull,
98 CorruptedData,
100 Storage(sequential_storage::Error<E>),
103}
104
105impl<E> From<sequential_storage::Error<E>> for Error<E> {
106 fn from(err: sequential_storage::Error<E>) -> Self {
107 Self::Storage(err)
108 }
109}
110
111pub struct FlashStore<F, M>
117where
118 F: MultiwriteNorFlash,
119 M: RawMutex,
120{
121 map: Mutex<M, MapStorage<StoreKey, F, NoCache>>,
122}
123
124impl<F, M> FlashStore<F, M>
125where
126 F: MultiwriteNorFlash,
127 M: RawMutex,
128{
129 pub fn new(flash: F, range: Range<u32>) -> Self {
137 let cfg = MapConfig::new(range);
138 Self {
139 map: Mutex::new(MapStorage::new(flash, cfg, NoCache::new())),
140 }
141 }
142
143 async fn load_bytes(
144 &self,
145 key: &[u8],
146 out: &mut [u8],
147 ) -> Result<Option<usize>, Error<F::Error>> {
148 let store_key = make_key(key)?;
149 let mut scratch = [0u8; SCRATCH_LEN];
150 let mut guard = self.map.lock().await;
151 let result: Option<&[u8]> = guard.fetch_item(&mut scratch, &store_key).await?;
152 match result {
153 None => Ok(None),
154 Some(bytes) => {
155 if bytes.len() > out.len() {
156 return Err(Error::ValueTooLong);
157 }
158 out[..bytes.len()].copy_from_slice(bytes);
159 Ok(Some(bytes.len()))
160 }
161 }
162 }
163
164 async fn store_bytes(&self, key: &[u8], value: &[u8]) -> Result<(), Error<F::Error>> {
165 let store_key = make_key(key)?;
166 let mut scratch = [0u8; SCRATCH_LEN];
167 let mut guard = self.map.lock().await;
168 guard.store_item(&mut scratch, &store_key, &value).await?;
169 Ok(())
170 }
171
172 async fn delete_bytes(&self, key: &[u8]) -> Result<(), Error<F::Error>> {
173 let store_key = make_key(key)?;
174 let mut scratch = [0u8; SCRATCH_LEN];
175 let mut guard = self.map.lock().await;
176 guard.remove_item(&mut scratch, &store_key).await?;
177 Ok(())
178 }
179}
180
181fn make_key<E>(bytes: &[u8]) -> Result<StoreKey, Error<E>> {
182 StoreKey::from_slice(bytes).map_err(|_| Error::KeyTooLong)
183}
184
185const SK_KEY: &[u8] = b"id.sk";
189const TRACKER_PREFERENCES_KEY: &[u8] = b"ux.tracker";
190
191impl<F, M> FlashStore<F, M>
192where
193 F: MultiwriteNorFlash,
194 M: RawMutex,
195{
196 pub async fn load_tracker_preferences(&self) -> Result<Option<u8>, Error<F::Error>> {
198 let mut byte = [0u8; 1];
199 match self.load_bytes(TRACKER_PREFERENCES_KEY, &mut byte).await? {
200 Some(1) => Ok(Some(byte[0])),
201 Some(_) => Err(Error::CorruptedData),
202 None => Ok(None),
203 }
204 }
205
206 pub async fn store_tracker_preferences(&self, value: u8) -> Result<(), Error<F::Error>> {
208 self.store_bytes(TRACKER_PREFERENCES_KEY, &[value]).await
209 }
210
211 pub async fn load_sk(&self) -> Result<Option<[u8; 32]>, Error<F::Error>> {
217 let mut buf = [0u8; 32];
218 match self.load_bytes(SK_KEY, &mut buf).await? {
219 Some(32) => Ok(Some(buf)),
220 Some(_) | None => Ok(None),
222 }
223 }
224
225 pub async fn store_sk(&self, sk: &[u8; 32]) -> Result<(), Error<F::Error>> {
232 self.store_bytes(SK_KEY, sk).await
233 }
234}
235
236const PEER_INDEX_KEY: &[u8] = b"peers";
240const PEER_KEY_PREFIX: &[u8] = b"peer:";
242
243fn make_peer_key<E>(pk: &[u8; 32]) -> Result<StoreKey, Error<E>> {
244 let mut key = StoreKey::new();
245 let r1 = key.extend_from_slice(PEER_KEY_PREFIX);
246 let r2 = key.extend_from_slice(pk);
247 if r1.is_err() || r2.is_err() {
248 return Err(Error::KeyTooLong);
249 }
250 Ok(key)
251}
252
253impl<F, M> FlashStore<F, M>
254where
255 F: MultiwriteNorFlash,
256 M: RawMutex,
257{
258 pub async fn load_all_peers<const N: usize>(
263 &self,
264 out: &mut Vec<([u8; 32], Option<heapless::String<MAX_ALIAS_LEN>>), N>,
265 ) -> Result<(), Error<F::Error>> {
266 let mut index_buf = [0u8; 32 * MAX_PEERS];
267 let n = match self.load_bytes(PEER_INDEX_KEY, &mut index_buf).await? {
268 None => return Ok(()),
269 Some(n) if n % 32 == 0 => n,
270 Some(_) => return Err(Error::CorruptedData),
271 };
272 for chunk in index_buf[..n].chunks_exact(32) {
273 let mut pk = [0u8; 32];
274 pk.copy_from_slice(chunk);
275 let alias = self.load_peer_alias(&pk).await?;
276 let _ = out.push((pk, alias));
277 }
278 Ok(())
279 }
280
281 async fn read_peer_record(
287 &self,
288 pk: &[u8; 32],
289 ) -> Result<Option<([u8; MAX_PEER_RECORD_LEN], usize)>, Error<F::Error>> {
290 let key = make_peer_key(pk)?;
291 let mut buf = [0u8; MAX_PEER_RECORD_LEN];
292 match self.load_bytes(&key, &mut buf).await? {
293 None => Ok(None),
294 Some(n) => Ok(Some((buf, n))),
295 }
296 }
297
298 async fn load_peer_alias(
299 &self,
300 pk: &[u8; 32],
301 ) -> Result<Option<heapless::String<MAX_ALIAS_LEN>>, Error<F::Error>> {
302 let (buf, n) = match self.read_peer_record(pk).await? {
303 None => return Ok(None),
304 Some(x) => x,
305 };
306 if n < 1 {
307 return Ok(None);
308 }
309 let alias_len = buf[0] as usize;
310 if alias_len == 0 || n < 1 + alias_len {
311 return Ok(None);
312 }
313 let s = core::str::from_utf8(&buf[1..1 + alias_len]).map_err(|_| Error::CorruptedData)?;
314 Ok(heapless::String::try_from(s).ok())
315 }
316
317 pub async fn store_peer_entry(
323 &self,
324 pk: &[u8; 32],
325 alias: Option<&[u8]>,
326 ) -> Result<(), Error<F::Error>> {
327 let key = make_peer_key(pk)?;
328
329 let (mut value, existing_len) = match self.read_peer_record(pk).await? {
331 Some((buf, n)) => (buf, n),
332 None => ([0u8; MAX_PEER_RECORD_LEN], ALIAS_HEADER_LEN),
333 };
334 let identity_end = existing_len.max(ALIAS_HEADER_LEN);
335
336 value[0] = 0;
338 if let Some(a) = alias {
339 if a.len() > MAX_ALIAS_LEN {
340 return Err(Error::ValueTooLong);
341 }
342 value[0] = a.len() as u8;
343 value[1..1 + a.len()].copy_from_slice(a);
344 value[1 + a.len()..ALIAS_HEADER_LEN].fill(0);
346 } else {
347 value[1..ALIAS_HEADER_LEN].fill(0);
348 }
349
350 self.store_bytes(&key, &value[..identity_end]).await?;
351
352 let mut index_buf = [0u8; 32 * MAX_PEERS];
354 let existing_n = match self.load_bytes(PEER_INDEX_KEY, &mut index_buf).await? {
355 Some(n) => n,
356 None => 0,
357 };
358 let already_present = index_buf[..existing_n]
359 .chunks_exact(32)
360 .any(|c| c == pk.as_slice());
361 if !already_present {
362 let new_n = existing_n + 32;
363 if new_n > index_buf.len() {
364 return Err(Error::PeerIndexFull);
365 }
366 index_buf[existing_n..new_n].copy_from_slice(pk);
367 self.store_bytes(PEER_INDEX_KEY, &index_buf[..new_n])
368 .await?;
369 }
370 Ok(())
371 }
372
373 pub async fn update_peer_identity(
379 &self,
380 pk: &[u8; 32],
381 identity_bytes: &[u8],
382 ) -> Result<(), Error<F::Error>> {
383 let new_len = ALIAS_HEADER_LEN + identity_bytes.len();
384 if new_len > MAX_PEER_RECORD_LEN {
385 return Err(Error::ValueTooLong);
386 }
387 let key = make_peer_key(pk)?;
388
389 let (mut value, _) = match self.read_peer_record(pk).await? {
391 Some(x) => x,
392 None => ([0u8; MAX_PEER_RECORD_LEN], 0), };
394
395 value[ALIAS_HEADER_LEN..new_len].copy_from_slice(identity_bytes);
396 self.store_bytes(&key, &value[..new_len]).await?;
397 Ok(())
398 }
399
400 pub async fn load_peer_identity(
405 &self,
406 pk: &[u8; 32],
407 out: &mut [u8],
408 ) -> Result<Option<usize>, Error<F::Error>> {
409 let (buf, n) = match self.read_peer_record(pk).await? {
410 None => return Ok(None),
411 Some(x) => x,
412 };
413 if n <= ALIAS_HEADER_LEN {
414 return Ok(None);
415 }
416 let identity = &buf[ALIAS_HEADER_LEN..n];
417 if identity.len() > out.len() {
418 return Err(Error::ValueTooLong);
419 }
420 out[..identity.len()].copy_from_slice(identity);
421 Ok(Some(identity.len()))
422 }
423
424 pub async fn peer_exists(&self, pk: &[u8; 32]) -> Result<bool, Error<F::Error>> {
429 let mut index_buf = [0u8; 32 * MAX_PEERS];
430 let n = match self.load_bytes(PEER_INDEX_KEY, &mut index_buf).await? {
431 Some(n) => n,
432 None => return Ok(false),
433 };
434 Ok(index_buf[..n].chunks_exact(32).any(|c| c == pk.as_slice()))
435 }
436
437 pub async fn delete_peer_entry(&self, pk: &[u8; 32]) -> Result<(), Error<F::Error>> {
440 let key = make_peer_key(pk)?;
442 let _ = self.delete_bytes(&key).await;
443
444 let mut index_buf = [0u8; 32 * MAX_PEERS];
446 let n = match self.load_bytes(PEER_INDEX_KEY, &mut index_buf).await? {
447 Some(n) => n,
448 None => return Ok(()),
449 };
450 let mut new_buf = [0u8; 32 * MAX_PEERS];
451 let mut new_n = 0usize;
452 for chunk in index_buf[..n].chunks_exact(32) {
453 if chunk != pk.as_slice() {
454 new_buf[new_n..new_n + 32].copy_from_slice(chunk);
455 new_n += 32;
456 }
457 }
458 if new_n == 0 {
459 let _ = self.delete_bytes(PEER_INDEX_KEY).await;
460 } else {
461 self.store_bytes(PEER_INDEX_KEY, &new_buf[..new_n]).await?;
462 }
463 Ok(())
464 }
465}
466
467const CH_INDEX_KEY: &[u8] = b"channels";
471const CH_KEY_PREFIX: &[u8] = b"ch:";
473pub const MAX_CHANNEL_NAME_LEN: usize = 16;
475const CH_NAME_SLOT_LEN: usize = 1 + MAX_CHANNEL_NAME_LEN;
478pub const MAX_CHANNELS: usize = 8;
480
481fn make_channel_key<E>(name: &[u8]) -> Result<StoreKey, Error<E>> {
482 if name.len() > MAX_CHANNEL_NAME_LEN {
483 return Err(Error::KeyTooLong);
484 }
485 let mut key = StoreKey::new();
486 let r1 = key.extend_from_slice(CH_KEY_PREFIX);
487 let r2 = key.extend_from_slice(name);
488 if r1.is_err() || r2.is_err() {
489 return Err(Error::KeyTooLong);
490 }
491 Ok(key)
492}
493
494impl<F, M> FlashStore<F, M>
495where
496 F: MultiwriteNorFlash,
497 M: RawMutex,
498{
499 pub async fn load_all_channels<const N: usize>(
504 &self,
505 out: &mut Vec<(heapless::String<MAX_CHANNEL_NAME_LEN>, [u8; 32]), N>,
506 ) -> Result<(), Error<F::Error>> {
507 let mut index_buf = [0u8; CH_NAME_SLOT_LEN * MAX_CHANNELS];
508 let n = match self.load_bytes(CH_INDEX_KEY, &mut index_buf).await? {
509 None => return Ok(()),
510 Some(n) if n % CH_NAME_SLOT_LEN == 0 => n,
511 Some(_) => return Err(Error::CorruptedData),
512 };
513 for slot in index_buf[..n].chunks_exact(CH_NAME_SLOT_LEN) {
514 let name_len = slot[0] as usize;
515 if name_len == 0 || name_len > MAX_CHANNEL_NAME_LEN {
516 continue;
517 }
518 let name_bytes = &slot[1..1 + name_len];
519 let name = match core::str::from_utf8(name_bytes) {
520 Ok(s) => match heapless::String::try_from(s) {
521 Ok(h) => h,
522 Err(_) => continue,
523 },
524 Err(_) => continue,
525 };
526 let key_bytes = match self.load_channel_key(name_bytes).await? {
527 Some(k) => k,
528 None => continue,
529 };
530 let _ = out.push((name, key_bytes));
531 }
532 Ok(())
533 }
534
535 async fn load_channel_key(&self, name: &[u8]) -> Result<Option<[u8; 32]>, Error<F::Error>> {
536 let key = make_channel_key(name)?;
537 let mut buf = [0u8; 32];
538 match self.load_bytes(&key, &mut buf).await? {
539 Some(32) => Ok(Some(buf)),
540 _ => Ok(None),
541 }
542 }
543
544 pub async fn store_channel_entry(
549 &self,
550 name: &[u8],
551 key: &[u8; 32],
552 ) -> Result<(), Error<F::Error>> {
553 if name.len() > MAX_CHANNEL_NAME_LEN {
554 return Err(Error::ValueTooLong);
555 }
556 let ch_key = make_channel_key(name)?;
558 self.store_bytes(&ch_key, key).await?;
559
560 let mut index_buf = [0u8; CH_NAME_SLOT_LEN * MAX_CHANNELS];
562 let existing_n = match self.load_bytes(CH_INDEX_KEY, &mut index_buf).await? {
563 Some(n) => n,
564 None => 0,
565 };
566 let already_present = index_buf[..existing_n]
567 .chunks_exact(CH_NAME_SLOT_LEN)
568 .any(|slot| slot[0] as usize == name.len() && &slot[1..1 + name.len()] == name);
569 if !already_present {
570 let new_n = existing_n + CH_NAME_SLOT_LEN;
571 if new_n > index_buf.len() {
572 return Err(Error::PeerIndexFull);
573 }
574 index_buf[existing_n] = name.len() as u8;
575 index_buf[existing_n + 1..existing_n + 1 + name.len()].copy_from_slice(name);
576 index_buf[existing_n + 1 + name.len()..new_n].fill(0);
578 self.store_bytes(CH_INDEX_KEY, &index_buf[..new_n]).await?;
579 }
580 Ok(())
581 }
582
583 pub async fn delete_channel_entry(&self, name: &[u8]) -> Result<(), Error<F::Error>> {
586 if let Ok(ch_key) = make_channel_key::<F::Error>(name) {
588 let _ = self.delete_bytes(&ch_key).await;
589 }
590
591 let mut index_buf = [0u8; CH_NAME_SLOT_LEN * MAX_CHANNELS];
593 let n = match self.load_bytes(CH_INDEX_KEY, &mut index_buf).await? {
594 Some(n) => n,
595 None => return Ok(()),
596 };
597 let mut new_buf = [0u8; CH_NAME_SLOT_LEN * MAX_CHANNELS];
598 let mut new_n = 0usize;
599 for slot in index_buf[..n].chunks_exact(CH_NAME_SLOT_LEN) {
600 let slot_name_len = slot[0] as usize;
601 let matches = slot_name_len == name.len()
602 && &slot[1..1 + slot_name_len.min(MAX_CHANNEL_NAME_LEN)] == name;
603 if !matches {
604 new_buf[new_n..new_n + CH_NAME_SLOT_LEN].copy_from_slice(slot);
605 new_n += CH_NAME_SLOT_LEN;
606 }
607 }
608 if new_n == 0 {
609 let _ = self.delete_bytes(CH_INDEX_KEY).await;
610 } else {
611 self.store_bytes(CH_INDEX_KEY, &new_buf[..new_n]).await?;
612 }
613 Ok(())
614 }
615}
616
617pub struct ChannelView<F, M>
620where
621 F: MultiwriteNorFlash + 'static,
622 M: RawMutex + 'static,
623{
624 storage: &'static FlashStore<F, M>,
625}
626
627impl<F, M> ChannelView<F, M>
628where
629 F: MultiwriteNorFlash + 'static,
630 M: RawMutex + 'static,
631{
632 pub fn new(storage: &'static FlashStore<F, M>) -> Self {
634 Self { storage }
635 }
636}
637
638impl<F, M> umsh_hal::ChannelStore for ChannelView<F, M>
639where
640 F: MultiwriteNorFlash + 'static,
641 M: RawMutex + 'static,
642{
643 type Error = Error<F::Error>;
644
645 async fn store_channel(&self, name: &[u8], key: &[u8; 32]) -> Result<(), Self::Error> {
646 self.storage.store_channel_entry(name, key).await
647 }
648
649 async fn delete_channel(&self, name: &[u8]) -> Result<(), Self::Error> {
650 self.storage.delete_channel_entry(name).await
651 }
652
653 async fn for_each_channel(
654 &self,
655 f: &mut dyn FnMut(&[u8], &[u8; 32]),
656 ) -> Result<(), Self::Error> {
657 let mut buf: heapless::Vec<
658 (heapless::String<MAX_CHANNEL_NAME_LEN>, [u8; 32]),
659 MAX_CHANNELS,
660 > = heapless::Vec::new();
661 self.storage.load_all_channels(&mut buf).await?;
662 for (name, key) in buf.iter() {
663 f(name.as_bytes(), key);
664 }
665 Ok(())
666 }
667}
668
669pub struct PeerView<F, M>
673where
674 F: MultiwriteNorFlash + 'static,
675 M: RawMutex + 'static,
676{
677 storage: &'static FlashStore<F, M>,
678}
679
680impl<F, M> PeerView<F, M>
681where
682 F: MultiwriteNorFlash + 'static,
683 M: RawMutex + 'static,
684{
685 pub fn new(storage: &'static FlashStore<F, M>) -> Self {
687 Self { storage }
688 }
689}
690
691impl<F, M> umsh_hal::PeerStore for PeerView<F, M>
692where
693 F: MultiwriteNorFlash + 'static,
694 M: RawMutex + 'static,
695{
696 type Error = Error<F::Error>;
697
698 async fn store_peer(&self, key: &[u8; 32], alias: Option<&[u8]>) -> Result<(), Self::Error> {
699 self.storage.store_peer_entry(key, alias).await
700 }
701
702 async fn delete_peer(&self, key: &[u8; 32]) -> Result<(), Self::Error> {
703 self.storage.delete_peer_entry(key).await
704 }
705
706 async fn for_each_peer(
707 &self,
708 f: &mut dyn FnMut(&[u8; 32], Option<&[u8]>),
709 ) -> Result<(), Self::Error> {
710 let mut buf: heapless::Vec<([u8; 32], Option<heapless::String<MAX_ALIAS_LEN>>), MAX_PEERS> =
711 heapless::Vec::new();
712 self.storage.load_all_peers(&mut buf).await?;
713 for (pk, alias) in buf.iter() {
714 f(pk, alias.as_ref().map(|s| s.as_bytes()));
715 }
716 Ok(())
717 }
718}
719
720pub struct KeyValueView<F, M>
724where
725 F: MultiwriteNorFlash + 'static,
726 M: RawMutex + 'static,
727{
728 storage: &'static FlashStore<F, M>,
729}
730
731impl<F, M> KeyValueView<F, M>
732where
733 F: MultiwriteNorFlash + 'static,
734 M: RawMutex + 'static,
735{
736 pub fn new(storage: &'static FlashStore<F, M>) -> Self {
738 Self { storage }
739 }
740}
741
742impl<F, M> umsh_hal::KeyValueStore for KeyValueView<F, M>
743where
744 F: MultiwriteNorFlash + 'static,
745 M: RawMutex + 'static,
746{
747 type Error = Error<F::Error>;
748
749 async fn load(&self, key: &[u8], buf: &mut [u8]) -> Result<Option<usize>, Self::Error> {
750 self.storage.load_bytes(key, buf).await
751 }
752
753 async fn store(&self, key: &[u8], value: &[u8]) -> Result<(), Self::Error> {
754 self.storage.store_bytes(key, value).await
755 }
756
757 async fn delete(&self, key: &[u8]) -> Result<(), Self::Error> {
758 self.storage.delete_bytes(key).await
759 }
760}
761
762pub struct CounterView<F, M>
767where
768 F: MultiwriteNorFlash + 'static,
769 M: RawMutex + 'static,
770{
771 storage: &'static FlashStore<F, M>,
772}
773
774impl<F, M> CounterView<F, M>
775where
776 F: MultiwriteNorFlash + 'static,
777 M: RawMutex + 'static,
778{
779 pub fn new(storage: &'static FlashStore<F, M>) -> Self {
781 Self { storage }
782 }
783}
784
785impl<F, M> umsh_hal::CounterStore for CounterView<F, M>
786where
787 F: MultiwriteNorFlash + 'static,
788 M: RawMutex + 'static,
789{
790 type Error = Error<F::Error>;
791
792 async fn load(&self, context: &[u8]) -> Result<u32, Self::Error> {
793 let mut buf = [0u8; 4];
794 match self.storage.load_bytes(context, &mut buf).await? {
795 Some(4) => Ok(u32::from_le_bytes(buf)),
796 Some(_) | None => Ok(0),
799 }
800 }
801
802 async fn store(&self, context: &[u8], value: u32) -> Result<(), Self::Error> {
803 let bytes = value.to_le_bytes();
804 self.storage.store_bytes(context, &bytes).await
805 }
806
807 async fn flush(&self) -> Result<(), Self::Error> {
808 Ok(())
813 }
814}