EIS-BLE-S3/main/eis4.c

329 lines
11 KiB
C

#include <stdio.h>
#include "ad5940.h"
#include "ad5941_port.h"
#include "eis.h"
#include "echem.h"
#include "protocol.h"
#include "wifi_transport.h"
#include "temp.h"
#include "refs.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_event.h"
#include "esp_timer.h"
#define AD5941_EXPECTED_ADIID 0x4144
static EISConfig cfg;
static uint16_t measurement_counter = 0;
static EISPoint results[EIS_MAX_POINTS];
static LSVPoint lsv_results[ECHEM_MAX_POINTS];
static AmpPoint amp_results[ECHEM_MAX_POINTS];
static ClPoint cl_results[ECHEM_MAX_POINTS];
static RefStore ref_store;
static void do_sweep(void)
{
eis_init(&cfg);
uint32_t ts_ms = (uint32_t)(esp_timer_get_time() / 1000);
measurement_counter++;
uint32_t n = eis_calc_num_points(&cfg);
send_sweep_start(n, cfg.freq_start_hz, cfg.freq_stop_hz, ts_ms, measurement_counter);
int got = eis_sweep(results, n, send_eis_point);
printf("Sweep complete: %d points\n", got);
send_sweep_end();
}
void app_main(void)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
nvs_flash_erase();
nvs_flash_init();
}
printf("EIS4: AD5941 bring-up\n");
AD5940_MCUResourceInit(NULL);
vTaskDelay(pdMS_TO_TICKS(50));
AD5940_HWReset();
vTaskDelay(pdMS_TO_TICKS(200));
AD5940_Initialize();
uint32_t adiid = AD5940_ReadReg(REG_AFECON_ADIID);
printf("ADIID: 0x%04lX %s\n", adiid,
adiid == AD5941_EXPECTED_ADIID ? "(OK)" : "(FAIL)");
if (adiid != AD5941_EXPECTED_ADIID) return;
eis_default_config(&cfg);
eis_load_open_cal();
eis_load_cell_k();
eis_load_cl_factor();
eis_load_ph_cal();
temp_init();
esp_netif_init();
esp_event_loop_create_default();
protocol_init();
wifi_transport_init();
printf("EIS4: WiFi transport ready, waiting for clients\n");
Command cmd;
for (;;) {
if (protocol_recv_command(&cmd, UINT32_MAX) != 0)
continue;
switch (cmd.type) {
case CMD_SET_SWEEP:
cfg.freq_start_hz = cmd.sweep.freq_start;
cfg.freq_stop_hz = cmd.sweep.freq_stop;
cfg.points_per_decade = cmd.sweep.ppd;
eis_reconfigure(&cfg);
printf("Sweep: %.0f-%.0f Hz, %u ppd\n",
cfg.freq_start_hz, cfg.freq_stop_hz, cfg.points_per_decade);
break;
case CMD_SET_RTIA:
if (cmd.rtia < RTIA_COUNT) {
cfg.rtia = cmd.rtia;
eis_reconfigure(&cfg);
printf("RTIA: %u\n", cfg.rtia);
}
break;
case CMD_SET_RCAL:
if (cmd.rcal < RCAL_COUNT) {
cfg.rcal = cmd.rcal;
eis_reconfigure(&cfg);
printf("RCAL: %u\n", cfg.rcal);
}
break;
case CMD_SET_ELECTRODE:
if (cmd.electrode < ELEC_COUNT) {
cfg.electrode = cmd.electrode;
eis_reconfigure(&cfg);
printf("Electrode: %s\n",
cfg.electrode == ELEC_3WIRE ? "3-wire (CE0/RE0/SE0)" : "4-wire (AIN)");
}
break;
case CMD_START_SWEEP:
printf("Config: %.0f-%.0f Hz, %u ppd, rtia=%u, rcal=%u, elec=%s\n",
cfg.freq_start_hz, cfg.freq_stop_hz, cfg.points_per_decade,
cfg.rtia, cfg.rcal,
cfg.electrode == ELEC_3WIRE ? "3-wire" : "4-wire");
do_sweep();
break;
case CMD_GET_CONFIG:
send_config(&cfg);
break;
case CMD_START_LSV: {
LSVConfig lsv_cfg;
lsv_cfg.v_start = cmd.lsv.v_start;
lsv_cfg.v_stop = cmd.lsv.v_stop;
lsv_cfg.scan_rate = cmd.lsv.scan_rate;
lsv_cfg.lp_rtia = cmd.lsv.lp_rtia;
uint32_t max_pts = ECHEM_MAX_POINTS;
if (cmd.lsv.num_points > 0 && cmd.lsv.num_points < ECHEM_MAX_POINTS)
max_pts = cmd.lsv.num_points;
printf("LSV: %.0f-%.0f mV, %.0f mV/s, rtia=%u, max_pts=%lu\n",
lsv_cfg.v_start, lsv_cfg.v_stop, lsv_cfg.scan_rate, lsv_cfg.lp_rtia,
(unsigned long)max_pts);
uint32_t ts_ms = (uint32_t)(esp_timer_get_time() / 1000);
measurement_counter++;
uint32_t n = echem_lsv_calc_steps(&lsv_cfg, max_pts);
send_lsv_start(n, lsv_cfg.v_start, lsv_cfg.v_stop, ts_ms, measurement_counter);
int got = echem_lsv(&lsv_cfg, lsv_results, max_pts, send_lsv_point);
printf("LSV complete: %d points\n", got);
send_lsv_end();
break;
}
case CMD_START_AMP: {
AmpConfig amp_cfg;
amp_cfg.v_hold = cmd.amp.v_hold;
amp_cfg.interval_ms = cmd.amp.interval_ms;
amp_cfg.duration_s = cmd.amp.duration_s;
amp_cfg.lp_rtia = cmd.amp.lp_rtia;
printf("Amp: %.0f mV, %.0f ms interval, %.0f s\n",
amp_cfg.v_hold, amp_cfg.interval_ms, amp_cfg.duration_s);
{
uint32_t ts_ms = (uint32_t)(esp_timer_get_time() / 1000);
measurement_counter++;
send_amp_start(amp_cfg.v_hold, ts_ms, measurement_counter);
}
int got = echem_amp(&amp_cfg, amp_results, ECHEM_MAX_POINTS, send_amp_point);
printf("Amp complete: %d points\n", got);
send_amp_end();
break;
}
case CMD_GET_TEMP:
send_temp(temp_get());
break;
case CMD_START_PH: {
PhConfig ph_cfg;
ph_cfg.stabilize_s = cmd.ph.stabilize_s;
ph_cfg.temp_c = temp_get();
printf("pH: stabilize %.0f s, temp %.1f C\n",
ph_cfg.stabilize_s, ph_cfg.temp_c);
PhResult ph_result;
echem_ph_ocp(&ph_cfg, &ph_result);
printf("pH: OCP=%.1f mV, pH=%.2f\n",
ph_result.v_ocp_mv, ph_result.ph);
{
uint32_t ts_ms = (uint32_t)(esp_timer_get_time() / 1000);
measurement_counter++;
send_ph_result(ph_result.v_ocp_mv, ph_result.ph, ph_result.temp_c,
ts_ms, measurement_counter);
}
break;
}
case CMD_START_CLEAN:
printf("Clean: %.0f mV, %.0f s\n", cmd.clean.v_mv, cmd.clean.duration_s);
echem_clean(cmd.clean.v_mv, cmd.clean.duration_s);
break;
case CMD_START_REFS:
printf("Ref collection starting\n");
refs_collect(&ref_store, &cfg);
break;
case CMD_GET_REFS:
refs_send(&ref_store);
break;
case CMD_CLEAR_REFS:
refs_clear(&ref_store);
printf("Refs cleared\n");
break;
case CMD_OPEN_CAL: {
printf("Open-circuit cal starting\n");
eis_init(&cfg);
uint32_t ts_ms = (uint32_t)(esp_timer_get_time() / 1000);
measurement_counter++;
uint32_t n = eis_calc_num_points(&cfg);
send_sweep_start(n, cfg.freq_start_hz, cfg.freq_stop_hz, ts_ms, measurement_counter);
int got = eis_open_cal(results, n, send_eis_point);
printf("Open-circuit cal: %d points\n", got);
send_sweep_end();
break;
}
case CMD_CLEAR_OPEN_CAL:
eis_clear_open_cal();
printf("Open-circuit cal cleared\n");
break;
case CMD_SET_CELL_K:
eis_set_cell_k(cmd.cell_k);
send_cell_k(cmd.cell_k);
printf("Cell K set: %.4f cm^-1\n", cmd.cell_k);
break;
case CMD_GET_CELL_K:
send_cell_k(eis_get_cell_k());
break;
case CMD_SET_CL_FACTOR:
eis_set_cl_factor(cmd.cl_factor);
send_cl_factor(cmd.cl_factor);
printf("Cl factor set: %.6f\n", cmd.cl_factor);
break;
case CMD_GET_CL_FACTOR:
send_cl_factor(eis_get_cl_factor());
break;
case CMD_SET_PH_CAL:
eis_set_ph_cal(cmd.ph_cal.slope, cmd.ph_cal.offset);
send_ph_cal(cmd.ph_cal.slope, cmd.ph_cal.offset);
printf("pH cal set: slope=%.4f offset=%.4f\n", cmd.ph_cal.slope, cmd.ph_cal.offset);
break;
case CMD_GET_PH_CAL:
send_ph_cal(eis_get_ph_slope(), eis_get_ph_offset());
break;
case CMD_START_CL: {
ClConfig cl_cfg;
cl_cfg.v_cond = cmd.cl.v_cond;
cl_cfg.t_cond_ms = cmd.cl.t_cond_ms;
cl_cfg.v_free = cmd.cl.v_free;
cl_cfg.v_total = cmd.cl.v_total;
cl_cfg.t_dep_ms = cmd.cl.t_dep_ms;
cl_cfg.t_meas_ms = cmd.cl.t_meas_ms;
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;
{
uint32_t ts_ms = (uint32_t)(esp_timer_get_time() / 1000);
measurement_counter++;
send_cl_start(2 * n_per, ts_ms, measurement_counter);
}
ClResult cl_result;
int got = echem_chlorine(&cl_cfg, cl_results, ECHEM_MAX_POINTS,
&cl_result, send_cl_point);
printf("Cl complete: %d points, free=%.3f uA, total=%.3f uA\n",
got, cl_result.i_free_ua, cl_result.i_total_ua);
send_cl_result(cl_result.i_free_ua, cl_result.i_total_ua);
send_cl_end();
break;
}
case CMD_SESSION_CREATE: {
uint8_t id = session_create(cmd.session_create.name,
cmd.session_create.name_len);
if (id != 0xFF) {
send_session_created(id, cmd.session_create.name,
cmd.session_create.name_len);
printf("Session created: %u \"%.*s\"\n",
id, cmd.session_create.name_len, cmd.session_create.name);
}
break;
}
case CMD_SESSION_SWITCH:
if (session_switch(cmd.session_switch.id) == 0) {
send_session_switched(cmd.session_switch.id);
printf("Session switched: %u\n", cmd.session_switch.id);
}
break;
case CMD_SESSION_LIST:
send_session_list();
break;
case CMD_SESSION_RENAME:
if (session_rename(cmd.session_rename.id, cmd.session_rename.name,
cmd.session_rename.name_len) == 0) {
send_session_renamed(cmd.session_rename.id, cmd.session_rename.name,
cmd.session_rename.name_len);
printf("Session renamed: %u \"%.*s\"\n",
cmd.session_rename.id, cmd.session_rename.name_len,
cmd.session_rename.name);
}
break;
case CMD_HEARTBEAT:
send_client_list((uint8_t)wifi_get_client_count());
send_session_list();
send_config(&cfg);
break;
}
}
}