22use bytes:: Bytes ;
33use hyper:: { http:: uri:: InvalidUri , Uri } ;
44use prost:: { DecodeError , Message } ;
5- use std:: { cell:: RefCell , rc:: Rc } ;
5+ use std:: { cell:: RefCell , ffi :: CString , num :: NonZeroI32 , rc:: Rc } ;
66use thiserror:: Error ;
77
88use crate :: {
99 common:: {
1010 credentials_storage:: {
11- RobotConfigurationStorage , RobotCredentials , TlsCertificate , WifiCredentialStorage ,
12- WifiCredentials ,
11+ RobotConfigurationStorage , RobotCredentials , StorageDiagnostic , TlsCertificate ,
12+ WifiCredentialStorage , WifiCredentials ,
1313 } ,
1414 grpc:: { GrpcError , ServerError } ,
1515 } ,
1616 esp32:: esp_idf_svc:: {
1717 nvs:: { EspCustomNvs , EspCustomNvsPartition , EspNvs } ,
18- sys:: EspError ,
18+ sys:: { esp , nvs_get_stats , nvs_stats_t , EspError , ESP_ERR_INVALID_ARG } ,
1919 } ,
2020 proto:: { app:: v1:: RobotConfig , provisioning:: v1:: CloudConfig } ,
2121} ;
@@ -41,6 +41,7 @@ pub struct NVSStorage {
4141 // esp-idf-svc partition driver ensures that only one handle of a type can be created
4242 // so inner mutability can be achieves safely with RefCell
4343 nvs : Rc < RefCell < EspCustomNvs > > ,
44+ partition_name : CString ,
4445}
4546
4647impl NVSStorage {
@@ -51,6 +52,9 @@ impl NVSStorage {
5152
5253 Ok ( Self {
5354 nvs : Rc :: new ( nvs. into ( ) ) ,
55+ partition_name : CString :: new ( partition_name) . map_err ( |_| {
56+ EspError :: from_non_zero ( NonZeroI32 :: new ( ESP_ERR_INVALID_ARG ) . unwrap ( ) )
57+ } ) ?,
5458 } )
5559 }
5660
@@ -126,6 +130,41 @@ impl NVSStorage {
126130 }
127131}
128132
133+ const BYTES_PER_ENTRY : usize = 32 ;
134+
135+ impl StorageDiagnostic for NVSStorage {
136+ fn log_space_diagnostic ( & self ) {
137+ let mut stats: nvs_stats_t = Default :: default ( ) ;
138+ if let Err ( err) =
139+ esp ! ( unsafe { nvs_get_stats( self . partition_name. as_ptr( ) , & mut stats as * mut _) } )
140+ {
141+ log:: error!( "could not acquire NVS stats: {:?}" , err) ;
142+ return ;
143+ }
144+
145+ let used_entries = stats. used_entries ;
146+ let used_space = used_entries * BYTES_PER_ENTRY ;
147+ let total_space = stats. total_entries * BYTES_PER_ENTRY ;
148+
149+ // From experimentation we have found that NVS requires 4000 bytes of
150+ // unused space for reasons unknown. The percentage portion of the calculation (0.976)
151+ // comes from the blob size restriction as stated in the ESP32 documentation
152+ // on NVS
153+ let total_usable_space = ( 0.976 * ( total_space as f64 ) ) - 4000.0 ;
154+ let fraction_used = ( used_space as f64 ) / total_usable_space;
155+ log:: log!(
156+ if fraction_used > 0.9 {
157+ log:: Level :: Warn
158+ } else {
159+ log:: Level :: Info
160+ } ,
161+ "NVS stats: {:?} bytes used of {:?} available" ,
162+ used_space,
163+ total_space
164+ ) ;
165+ }
166+ }
167+
129168const NVS_ROBOT_SECRET_KEY : & str = "ROBOT_SECRET" ;
130169const NVS_ROBOT_ID_KEY : & str = "ROBOT_ID" ;
131170const NVS_ROBOT_APP_ADDRESS : & str = "ROBOT_APP_ADDR" ;
0 commit comments