diff --git a/src/config.rs b/src/config.rs index 0266081..19bdbf8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,3 @@ -#![warn(missing_docs)] - use core::num::NonZeroU8; use num::Zero; @@ -8,6 +6,7 @@ use error::ConfigError; use error::ConfigError::ContinuousSweepMode; use frame_rate::FrameRate; use profile::RadarProfile; +use state_shift::{impl_state, type_state}; use crate::config::hwaas::Hwaas; use crate::config::prf::PulseRepetitionFrequency; @@ -15,7 +14,7 @@ use crate::config::subsweep::Subsweep; use a121_sys::*; /// Module for radar configuration errors -mod error; +pub mod error; /// Module for frame rate values pub mod frame_rate; /// Module for hardware accelerated average samples (HWAAS) values @@ -27,35 +26,12 @@ pub mod profile; /// Module for subsweep configuration pub mod subsweep; -#[derive(Debug, PartialEq)] -/// Idle states for the radar sensor between sweeps or frames. -pub enum RadarIdleState { - /// Deep sleep state for maximum power saving. - DeepSleep = 0, - /// Sleep state with reduced power consumption. - Sleep, - /// Ready state for quick start of operations. - Ready, -} - -/// Enum representing different sweep modes for the radar sensor. -pub enum SweepMode { - /// Continuous sweep mode with specified constraints. - Continuous { - /// Sweep rate in Hz, must be >= 0 - sweep_rate: f32, - }, - /// Non-continuous (or discrete) sweep mode with different settings. - Discrete { - /// Frame rate in Hz - frame_rate: FrameRate, - /// Number of sweeps per frame - sweeps_per_frame: u16, - }, -} - -#[derive(Debug)] +#[type_state( + states = (Locked, Unlocked), + slots = (Locked) +)] /// Radar configuration structure to manage the settings of a radar sensor. +#[derive(Debug)] pub struct RadarConfig { /// Number of subsweeps in the radar configuration. num_subsweep: Option, @@ -63,14 +39,9 @@ pub struct RadarConfig { inner: *mut acc_config_t, } -impl Default for RadarConfig { - /// Provides a default instance of `RadarConfig` with an ID of 1. - fn default() -> Self { - Self::new() - } -} - +#[impl_state] impl Drop for RadarConfig { + #[require(A)] /// Destroys the radar configuration instance, freeing any allocated resources. fn drop(&mut self) { debug_assert!(!self.inner.is_null(), "Radar configuration is null"); @@ -78,29 +49,62 @@ impl Drop for RadarConfig { } } +#[impl_state] +impl Default for RadarConfig { + #[require(A)] + fn default() -> RadarConfig { + RadarConfig::new() + } +} + +#[impl_state] impl RadarConfig { - /// Creates a new radar configuration instance with a specified ID. - pub fn new() -> Self { + /// Creates a new radar configuration instance. + #[require(Locked)] + pub(crate) fn new() -> RadarConfig { #[cfg(feature = "defmt")] defmt::trace!("Creating radar configuration"); let inner = unsafe { acc_config_create() }; #[cfg(feature = "defmt")] defmt::trace!("Radar configuration created"); - Self { + RadarConfig { inner, num_subsweep: None, } } + #[require(Unlocked)] + #[switch_to(Locked)] + pub fn lock(self) -> RadarConfig { + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } + } + + #[require(Locked)] + #[switch_to(Unlocked)] + pub fn unlock(self) -> RadarConfig { + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } + } + + #[require(Locked)] + pub fn apply_config(&self) {} + /// Returns a mutable pointer to the internal radar configuration structure /// # Safety /// This function is unsafe because it returns a raw pointer. + #[require(A)] pub unsafe fn mut_ptr(&mut self) -> *mut acc_config_t { debug_assert!(!self.inner.is_null(), "Radar configuration is null"); self.inner } /// Returns a pointer to the internal radar configuration structure + #[require(A)] pub fn ptr(&self) -> *const acc_config_t { self.inner } @@ -108,22 +112,38 @@ impl RadarConfig { /// Sets the sweep mode for the radar sensor /// # Arguments /// * `sweep_mode` - The sweep mode to set - pub fn set_sweep_mode(&mut self, sweep_mode: SweepMode) -> Result<(), ConfigError> { + #[require(Unlocked)] + pub fn set_sweep_mode(self, sweep_mode: SweepMode) -> Result { match sweep_mode { SweepMode::Continuous { sweep_rate } => { - self.set_continuous_sweep_mode(true)?; - self.set_sweep_rate(sweep_rate)?; + // Do all operations directly to avoid ownership issues + if self.frame_rate().is_limited() { + return Err(ContinuousSweepMode); + } + if sweep_rate.is_zero() || sweep_rate.is_sign_negative() { + return Err(ConfigError::SweepRate); + } + unsafe { + acc_config_continuous_sweep_mode_set(self.inner, true); + acc_config_sweep_rate_set(self.inner, sweep_rate); + } } SweepMode::Discrete { frame_rate, sweeps_per_frame, - } => { - self.set_continuous_sweep_mode(false)?; - self.set_frame_rate(frame_rate); - self.set_sweeps_per_frame(sweeps_per_frame); - } + } => unsafe { + acc_config_continuous_sweep_mode_set(self.inner, false); + match frame_rate { + FrameRate::Unlimited => acc_config_frame_rate_set(self.inner, 0.0), + FrameRate::Limited(rate) => acc_config_frame_rate_set(self.inner, rate), + } + acc_config_sweeps_per_frame_set(self.inner, sweeps_per_frame); + }, } - Ok(()) + Ok(RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + }) } /// Sets the starting point of the sweep. @@ -131,11 +151,17 @@ impl RadarConfig { /// # Arguments /// /// * `start_point` - The starting point of the sweep in millimeters. - pub fn set_start_point(&mut self, start_point: i32) { + #[require(Unlocked)] + pub fn set_start_point(self, start_point: i32) -> RadarConfig { unsafe { acc_config_start_point_set(self.inner, start_point) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get the starting point of the sweep. + #[require(A)] pub fn start_point(&self) -> i32 { unsafe { acc_config_start_point_get(self.inner) } } @@ -145,11 +171,17 @@ impl RadarConfig { /// # Arguments /// /// * `num_points` - Number of data points to measure. - pub fn set_num_points(&mut self, num_points: u16) { + #[require(Unlocked)] + pub fn set_num_points(self, num_points: u16) -> RadarConfig { unsafe { acc_config_num_points_set(self.inner, num_points) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get the number of data points set to measure in a sweep. + #[require(A)] pub fn num_points(&self) -> u16 { unsafe { acc_config_num_points_get(self.inner) } } @@ -159,11 +191,17 @@ impl RadarConfig { /// # Arguments /// /// * `step_length` - The step length. - pub fn set_step_length(&mut self, step_length: u16) { + #[require(Unlocked)] + pub fn set_step_length(self, step_length: u16) -> RadarConfig { unsafe { acc_config_step_length_set(self.inner, step_length) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get the current step length between each data point in a sweep. + #[require(A)] pub fn step_length(&self) -> u16 { unsafe { acc_config_step_length_get(self.inner) } } @@ -173,11 +211,17 @@ impl RadarConfig { /// # Arguments /// /// * `profile` - The radar profile to set. - pub fn set_profile(&mut self, profile: RadarProfile) { + #[require(Unlocked)] + pub fn set_profile(self, profile: RadarProfile) -> RadarConfig { unsafe { acc_config_profile_set(self.inner, profile as u32) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get the currently used radar profile + #[require(A)] pub fn profile(&self) -> RadarProfile { unsafe { acc_config_profile_get(self.inner) }.into() } @@ -193,14 +237,19 @@ impl RadarConfig { /// # Arguments /// /// * `hwaas` - Number of hardware accelerated average samples. - pub fn set_hwaas(&mut self, hwaas: Hwaas) -> Result<(), ConfigError> { + #[require(Unlocked)] + pub fn set_hwaas(self, hwaas: Hwaas) -> Result { unsafe { acc_config_hwaas_set(self.inner, hwaas.into()) }; - Ok(()) + Ok(RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + }) } /// Get the hardware accelerated average samples (HWAAS). /// /// Returns the number of hardware accelerated average samples currently set. + #[require(A)] pub fn hwaas(&self) -> Hwaas { unsafe { acc_config_hwaas_get(self.inner) } .try_into() @@ -216,13 +265,19 @@ impl RadarConfig { /// # Arguments /// /// * `receiver_gain` - Receiver gain setting. - pub fn receiver_gain_set(&mut self, receiver_gain: u8) { + #[require(Unlocked)] + pub fn receiver_gain_set(self, receiver_gain: u8) -> RadarConfig { unsafe { acc_config_receiver_gain_set(self.inner, receiver_gain) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get the current receiver gain setting. /// /// Returns the receiver gain setting. The range is between 0 (lowest gain) and 23 (highest gain). + #[require(A)] pub fn receiver_gain(&self) -> u8 { unsafe { acc_config_receiver_gain_get(self.inner) } } @@ -232,11 +287,17 @@ impl RadarConfig { /// # Arguments /// /// * `sweeps_per_frame` - Number of sweeps per frame. - pub fn set_sweeps_per_frame(&mut self, sweeps_per_frame: u16) { + #[require(Unlocked)] + pub fn set_sweeps_per_frame(self, sweeps_per_frame: u16) -> RadarConfig { unsafe { acc_config_sweeps_per_frame_set(self.inner, sweeps_per_frame) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get the number of sweeps captured in each frame (measurement). + #[require(A)] pub fn sweeps_per_frame(&self) -> u16 { unsafe { acc_config_sweeps_per_frame_get(self.inner) } } @@ -248,13 +309,19 @@ impl RadarConfig { /// # Arguments /// /// * `prf` - The Pulse Repetition Frequency to use - pub fn set_prf(&mut self, prf: PulseRepetitionFrequency) { + #[require(Unlocked)] + pub fn set_prf(self, prf: PulseRepetitionFrequency) -> RadarConfig { unsafe { acc_config_prf_set(self.inner, prf as acc_config_prf_t) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get the Pulse Repetition Frequency /// /// Returns the currently set Pulse Repetition Frequency. + #[require(A)] pub fn prf(&self) -> PulseRepetitionFrequency { unsafe { acc_config_prf_get(self.inner) } .try_into() @@ -268,13 +335,19 @@ impl RadarConfig { /// # Arguments /// /// * `enable` - true to enable phase enhancement, false to disable - pub fn set_phase_enhancement(&mut self, enable: bool) { + #[require(Unlocked)] + pub fn set_phase_enhancement(self, enable: bool) -> RadarConfig { unsafe { acc_config_phase_enhancement_set(self.inner, enable) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Check if phase enhancement is enabled /// /// Returns true if phase enhancement is enabled. + #[require(A)] pub fn is_phase_enhancement_enabled(&self) -> bool { unsafe { acc_config_phase_enhancement_get(self.inner) } } @@ -286,13 +359,19 @@ impl RadarConfig { /// # Arguments /// /// * `enable` - true to enable loopback, false otherwise - pub fn set_loopback(&mut self, enable: bool) { + #[require(Unlocked)] + pub fn set_loopback(self, enable: bool) -> RadarConfig { unsafe { acc_config_enable_loopback_set(self.inner, enable) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get the enable loopback configuration /// /// Returns true if loopback is enabled. + #[require(A)] pub fn is_loopback_enabled(&self) -> bool { unsafe { acc_config_enable_loopback_get(self.inner) } } @@ -305,13 +384,19 @@ impl RadarConfig { /// # Arguments /// /// * `enable` - true to enable double buffering, false otherwise - pub fn set_double_buffering(&mut self, enable: bool) { + #[require(Unlocked)] + pub fn set_double_buffering(self, enable: bool) -> RadarConfig { unsafe { acc_config_double_buffering_set(self.inner, enable) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get the double buffering configuration /// /// Returns true if double buffering is enabled. + #[require(A)] pub fn is_double_buffering_enabled(&self) -> bool { unsafe { acc_config_double_buffering_get(self.inner) } } @@ -323,16 +408,22 @@ impl RadarConfig { /// # Arguments /// /// * `frame_rate` - Frame rate in Hz. 0 is interpreted as unlimited - pub fn set_frame_rate(&mut self, frame_rate: FrameRate) { + #[require(Unlocked)] + pub fn set_frame_rate(self, frame_rate: FrameRate) -> RadarConfig { match frame_rate { FrameRate::Unlimited => unsafe { acc_config_frame_rate_set(self.inner, 0.0) }, FrameRate::Limited(rate) => unsafe { acc_config_frame_rate_set(self.inner, rate) }, } + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get the frame rate /// /// Returns the currently set frame rate in Hz. + #[require(A)] pub fn frame_rate(&self) -> FrameRate { let val = unsafe { acc_config_frame_rate_get(self.inner) }; if val.is_zero() { @@ -347,13 +438,19 @@ impl RadarConfig { /// # Arguments /// /// * `enable` - true to enable the transmitter, false to disable it - pub fn set_transmitter_enabled(&mut self, enable: bool) { + #[require(Unlocked)] + pub fn set_transmitter_enabled(self, enable: bool) -> RadarConfig { unsafe { acc_config_enable_tx_set(self.inner, enable) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get transmitter enable configuration /// /// Returns true if the transmitter is enabled. + #[require(A)] pub fn is_transmitter_enabled(&self) -> bool { unsafe { acc_config_enable_tx_get(self.inner) } } @@ -363,13 +460,19 @@ impl RadarConfig { /// # Arguments /// /// * `idle_state` - The idle state to use between frames - pub fn set_inter_frame_idle_state(&mut self, idle_state: RadarIdleState) { + #[require(Unlocked)] + pub fn set_inter_frame_idle_state(self, idle_state: RadarIdleState) -> RadarConfig { unsafe { acc_config_inter_frame_idle_state_set(self.inner, idle_state as u32) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get inter frame idle state /// /// Returns the currently set idle state used between frames. + #[require(A)] pub fn inter_frame_idle_state(&self) -> RadarIdleState { let val = unsafe { acc_config_inter_frame_idle_state_get(self.inner) }; match val { @@ -385,13 +488,19 @@ impl RadarConfig { /// # Arguments /// /// * `idle_state` - The idle state to use between sweeps within a frame - pub fn set_inter_sweep_idle_state(&mut self, idle_state: RadarIdleState) { + #[require(Unlocked)] + pub fn set_inter_sweep_idle_state(self, idle_state: RadarIdleState) -> RadarConfig { unsafe { acc_config_inter_sweep_idle_state_set(self.inner, idle_state as u32) }; + RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + } } /// Get inter sweep idle state /// /// Returns the currently set idle state used between sweeps within a frame. + #[require(A)] pub fn inter_sweep_idle_state(&self) -> RadarIdleState { let val = unsafe { acc_config_inter_sweep_idle_state_get(self.inner) }; match val { @@ -413,7 +522,8 @@ impl RadarConfig { /// # Arguments /// /// * `enabled` - true to enable continuous sweep mode, false to disable it. - fn set_continuous_sweep_mode(&mut self, enabled: bool) -> Result<(), ConfigError> { + #[require(Unlocked)] + fn set_continuous_sweep_mode(self, enabled: bool) -> Result { if enabled { if self.frame_rate().is_limited() { return Err(ContinuousSweepMode); @@ -426,12 +536,16 @@ impl RadarConfig { } } unsafe { acc_config_continuous_sweep_mode_set(self.inner, enabled) }; - Ok(()) + Ok(RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + }) } /// Get continuous sweep mode /// /// Returns true if continuous sweep mode is enabled. + #[require(A)] pub fn is_continuous_sweep_mode_enabled(&self) -> bool { unsafe { acc_config_continuous_sweep_mode_get(self.inner) } } @@ -441,17 +555,22 @@ impl RadarConfig { /// # Arguments /// /// * `sweep_rate` - Sweep rate in Hz. Must be >= 0, 0 is interpreted as max sweep rate - fn set_sweep_rate(&mut self, sweep_rate: f32) -> Result<(), ConfigError> { + #[require(Unlocked)] + fn set_sweep_rate(self, sweep_rate: f32) -> Result { if sweep_rate.is_zero() || sweep_rate.is_sign_negative() { return Err(ConfigError::SweepRate); } unsafe { acc_config_sweep_rate_set(self.inner, sweep_rate) }; - Ok(()) + Ok(RadarConfig { + inner: self.inner, + num_subsweep: self.num_subsweep, + }) } /// Get the sweep rate /// /// Returns the currently set sweep rate in Hz. + #[require(A)] pub fn sweep_rate(&self) -> f32 { unsafe { acc_config_sweep_rate_get(self.inner) } } @@ -459,6 +578,7 @@ impl RadarConfig { /// Set the number of subsweeps in the radar configuration. /// # Arguments /// * `num_subsweep` - The number of subsweeps to set + #[require(A)] pub fn set_num_subsweep(&mut self, num_subsweep: u8) -> Result<(), ConfigError> { if num_subsweep == 0 { return Err(ConfigError::NumSubsweep); @@ -469,6 +589,7 @@ impl RadarConfig { } /// Get the number of subsweeps in the radar configuration. + #[require(A)] pub fn num_subsweep(&self) -> u8 { unsafe { acc_config_num_subsweeps_get(self.inner) } } @@ -479,6 +600,7 @@ impl RadarConfig { /// # Returns /// * `Some(Subsweep)` - The subsweep at the given index /// * `None` - If the index is out of bounds + #[require(A)] pub fn get_subsweep(&self, index: u8) -> Option { if index >= self.num_subsweep() { return None; @@ -490,6 +612,7 @@ impl RadarConfig { /// # Returns /// * `Ok(u32)` - The buffer size needed for the current configuration /// * `Err(ConfigError::BufferSize)` - If the buffer size could not be determined + #[require(A)] pub fn config_buffer_size(&self) -> Result { let mut buffer_size = 0; let result: bool; @@ -503,3 +626,30 @@ impl RadarConfig { } } } + +#[derive(Debug, PartialEq)] +/// Idle states for the radar sensor between sweeps or frames. +pub enum RadarIdleState { + /// Deep sleep state for maximum power saving. + DeepSleep = 0, + /// Sleep state with reduced power consumption. + Sleep, + /// Ready state for quick start of operations. + Ready, +} + +/// Enum representing different sweep modes for the radar sensor. +pub enum SweepMode { + /// Continuous sweep mode with specified constraints. + Continuous { + /// Sweep rate in Hz, must be >= 0 + sweep_rate: f32, + }, + /// Non-continuous (or discrete) sweep mode with different settings. + Discrete { + /// Frame rate in Hz + frame_rate: FrameRate, + /// Number of sweeps per frame + sweeps_per_frame: u16, + }, +} diff --git a/src/config/error.rs b/src/config/error.rs index d3e0b6c..cc87a5c 100644 --- a/src/config/error.rs +++ b/src/config/error.rs @@ -9,6 +9,6 @@ pub enum ConfigError { SweepRate, /// Error indicating invalid number of subsweeps setting. NumSubsweep, - + /// Error indicating invalid buffer size configuration BufferSize, } diff --git a/src/detector/distance.rs b/src/detector/distance.rs index 192933c..dc94536 100644 --- a/src/detector/distance.rs +++ b/src/detector/distance.rs @@ -3,9 +3,10 @@ pub mod results; use crate::detector::distance::config::RadarDistanceConfig; use crate::detector::distance::results::{DistanceSizes, ProcessDataError}; +use crate::radar::error::RadarError; use crate::radar::{Radar, RadarReady}; use crate::sensor::calibration::CalibrationResult; -use crate::sensor::error::SensorError; +use crate::sensor::error::SensorError::*; use a121_sys::*; use core::ffi::c_void; use embedded_hal::digital::OutputPin; @@ -94,7 +95,7 @@ where sensor_cal_result: &CalibrationResult, buffer: &mut [u8], detector_cal_result_static: &mut [u8], - ) -> Result { + ) -> Result { let mut calibration_complete: bool = false; let mut detector_cal_result_dynamic = DynamicResult::default(); let distances = DistanceSizes::new(&self.inner); @@ -103,7 +104,7 @@ where if buffer.len() < distances.buffer_size || detector_cal_result_static.len() < distances.detector_cal_result_static_size { - return Err(SensorError::BufferTooSmall); + return Err(RadarError::SensorError(BufferTooSmall)); } loop { @@ -124,7 +125,7 @@ where // Check if the calibration attempt was successful if !calibration_attempt { - return Err(SensorError::CalibrationFailed); + return Err(RadarError::SensorError(CalibrationFailed)); } // Break the loop if calibration is complete @@ -159,7 +160,7 @@ where &mut self, sensor_cal_result: &CalibrationResult, buffer: &mut [u8], - ) -> Result { + ) -> Result { let mut calibration_complete: bool = false; let mut detector_cal_result_dynamic = DynamicResult::default(); let calibration_attempt: bool; @@ -200,7 +201,7 @@ where Ok(detector_cal_result_dynamic) } else { - Err(SensorError::CalibrationFailed) + Err(RadarError::SensorError(CalibrationFailed)) } } @@ -211,7 +212,7 @@ where &mut self, sensor_cal_result: &CalibrationResult, buffer: &mut [u8], - ) -> Result<(), SensorError> { + ) -> Result<(), RadarError> { unsafe { if acc_detector_distance_prepare( self.inner.inner(), @@ -223,7 +224,7 @@ where ) { Ok(()) } else { - Err(SensorError::PrepareFailed) + Err(RadarError::SensorError(PrepareFailed)) } } } @@ -231,14 +232,14 @@ where /// Performs a distance measurement operation asynchronously. /// /// This function initiates a measurement operation, returning the results asynchronously. - pub async fn measure(&mut self, data: &mut [u8]) -> Result<(), SensorError> { + pub async fn measure(&mut self, data: &mut [u8]) -> Result<(), RadarError> { self.radar.measure(data).await } /// Calibrates the associated radar asynchronously. /// /// This function performs a calibration operation on the radar, necessary for accurate distance measurements. - pub async fn calibrate(&mut self) -> Result { + pub async fn calibrate(&mut self) -> Result { self.radar.calibrate().await } @@ -252,7 +253,7 @@ where detector_cal_result_dynamic: &mut DynamicResult, ) -> Result, ProcessDataError> { let mut result_available: bool = false; - let mut distance_result = DistanceResult::new(&self.radar.config); + let mut distance_result = DistanceResult::new(self.radar.config()); let mut distance_result_ptr: acc_detector_distance_result_t = distance_result.inner(); let process_attempt: bool = unsafe { diff --git a/src/radar.rs b/src/radar.rs index b78911c..13dd722 100644 --- a/src/radar.rs +++ b/src/radar.rs @@ -1,5 +1,14 @@ +pub mod error; pub mod version; +use crate::config::RadarConfig; +use crate::config::RadarConfigUnlocked; +use crate::hal::AccHalImpl; +use crate::processing::Processing; +use crate::radar::error::RadarError; +use crate::sensor::calibration::CalibrationResult; +use crate::sensor::error::SensorError::*; +use crate::sensor::Sensor; use a121_sys::{acc_sensor_connected, acc_sensor_id_t, acc_sensor_t}; use core::marker::PhantomData; use embedded_hal::digital::OutputPin; @@ -8,13 +17,6 @@ use embedded_hal_async::delay::DelayNs; use embedded_hal_async::digital::Wait; use state_shift::{impl_state, type_state}; -use crate::config::RadarConfig; -use crate::hal::AccHalImpl; -use crate::processing::Processing; -use crate::sensor::calibration::CalibrationResult; -use crate::sensor::error::SensorError; -use crate::sensor::Sensor; - #[type_state( states = (Enabled, Ready, Hibernating), slots = (Enabled) @@ -26,7 +28,7 @@ where DLY: DelayNs, { id: u32, - pub config: RadarConfig, + config: Option, sensor: Sensor, pub processing: Processing, pub(crate) interrupt: SINT, @@ -55,12 +57,12 @@ where delay.delay_ms(2).await; let hal = AccHalImpl::new(spi); hal.register(); - let config = RadarConfig::default(); + let config = RadarConfig::new(); let sensor = Sensor::new(id, enable_pin, delay).expect("Failed to create sensor"); let processing = Processing::new(&config); Radar { id, - config, + config: Some(config), interrupt, sensor, processing, @@ -73,16 +75,17 @@ where pub fn prepare_sensor( mut self, calibration_result: &mut CalibrationResult, - ) -> Result, SensorError> { + ) -> Result, RadarError> { let mut buf = [0u8; 2560]; + let config = &self.config.as_ref().unwrap(); if self .sensor - .prepare(&self.config, calibration_result, &mut buf) + .prepare(config, calibration_result, &mut buf) .is_ok() { Ok(Radar { id: self.id, - config: self.config, + config: Some(self.config.unwrap()), sensor: self.sensor, processing: self.processing, interrupt: self.interrupt, @@ -90,13 +93,13 @@ where _state: PhantomData, }) } else { - Err(SensorError::PrepareFailed) + Err(RadarError::SensorError(PrepareFailed)) } } #[require(Hibernating)] #[switch_to(Ready)] - pub fn hibernate_off(self) -> Result, SensorError> { + pub fn hibernate_off(self) -> Result, RadarError> { if self.sensor.hibernate_off().is_ok() { Ok(Radar { id: self.id, @@ -108,26 +111,26 @@ where _state: PhantomData, }) } else { - Err(SensorError::HibernationOffFailed) + Err(RadarError::SensorError(HibernationOffFailed)) } } #[require(Ready)] - pub async fn measure(&mut self, data: &mut [u8]) -> Result<(), SensorError> { + pub async fn measure(&mut self, data: &mut [u8]) -> Result<(), RadarError> { if (self.sensor.measure(&mut self.interrupt).await).is_ok() { if self.sensor.read(data).is_ok() { Ok(()) } else { - Err(SensorError::ReadError) + Err(RadarError::SensorError(ReadError)) } } else { - Err(SensorError::MeasurementError) + Err(RadarError::SensorError(MeasurementError)) } } #[require(Ready)] #[switch_to(Hibernating)] - pub fn hibernate_on(mut self) -> Result, SensorError> { + pub fn hibernate_on(mut self) -> Result, RadarError> { if self.sensor.hibernate_on().is_ok() { Ok(Radar { id: self.id, @@ -139,7 +142,7 @@ where _state: PhantomData, }) } else { - Err(SensorError::HibernationOnFailed) + Err(RadarError::SensorError(HibernationOnFailed)) } } @@ -150,9 +153,12 @@ where } #[require(A)] - pub async fn calibrate(&mut self) -> Result { + pub async fn calibrate(&mut self) -> Result { let mut buf = [0u8; 5560]; - self.sensor.calibrate(&mut self.interrupt, &mut buf).await + self.sensor + .calibrate(&mut self.interrupt, &mut buf) + .await + .map_err(|e| RadarError::SensorError(e)) } #[require(A)] @@ -175,4 +181,55 @@ where debug_assert!(!self.sensor.inner().is_null(), "Sensor pointer is null"); self.sensor.inner() } + + /// Applies configuration changes to the radar sensor atomically. + /// + /// Temporarily unlocks the configuration, applies changes via the provided closure, + /// resets the sensor, then locks the configuration again. If any step fails, the + /// configuration remains unchanged. + /// + /// # Arguments + /// * `f` - Closure receiving mutable access to unlocked configuration, returns Result + /// + /// # Example + /// ```no_run + /// radar.apply_config(|config| { + /// config.set_start_point(100); + /// config.set_profile(RadarProfile::AccProfile1)?; + /// Ok(()) + /// }).await?; + /// ``` + #[require(Ready)] + pub async fn apply_config(&mut self, f: F) -> Result<(), RadarError> + where + E: Into, + F: FnOnce(&mut RadarConfig) -> Result<(), E>, + { + // Unlock the config temporarily + let mut tmp = self.config.take().unwrap().unlock(); + + // Let the closure modify the config + match f(&mut tmp) { + Ok(()) => { + // Reset the sensor to apply changes + self.reset_sensor().await; + + // Lock the config again + self.config = Some(tmp.lock()); + + Ok(()) + } + Err(e) => { + // Lock the config again + self.config = Some(tmp.lock()); + + return Err(e.into()); + } + } + } + + #[require(A)] + pub fn config(&self) -> &RadarConfig { + self.config.as_ref().unwrap() + } } diff --git a/src/radar/error.rs b/src/radar/error.rs new file mode 100644 index 0000000..6f6803a --- /dev/null +++ b/src/radar/error.rs @@ -0,0 +1,8 @@ +use crate::config::error::ConfigError; +use crate::sensor::error::SensorError; + +#[derive(Debug)] +pub enum RadarError { + SensorError(SensorError), + ConfigError(ConfigError), +}