From 2c9706dd2acb462d226e3b0cf75a71b6e314e980 Mon Sep 17 00:00:00 2001 From: Hubald Verzijl Date: Mon, 2 Mar 2026 19:05:57 +0100 Subject: [PATCH] Pass electrode config from GUI to hardware. --- src/communication.rs | 88 ++++++++++++++++++++++++++++++++++++++------ src/electrodes.rs | 3 +- src/icd_mapping.rs | 38 ++++++++++++++++++- src/impedance.rs | 2 +- src/main.rs | 2 +- 5 files changed, 117 insertions(+), 16 deletions(-) diff --git a/src/communication.rs b/src/communication.rs index 4a36559..35ef2f9 100644 --- a/src/communication.rs +++ b/src/communication.rs @@ -1,4 +1,4 @@ -use defmt::info; +use defmt::{info, error}; use embassy_executor::Spawner; use embassy_sync::blocking_mutex::raw::{ThreadModeRawMutex, CriticalSectionRawMutex}; @@ -20,10 +20,13 @@ use postcard_rpc::{ }, }; -use bioz_icd_rs::{GetUniqueIdEndpoint, MeasurementPointSet, SweepImpedanceOutputTopic, SweepImpedanceResult, SweepImpedanceStartRequest, PingEndpoint, SetGreenLedEndpoint, SingleImpedanceOutputTopic, SingleImpedanceStartRequest, StartSweepImpedanceEndpoint, StartSingleImpedanceEndpoint, StopImpedanceEndpoint, BioImpedanceLeadMode, ENDPOINT_LIST, TOPICS_IN_LIST, TOPICS_OUT_LIST}; +use bioz_icd_rs::{GetUniqueIdEndpoint, GetMultiplexerCapabilityEndpoint, MultiplexerCapability, ElectrodeConfiguration, MeasurementPointSet, SweepImpedanceOutputTopic, SweepImpedanceResult, SweepImpedanceStartRequest, PingEndpoint, SetGreenLedEndpoint, SingleImpedanceOutputTopic, SingleImpedanceStartRequest, StartSweepImpedanceEndpoint, StartSingleImpedanceEndpoint, StopImpedanceEndpoint, BioImpedanceLeadMode, ENDPOINT_LIST, TOPICS_IN_LIST, TOPICS_OUT_LIST}; +use crate::electrodes; use crate::impedance::{ImpedanceSetupType, RunningMode, IMPEDANCE_CHANNEL_SWEEP, IMPEDANCE_CHANNEL_SINGLE}; +use crate::icd_mapping::IntoLocalElectrode; + // Postcard RPC types type AppDriver = usb::Driver<'static, peripherals::USB>; type AppStorage = WireStorage; @@ -64,14 +67,15 @@ define_dispatch! { endpoints: { list: ENDPOINT_LIST; - | EndpointTy | kind | handler | - | ---------- | ---- | ------- | - | PingEndpoint | blocking | ping_handler | - | GetUniqueIdEndpoint | blocking | get_unique_id_handler | - | SetGreenLedEndpoint | async | set_green_led_handler | - | StartSingleImpedanceEndpoint | spawn | start_single_impedance_handler | - | StartSweepImpedanceEndpoint | spawn | start_sweep_impedance_handler | - | StopImpedanceEndpoint | async | stop_impedance_handler | + | EndpointTy | kind | handler | + | ---------- | ---- | ------- | + | PingEndpoint | blocking | ping_handler | + | GetUniqueIdEndpoint | blocking | get_unique_id_handler | + | GetMultiplexerCapabilityEndpoint | async | get_multiplexer_capability_handler | + | SetGreenLedEndpoint | async | set_green_led_handler | + | StartSingleImpedanceEndpoint | spawn | start_single_impedance_handler | + | StartSweepImpedanceEndpoint | spawn | start_sweep_impedance_handler | + | StopImpedanceEndpoint | async | stop_impedance_handler | }; topics_in: { list: TOPICS_IN_LIST; @@ -153,6 +157,15 @@ pub fn get_unique_id_handler(context: &mut Context, _header: VarHeader, _rqst: ( context.unique_id } +pub async fn get_multiplexer_capability_handler(context: &mut Context, _header: VarHeader, _rqst: ()) -> MultiplexerCapability { + info!("get_multiplexer_capability"); + if context.impedance_setup.lock().await.electrodes.is_some() { + MultiplexerCapability::Present + } else { + MultiplexerCapability::Absent + } +} + pub static LED_FREQUENCY_SIGNAL: Signal = Signal::new(); pub async fn set_green_led_handler(_context: &mut Context, _header: VarHeader, rqst: f32) { @@ -167,6 +180,31 @@ static STOP: Signal = Signal::new(); pub async fn start_single_impedance_handler(context: SpawnCtx, header: VarHeader, rqst: SingleImpedanceStartRequest, sender: Sender) { info!("Start impedance measurement at {:?} Hz.", rqst.sinus_frequency); + // Set the electrodes + if let Some(config) = rqst.electrode_config { + let mut setup = context.impedance_setup.lock().await; + + let Some(e) = &mut setup.electrodes else { + error!("Cannot set electrode configuration, multiplexer not present"); + return; + }; + + e.reset_all(); + + match config { + ElectrodeConfiguration::WithMultiplexer2Lead(i1, i2) => { + e.set(i1.into_embedded_electrode_number(), electrodes::AD5940Pin::CE0, crate::State::ENABLED); + e.set(i2.into_embedded_electrode_number(), electrodes::AD5940Pin::AIN1, crate::State::ENABLED); + } + ElectrodeConfiguration::WithMultiplexer4Lead(i1, i2, v1, v2) => { + e.set(i1.into_embedded_electrode_number(), electrodes::AD5940Pin::CE0, crate::State::ENABLED); + e.set(i2.into_embedded_electrode_number(), electrodes::AD5940Pin::AIN1, crate::State::ENABLED); + e.set(v1.into_embedded_electrode_number(), electrodes::AD5940Pin::AIN2, crate::State::ENABLED); + e.set(v2.into_embedded_electrode_number(), electrodes::AD5940Pin::AIN3, crate::State::ENABLED); + } + } + } + // Mark the impedance setup as running match rqst.lead_mode { BioImpedanceLeadMode::TwoLead => context.impedance_setup.lock().await.running_mode = RunningMode::SingleFrequency2Lead, @@ -221,8 +259,36 @@ pub async fn start_single_impedance_handler(context: SpawnCtx, header: VarHeader #[embassy_executor::task] pub async fn start_sweep_impedance_handler(context: SpawnCtx, header: VarHeader, rqst: SweepImpedanceStartRequest, sender: Sender) { + // Set the electrodes + if let Some(config) = rqst.electrode_config { + let mut setup = context.impedance_setup.lock().await; + + let Some(e) = &mut setup.electrodes else { + error!("Cannot set electrode configuration, multiplexer not present"); + return; + }; + + e.reset_all(); + + match config { + ElectrodeConfiguration::WithMultiplexer2Lead(i1, i2) => { + e.set(i1.into_embedded_electrode_number(), electrodes::AD5940Pin::CE0, crate::State::ENABLED); + e.set(i2.into_embedded_electrode_number(), electrodes::AD5940Pin::AIN1, crate::State::ENABLED); + } + ElectrodeConfiguration::WithMultiplexer4Lead(i1, i2, v1, v2) => { + e.set(i1.into_embedded_electrode_number(), electrodes::AD5940Pin::CE0, crate::State::ENABLED); + e.set(i2.into_embedded_electrode_number(), electrodes::AD5940Pin::AIN1, crate::State::ENABLED); + e.set(v1.into_embedded_electrode_number(), electrodes::AD5940Pin::AIN2, crate::State::ENABLED); + e.set(v2.into_embedded_electrode_number(), electrodes::AD5940Pin::AIN3, crate::State::ENABLED); + } + } + } + // Mark the impedance setup as running - + match rqst.lead_mode { + BioImpedanceLeadMode::TwoLead => context.impedance_setup.lock().await.running_mode = RunningMode::SweepFrequency2Lead(rqst.points), + BioImpedanceLeadMode::FourLead => context.impedance_setup.lock().await.running_mode = RunningMode::SweepFrequency4Lead(rqst.points), + } // Init the sequencer let response = match (rqst.lead_mode, rqst.points) { diff --git a/src/electrodes.rs b/src/electrodes.rs index 276e4b4..e127988 100644 --- a/src/electrodes.rs +++ b/src/electrodes.rs @@ -4,7 +4,7 @@ use embassy_sync::blocking_mutex::NoopMutex; use static_cell::StaticCell; use core::cell::RefCell; -use crate::{ad5940, adg2128::{GetX, SetX, SetY, State, ADG2128}}; +use crate::{adg2128::{GetX, SetX, SetY, State, ADG2128}}; static I2C_BUS: StaticCell>>> = StaticCell::new(); @@ -26,7 +26,6 @@ impl Electrode { Electrode::E16, Electrode::E17, Electrode::E18, Electrode::E19, Electrode::E20, Electrode::E21, Electrode::E22, Electrode::E23, ]; - *VARIANTS.get(value as usize).expect("Invalid value for SetX") } } diff --git a/src/icd_mapping.rs b/src/icd_mapping.rs index 72ec4d8..0eebd8b 100644 --- a/src/icd_mapping.rs +++ b/src/icd_mapping.rs @@ -1,5 +1,6 @@ use crate::ad5940_registers::DFTNUM; -use bioz_icd_rs::IcdDftNum; +use crate::electrodes::Electrode; +use bioz_icd_rs::{IcdDftNum, ElectrodeOptionsWithMultiplexer}; // Map ICD types to register types pub trait IntoDftnum { @@ -24,4 +25,39 @@ impl IntoDftnum for IcdDftNum { IcdDftNum::Num16384 => DFTNUM::Num16384, } } +} + +pub trait IntoLocalElectrode { + fn into_embedded_electrode_number(self) -> Electrode; +} + +impl IntoLocalElectrode for ElectrodeOptionsWithMultiplexer { + fn into_embedded_electrode_number(self) -> Electrode { + match self { + ElectrodeOptionsWithMultiplexer::E0 => Electrode::E0, + ElectrodeOptionsWithMultiplexer::E1 => Electrode::E1, + ElectrodeOptionsWithMultiplexer::E2 => Electrode::E2, + ElectrodeOptionsWithMultiplexer::E3 => Electrode::E3, + ElectrodeOptionsWithMultiplexer::E4 => Electrode::E4, + ElectrodeOptionsWithMultiplexer::E5 => Electrode::E5, + ElectrodeOptionsWithMultiplexer::E6 => Electrode::E6, + ElectrodeOptionsWithMultiplexer::E7 => Electrode::E7, + ElectrodeOptionsWithMultiplexer::E8 => Electrode::E8, + ElectrodeOptionsWithMultiplexer::E9 => Electrode::E9, + ElectrodeOptionsWithMultiplexer::E10 => Electrode::E10, + ElectrodeOptionsWithMultiplexer::E11 => Electrode::E11, + ElectrodeOptionsWithMultiplexer::E12 => Electrode::E12, + ElectrodeOptionsWithMultiplexer::E13 => Electrode::E13, + ElectrodeOptionsWithMultiplexer::E14 => Electrode::E14, + ElectrodeOptionsWithMultiplexer::E15 => Electrode::E15, + ElectrodeOptionsWithMultiplexer::E16 => Electrode::E16, + ElectrodeOptionsWithMultiplexer::E17 => Electrode::E17, + ElectrodeOptionsWithMultiplexer::E18 => Electrode::E18, + ElectrodeOptionsWithMultiplexer::E19 => Electrode::E19, + ElectrodeOptionsWithMultiplexer::E20 => Electrode::E20, + ElectrodeOptionsWithMultiplexer::E21 => Electrode::E21, + ElectrodeOptionsWithMultiplexer::E22 => Electrode::E22, + ElectrodeOptionsWithMultiplexer::E23 => Electrode::E23, + } + } } \ No newline at end of file diff --git a/src/impedance.rs b/src/impedance.rs index c919acb..98cf7f3 100644 --- a/src/impedance.rs +++ b/src/impedance.rs @@ -1,4 +1,4 @@ -use defmt::{info, error}; +use defmt::error; use embassy_stm32::spi::Error; use embassy_stm32::exti::ExtiInput; diff --git a/src/main.rs b/src/main.rs index b662c50..3d5ffbc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -96,7 +96,7 @@ async fn main(spawner: Spawner) { // ad5940.init_waveform().await.unwrap(); let mut impedance_setup = ImpedanceSetup::new(ad5940); impedance_setup.init().await.unwrap(); - let mut impedance_setup = IMPEDANCE_SETUP.init(Mutex::new(impedance_setup)); + let impedance_setup = IMPEDANCE_SETUP.init(Mutex::new(impedance_setup)); // impedance_setup.lock().await.init_single_frequency_measurement().await;