From 5ae607eec495755d4a7e66c32ad80c0403840ce3 Mon Sep 17 00:00:00 2001 From: jess Date: Mon, 30 Mar 2026 18:28:57 -0700 Subject: [PATCH] recovered working tree: paired DFT, ratiometric Z, open-cal, BLE event refactor --- cue/src/app.rs | 28 ++++++- cue/src/ble.rs | 62 +++++---------- main/ble.c | 2 + main/ble.h | 2 + main/eis.c | 202 ++++++++++++++++++++++++++++++++++++++++--------- main/eis.h | 5 ++ main/eis4.c | 17 +++++ 7 files changed, 238 insertions(+), 80 deletions(-) diff --git a/cue/src/app.rs b/cue/src/app.rs index 13bc053..859497a 100644 --- a/cue/src/app.rs +++ b/cue/src/app.rs @@ -8,6 +8,7 @@ use std::fmt::Write; use std::time::Duration; use tokio::sync::mpsc; +use crate::ble::BleEvent; use crate::native_menu::{MenuAction, NativeMenu}; use crate::protocol::{ self, AmpPoint, ClPoint, ClResult, Electrode, EisMessage, EisPoint, LpRtia, LsvPoint, @@ -732,11 +733,30 @@ impl App { self.midi_gen, iced::stream::channel(100, |mut output| async move { loop { - let _ = output.send(Message::BleStatus("Looking for MIDI device...".into())).await; - match crate::ble::connect_and_stream(&mut output).await { - Ok(()) => eprintln!("BLE: session ended cleanly"), - Err(e) => eprintln!("BLE: session error: {e}"), + let (ble_tx, mut ble_rx) = mpsc::unbounded_channel::(); + let (cmd_tx, cmd_rx) = mpsc::unbounded_channel::>(); + + let tx = ble_tx.clone(); + tokio::spawn(async move { + if let Err(e) = crate::ble::connect_and_run(tx, cmd_rx).await { + eprintln!("BLE: {e}"); + } + }); + + let mut ready_sent = false; + while let Some(ev) = ble_rx.recv().await { + let msg = match ev { + BleEvent::Status(ref s) if s == "Connected" && !ready_sent => { + ready_sent = true; + let _ = output.send(Message::BleReady(cmd_tx.clone())).await; + Message::BleStatus(s.clone()) + } + BleEvent::Status(s) => Message::BleStatus(s), + BleEvent::Data(m) => Message::BleData(m), + }; + let _ = output.send(msg).await; } + let _ = output.send(Message::BleStatus("Reconnecting...".into())).await; tokio::time::sleep(Duration::from_millis(500)).await; } diff --git a/cue/src/ble.rs b/cue/src/ble.rs index 983e097..892d22e 100644 --- a/cue/src/ble.rs +++ b/cue/src/ble.rs @@ -1,29 +1,31 @@ -use futures::SinkExt; use midir::{MidiInput, MidiOutput, MidiInputConnection, MidiOutputConnection}; use std::sync::mpsc as std_mpsc; use tokio::sync::mpsc; -use crate::app::Message; -use crate::protocol; +use crate::protocol::{self, EisMessage}; const DEVICE_NAME: &str = "EIS4"; -pub async fn connect_and_stream( - output: &mut futures::channel::mpsc::Sender, +#[derive(Debug, Clone)] +pub enum BleEvent { + Status(String), + Data(EisMessage), +} + +pub async fn connect_and_run( + tx: mpsc::UnboundedSender, + mut cmd_rx: mpsc::UnboundedReceiver>, ) -> Result<(), Box> { - eprintln!("BLE: scanning for MIDI device '{DEVICE_NAME}'..."); + let _ = tx.send(BleEvent::Status("Looking for MIDI device...".into())); let (midi_in, in_port, midi_out, out_port) = loop { - match find_midi_ports() { - Some(found) => break found, - None => { - tokio::time::sleep(std::time::Duration::from_millis(500)).await; - } + if let Some(found) = find_midi_ports() { + break found; } + tokio::time::sleep(std::time::Duration::from_millis(500)).await; }; - eprintln!("BLE: found ports, connecting..."); - let _ = output.send(Message::BleStatus("Connecting MIDI...".into())).await; + let _ = tx.send(BleEvent::Status("Connecting MIDI...".into())); let (sysex_tx, sysex_rx) = std_mpsc::channel::>(); @@ -41,16 +43,12 @@ pub async fn connect_and_stream( &out_port, "cue-out", ).map_err(|e| format!("MIDI output connect: {e}"))?; - eprintln!("BLE: connected"); - let _ = output.send(Message::BleStatus("Connected".into())).await; - - let (cmd_tx, mut cmd_rx) = mpsc::unbounded_channel::>(); - let _ = output.send(Message::BleReady(cmd_tx)).await; + let _ = tx.send(BleEvent::Status("Connected".into())); loop { while let Ok(sysex) = sysex_rx.try_recv() { if let Some(msg) = protocol::parse_sysex(&sysex) { - let _ = output.send(Message::BleData(msg)).await; + let _ = tx.send(BleEvent::Data(msg)); } } @@ -58,14 +56,10 @@ pub async fn connect_and_stream( match cmd_rx.try_recv() { Ok(pkt) => { if let Err(e) = out_conn.send(&pkt) { - eprintln!("BLE: MIDI send error: {e}"); - return Err(e.into()); + eprintln!("MIDI send error: {e}"); } } - Err(mpsc::error::TryRecvError::Disconnected) => { - eprintln!("BLE: cmd channel closed"); - return Ok(()); - } + Err(mpsc::error::TryRecvError::Disconnected) => return Ok(()), Err(mpsc::error::TryRecvError::Empty) => break, } } @@ -81,25 +75,11 @@ fn find_midi_ports() -> Option<( let midi_in = MidiInput::new("cue-in").ok()?; let midi_out = MidiOutput::new("cue-out").ok()?; - let in_ports = midi_in.ports(); - let out_ports = midi_out.ports(); - - let in_names: Vec<_> = in_ports.iter() - .filter_map(|p| midi_in.port_name(p).ok()) - .collect(); - let out_names: Vec<_> = out_ports.iter() - .filter_map(|p| midi_out.port_name(p).ok()) - .collect(); - - if !in_names.is_empty() || !out_names.is_empty() { - eprintln!("BLE: MIDI ports — in: {:?}, out: {:?}", in_names, out_names); - } - - let in_port = in_ports.into_iter().find(|p| { + let in_port = midi_in.ports().into_iter().find(|p| { midi_in.port_name(p).map_or(false, |n| n.contains(DEVICE_NAME)) })?; - let out_port = out_ports.into_iter().find(|p| { + let out_port = midi_out.ports().into_iter().find(|p| { midi_out.port_name(p).map_or(false, |n| n.contains(DEVICE_NAME)) })?; diff --git a/main/ble.c b/main/ble.c index e406176..57564ad 100644 --- a/main/ble.c +++ b/main/ble.c @@ -185,6 +185,8 @@ static void parse_one_sysex(const uint8_t *midi, uint16_t mlen) case CMD_START_REFS: case CMD_GET_REFS: case CMD_CLEAR_REFS: + case CMD_OPEN_CAL: + case CMD_CLEAR_OPEN_CAL: break; default: return; diff --git a/main/ble.h b/main/ble.h index 27c8b30..929d41e 100644 --- a/main/ble.h +++ b/main/ble.h @@ -18,6 +18,8 @@ #define CMD_START_CL 0x23 #define CMD_START_PH 0x24 #define CMD_START_CLEAN 0x25 +#define CMD_OPEN_CAL 0x26 +#define CMD_CLEAR_OPEN_CAL 0x27 #define CMD_START_REFS 0x30 #define CMD_GET_REFS 0x31 #define CMD_CLEAR_REFS 0x32 diff --git a/main/eis.c b/main/eis.c index d93da6e..30b0085 100644 --- a/main/eis.c +++ b/main/eis.c @@ -4,6 +4,8 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "nvs_flash.h" +#include "nvs.h" #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -21,6 +23,14 @@ static struct { uint32_t dertia_reg; } ctx; +/* open-circuit calibration data */ +static struct { + fImpCar_Type y[EIS_MAX_POINTS]; /* admittance at each freq */ + float freq[EIS_MAX_POINTS]; + uint32_t n; + int valid; +} ocal; + static const uint32_t rtia_map[] = { [RTIA_200] = HSTIARTIA_200, [RTIA_1K] = HSTIARTIA_1K, @@ -127,9 +137,13 @@ void eis_default_config(EISConfig *cfg) uint32_t eis_calc_num_points(const EISConfig *cfg) { - if (cfg->freq_stop_hz <= cfg->freq_start_hz || cfg->points_per_decade == 0) + if (cfg->points_per_decade == 0) return 1; - float decades = log10f(cfg->freq_stop_hz / cfg->freq_start_hz); + if (cfg->freq_start_hz == cfg->freq_stop_hz) + return 24; /* fixed-freq repeatability test */ + float lo = fminf(cfg->freq_start_hz, cfg->freq_stop_hz); + float hi = fmaxf(cfg->freq_start_hz, cfg->freq_stop_hz); + float decades = log10f(hi / lo); uint32_t n = (uint32_t)(decades * cfg->points_per_decade + 0.5f) + 1; if (n > EIS_MAX_POINTS) n = EIS_MAX_POINTS; if (n < 2) n = 2; @@ -164,7 +178,7 @@ void eis_init(const EISConfig *cfg) ref.LpRefBufEn = bFALSE; AD5940_REFCfgS(&ref); - AD5940_AFEPwrBW(AFEPWR_LP, AFEBW_250KHZ); + AD5940_AFEPwrBW(AFEPWR_HP, AFEBW_250KHZ); AD5940_INTCCfg(AFEINTC_0, AFEINTSRC_DFTRDY, bTRUE); AD5940_INTCCfg(AFEINTC_1, AFEINTSRC_DFTRDY, bTRUE); @@ -214,7 +228,7 @@ static void configure_freq(float freq_hz) fp.DftSrc = DFTSRC_ADCRAW; fp.ADCSinc3Osr = ADCSINC3OSR_2; fp.ADCSinc2Osr = 0; - fp.DftNum = DFTNUM_16384; + fp.DftNum = DFTNUM_4096; } AD5940_WriteReg(REG_AFE_WGFCW, @@ -247,7 +261,10 @@ static int32_t sign_extend_18(uint32_t v) return (v & (1UL << 17)) ? (int32_t)(v | 0xFFFC0000UL) : (int32_t)v; } -static void dft_measure(uint32_t mux_p, uint32_t mux_n, iImpCar_Type *out) +/* paired DFT: two measurements under continuous WG excitation */ +static void dft_measure_pair( + uint32_t mux1_p, uint32_t mux1_n, iImpCar_Type *out1, + uint32_t mux2_p, uint32_t mux2_n, iImpCar_Type *out2) { AD5940_AFECtrlS(AFECTRL_ADCCNV | AFECTRL_DFT, bFALSE); AD5940_WriteReg(REG_AFE_FIFOCON, 0); @@ -255,32 +272,48 @@ static void dft_measure(uint32_t mux_p, uint32_t mux_n, iImpCar_Type *out) AD5940_ReadAfeResult(AFERESULT_DFTIMAGE); AD5940_INTCClrFlag(AFEINTSRC_DFTRDY); - AD5940_ADCMuxCfgS(mux_p, mux_n); - + AD5940_ADCMuxCfgS(mux1_p, mux1_n); AD5940_AFECtrlS(AFECTRL_WG | AFECTRL_ADCPWR, bTRUE); AD5940_Delay10us(25); AD5940_ClrMCUIntFlag(); AD5940_AFECtrlS(AFECTRL_ADCCNV | AFECTRL_DFT, bTRUE); - while (!AD5940_GetMCUIntFlag()) vTaskDelay(1); + AD5940_AFECtrlS(AFECTRL_ADCCNV | AFECTRL_DFT, bFALSE); + AD5940_INTCClrFlag(AFEINTSRC_DFTRDY); + out1->Real = sign_extend_18(AD5940_ReadAfeResult(AFERESULT_DFTREAL)); + out1->Image = sign_extend_18(AD5940_ReadAfeResult(AFERESULT_DFTIMAGE)); + out1->Image = -out1->Image; + + /* switch ADC mux, flush stale pipeline, short settle */ + AD5940_ADCMuxCfgS(mux2_p, mux2_n); + AD5940_ReadAfeResult(AFERESULT_DFTREAL); + AD5940_ReadAfeResult(AFERESULT_DFTIMAGE); + AD5940_INTCClrFlag(AFEINTSRC_DFTRDY); + AD5940_Delay10us(5); + + AD5940_ClrMCUIntFlag(); + AD5940_AFECtrlS(AFECTRL_ADCCNV | AFECTRL_DFT, bTRUE); + while (!AD5940_GetMCUIntFlag()) + vTaskDelay(1); AD5940_AFECtrlS(AFECTRL_ADCCNV | AFECTRL_DFT | AFECTRL_WG | AFECTRL_ADCPWR, bFALSE); AD5940_INTCClrFlag(AFEINTSRC_DFTRDY); - out->Real = sign_extend_18(AD5940_ReadAfeResult(AFERESULT_DFTREAL)); - out->Image = sign_extend_18(AD5940_ReadAfeResult(AFERESULT_DFTIMAGE)); - out->Image = -out->Image; + out2->Real = sign_extend_18(AD5940_ReadAfeResult(AFERESULT_DFTREAL)); + out2->Image = sign_extend_18(AD5940_ReadAfeResult(AFERESULT_DFTIMAGE)); + out2->Image = -out2->Image; } -/* RTIA calibration: 2 DFTs through current RCAL switch config */ -static fImpCar_Type measure_rtia(void) +static fImpCar_Type measure_rtia(iImpCar_Type *out_hstia) { iImpCar_Type v_rcal, v_raw; - dft_measure(ADCMUXP_P_NODE, ADCMUXN_N_NODE, &v_rcal); - dft_measure(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N, &v_raw); + dft_measure_pair( + ADCMUXP_P_NODE, ADCMUXN_N_NODE, &v_rcal, + ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N, &v_raw); + if (out_hstia) *out_hstia = v_raw; v_raw.Real = -v_raw.Real; v_raw.Image = -v_raw.Image; fImpCar_Type rtia = AD5940_ComplexDivInt(&v_raw, &v_rcal); @@ -309,8 +342,9 @@ int eis_measure_point(float freq_hz, EISPoint *out) AFECTRL_EXTBUFPWR | AFECTRL_DACREFPWR | AFECTRL_HSDACPWR | AFECTRL_SINC2NOTCH, bTRUE); - /* RCAL before */ - fImpCar_Type rtia_before = measure_rtia(); + /* RCAL before — capture raw HSTIA DFT for ratiometric diagnostic */ + iImpCar_Type rcal_hstia; + fImpCar_Type rtia_before = measure_rtia(&rcal_hstia); /* DUT forward */ sw.Dswitch = ctx.dut_sw_d; @@ -320,10 +354,11 @@ int eis_measure_point(float freq_hz, EISPoint *out) AD5940_SWMatrixCfgS(&sw); AD5940_Delay10us(50); - dft_measure(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N, &v_tia); + dft_measure_pair(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N, &v_tia, + ctx.dut_mux_vp, ctx.dut_mux_vn, &v_sense); + iImpCar_Type dut_hstia_raw = v_tia; v_tia.Real = -v_tia.Real; v_tia.Image = -v_tia.Image; - dft_measure(ctx.dut_mux_vp, ctx.dut_mux_vn, &v_sense); iImpCar_Type v_tia_fwd = v_tia; iImpCar_Type v_sense_fwd = v_sense; @@ -336,7 +371,7 @@ int eis_measure_point(float freq_hz, EISPoint *out) AD5940_SWMatrixCfgS(&sw); AD5940_Delay10us(50); - fImpCar_Type rtia_after = measure_rtia(); + fImpCar_Type rtia_after = measure_rtia(NULL); /* DUT reverse (DUT first, then RCAL) */ sw.Dswitch = ctx.dut_sw_d; @@ -346,10 +381,10 @@ int eis_measure_point(float freq_hz, EISPoint *out) AD5940_SWMatrixCfgS(&sw); AD5940_Delay10us(50); - dft_measure(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N, &v_tia); + dft_measure_pair(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N, &v_tia, + ctx.dut_mux_vp, ctx.dut_mux_vn, &v_sense); v_tia.Real = -v_tia.Real; v_tia.Image = -v_tia.Image; - dft_measure(ctx.dut_mux_vp, ctx.dut_mux_vn, &v_sense); iImpCar_Type v_tia_rev = v_tia; iImpCar_Type v_sense_rev = v_sense; @@ -362,7 +397,7 @@ int eis_measure_point(float freq_hz, EISPoint *out) AD5940_SWMatrixCfgS(&sw); AD5940_Delay10us(50); - fImpCar_Type rtia_rev = measure_rtia(); + fImpCar_Type rtia_rev = measure_rtia(NULL); /* power down, open switches */ AD5940_AFECtrlS(AFECTRL_WG | AFECTRL_ADCPWR | AFECTRL_ADCCNV | @@ -391,9 +426,29 @@ int eis_measure_point(float freq_hz, EISPoint *out) fImpCar_Type ft_rev = { (float)v_tia_rev.Real, (float)v_tia_rev.Image }; num = AD5940_ComplexMulFloat(&fs_rev, &rtia_rev); fImpCar_Type z_rev = AD5940_ComplexDivFloat(&num, &ft_rev); + (void)z_rev; + + /* HSTIA-only ratiometric: Z = (DftRcal / DftDut) * RCAL */ + fImpCar_Type fr = { (float)rcal_hstia.Real, (float)rcal_hstia.Image }; + fImpCar_Type fd = { (float)dut_hstia_raw.Real, (float)dut_hstia_raw.Image }; + fImpCar_Type z_ratio = AD5940_ComplexDivFloat(&fr, &fd); + z_ratio.Real *= ctx.rcal_ohms; + z_ratio.Image *= ctx.rcal_ohms; + + /* apply open-circuit compensation if available */ + if (ocal.valid) { + for (uint32_t k = 0; k < ocal.n; k++) { + if (fabsf(ocal.freq[k] - freq_hz) < freq_hz * 0.01f) { + fImpCar_Type one = {1.0f, 0.0f}; + fImpCar_Type y_meas = AD5940_ComplexDivFloat(&one, &z_fwd); + fImpCar_Type y_corr = AD5940_ComplexSubFloat(&y_meas, &ocal.y[k]); + z_fwd = AD5940_ComplexDivFloat(&one, &y_corr); + break; + } + } + } float mag_fwd = AD5940_ComplexMag(&z_fwd); - float mag_rev = AD5940_ComplexMag(&z_rev); out->freq_hz = freq_hz; out->z_real = z_fwd.Real; @@ -402,10 +457,9 @@ int eis_measure_point(float freq_hz, EISPoint *out) out->phase_deg = AD5940_ComplexPhase(&z_fwd) * (float)(180.0 / M_PI); out->rtia_mag_before = AD5940_ComplexMag(&rtia_before); out->rtia_mag_after = AD5940_ComplexMag(&rtia_after); - out->rev_mag = mag_rev; - out->rev_phase = AD5940_ComplexPhase(&z_rev) * (float)(180.0 / M_PI); - out->pct_err = (mag_fwd > 0.0f) - ? fabsf(mag_fwd - mag_rev) / mag_fwd * 100.0f : 0.0f; + out->rev_mag = AD5940_ComplexMag(&z_ratio); + out->rev_phase = AD5940_ComplexPhase(&z_ratio) * (float)(180.0 / M_PI); + out->pct_err = 0.0f; return 0; } @@ -427,23 +481,33 @@ int eis_sweep(EISPoint *out, uint32_t max_points, eis_point_cb_t cb) sweep.SweepLog = bTRUE; sweep.SweepIndex = 0; - printf("\n%10s %12s %10s %12s %12s %7s\n", - "Freq(Hz)", "|Z|(Ohm)", "Phase(deg)", "Re(Ohm)", "Im(Ohm)", "Err%"); - printf("---------------------------------------------------------------------\n"); + printf("\n%10s %12s %10s %12s %12s | %12s %10s %6s\n", + "Freq(Hz)", "|Z|dual", "Ph_dual", "Re_dual", "Im_dual", + "|Z|ratio", "Ph_ratio", "ms"); + printf("--------------------------------------------------------------------------" + "-------------------------\n"); + uint32_t t0 = xTaskGetTickCount(); eis_measure_point(ctx.cfg.freq_start_hz, &out[0]); - printf("%10.1f %12.2f %10.2f %12.2f %12.2f %6.2f%%\n", + uint32_t t1 = xTaskGetTickCount(); + printf("%10.1f %12.2f %10.2f %12.2f %12.2f | %12.2f %10.2f %6lu\n", out[0].freq_hz, out[0].mag_ohms, out[0].phase_deg, - out[0].z_real, out[0].z_imag, out[0].pct_err); + out[0].z_real, out[0].z_imag, + out[0].rev_mag, out[0].rev_phase, + (unsigned long)((t1 - t0) * portTICK_PERIOD_MS)); if (cb) cb(0, &out[0]); for (uint32_t i = 1; i < n; i++) { float freq; AD5940_SweepNext(&sweep, &freq); + t0 = xTaskGetTickCount(); eis_measure_point(freq, &out[i]); - printf("%10.1f %12.2f %10.2f %12.2f %12.2f %6.2f%%\n", + t1 = xTaskGetTickCount(); + printf("%10.1f %12.2f %10.2f %12.2f %12.2f | %12.2f %10.2f %6lu\n", out[i].freq_hz, out[i].mag_ohms, out[i].phase_deg, - out[i].z_real, out[i].z_imag, out[i].pct_err); + out[i].z_real, out[i].z_imag, + out[i].rev_mag, out[i].rev_phase, + (unsigned long)((t1 - t0) * portTICK_PERIOD_MS)); if (cb) cb((uint16_t)i, &out[i]); } @@ -453,3 +517,71 @@ int eis_sweep(EISPoint *out, uint32_t max_points, eis_point_cb_t cb) AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); return (int)n; } + +#define NVS_OCAL_NS "eis" +#define NVS_OCAL_KEY "ocal" + +static void ocal_save_nvs(void) +{ + nvs_handle_t h; + if (nvs_open(NVS_OCAL_NS, NVS_READWRITE, &h) != ESP_OK) return; + nvs_set_blob(h, NVS_OCAL_KEY, &ocal, sizeof(ocal)); + nvs_commit(h); + nvs_close(h); +} + +static void ocal_erase_nvs(void) +{ + nvs_handle_t h; + if (nvs_open(NVS_OCAL_NS, NVS_READWRITE, &h) != ESP_OK) return; + nvs_erase_key(h, NVS_OCAL_KEY); + nvs_commit(h); + nvs_close(h); +} + +void eis_load_open_cal(void) +{ + nvs_handle_t h; + if (nvs_open(NVS_OCAL_NS, NVS_READONLY, &h) != ESP_OK) return; + size_t len = sizeof(ocal); + if (nvs_get_blob(h, NVS_OCAL_KEY, &ocal, &len) == ESP_OK && len == sizeof(ocal) && ocal.valid) { + printf("Open-circuit cal loaded from NVS: %u points\n", (unsigned)ocal.n); + } else { + ocal.valid = 0; + ocal.n = 0; + } + nvs_close(h); +} + +int eis_open_cal(EISPoint *buf, uint32_t max_points, eis_point_cb_t cb) +{ + ocal.valid = 0; + ocal.n = 0; + + int n = eis_sweep(buf, max_points, cb); + if (n <= 0) return n; + + fImpCar_Type one = {1.0f, 0.0f}; + for (int i = 0; i < n && i < EIS_MAX_POINTS; i++) { + fImpCar_Type z = { buf[i].z_real, buf[i].z_imag }; + ocal.y[i] = AD5940_ComplexDivFloat(&one, &z); + ocal.freq[i] = buf[i].freq_hz; + } + ocal.n = (uint32_t)n; + ocal.valid = 1; + ocal_save_nvs(); + printf("Open-circuit cal stored: %d points\n", n); + return n; +} + +void eis_clear_open_cal(void) +{ + ocal.valid = 0; + ocal.n = 0; + ocal_erase_nvs(); +} + +int eis_has_open_cal(void) +{ + return ocal.valid; +} diff --git a/main/eis.h b/main/eis.h index c43b27a..4348c75 100644 --- a/main/eis.h +++ b/main/eis.h @@ -58,4 +58,9 @@ int eis_measure_point(float freq_hz, EISPoint *out); int eis_sweep(EISPoint *out, uint32_t max_points, eis_point_cb_t cb); uint32_t eis_calc_num_points(const EISConfig *cfg); +int eis_open_cal(EISPoint *buf, uint32_t max_points, eis_point_cb_t cb); +void eis_clear_open_cal(void); +int eis_has_open_cal(void); +void eis_load_open_cal(void); + #endif diff --git a/main/eis4.c b/main/eis4.c index 4f023e3..ef0fdb0 100644 --- a/main/eis4.c +++ b/main/eis4.c @@ -52,6 +52,7 @@ void app_main(void) if (adiid != AD5941_EXPECTED_ADIID) return; eis_default_config(&cfg); + eis_load_open_cal(); temp_init(); esp_log_level_set("NimBLE", ESP_LOG_WARN); @@ -183,6 +184,22 @@ void app_main(void) printf("Refs cleared\n"); break; + case CMD_OPEN_CAL: { + printf("Open-circuit cal starting\n"); + eis_init(&cfg); + uint32_t n = eis_calc_num_points(&cfg); + ble_send_sweep_start(n, cfg.freq_start_hz, cfg.freq_stop_hz); + int got = eis_open_cal(results, n, ble_send_eis_point); + printf("Open-circuit cal: %d points\n", got); + ble_send_sweep_end(); + break; + } + + case CMD_CLEAR_OPEN_CAL: + eis_clear_open_cal(); + printf("Open-circuit cal cleared\n"); + break; + case CMD_START_CL: { ClConfig cl_cfg; cl_cfg.v_cond = cmd.cl.v_cond;