nah it really does work pretty good now, the hard part is working out

the electrode arrays themsevles now
This commit is contained in:
pszsh 2026-03-12 04:33:49 -07:00
parent a3749af7b5
commit 8130f17b44
11 changed files with 5300 additions and 5245 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 255 KiB

After

Width:  |  Height:  |  Size: 433 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 433 KiB

1212
cue/assets/cue22.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 255 KiB

View File

@ -20,7 +20,12 @@ render_svg() {
if command -v rsvg-convert >/dev/null 2>&1; then if command -v rsvg-convert >/dev/null 2>&1; then
rsvg-convert -w "$size" -h "$size" "$svg" -o "$out" rsvg-convert -w "$size" -h "$size" "$svg" -o "$out"
elif command -v magick >/dev/null 2>&1; then elif command -v magick >/dev/null 2>&1; then
magick "$svg" -background none -resize "${size}x${size}" "$out" # Compute DPI so SVG viewport rasterizes at target pixel size.
# Default 72 DPI renders the 83.25-unit viewport at 83px;
# scaling DPI proportionally renders at exact target dimensions.
local dpi=$(( (size * 72 + 82) / 83 ))
magick -background none -density "$dpi" "$svg" \
-resize "${size}x${size}" "PNG32:$out"
else else
echo "Error: need rsvg-convert (librsvg) or magick (ImageMagick 7)" echo "Error: need rsvg-convert (librsvg) or magick (ImageMagick 7)"
exit 1 exit 1
@ -32,7 +37,7 @@ case "$(uname -s)" in
echo "==> Generating .icns" echo "==> Generating .icns"
ICONSET=$(mktemp -d)/cue.iconset ICONSET=$(mktemp -d)/cue.iconset
mkdir -p "$ICONSET" mkdir -p "$ICONSET"
for size in 16 32 64 128 256 512; do for size in 16 32 128 256 512; do
render_svg "$SVG" "$size" "$ICONSET/icon_${size}x${size}.png" render_svg "$SVG" "$size" "$ICONSET/icon_${size}x${size}.png"
double=$((size * 2)) double=$((size * 2))
render_svg "$SVG" "$double" "$ICONSET/icon_${size}x${size}@2x.png" render_svg "$SVG" "$double" "$ICONSET/icon_${size}x${size}@2x.png"

View File

@ -708,27 +708,27 @@ impl App {
Tab::Eis => row![ Tab::Eis => row![
column![ column![
text("Start Hz").size(12), text("Start Hz").size(12),
text_input("1000", &self.freq_start).on_input(Message::FreqStartChanged).width(100), text_input("1000", &self.freq_start).on_input(Message::FreqStartChanged).width(90),
].spacing(2), ].spacing(2),
column![ column![
text("Stop Hz").size(12), text("Stop Hz").size(12),
text_input("200000", &self.freq_stop).on_input(Message::FreqStopChanged).width(100), text_input("200000", &self.freq_stop).on_input(Message::FreqStopChanged).width(90),
].spacing(2), ].spacing(2),
column![ column![
text("PPD").size(12), text("PPD").size(12),
text_input("10", &self.ppd).on_input(Message::PpdChanged).width(60), text_input("10", &self.ppd).on_input(Message::PpdChanged).width(50),
].spacing(2), ].spacing(2),
column![ column![
text("RTIA").size(12), text("RTIA").size(12),
pick_list(Rtia::ALL, Some(self.rtia), Message::RtiaSelected), pick_list(Rtia::ALL, Some(self.rtia), Message::RtiaSelected).width(110),
].spacing(2), ].spacing(2),
column![ column![
text("RCAL").size(12), text("RCAL").size(12),
pick_list(Rcal::ALL, Some(self.rcal), Message::RcalSelected), pick_list(Rcal::ALL, Some(self.rcal), Message::RcalSelected).width(160),
].spacing(2), ].spacing(2),
column![ column![
text("Electrodes").size(12), text("Electrodes").size(12),
pick_list(Electrode::ALL, Some(self.electrode), Message::ElectrodeSelected), pick_list(Electrode::ALL, Some(self.electrode), Message::ElectrodeSelected).width(170),
].spacing(2), ].spacing(2),
button(text("Apply").size(13)) button(text("Apply").size(13))
.style(style_apply()) .style(style_apply())
@ -739,7 +739,7 @@ impl App {
.padding([6, 20]) .padding([6, 20])
.on_press(Message::StartSweep), .on_press(Message::StartSweep),
] ]
.spacing(10) .spacing(8)
.align_y(iced::Alignment::End) .align_y(iced::Alignment::End)
.into(), .into(),
@ -758,7 +758,7 @@ impl App {
].spacing(2), ].spacing(2),
column![ column![
text("RTIA").size(12), text("RTIA").size(12),
pick_list(LpRtia::ALL, Some(self.lsv_rtia), Message::LsvRtiaSelected), pick_list(LpRtia::ALL, Some(self.lsv_rtia), Message::LsvRtiaSelected).width(Length::Shrink),
].spacing(2), ].spacing(2),
button(text("Start LSV").size(13)) button(text("Start LSV").size(13))
.style(style_action()) .style(style_action())
@ -784,7 +784,7 @@ impl App {
].spacing(2), ].spacing(2),
column![ column![
text("RTIA").size(12), text("RTIA").size(12),
pick_list(LpRtia::ALL, Some(self.amp_rtia), Message::AmpRtiaSelected), pick_list(LpRtia::ALL, Some(self.amp_rtia), Message::AmpRtiaSelected).width(Length::Shrink),
].spacing(2), ].spacing(2),
if self.amp_running { if self.amp_running {
button(text("Stop").size(13)) button(text("Stop").size(13))
@ -829,7 +829,7 @@ impl App {
].spacing(2), ].spacing(2),
column![ column![
text("RTIA").size(12), text("RTIA").size(12),
pick_list(LpRtia::ALL, Some(self.cl_rtia), Message::ClRtiaSelected), pick_list(LpRtia::ALL, Some(self.cl_rtia), Message::ClRtiaSelected).width(Length::Shrink),
].spacing(2), ].spacing(2),
button(text("Measure").size(13)) button(text("Measure").size(13))
.style(style_action()) .style(style_action())

View File

@ -161,6 +161,10 @@ static float read_current_ua(float rtia_ohms)
uint32_t raw = AD5940_ReadAfeResult(AFERESULT_SINC2); uint32_t raw = AD5940_ReadAfeResult(AFERESULT_SINC2);
int32_t code = (raw & (1UL << 15)) ? (int32_t)(raw | 0xFFFF0000UL) : (int32_t)raw; int32_t code = (raw & (1UL << 15)) ? (int32_t)(raw | 0xFFFF0000UL) : (int32_t)raw;
/* clamp near ADC saturation to prevent sign-flip wrap artifact */
if (code > 32700) code = 32700;
if (code < -32700) code = -32700;
/* I = V_tia / RTIA, V_tia = code * Vref / (PGA * 32768) */ /* I = V_tia / RTIA, V_tia = code * Vref / (PGA * 32768) */
float v_tia = (float)code * 1.82f / (1.5f * 32768.0f); float v_tia = (float)code * 1.82f / (1.5f * 32768.0f);
float i_a = v_tia / rtia_ohms; float i_a = v_tia / rtia_ohms;
@ -245,6 +249,34 @@ static float read_voltage_mv(uint32_t muxp)
return (float)code * 1820.0f / (1.5f * 32768.0f); return (float)code * 1820.0f / (1.5f * 32768.0f);
} }
static void echem_shutdown_lp(void)
{
LPLoopCfg_Type lp;
AD5940_StructInit(&lp, sizeof(lp));
lp.LpDacCfg.LpdacSel = LPDAC0;
lp.LpDacCfg.LpDacSrc = LPDACSRC_MMR;
lp.LpDacCfg.LpDacVzeroMux = LPDACVZERO_6BIT;
lp.LpDacCfg.LpDacVbiasMux = LPDACVBIAS_12BIT;
lp.LpDacCfg.LpDacSW = 0;
lp.LpDacCfg.LpDacRef = LPDACREF_2P5;
lp.LpDacCfg.PowerEn = bFALSE;
lp.LpDacCfg.DataRst = bFALSE;
lp.LpDacCfg.DacData6Bit = 0;
lp.LpDacCfg.DacData12Bit = 0;
lp.LpAmpCfg.LpAmpSel = LPAMP0;
lp.LpAmpCfg.LpAmpPwrMod = LPAMPPWR_NORM;
lp.LpAmpCfg.LpPaPwrEn = bFALSE;
lp.LpAmpCfg.LpTiaPwrEn = bFALSE;
lp.LpAmpCfg.LpTiaRf = LPTIARF_OPEN;
lp.LpAmpCfg.LpTiaRload = LPTIARLOAD_SHORT;
lp.LpAmpCfg.LpTiaRtia = LPTIARTIA_OPEN;
lp.LpAmpCfg.LpTiaSW = 0;
AD5940_LPLoopCfgS(&lp);
SWMatrixCfg_Type sw = { SWD_OPEN, SWP_OPEN, SWN_OPEN, SWT_OPEN };
AD5940_SWMatrixCfgS(&sw);
}
/* ---- public ---- */ /* ---- public ---- */
void echem_default_lsv(LSVConfig *cfg) void echem_default_lsv(LSVConfig *cfg)
@ -265,7 +297,33 @@ void echem_default_amp(AmpConfig *cfg)
cfg->lp_rtia = LP_RTIA_10K; cfg->lp_rtia = LP_RTIA_10K;
} }
int echem_lsv(const LSVConfig *cfg, LSVPoint *out, uint32_t max_points) static void lsv_calc_step(const LSVConfig *cfg, uint32_t max_points,
uint32_t *n_out, float *step_out)
{
float v_range = cfg->v_stop - cfg->v_start;
uint32_t n_lsb = (uint32_t)(fabsf(v_range / VBIAS_LSB) + 0.5f);
uint32_t n_steps = n_lsb;
uint32_t step_mult = 1;
if (n_steps > max_points) {
step_mult = (n_lsb + max_points - 1) / max_points;
n_steps = (n_lsb + step_mult - 1) / step_mult;
}
if (n_steps < 2) n_steps = 2;
*n_out = n_steps;
*step_out = (v_range > 0) ? VBIAS_LSB * step_mult : -VBIAS_LSB * step_mult;
}
uint32_t echem_lsv_calc_steps(const LSVConfig *cfg, uint32_t max_points)
{
float v_range = cfg->v_stop - cfg->v_start;
if (fabsf(v_range) < 0.001f) return 0;
uint32_t n;
float step;
lsv_calc_step(cfg, max_points, &n, &step);
return n;
}
int echem_lsv(const LSVConfig *cfg, LSVPoint *out, uint32_t max_points, lsv_point_cb_t cb)
{ {
if (cfg->lp_rtia >= LP_RTIA_COUNT) return 0; if (cfg->lp_rtia >= LP_RTIA_COUNT) return 0;
float rtia = lp_rtia_ohms[cfg->lp_rtia]; float rtia = lp_rtia_ohms[cfg->lp_rtia];
@ -281,17 +339,9 @@ int echem_lsv(const LSVConfig *cfg, LSVPoint *out, uint32_t max_points)
float v_range = cfg->v_stop - cfg->v_start; float v_range = cfg->v_stop - cfg->v_start;
if (fabsf(v_range) < 0.001f) return 0; if (fabsf(v_range) < 0.001f) return 0;
/* compute steps to always cover full range within max_points */ uint32_t n_steps;
uint32_t n_lsb = (uint32_t)(fabsf(v_range / VBIAS_LSB) + 0.5f); float step;
uint32_t n_steps = n_lsb; lsv_calc_step(cfg, max_points, &n_steps, &step);
uint32_t step_mult = 1;
if (n_steps > max_points) {
step_mult = (n_lsb + max_points - 1) / max_points;
n_steps = (n_lsb + step_mult - 1) / step_mult;
}
if (n_steps < 2) n_steps = 2;
float step = (v_range > 0) ? VBIAS_LSB * step_mult : -VBIAS_LSB * step_mult;
float delay_ms = fabsf(step / cfg->scan_rate) * 1000.0f; float delay_ms = fabsf(step / cfg->scan_rate) * 1000.0f;
if (delay_ms < 1.0f) delay_ms = 1.0f; if (delay_ms < 1.0f) delay_ms = 1.0f;
@ -312,13 +362,15 @@ int echem_lsv(const LSVConfig *cfg, LSVPoint *out, uint32_t max_points)
out[i].i_ua = i_ua; out[i].i_ua = i_ua;
printf("%10.1f %10.3f\n", v_mv, i_ua); printf("%10.1f %10.3f\n", v_mv, i_ua);
if (cb) cb((uint16_t)i, v_mv, i_ua);
} }
echem_shutdown_lp();
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
return (int)n_steps; return (int)n_steps;
} }
int echem_amp(const AmpConfig *cfg, AmpPoint *out, uint32_t max_points) int echem_amp(const AmpConfig *cfg, AmpPoint *out, uint32_t max_points, amp_point_cb_t cb)
{ {
if (cfg->lp_rtia >= LP_RTIA_COUNT) return 0; if (cfg->lp_rtia >= LP_RTIA_COUNT) return 0;
float rtia = lp_rtia_ohms[cfg->lp_rtia]; float rtia = lp_rtia_ohms[cfg->lp_rtia];
@ -347,7 +399,6 @@ int echem_amp(const AmpConfig *cfg, AmpPoint *out, uint32_t max_points)
uint32_t count = 0; uint32_t count = 0;
for (uint32_t i = 0; i < max_samples; i++) { for (uint32_t i = 0; i < max_samples; i++) {
/* check for stop command (non-blocking) */
BleCommand cmd; BleCommand cmd;
if (ble_recv_command(&cmd, 0) == 0 && cmd.type == CMD_STOP_AMP) if (ble_recv_command(&cmd, 0) == 0 && cmd.type == CMD_STOP_AMP)
break; break;
@ -360,10 +411,12 @@ int echem_amp(const AmpConfig *cfg, AmpPoint *out, uint32_t max_points)
count++; count++;
printf("%10.1f %10.3f\n", t_ms, i_ua); printf("%10.1f %10.3f\n", t_ms, i_ua);
if (cb) cb((uint16_t)i, t_ms, i_ua);
vTaskDelay(interval); vTaskDelay(interval);
} }
echem_shutdown_lp();
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
return (int)count; return (int)count;
} }
@ -383,7 +436,7 @@ void echem_default_cl(ClConfig *cfg)
static uint32_t sample_phase(float v_mv, float t_dep_ms, float t_meas_ms, static uint32_t sample_phase(float v_mv, float t_dep_ms, float t_meas_ms,
uint8_t phase, float rtia_ohms, uint8_t phase, float rtia_ohms,
ClPoint *out, uint32_t idx, uint32_t max_points, ClPoint *out, uint32_t idx, uint32_t max_points,
TickType_t t0, float *avg_out) TickType_t t0, float *avg_out, cl_point_cb_t cb)
{ {
AD5940_LPDAC0WriteS(mv_to_vbias_code(v_mv), VZERO_CODE); AD5940_LPDAC0WriteS(mv_to_vbias_code(v_mv), VZERO_CODE);
@ -405,6 +458,8 @@ static uint32_t sample_phase(float v_mv, float t_dep_ms, float t_meas_ms,
out[idx].t_ms = t_ms; out[idx].t_ms = t_ms;
out[idx].i_ua = i_ua; out[idx].i_ua = i_ua;
out[idx].phase = phase; out[idx].phase = phase;
if (cb) cb((uint16_t)idx, t_ms, i_ua, phase);
idx++; idx++;
sum += i_ua; sum += i_ua;
@ -417,7 +472,8 @@ static uint32_t sample_phase(float v_mv, float t_dep_ms, float t_meas_ms,
return idx; return idx;
} }
int echem_chlorine(const ClConfig *cfg, ClPoint *out, uint32_t max_points, ClResult *result) int echem_chlorine(const ClConfig *cfg, ClPoint *out, uint32_t max_points,
ClResult *result, cl_point_cb_t cb)
{ {
if (cfg->lp_rtia >= LP_RTIA_COUNT) return 0; if (cfg->lp_rtia >= LP_RTIA_COUNT) return 0;
float rtia = lp_rtia_ohms[cfg->lp_rtia]; float rtia = lp_rtia_ohms[cfg->lp_rtia];
@ -434,15 +490,16 @@ int echem_chlorine(const ClConfig *cfg, ClPoint *out, uint32_t max_points, ClRes
printf("Cl: free chlorine at %.0f mV\n", cfg->v_free); printf("Cl: free chlorine at %.0f mV\n", cfg->v_free);
idx = sample_phase(cfg->v_free, cfg->t_dep_ms, cfg->t_meas_ms, idx = sample_phase(cfg->v_free, cfg->t_dep_ms, cfg->t_meas_ms,
CL_PHASE_FREE, rtia, out, idx, max_points, t0, CL_PHASE_FREE, rtia, out, idx, max_points, t0,
&result->i_free_ua); &result->i_free_ua, cb);
printf("Cl: total chlorine at %.0f mV\n", cfg->v_total); printf("Cl: total chlorine at %.0f mV\n", cfg->v_total);
idx = sample_phase(cfg->v_total, cfg->t_dep_ms, cfg->t_meas_ms, idx = sample_phase(cfg->v_total, cfg->t_dep_ms, cfg->t_meas_ms,
CL_PHASE_TOTAL, rtia, out, idx, max_points, t0, CL_PHASE_TOTAL, rtia, out, idx, max_points, t0,
&result->i_total_ua); &result->i_total_ua, cb);
printf("Cl: free=%.3f uA, total=%.3f uA\n", result->i_free_ua, result->i_total_ua); printf("Cl: free=%.3f uA, total=%.3f uA\n", result->i_free_ua, result->i_total_ua);
echem_shutdown_lp();
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
return (int)idx; return (int)idx;
} }
@ -490,6 +547,7 @@ int echem_ph_ocp(const PhConfig *cfg, PhResult *result)
printf("pH: SE0=%.1f mV, RE0=%.1f mV, OCP=%.1f mV, pH=%.2f\n", printf("pH: SE0=%.1f mV, RE0=%.1f mV, OCP=%.1f mV, pH=%.2f\n",
v_se0, v_re0, ocp, result->ph); v_se0, v_re0, ocp, result->ph);
echem_shutdown_lp();
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
return 0; return 0;
} }

View File

@ -80,14 +80,19 @@ typedef struct {
float temp_c; /* temperature used */ float temp_c; /* temperature used */
} PhResult; } PhResult;
typedef int (*lsv_point_cb_t)(uint16_t idx, float v_mv, float i_ua);
typedef int (*amp_point_cb_t)(uint16_t idx, float t_ms, float i_ua);
typedef int (*cl_point_cb_t)(uint16_t idx, float t_ms, float i_ua, uint8_t phase);
void echem_default_lsv(LSVConfig *cfg); void echem_default_lsv(LSVConfig *cfg);
void echem_default_amp(AmpConfig *cfg); void echem_default_amp(AmpConfig *cfg);
void echem_default_cl(ClConfig *cfg); void echem_default_cl(ClConfig *cfg);
void echem_default_ph(PhConfig *cfg); void echem_default_ph(PhConfig *cfg);
int echem_lsv(const LSVConfig *cfg, LSVPoint *out, uint32_t max_points); uint32_t echem_lsv_calc_steps(const LSVConfig *cfg, uint32_t max_points);
int echem_amp(const AmpConfig *cfg, AmpPoint *out, uint32_t max_points); int echem_lsv(const LSVConfig *cfg, LSVPoint *out, uint32_t max_points, lsv_point_cb_t cb);
int echem_chlorine(const ClConfig *cfg, ClPoint *out, uint32_t max_points, ClResult *result); int echem_amp(const AmpConfig *cfg, AmpPoint *out, uint32_t max_points, amp_point_cb_t cb);
int echem_chlorine(const ClConfig *cfg, ClPoint *out, uint32_t max_points, ClResult *result, cl_point_cb_t cb);
int echem_ph_ocp(const PhConfig *cfg, PhResult *result); int echem_ph_ocp(const PhConfig *cfg, PhResult *result);
#endif #endif

