Pass electrode config from GUI to hardware.

This commit is contained in:
2026-03-02 19:05:57 +01:00
parent 8d3fa53624
commit 2c9706dd2a
5 changed files with 117 additions and 16 deletions

View File

@@ -1,4 +1,4 @@
use defmt::info; use defmt::{info, error};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_sync::blocking_mutex::raw::{ThreadModeRawMutex, CriticalSectionRawMutex}; 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::impedance::{ImpedanceSetupType, RunningMode, IMPEDANCE_CHANNEL_SWEEP, IMPEDANCE_CHANNEL_SINGLE};
use crate::icd_mapping::IntoLocalElectrode;
// Postcard RPC types // Postcard RPC types
type AppDriver = usb::Driver<'static, peripherals::USB>; type AppDriver = usb::Driver<'static, peripherals::USB>;
type AppStorage = WireStorage<ThreadModeRawMutex, AppDriver, 256, 256, 64, 256>; type AppStorage = WireStorage<ThreadModeRawMutex, AppDriver, 256, 256, 64, 256>;
@@ -64,14 +67,15 @@ define_dispatch! {
endpoints: { endpoints: {
list: ENDPOINT_LIST; list: ENDPOINT_LIST;
| EndpointTy | kind | handler | | EndpointTy | kind | handler |
| ---------- | ---- | ------- | | ---------- | ---- | ------- |
| PingEndpoint | blocking | ping_handler | | PingEndpoint | blocking | ping_handler |
| GetUniqueIdEndpoint | blocking | get_unique_id_handler | | GetUniqueIdEndpoint | blocking | get_unique_id_handler |
| SetGreenLedEndpoint | async | set_green_led_handler | | GetMultiplexerCapabilityEndpoint | async | get_multiplexer_capability_handler |
| StartSingleImpedanceEndpoint | spawn | start_single_impedance_handler | | SetGreenLedEndpoint | async | set_green_led_handler |
| StartSweepImpedanceEndpoint | spawn | start_sweep_impedance_handler | | StartSingleImpedanceEndpoint | spawn | start_single_impedance_handler |
| StopImpedanceEndpoint | async | stop_impedance_handler | | StartSweepImpedanceEndpoint | spawn | start_sweep_impedance_handler |
| StopImpedanceEndpoint | async | stop_impedance_handler |
}; };
topics_in: { topics_in: {
list: TOPICS_IN_LIST; list: TOPICS_IN_LIST;
@@ -153,6 +157,15 @@ pub fn get_unique_id_handler(context: &mut Context, _header: VarHeader, _rqst: (
context.unique_id 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<CriticalSectionRawMutex, f32> = Signal::new(); pub static LED_FREQUENCY_SIGNAL: Signal<CriticalSectionRawMutex, f32> = Signal::new();
pub async fn set_green_led_handler(_context: &mut Context, _header: VarHeader, rqst: f32) { pub async fn set_green_led_handler(_context: &mut Context, _header: VarHeader, rqst: f32) {
@@ -167,6 +180,31 @@ static STOP: Signal<CriticalSectionRawMutex, ()> = Signal::new();
pub async fn start_single_impedance_handler(context: SpawnCtx, header: VarHeader, rqst: SingleImpedanceStartRequest, sender: Sender<AppTx>) { pub async fn start_single_impedance_handler(context: SpawnCtx, header: VarHeader, rqst: SingleImpedanceStartRequest, sender: Sender<AppTx>) {
info!("Start impedance measurement at {:?} Hz.", rqst.sinus_frequency); 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 // Mark the impedance setup as running
match rqst.lead_mode { match rqst.lead_mode {
BioImpedanceLeadMode::TwoLead => context.impedance_setup.lock().await.running_mode = RunningMode::SingleFrequency2Lead, 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] #[embassy_executor::task]
pub async fn start_sweep_impedance_handler(context: SpawnCtx, header: VarHeader, rqst: SweepImpedanceStartRequest, sender: Sender<AppTx>) { pub async fn start_sweep_impedance_handler(context: SpawnCtx, header: VarHeader, rqst: SweepImpedanceStartRequest, sender: Sender<AppTx>) {
// Mark the impedance setup as running // 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 // Init the sequencer
let response = match (rqst.lead_mode, rqst.points) { let response = match (rqst.lead_mode, rqst.points) {

View File

@@ -4,7 +4,7 @@ use embassy_sync::blocking_mutex::NoopMutex;
use static_cell::StaticCell; use static_cell::StaticCell;
use core::cell::RefCell; 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<NoopMutex<RefCell<i2c::I2c<'static, Blocking, Master>>>> = StaticCell::new(); static I2C_BUS: StaticCell<NoopMutex<RefCell<i2c::I2c<'static, Blocking, Master>>>> = StaticCell::new();
@@ -26,7 +26,6 @@ impl Electrode {
Electrode::E16, Electrode::E17, Electrode::E18, Electrode::E19, Electrode::E16, Electrode::E17, Electrode::E18, Electrode::E19,
Electrode::E20, Electrode::E21, Electrode::E22, Electrode::E23, Electrode::E20, Electrode::E21, Electrode::E22, Electrode::E23,
]; ];
*VARIANTS.get(value as usize).expect("Invalid value for SetX") *VARIANTS.get(value as usize).expect("Invalid value for SetX")
} }
} }

View File

@@ -1,5 +1,6 @@
use crate::ad5940_registers::DFTNUM; 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 // Map ICD types to register types
pub trait IntoDftnum { pub trait IntoDftnum {
@@ -25,3 +26,38 @@ impl IntoDftnum for IcdDftNum {
} }
} }
} }
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,
}
}
}

View File

@@ -1,4 +1,4 @@
use defmt::{info, error}; use defmt::error;
use embassy_stm32::spi::Error; use embassy_stm32::spi::Error;
use embassy_stm32::exti::ExtiInput; use embassy_stm32::exti::ExtiInput;

View File

@@ -96,7 +96,7 @@ async fn main(spawner: Spawner) {
// ad5940.init_waveform().await.unwrap(); // ad5940.init_waveform().await.unwrap();
let mut impedance_setup = ImpedanceSetup::new(ad5940); let mut impedance_setup = ImpedanceSetup::new(ad5940);
impedance_setup.init().await.unwrap(); 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; // impedance_setup.lock().await.init_single_frequency_measurement().await;