ove/nvs.rs
1// Copyright (C) 2026 Kamil Lulko <kamil.lulko@gmail.com>
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4//
5// This file is part of oveRTOS.
6
7//! Non-Volatile Storage (NVS) subsystem for oveRTOS.
8//!
9//! Provides key-value persistence backed by flash or EEPROM. All keys must be
10//! null-terminated byte slices (e.g. `b"my_key\0"`).
11
12use crate::bindings;
13use crate::error::{Error, Result};
14
15// SAFETY (module-wide contract for the `unsafe { bindings::ove_*(...) }` FFI
16// calls below): any handle passed to the C API is non-null and refers to a
17// live RTOS object — wrapper constructors establish validity via
18// `Error::from_code`, and `Drop` (or an explicit `deinit`) is the only place
19// a handle is released. Pointer and slice arguments reference caller-owned
20// memory valid for the duration of the call; the C side copies whatever it
21// retains and does not alias them past return (verified against the
22// signatures in `include/ove/*.h`). Blocks that deviate — `transmute`, raw
23// pointer casts from user data, slice reconstruction via `from_raw_parts`,
24// or storing a callback across the FFI boundary — carry their own
25// `// SAFETY:` comment.
26
27/// Initialize the NVS subsystem.
28///
29/// Must be called once before any `read`, `write`, or `erase` operations.
30///
31/// # Errors
32/// Returns an error if the underlying storage backend fails to initialize.
33pub fn init() -> Result<()> {
34 let rc = unsafe { bindings::ove_nvs_init() };
35 Error::from_code(rc)
36}
37
38/// Read a value from NVS into `buf`. `key` must be `\0`-terminated.
39///
40/// Returns the number of bytes actually read, which may be less than `buf.len()`
41/// if the stored value is shorter.
42///
43/// # Errors
44/// Returns [`Error::NotFound`] if the key does not exist, or another error
45/// if the read fails.
46pub fn read(key: &[u8], buf: &mut [u8]) -> Result<usize> {
47 let mut out_len: usize = 0;
48 let rc = unsafe {
49 bindings::ove_nvs_read(
50 key.as_ptr() as *const _,
51 buf.as_mut_ptr() as *mut _,
52 buf.len(),
53 &mut out_len,
54 )
55 };
56 Error::from_code(rc)?;
57 Ok(out_len)
58}
59
60/// Write `data` under `key` in NVS. `key` must be `\0`-terminated.
61///
62/// If the key already exists its value is replaced.
63///
64/// # Errors
65/// Returns [`Error::NoMemory`] if storage is full, or another error on failure.
66pub fn write(key: &[u8], data: &[u8]) -> Result<()> {
67 let rc = unsafe {
68 bindings::ove_nvs_write(
69 key.as_ptr() as *const _,
70 data.as_ptr() as *const _,
71 data.len(),
72 )
73 };
74 Error::from_code(rc)
75}
76
77/// Erase the entry for `key` from NVS. `key` must be `\0`-terminated.
78///
79/// No-op when the key does not exist (the C API treats erase-of-missing
80/// as success).
81///
82/// # Errors
83/// Returns an error if the underlying storage backend reports a failure.
84pub fn erase(key: &[u8]) -> Result<()> {
85 let rc = unsafe { bindings::ove_nvs_erase(key.as_ptr() as *const _) };
86 Error::from_code(rc)
87}