View File

@ -410,7 +410,7 @@ int eis_measure_point(float freq_hz, EISPoint *out)
return 0; return 0;
} }
int eis_sweep(EISPoint *out, uint32_t max_points) int eis_sweep(EISPoint *out, uint32_t max_points, eis_point_cb_t cb)
{ {
uint32_t n = eis_calc_num_points(&ctx.cfg); uint32_t n = eis_calc_num_points(&ctx.cfg);
if (n > max_points) n = max_points; if (n > max_points) n = max_points;
@ -435,6 +435,7 @@ int eis_sweep(EISPoint *out, uint32_t max_points)
printf("%10.1f %12.2f %10.2f %12.2f %12.2f %6.2f%%\n", printf("%10.1f %12.2f %10.2f %12.2f %12.2f %6.2f%%\n",
out[0].freq_hz, out[0].mag_ohms, out[0].phase_deg, 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].pct_err);
if (cb) cb(0, &out[0]);
for (uint32_t i = 1; i < n; i++) { for (uint32_t i = 1; i < n; i++) {
float freq; float freq;
@ -443,6 +444,7 @@ int eis_sweep(EISPoint *out, uint32_t max_points)
printf("%10.1f %12.2f %10.2f %12.2f %12.2f %6.2f%%\n", printf("%10.1f %12.2f %10.2f %12.2f %12.2f %6.2f%%\n",
out[i].freq_hz, out[i].mag_ohms, out[i].phase_deg, 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].pct_err);
if (cb) cb((uint16_t)i, &out[i]);
} }
/* guard: throwaway at stop frequency to cap the sweep cleanly */ /* guard: throwaway at stop frequency to cap the sweep cleanly */

View File

@ -49,11 +49,13 @@ typedef struct {
float pct_err; float pct_err;
} EISPoint; } EISPoint;
typedef int (*eis_point_cb_t)(uint16_t idx, const EISPoint *pt);
void eis_default_config(EISConfig *cfg); void eis_default_config(EISConfig *cfg);
void eis_init(const EISConfig *cfg); void eis_init(const EISConfig *cfg);
void eis_reconfigure(const EISConfig *cfg); void eis_reconfigure(const EISConfig *cfg);
int eis_measure_point(float freq_hz, EISPoint *out); int eis_measure_point(float freq_hz, EISPoint *out);
int eis_sweep(EISPoint *out, uint32_t max_points); int eis_sweep(EISPoint *out, uint32_t max_points, eis_point_cb_t cb);
uint32_t eis_calc_num_points(const EISConfig *cfg); uint32_t eis_calc_num_points(const EISConfig *cfg);
#endif #endif

View File

@ -22,14 +22,9 @@ static void do_sweep(void)
eis_init(&cfg); eis_init(&cfg);
uint32_t n = eis_calc_num_points(&cfg); uint32_t n = eis_calc_num_points(&cfg);
int got = eis_sweep(results, n); ble_send_sweep_start(n, cfg.freq_start_hz, cfg.freq_stop_hz);
int got = eis_sweep(results, n, ble_send_eis_point);
printf("Sweep complete: %d points\n", got); printf("Sweep complete: %d points\n", got);
ble_send_sweep_start(got, cfg.freq_start_hz, cfg.freq_stop_hz);
for (int i = 0; i < got; i++) {
ble_send_eis_point(i, &results[i]);
vTaskDelay(pdMS_TO_TICKS(10));
}
ble_send_sweep_end(); ble_send_sweep_end();
} }
@ -124,14 +119,10 @@ void app_main(void)
printf("LSV: %.0f-%.0f mV, %.0f mV/s, rtia=%u\n", printf("LSV: %.0f-%.0f mV, %.0f mV/s, rtia=%u\n",
lsv_cfg.v_start, lsv_cfg.v_stop, lsv_cfg.scan_rate, lsv_cfg.lp_rtia); lsv_cfg.v_start, lsv_cfg.v_stop, lsv_cfg.scan_rate, lsv_cfg.lp_rtia);
int got = echem_lsv(&lsv_cfg, lsv_results, ECHEM_MAX_POINTS); uint32_t n = echem_lsv_calc_steps(&lsv_cfg, ECHEM_MAX_POINTS);
ble_send_lsv_start(n, lsv_cfg.v_start, lsv_cfg.v_stop);
int got = echem_lsv(&lsv_cfg, lsv_results, ECHEM_MAX_POINTS, ble_send_lsv_point);
printf("LSV complete: %d points\n", got); printf("LSV complete: %d points\n", got);
ble_send_lsv_start(got, lsv_cfg.v_start, lsv_cfg.v_stop);
for (int i = 0; i < got; i++) {
ble_send_lsv_point(i, lsv_results[i].v_mv, lsv_results[i].i_ua);
vTaskDelay(pdMS_TO_TICKS(10));
}
ble_send_lsv_end(); ble_send_lsv_end();
break; break;
} }
@ -146,14 +137,8 @@ void app_main(void)
amp_cfg.v_hold, amp_cfg.interval_ms, amp_cfg.duration_s); amp_cfg.v_hold, amp_cfg.interval_ms, amp_cfg.duration_s);
ble_send_amp_start(amp_cfg.v_hold); ble_send_amp_start(amp_cfg.v_hold);
int got = echem_amp(&amp_cfg, amp_results, ECHEM_MAX_POINTS, ble_send_amp_point);
int got = echem_amp(&amp_cfg, amp_results, ECHEM_MAX_POINTS);
printf("Amp complete: %d points\n", got); printf("Amp complete: %d points\n", got);
for (int i = 0; i < got; i++) {
ble_send_amp_point(i, amp_results[i].t_ms, amp_results[i].i_ua);
vTaskDelay(pdMS_TO_TICKS(10));
}
ble_send_amp_end(); ble_send_amp_end();
break; break;
} }
@ -187,16 +172,14 @@ void app_main(void)
cl_cfg.t_meas_ms = cmd.cl.t_meas_ms; cl_cfg.t_meas_ms = cmd.cl.t_meas_ms;
cl_cfg.lp_rtia = cmd.cl.lp_rtia; cl_cfg.lp_rtia = cmd.cl.lp_rtia;
uint32_t n_per = (uint32_t)(cl_cfg.t_meas_ms / 50.0f + 0.5f);
if (n_per < 2) n_per = 2;
ble_send_cl_start(2 * n_per);
ClResult cl_result; ClResult cl_result;
int got = echem_chlorine(&cl_cfg, cl_results, ECHEM_MAX_POINTS, &cl_result); int got = echem_chlorine(&cl_cfg, cl_results, ECHEM_MAX_POINTS,
&cl_result, ble_send_cl_point);
printf("Cl complete: %d points, free=%.3f uA, total=%.3f uA\n", printf("Cl complete: %d points, free=%.3f uA, total=%.3f uA\n",
got, cl_result.i_free_ua, cl_result.i_total_ua); got, cl_result.i_free_ua, cl_result.i_total_ua);
ble_send_cl_start(got);
for (int i = 0; i < got; i++) {
ble_send_cl_point(i, cl_results[i].t_ms, cl_results[i].i_ua, cl_results[i].phase);
vTaskDelay(pdMS_TO_TICKS(10));
}
ble_send_cl_result(cl_result.i_free_ua, cl_result.i_total_ua); ble_send_cl_result(cl_result.i_free_ua, cl_result.i_total_ua);
ble_send_cl_end(); ble_send_cl_end();
break; break;