merge integration
# Conflicts: # cue-ios/CueIOS/AppState.swift # cue-ios/CueIOS/Models/Protocol.swift # cue/src/app.rs # cue/src/protocol.rs # main/protocol.h # main/wifi_transport.c
This commit is contained in:
commit
5f550f031a
|
|
@ -323,6 +323,9 @@ final class AppState {
|
|||
phSlope = Double(slope)
|
||||
phOffset = Double(offset)
|
||||
status = String(format: "pH cal: slope=%.4f offset=%.4f", slope, offset)
|
||||
|
||||
case .keepalive:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ let RSP_REFS_DONE: UInt8 = 0x22
|
|||
let RSP_REF_STATUS: UInt8 = 0x23
|
||||
let RSP_CL_FACTOR: UInt8 = 0x24
|
||||
let RSP_PH_CAL: UInt8 = 0x25
|
||||
let RSP_KEEPALIVE: UInt8 = 0x50
|
||||
|
||||
// Cue -> ESP32
|
||||
let CMD_SET_SWEEP: UInt8 = 0x10
|
||||
|
|
@ -131,6 +132,7 @@ enum EisMessage {
|
|||
case cellK(Float)
|
||||
case clFactor(Float)
|
||||
case phCal(slope: Float, offset: Float)
|
||||
case keepalive
|
||||
}
|
||||
|
||||
// MARK: - Response parser
|
||||
|
|
@ -271,6 +273,9 @@ func parseSysex(_ data: [UInt8]) -> EisMessage? {
|
|||
offset: decodeFloat(p, at: 5)
|
||||
)
|
||||
|
||||
case RSP_KEEPALIVE:
|
||||
return .keepalive
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -866,6 +866,7 @@ impl App {
|
|||
self.ph_offset = Some(offset);
|
||||
self.status = format!("pH cal: slope={:.4} offset={:.4}", slope, offset);
|
||||
}
|
||||
EisMessage::Keepalive => {}
|
||||
},
|
||||
Message::TabSelected(t) => {
|
||||
if t == Tab::Browse {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ pub const RSP_CELL_K: u8 = 0x11;
|
|||
pub const RSP_REF_STATUS: u8 = 0x23;
|
||||
pub const RSP_CL_FACTOR: u8 = 0x24;
|
||||
pub const RSP_PH_CAL: u8 = 0x25;
|
||||
pub const RSP_KEEPALIVE: u8 = 0x50;
|
||||
|
||||
/* Cue → ESP32 */
|
||||
pub const CMD_SET_SWEEP: u8 = 0x10;
|
||||
|
|
@ -266,6 +267,7 @@ pub enum EisMessage {
|
|||
CellK(f32),
|
||||
ClFactor(f32),
|
||||
PhCal { slope: f32, offset: f32 },
|
||||
Keepalive,
|
||||
}
|
||||
|
||||
fn decode_u16(data: &[u8]) -> u16 {
|
||||
|
|
@ -432,6 +434,7 @@ pub fn parse_sysex(data: &[u8]) -> Option<EisMessage> {
|
|||
offset: decode_float(&p[5..10]),
|
||||
})
|
||||
}
|
||||
RSP_KEEPALIVE => Some(EisMessage::Keepalive),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
38
main/echem.c
38
main/echem.c
|
|
@ -327,7 +327,14 @@ int echem_clean(float v_mv, float duration_s)
|
|||
AD5940_LPDAC0WriteS(code, VZERO_CODE);
|
||||
|
||||
printf("Clean: %.0f mV for %.0f s\n", v_mv, duration_s);
|
||||
vTaskDelay(pdMS_TO_TICKS((uint32_t)(duration_s * 1000.0f)));
|
||||
|
||||
uint32_t remain_ms = (uint32_t)(duration_s * 1000.0f);
|
||||
while (remain_ms > 0) {
|
||||
uint32_t chunk = remain_ms > 3000 ? 3000 : remain_ms;
|
||||
vTaskDelay(pdMS_TO_TICKS(chunk));
|
||||
remain_ms -= chunk;
|
||||
if (remain_ms > 0) send_keepalive();
|
||||
}
|
||||
|
||||
echem_shutdown_lp();
|
||||
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
|
||||
|
|
@ -497,7 +504,15 @@ static uint32_t sample_phase(float v_mv, float t_dep_ms, float t_meas_ms,
|
|||
AD5940_LPDAC0WriteS(mv_to_vbias_code(v_mv), VZERO_CODE);
|
||||
|
||||
/* settling — no samples recorded */
|
||||
vTaskDelay(pdMS_TO_TICKS((uint32_t)t_dep_ms));
|
||||
{
|
||||
uint32_t remain_ms = (uint32_t)t_dep_ms;
|
||||
while (remain_ms > 0) {
|
||||
uint32_t chunk = remain_ms > 3000 ? 3000 : remain_ms;
|
||||
vTaskDelay(pdMS_TO_TICKS(chunk));
|
||||
remain_ms -= chunk;
|
||||
if (remain_ms > 0) send_keepalive();
|
||||
}
|
||||
}
|
||||
|
||||
/* measurement — sample at ~50ms intervals */
|
||||
uint32_t n_samples = (uint32_t)(t_meas_ms / 50.0f + 0.5f);
|
||||
|
|
@ -541,7 +556,15 @@ int echem_chlorine(const ClConfig *cfg, ClPoint *out, uint32_t max_points,
|
|||
|
||||
printf("Cl: conditioning at %.0f mV for %.0f ms\n", cfg->v_cond, cfg->t_cond_ms);
|
||||
AD5940_LPDAC0WriteS(mv_to_vbias_code(cfg->v_cond), VZERO_CODE);
|
||||
vTaskDelay(pdMS_TO_TICKS((uint32_t)cfg->t_cond_ms));
|
||||
{
|
||||
uint32_t remain_ms = (uint32_t)cfg->t_cond_ms;
|
||||
while (remain_ms > 0) {
|
||||
uint32_t chunk = remain_ms > 3000 ? 3000 : remain_ms;
|
||||
vTaskDelay(pdMS_TO_TICKS(chunk));
|
||||
remain_ms -= chunk;
|
||||
if (remain_ms > 0) send_keepalive();
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
@ -579,7 +602,14 @@ int echem_ph_ocp(const PhConfig *cfg, PhResult *result)
|
|||
AD5940_ADCBaseCfgS(&adc);
|
||||
|
||||
printf("pH: stabilizing %0.f s\n", cfg->stabilize_s);
|
||||
vTaskDelay(pdMS_TO_TICKS((uint32_t)(cfg->stabilize_s * 1000.0f)));
|
||||
|
||||
uint32_t remain_ms = (uint32_t)(cfg->stabilize_s * 1000.0f);
|
||||
while (remain_ms > 0) {
|
||||
uint32_t chunk = remain_ms > 3000 ? 3000 : remain_ms;
|
||||
vTaskDelay(pdMS_TO_TICKS(chunk));
|
||||
remain_ms -= chunk;
|
||||
if (remain_ms > 0) send_keepalive();
|
||||
}
|
||||
|
||||
/* average N readings of V(SE0) and V(RE0) */
|
||||
#define PH_AVG_N 10
|
||||
|
|
|
|||
|
|
@ -144,6 +144,14 @@ static int send_sysex(const uint8_t *sysex, uint16_t len)
|
|||
return wifi_send_sysex(sysex, len);
|
||||
}
|
||||
|
||||
/* ---- outbound: keepalive ---- */
|
||||
|
||||
int send_keepalive(void)
|
||||
{
|
||||
uint8_t sx[] = { 0xF0, 0x7D, RSP_KEEPALIVE, 0xF7 };
|
||||
return send_sysex(sx, sizeof(sx));
|
||||
}
|
||||
|
||||
/* ---- outbound: EIS ---- */
|
||||
|
||||
int send_sweep_start(uint32_t num_points, float freq_start, float freq_stop)
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
#define RSP_REF_STATUS 0x23
|
||||
#define RSP_CL_FACTOR 0x24
|
||||
#define RSP_PH_CAL 0x25
|
||||
#define RSP_KEEPALIVE 0x50
|
||||
|
||||
/* Session sync responses (0x4x) */
|
||||
#define RSP_SESSION_CREATED 0x40
|
||||
|
|
@ -152,6 +153,9 @@ int send_ref_lp_range(uint8_t mode, uint8_t low_idx, uint8_t high_idx);
|
|||
int send_refs_done(void);
|
||||
int send_ref_status(uint8_t has_refs);
|
||||
|
||||
/* keepalive (sent during long blocking ops) */
|
||||
int send_keepalive(void);
|
||||
|
||||
/* session management */
|
||||
const Session *session_get_all(uint8_t *count);
|
||||
uint8_t session_get_current(void);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
#define UDP_PORT 5941
|
||||
#define UDP_BUF_SIZE 128
|
||||
#define MAX_UDP_CLIENTS 10
|
||||
#define UDP_CLIENTS_MAX 16
|
||||
#define CLIENT_TIMEOUT_MS 30000
|
||||
|
||||
static int udp_sock = -1;
|
||||
static esp_netif_t *ap_netif;
|
||||
|
||||
|
|
@ -26,7 +28,7 @@ static struct {
|
|||
struct sockaddr_in addr;
|
||||
uint8_t mac[6];
|
||||
bool active;
|
||||
} clients[MAX_UDP_CLIENTS];
|
||||
} clients[UDP_CLIENTS_MAX];
|
||||
|
||||
static int client_count;
|
||||
|
||||
|
|
@ -38,7 +40,7 @@ static void client_touch(const struct sockaddr_in *addr)
|
|||
return;
|
||||
}
|
||||
|
||||
if (client_count < MAX_UDP_CLIENTS) {
|
||||
if (client_count < UDP_CLIENTS_MAX) {
|
||||
clients[client_count].addr = *addr;
|
||||
clients[client_count].active = true;
|
||||
memset(clients[client_count].mac, 0, 6);
|
||||
|
|
@ -56,7 +58,7 @@ static void client_touch(const struct sockaddr_in *addr)
|
|||
}
|
||||
|
||||
client_count++;
|
||||
printf("UDP: client added (%d/%d)\n", client_count, MAX_UDP_CLIENTS);
|
||||
printf("UDP: client added (%d)\n", client_count);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +67,7 @@ static void client_remove_by_mac(const uint8_t *mac)
|
|||
for (int i = 0; i < client_count; ) {
|
||||
if (memcmp(clients[i].mac, mac, 6) == 0) {
|
||||
clients[i] = clients[--client_count];
|
||||
printf("UDP: client removed by MAC (%d/%d)\n", client_count, MAX_UDP_CLIENTS);
|
||||
printf("UDP: client removed by MAC (%d)\n", client_count);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue