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_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<ThreadModeRawMutex, AppDriver, 256, 256, 64, 256>;
@@ -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<CriticalSectionRawMutex, f32> = Signal::new();
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>) {
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<AppTx>) {
// 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) {

View File

@@ -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<NoopMutex<RefCell<i2c::I2c<'static, Blocking, Master>>>> = 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")
}
}

View File

@@ -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,
}
}
}

View File

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

View File

@@ -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;