#![cfg(feature = "serde")]
#![allow(unused)]
use embedded_storage_async::nor_flash::{ErrorType, NorFlash};
use sequential_storage::{
cache::NoCache,
map::{MapConfig, MapStorage, PostcardValue},
};
#[cfg(feature = "std")]
use embedded_storage_file::{NorMemoryAsync, NorMemoryInFile};
#[cfg(feature = "rp2350")]
use embassy_embedded_hal::adapter::BlockingAsync;
#[cfg(feature = "rp2350")]
use embassy_rp::{
Peri,
flash::{Blocking, Flash},
peripherals::FLASH,
};
#[cfg(feature = "rp2350")]
const FLASH_SIZE_BYTES: usize = 4 * 1024 * 1024;
use radio_controllers::RatesConfig;
extern crate paste;
use crate::{config::GLOBAL_CONFIG, flight::ImuFilterBankConfig, tasks::non_volatile_storage as nvs};
#[cfg(feature = "osd")]
use crate::osd::OsdConfig;
#[cfg(feature = "battery")]
use crate::sensors::BatteryConfig;
#[cfg(feature = "blackbox")]
use blackbox_logger::BlackboxConfig;
const PID_PROFILE_INDEX_KEY: u16 = 0x0001;
const RATE_PROFILE_INDEX_KEY: u16 = 0x0002;
const ACC_CALIBRATION_STATE_KEY: u16 = 0x0003;
const GYRO_CALIBRATION_STATE_KEY: u16 = 0x0004;
const MOTOR_MIXER_TYPE_KEY: u16 = 0x0005;
const ACC_OFFSET_KEY: u16 = 0x0200;
const GYRO_OFFSET_KEY: u16 = 0x0201;
const MAC_ADDRESS_KEY: u16 = 0x0202;
const DYNAMIC_NOTCH_FILTER_CONFIG_KEY: u16 = 0x0300;
const FLIGHT_CONTROLLER_FILTERS_CONFIG_KEY: u16 = 0x0400;
const DYNAMIC_IDLE_CONTROLLER_CONFIG_KEY: u16 = 0x0404;
const FLIGHT_CONTROLLER_FLIGHTMODE_CONFIG_KEY: u16 = 0x408;
const FLIGHT_CONTROLLER_TPA_CONFIG_KEY: u16 = 0x40C;
const FLIGHT_CONTROLLER_ANTI_GRAVITY_CONFIG_KEY: u16 = 0x0410;
const FLIGHT_CONTROLLER_DMAX_CONFIG_KEY: u16 = 0x0414;
const FLIGHT_CONTROLLER_ITERM_RELAX_CONFIG_KEY: u16 = 0x0418;
const FLIGHT_CONTROLLER_YAW_SPIN_RECOVERY_CONFIG_KEY: u16 = 0x041C;
const FLIGHT_CONTROLLER_CRASH_RECOVERY_CONFIG_KEY: u16 = 0x0420;
const FLIGHT_CONTROLLER_SIMPLIFIED_PID_SETTINGS_KEY: u16 = 0x0424;
const OSD_CONFIG_KEY: u16 = 0x0428;
const OSD_ELEMENTS_CONFIG_KEY: u16 = 0x042C;
const RATES_KEY: u16 = 0x0500;
const IMU_FILTERS_CONFIG_KEY: u16 = 0x0600;
const RPM_FILTERS_CONFIG_KEY: u16 = 0x0601;
const FAILSAFE_CONFIG_KEY: u16 = 0x0602;
const RX_CONFIG_KEY: u16 = 0x0603;
const AUTOPILOT_CONFIG_KEY: u16 = 0x604;
const AUTOPILOT_POSITION_CONFIG_KEY: u16 = 0x605;
const ALTITUDE_HOLD_CONFIG_KEY: u16 = 0x606;
const MOTOR_CONFIG_KEY: u16 = 0x607;
const MOTOR_MIXER_CONFIG_KEY: u16 = 0x0608;
const VTX_CONFIG_KEY: u16 = 0x0609;
const GPS_CONFIG_KEY: u16 = 0x060A;
const FLIGHT_CONTROLLER_CRASH_FLIP_KEY: u16 = 0x060B;
const RC_MODES_ACTIVATION_CONDITIONS_KEY: u16 = 0x060C;
const RC_ADJUSTMENT_RANGES_KEY: u16 = 0x060D;
const FEATURES_CONFIG_KEY: u16 = 0x060E;
const BLACKBOX_CONFIG_KEY: u16 = 0x060F;
const BATTERY_CONFIG_KEY: u16 = 0x0610;
macro_rules! generate_config_handlers {
($prefix:ident, $key:expr, $buf_size:expr) => {
paste::paste! {
pub async fn [<load_ $prefix:lower _config>]<F>(
config: &mut [<$prefix Config>],
storage: &mut MapStorage<u16, F, NoCache>
) where F: NorFlash {
let mut buffer = [0u8; $buf_size];
if let Ok(Some(Some(loaded_data))) = storage
.fetch_item::<Option<[<$prefix Config>]>>(&mut buffer, &$key)
.await
{
*config = loaded_data;
}
}
pub async fn [<save_ $prefix:lower _config>]<F>(
config: &[<$prefix Config>],
storage: &mut MapStorage<u16, F, NoCache>
) -> Result<(), sequential_storage::Error<<F as ErrorType>::Error>>
where
F: NorFlash,
[<$prefix Config>]: PartialEq {
let mut buffer = [0u8; $buf_size];
if let Ok(Some(Some(existing_data))) = storage
.fetch_item::<Option<[<$prefix Config>]>>(&mut buffer, &$key)
.await
{
if &existing_data == config {
#[cfg(not(target_arch = "arm"))]
return Ok(());
}
}
let data_to_save = Some(config.clone());
storage.store_item(&mut buffer, &$key, &data_to_save).await
}
pub async fn [<delete_ $prefix:lower _config>]<F>(
storage: &mut MapStorage<u16, F, NoCache>
) -> Result<(), sequential_storage::Error<<F as ErrorType>::Error>>
where F: NorFlash {
let mut buffer = [0u8; $buf_size];
if let Ok(Some(None)) = storage
.fetch_item::<Option<[<$prefix Config>]>>(&mut buffer, &$key)
.await
{
return Ok(());
}
let delete_marker: Option<[<$prefix Config>]> = None;
storage.store_item(&mut buffer, &$key, &delete_marker).await
}
}
};
}
#[cfg(feature = "osd")]
generate_config_handlers!(Osd, OSD_CONFIG_KEY, 128);
#[cfg(feature = "blackbox")]
generate_config_handlers!(Blackbox, BLACKBOX_CONFIG_KEY, 128);
generate_config_handlers!(Rates, RATES_KEY, 128);
pub async fn load_imu_filter_bank_config<F>(config: &mut ImuFilterBankConfig, storage: &mut MapStorage<u16, F, NoCache>)
where
F: NorFlash,
{
let mut buffer = [0u8; 256];
if let Ok(Some(loaded_data)) = storage.fetch_item(&mut buffer, &IMU_FILTERS_CONFIG_KEY).await {
*config = loaded_data;
}
}
pub async fn save_imu_filter_bank_config<F>(
config: &ImuFilterBankConfig, storage: &mut MapStorage<u16, F, NoCache>,
) -> Result<(), sequential_storage::Error<<F as ErrorType>::Error>>
where
F: NorFlash,
{
let mut buffer = [0u8; 256];
storage.store_item(&mut buffer, &IMU_FILTERS_CONFIG_KEY, config).await
}
pub async fn delete_imu_filter_bank_config<F>(
storage: &mut MapStorage<u16, F, NoCache>,
) -> Result<(), sequential_storage::Error<<F as ErrorType>::Error>>
where
F: NorFlash,
{
let mut buffer = [0u8; 256];
let delete_marker: Option<ImuFilterBankConfig> = None;
storage.store_item(&mut buffer, &IMU_FILTERS_CONFIG_KEY, &delete_marker).await
}
#[cfg(feature = "battery")]
pub async fn load_battery_config<F>(config: &mut BatteryConfig, storage: &mut MapStorage<u16, F, NoCache>)
where
F: NorFlash,
{
let mut buffer = [0u8; 256];
if let Ok(Some(Some(loaded_data))) =
storage.fetch_item::<Option<BatteryConfig>>(&mut buffer, &BATTERY_CONFIG_KEY).await
{
*config = loaded_data;
}
}
#[cfg(feature = "battery")]
pub async fn save_battery_config<F>(
config: &BatteryConfig,
storage: &mut MapStorage<u16, F, NoCache>,
) -> Result<(), sequential_storage::Error<<F as ErrorType>::Error>>
where
F: NorFlash,
{
let mut buffer = [0u8; 256];
if *config == BatteryConfig::default() {
let delete_marker: Option<BatteryConfig> = None;
storage.store_item(&mut buffer, &BATTERY_CONFIG_KEY, &delete_marker).await
} else {
storage.store_item(&mut buffer, &BATTERY_CONFIG_KEY, &Some(*config)).await
}
}
#[cfg(feature = "battery")]
pub async fn delete_battery_config<F>(
storage: &mut MapStorage<u16, F, NoCache>,
) -> Result<(), sequential_storage::Error<<F as ErrorType>::Error>>
where
F: NorFlash,
{
let mut buffer = [0u8; 256];
let delete_marker: Option<BatteryConfig> = None;
storage.store_item(&mut buffer, &BATTERY_CONFIG_KEY, &delete_marker).await
}
#[cfg(feature = "std")]
pub fn init_flash_driver() -> impl embedded_storage_async::nor_flash::NorFlash {
let path = "pc_mock_flash.nor";
let capacity_bytes = 1024 * 1024;
#[allow(clippy::expect_used)]
let inner_sync_nor =
NorMemoryInFile::<4, 4, 4096>::new(path, capacity_bytes).expect("Failed to create synchronous mock flash file");
NorMemoryAsync::new(inner_sync_nor)
}
#[cfg(feature = "std")]
pub async fn load_global_configs() {
let flash_driver = init_flash_driver();
let mut storage = MapStorage::new(flash_driver, const { MapConfig::new(0..1024 * 1024) }, NoCache::new());
let mut config = GLOBAL_CONFIG.lock().await;
nvs::load_imu_filter_bank_config(&mut config.imu_filter_bank, &mut storage).await;
nvs::load_rates_config(&mut config.rates, &mut storage).await;
}
#[cfg(not(feature = "std"))]
pub fn init_flash_driver<'a>(
flash_pin: Peri<'a, FLASH>,
) -> Flash<'a, FLASH, Blocking, FLASH_SIZE_BYTES> {
Flash::<_, Blocking, FLASH_SIZE_BYTES>::new_blocking(flash_pin)
}
#[cfg(feature = "rp2350")]
fn map_storage(
flash: Peri<'static, FLASH>,
) -> MapStorage<u16, BlockingAsync<Flash<'static, FLASH, Blocking, FLASH_SIZE_BYTES>>, NoCache> {
let flash_driver = init_flash_driver(flash);
let async_wrapped_driver = BlockingAsync::new(flash_driver);
let flash_range = (4096 - 128) * 1024..4096 * 1024;
MapStorage::new(async_wrapped_driver, const { MapConfig::new((4096 - 128) * 1024..4096 * 1024) }, NoCache::new())
}
#[cfg(feature = "rp2350")]
pub async fn load_global_configs(flash: Peri<'static, FLASH>) {
let mut storage = map_storage(flash);
let mut config = GLOBAL_CONFIG.lock().await;
nvs::load_imu_filter_bank_config(&mut config.imu_filter_bank, &mut storage).await;
nvs::load_rates_config(&mut config.rates, &mut storage).await;
}
#[cfg(feature = "rp2350")]
pub async fn save_global_configs(flash: Peri<'static, FLASH>) {
let mut storage = map_storage(flash);
let config = GLOBAL_CONFIG.lock().await;
nvs::save_imu_filter_bank_config(&config.imu_filter_bank, &mut storage).await;
}