Merge branch 'chlorine-calibration-ui'
This commit is contained in:
commit
3c33c7806d
|
|
@ -95,6 +95,8 @@ final class AppState {
|
||||||
var calTempC: String = "40"
|
var calTempC: String = "40"
|
||||||
var calCellConstant: Double? = nil
|
var calCellConstant: Double? = nil
|
||||||
var calRs: Double? = nil
|
var calRs: Double? = nil
|
||||||
|
var clFactor: Double? = nil
|
||||||
|
var clCalKnownPpm: String = "5"
|
||||||
|
|
||||||
// Clean
|
// Clean
|
||||||
var cleanV: String = "1200"
|
var cleanV: String = "1200"
|
||||||
|
|
@ -256,6 +258,10 @@ final class AppState {
|
||||||
case .cellK(let k):
|
case .cellK(let k):
|
||||||
calCellConstant = Double(k)
|
calCellConstant = Double(k)
|
||||||
status = String(format: "Device cell constant: %.4f cm\u{207B}\u{00B9}", k)
|
status = String(format: "Device cell constant: %.4f cm\u{207B}\u{00B9}", k)
|
||||||
|
|
||||||
|
case .clFactor(let f):
|
||||||
|
clFactor = Double(f)
|
||||||
|
status = String(format: "Device Cl factor: %.6f", f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ let RSP_REF_FRAME: UInt8 = 0x20
|
||||||
let RSP_REF_LP_RANGE: UInt8 = 0x21
|
let RSP_REF_LP_RANGE: UInt8 = 0x21
|
||||||
let RSP_REFS_DONE: UInt8 = 0x22
|
let RSP_REFS_DONE: UInt8 = 0x22
|
||||||
let RSP_REF_STATUS: UInt8 = 0x23
|
let RSP_REF_STATUS: UInt8 = 0x23
|
||||||
|
let RSP_CL_FACTOR: UInt8 = 0x24
|
||||||
|
|
||||||
// Cue -> ESP32
|
// Cue -> ESP32
|
||||||
let CMD_SET_SWEEP: UInt8 = 0x10
|
let CMD_SET_SWEEP: UInt8 = 0x10
|
||||||
|
|
@ -46,6 +47,8 @@ let CMD_START_PH: UInt8 = 0x24
|
||||||
let CMD_START_CLEAN: UInt8 = 0x25
|
let CMD_START_CLEAN: UInt8 = 0x25
|
||||||
let CMD_SET_CELL_K: UInt8 = 0x28
|
let CMD_SET_CELL_K: UInt8 = 0x28
|
||||||
let CMD_GET_CELL_K: UInt8 = 0x29
|
let CMD_GET_CELL_K: UInt8 = 0x29
|
||||||
|
let CMD_SET_CL_FACTOR: UInt8 = 0x33
|
||||||
|
let CMD_GET_CL_FACTOR: UInt8 = 0x34
|
||||||
let CMD_START_REFS: UInt8 = 0x30
|
let CMD_START_REFS: UInt8 = 0x30
|
||||||
let CMD_GET_REFS: UInt8 = 0x31
|
let CMD_GET_REFS: UInt8 = 0x31
|
||||||
let CMD_CLEAR_REFS: UInt8 = 0x32
|
let CMD_CLEAR_REFS: UInt8 = 0x32
|
||||||
|
|
@ -123,6 +126,7 @@ enum EisMessage {
|
||||||
case refsDone
|
case refsDone
|
||||||
case refStatus(hasRefs: Bool)
|
case refStatus(hasRefs: Bool)
|
||||||
case cellK(Float)
|
case cellK(Float)
|
||||||
|
case clFactor(Float)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Response parser
|
// MARK: - Response parser
|
||||||
|
|
@ -254,6 +258,9 @@ func parseSysex(_ data: [UInt8]) -> EisMessage? {
|
||||||
case RSP_CELL_K where p.count >= 5:
|
case RSP_CELL_K where p.count >= 5:
|
||||||
return .cellK(decodeFloat(p, at: 0))
|
return .cellK(decodeFloat(p, at: 0))
|
||||||
|
|
||||||
|
case RSP_CL_FACTOR where p.count >= 5:
|
||||||
|
return .clFactor(decodeFloat(p, at: 0))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -371,3 +378,14 @@ func buildSysexSetCellK(_ k: Float) -> [UInt8] {
|
||||||
func buildSysexGetCellK() -> [UInt8] {
|
func buildSysexGetCellK() -> [UInt8] {
|
||||||
[0xF0, sysexMfr, CMD_GET_CELL_K, 0xF7]
|
[0xF0, sysexMfr, CMD_GET_CELL_K, 0xF7]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildSysexSetClFactor(_ f: Float) -> [UInt8] {
|
||||||
|
var sx: [UInt8] = [0xF0, sysexMfr, CMD_SET_CL_FACTOR]
|
||||||
|
sx.append(contentsOf: encodeFloat(f))
|
||||||
|
sx.append(0xF7)
|
||||||
|
return sx
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildSysexGetClFactor() -> [UInt8] {
|
||||||
|
[0xF0, sysexMfr, CMD_GET_CL_FACTOR, 0xF7]
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ final class UDPManager: @unchecked Sendable {
|
||||||
send(buildSysexGetTemp())
|
send(buildSysexGetTemp())
|
||||||
send(buildSysexGetConfig())
|
send(buildSysexGetConfig())
|
||||||
send(buildSysexGetCellK())
|
send(buildSysexGetCellK())
|
||||||
|
send(buildSysexGetClFactor())
|
||||||
startTimers()
|
startTimers()
|
||||||
receiveLoop()
|
receiveLoop()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ struct CalibrateView: View {
|
||||||
inputSection
|
inputSection
|
||||||
resultsSection
|
resultsSection
|
||||||
cellConstantSection
|
cellConstantSection
|
||||||
|
chlorineCalSection
|
||||||
}
|
}
|
||||||
.navigationTitle("Calibrate")
|
.navigationTitle("Calibrate")
|
||||||
}
|
}
|
||||||
|
|
@ -115,6 +116,48 @@ struct CalibrateView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Chlorine calibration
|
||||||
|
|
||||||
|
private var chlorineCalSection: some View {
|
||||||
|
Section("Chlorine Calibration") {
|
||||||
|
if let f = state.clFactor {
|
||||||
|
Text(String(format: "Cl factor: %.6f ppm/\u{00B5}A", f))
|
||||||
|
}
|
||||||
|
if let r = state.clResult {
|
||||||
|
Text(String(format: "Last free Cl peak: %.3f \u{00B5}A", r.iFreeUa))
|
||||||
|
}
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Text("Known Cl ppm")
|
||||||
|
Spacer()
|
||||||
|
TextField("ppm", text: $state.clCalKnownPpm)
|
||||||
|
.multilineTextAlignment(.trailing)
|
||||||
|
.frame(width: 80)
|
||||||
|
#if os(iOS)
|
||||||
|
.keyboardType(.decimalPad)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Button("Set Cl Factor") {
|
||||||
|
guard let r = state.clResult else {
|
||||||
|
state.status = "No chlorine measurement"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let knownPpm = Double(state.clCalKnownPpm) ?? 0
|
||||||
|
let peak = abs(Double(r.iFreeUa))
|
||||||
|
guard peak > 0 else {
|
||||||
|
state.status = "Peak current is zero"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let factor = knownPpm / peak
|
||||||
|
state.clFactor = factor
|
||||||
|
state.send(buildSysexSetClFactor(Float(factor)))
|
||||||
|
state.status = String(format: "Cl factor: %.6f ppm/\u{00B5}A", factor)
|
||||||
|
}
|
||||||
|
.disabled(state.clResult == nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Calculations
|
// MARK: - Calculations
|
||||||
|
|
||||||
private func saltGrams(volumeGal: Double, ppm: Double) -> Double {
|
private func saltGrams(volumeGal: Double, ppm: Double) -> Double {
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,12 @@ struct ChlorineView: View {
|
||||||
Text(String(format: "Combined: %.3f uA", r.iTotalUa - r.iFreeUa))
|
Text(String(format: "Combined: %.3f uA", r.iTotalUa - r.iFreeUa))
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
|
|
||||||
|
if let f = state.clFactor {
|
||||||
|
let ppm = f * Double(abs(r.iFreeUa))
|
||||||
|
Text(String(format: "Free Cl: %.2f ppm", ppm))
|
||||||
|
.foregroundStyle(.cyan)
|
||||||
|
}
|
||||||
|
|
||||||
if let (_, refR) = state.clRef {
|
if let (_, refR) = state.clRef {
|
||||||
Divider().frame(height: 16)
|
Divider().frame(height: 16)
|
||||||
Text(String(format: "vs Ref: dFree=%.3f dTotal=%.3f",
|
Text(String(format: "vs Ref: dFree=%.3f dTotal=%.3f",
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@ pub enum Message {
|
||||||
CalBleachChanged(String),
|
CalBleachChanged(String),
|
||||||
CalTempChanged(String),
|
CalTempChanged(String),
|
||||||
CalComputeK,
|
CalComputeK,
|
||||||
|
ClCalKnownPpmChanged(String),
|
||||||
|
ClSetFactor,
|
||||||
/* Global */
|
/* Global */
|
||||||
PollTemp,
|
PollTemp,
|
||||||
NativeMenuTick,
|
NativeMenuTick,
|
||||||
|
|
@ -231,6 +233,8 @@ pub struct App {
|
||||||
cal_bleach_pct: String,
|
cal_bleach_pct: String,
|
||||||
cal_temp_c: String,
|
cal_temp_c: String,
|
||||||
cal_cell_constant: Option<f32>,
|
cal_cell_constant: Option<f32>,
|
||||||
|
cl_factor: Option<f32>,
|
||||||
|
cl_cal_known_ppm: String,
|
||||||
|
|
||||||
/* Global */
|
/* Global */
|
||||||
temp_c: f32,
|
temp_c: f32,
|
||||||
|
|
@ -463,6 +467,8 @@ impl App {
|
||||||
cal_bleach_pct: "7.825".into(),
|
cal_bleach_pct: "7.825".into(),
|
||||||
cal_temp_c: "40".into(),
|
cal_temp_c: "40".into(),
|
||||||
cal_cell_constant: None,
|
cal_cell_constant: None,
|
||||||
|
cl_factor: None,
|
||||||
|
cl_cal_known_ppm: String::from("5"),
|
||||||
|
|
||||||
temp_c: 25.0,
|
temp_c: 25.0,
|
||||||
conn_gen: 0,
|
conn_gen: 0,
|
||||||
|
|
@ -567,6 +573,7 @@ impl App {
|
||||||
self.connected = true;
|
self.connected = true;
|
||||||
self.send_cmd(&protocol::build_sysex_get_config());
|
self.send_cmd(&protocol::build_sysex_get_config());
|
||||||
self.send_cmd(&protocol::build_sysex_get_cell_k());
|
self.send_cmd(&protocol::build_sysex_get_cell_k());
|
||||||
|
self.send_cmd(&protocol::build_sysex_get_cl_factor());
|
||||||
}
|
}
|
||||||
Message::DeviceStatus(s) => {
|
Message::DeviceStatus(s) => {
|
||||||
if s.contains("Reconnecting") || s.contains("Connecting") {
|
if s.contains("Reconnecting") || s.contains("Connecting") {
|
||||||
|
|
@ -743,6 +750,10 @@ impl App {
|
||||||
self.cal_cell_constant = Some(k);
|
self.cal_cell_constant = Some(k);
|
||||||
self.status = format!("Device cell constant: {:.4} cm-1", k);
|
self.status = format!("Device cell constant: {:.4} cm-1", k);
|
||||||
}
|
}
|
||||||
|
EisMessage::ClFactor(f) => {
|
||||||
|
self.cl_factor = Some(f);
|
||||||
|
self.status = format!("Device Cl factor: {:.6}", f);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Message::TabSelected(t) => {
|
Message::TabSelected(t) => {
|
||||||
if t == Tab::Browse {
|
if t == Tab::Browse {
|
||||||
|
|
@ -968,6 +979,19 @@ impl App {
|
||||||
self.status = "No valid EIS data for Rs extraction".into();
|
self.status = "No valid EIS data for Rs extraction".into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::ClCalKnownPpmChanged(s) => { self.cl_cal_known_ppm = s; }
|
||||||
|
Message::ClSetFactor => {
|
||||||
|
let known_ppm = self.cl_cal_known_ppm.parse::<f32>().unwrap_or(0.0);
|
||||||
|
if let Some(r) = &self.cl_result {
|
||||||
|
let peak = r.i_free_ua.abs();
|
||||||
|
if peak > 0.0 {
|
||||||
|
let factor = known_ppm / peak;
|
||||||
|
self.cl_factor = Some(factor);
|
||||||
|
self.send_cmd(&protocol::build_sysex_set_cl_factor(factor));
|
||||||
|
self.status = format!("Cl factor: {:.6} ppm/uA", factor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Clean */
|
/* Clean */
|
||||||
Message::CleanVChanged(s) => self.clean_v = s,
|
Message::CleanVChanged(s) => self.clean_v = s,
|
||||||
Message::CleanDurChanged(s) => self.clean_dur = s,
|
Message::CleanDurChanged(s) => self.clean_dur = s,
|
||||||
|
|
@ -1574,6 +1598,10 @@ impl App {
|
||||||
"Free: {:.3} uA | Total: {:.3} uA | Combined: {:.3} uA",
|
"Free: {:.3} uA | Total: {:.3} uA | Combined: {:.3} uA",
|
||||||
r.i_free_ua, r.i_total_ua, r.i_total_ua - r.i_free_ua
|
r.i_free_ua, r.i_total_ua, r.i_total_ua - r.i_free_ua
|
||||||
));
|
));
|
||||||
|
if let (Some(f), Some(r)) = (self.cl_factor, &self.cl_result) {
|
||||||
|
let ppm = f * r.i_free_ua.abs();
|
||||||
|
result_parts.push(format!("Free Cl: {:.2} ppm", ppm));
|
||||||
|
}
|
||||||
if let Some((_, ref_r)) = &self.cl_ref {
|
if let Some((_, ref_r)) = &self.cl_ref {
|
||||||
let df = r.i_free_ua - ref_r.i_free_ua;
|
let df = r.i_free_ua - ref_r.i_free_ua;
|
||||||
let dt = r.i_total_ua - ref_r.i_total_ua;
|
let dt = r.i_total_ua - ref_r.i_total_ua;
|
||||||
|
|
@ -1681,6 +1709,28 @@ impl App {
|
||||||
.on_press(Message::CalComputeK);
|
.on_press(Message::CalComputeK);
|
||||||
results = results.push(compute_btn);
|
results = results.push(compute_btn);
|
||||||
|
|
||||||
|
results = results.push(iced::widget::horizontal_rule(1));
|
||||||
|
results = results.push(text("Chlorine Calibration").size(16));
|
||||||
|
if let Some(f) = self.cl_factor {
|
||||||
|
results = results.push(text(format!("Cl factor: {:.6} ppm/uA", f)).size(14));
|
||||||
|
}
|
||||||
|
if let Some(r) = &self.cl_result {
|
||||||
|
results = results.push(text(format!("Last free Cl peak: {:.3} uA", r.i_free_ua)).size(14));
|
||||||
|
}
|
||||||
|
results = results.push(
|
||||||
|
row![
|
||||||
|
column![
|
||||||
|
text("Known Cl ppm").size(12),
|
||||||
|
text_input("5", &self.cl_cal_known_ppm)
|
||||||
|
.on_input(Message::ClCalKnownPpmChanged).width(80),
|
||||||
|
].spacing(2),
|
||||||
|
button(text("Set Cl Factor").size(13))
|
||||||
|
.style(style_action())
|
||||||
|
.padding([6, 16])
|
||||||
|
.on_press(Message::ClSetFactor),
|
||||||
|
].spacing(10).align_y(iced::Alignment::End)
|
||||||
|
);
|
||||||
|
|
||||||
row![
|
row![
|
||||||
container(inputs).width(Length::FillPortion(2)),
|
container(inputs).width(Length::FillPortion(2)),
|
||||||
iced::widget::vertical_rule(1),
|
iced::widget::vertical_rule(1),
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ pub const RSP_REF_LP_RANGE: u8 = 0x21;
|
||||||
pub const RSP_REFS_DONE: u8 = 0x22;
|
pub const RSP_REFS_DONE: u8 = 0x22;
|
||||||
pub const RSP_CELL_K: u8 = 0x11;
|
pub const RSP_CELL_K: u8 = 0x11;
|
||||||
pub const RSP_REF_STATUS: u8 = 0x23;
|
pub const RSP_REF_STATUS: u8 = 0x23;
|
||||||
|
pub const RSP_CL_FACTOR: u8 = 0x24;
|
||||||
|
|
||||||
/* Cue → ESP32 */
|
/* Cue → ESP32 */
|
||||||
pub const CMD_SET_SWEEP: u8 = 0x10;
|
pub const CMD_SET_SWEEP: u8 = 0x10;
|
||||||
|
|
@ -44,6 +45,8 @@ pub const CMD_START_PH: u8 = 0x24;
|
||||||
pub const CMD_START_CLEAN: u8 = 0x25;
|
pub const CMD_START_CLEAN: u8 = 0x25;
|
||||||
pub const CMD_SET_CELL_K: u8 = 0x28;
|
pub const CMD_SET_CELL_K: u8 = 0x28;
|
||||||
pub const CMD_GET_CELL_K: u8 = 0x29;
|
pub const CMD_GET_CELL_K: u8 = 0x29;
|
||||||
|
pub const CMD_SET_CL_FACTOR: u8 = 0x33;
|
||||||
|
pub const CMD_GET_CL_FACTOR: u8 = 0x34;
|
||||||
pub const CMD_START_REFS: u8 = 0x30;
|
pub const CMD_START_REFS: u8 = 0x30;
|
||||||
pub const CMD_GET_REFS: u8 = 0x31;
|
pub const CMD_GET_REFS: u8 = 0x31;
|
||||||
pub const CMD_CLEAR_REFS: u8 = 0x32;
|
pub const CMD_CLEAR_REFS: u8 = 0x32;
|
||||||
|
|
@ -258,6 +261,7 @@ pub enum EisMessage {
|
||||||
RefsDone,
|
RefsDone,
|
||||||
RefStatus { has_refs: bool },
|
RefStatus { has_refs: bool },
|
||||||
CellK(f32),
|
CellK(f32),
|
||||||
|
ClFactor(f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_u16(data: &[u8]) -> u16 {
|
fn decode_u16(data: &[u8]) -> u16 {
|
||||||
|
|
@ -413,6 +417,10 @@ pub fn parse_sysex(data: &[u8]) -> Option<EisMessage> {
|
||||||
let p = &data[2..];
|
let p = &data[2..];
|
||||||
Some(EisMessage::CellK(decode_float(&p[0..5])))
|
Some(EisMessage::CellK(decode_float(&p[0..5])))
|
||||||
}
|
}
|
||||||
|
RSP_CL_FACTOR if data.len() >= 7 => {
|
||||||
|
let p = &data[2..];
|
||||||
|
Some(EisMessage::ClFactor(decode_float(&p[0..5])))
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -527,3 +535,14 @@ pub fn build_sysex_set_cell_k(k: f32) -> Vec<u8> {
|
||||||
pub fn build_sysex_get_cell_k() -> Vec<u8> {
|
pub fn build_sysex_get_cell_k() -> Vec<u8> {
|
||||||
vec![0xF0, SYSEX_MFR, CMD_GET_CELL_K, 0xF7]
|
vec![0xF0, SYSEX_MFR, CMD_GET_CELL_K, 0xF7]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn build_sysex_set_cl_factor(f: f32) -> Vec<u8> {
|
||||||
|
let mut sx = vec![0xF0, SYSEX_MFR, CMD_SET_CL_FACTOR];
|
||||||
|
sx.extend_from_slice(&encode_float(f));
|
||||||
|
sx.push(0xF7);
|
||||||
|
sx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_sysex_get_cl_factor() -> Vec<u8> {
|
||||||
|
vec![0xF0, SYSEX_MFR, CMD_GET_CL_FACTOR, 0xF7]
|
||||||
|
}
|
||||||
|
|
|
||||||
27
main/eis.c
27
main/eis.c
|
|
@ -25,6 +25,7 @@ static struct {
|
||||||
|
|
||||||
/* cell constant K (cm⁻¹), cached from NVS */
|
/* cell constant K (cm⁻¹), cached from NVS */
|
||||||
static float cell_k_cached;
|
static float cell_k_cached;
|
||||||
|
static float cl_factor_cached;
|
||||||
|
|
||||||
/* open-circuit calibration data */
|
/* open-circuit calibration data */
|
||||||
static struct {
|
static struct {
|
||||||
|
|
@ -594,6 +595,7 @@ int eis_has_open_cal(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NVS_CELLK_KEY "cell_k"
|
#define NVS_CELLK_KEY "cell_k"
|
||||||
|
#define NVS_CLFACTOR_KEY "cl_factor"
|
||||||
|
|
||||||
void eis_set_cell_k(float k)
|
void eis_set_cell_k(float k)
|
||||||
{
|
{
|
||||||
|
|
@ -619,3 +621,28 @@ void eis_load_cell_k(void)
|
||||||
cell_k_cached = 0.0f;
|
cell_k_cached = 0.0f;
|
||||||
nvs_close(h);
|
nvs_close(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void eis_set_cl_factor(float f)
|
||||||
|
{
|
||||||
|
cl_factor_cached = f;
|
||||||
|
nvs_handle_t h;
|
||||||
|
if (nvs_open(NVS_OCAL_NS, NVS_READWRITE, &h) != ESP_OK) return;
|
||||||
|
nvs_set_blob(h, NVS_CLFACTOR_KEY, &f, sizeof(f));
|
||||||
|
nvs_commit(h);
|
||||||
|
nvs_close(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
float eis_get_cl_factor(void)
|
||||||
|
{
|
||||||
|
return cl_factor_cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
void eis_load_cl_factor(void)
|
||||||
|
{
|
||||||
|
nvs_handle_t h;
|
||||||
|
if (nvs_open(NVS_OCAL_NS, NVS_READONLY, &h) != ESP_OK) return;
|
||||||
|
size_t len = sizeof(cl_factor_cached);
|
||||||
|
if (nvs_get_blob(h, NVS_CLFACTOR_KEY, &cl_factor_cached, &len) != ESP_OK || len != sizeof(cl_factor_cached))
|
||||||
|
cl_factor_cached = 0.0f;
|
||||||
|
nvs_close(h);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,8 @@ void eis_set_cell_k(float k);
|
||||||
float eis_get_cell_k(void);
|
float eis_get_cell_k(void);
|
||||||
void eis_load_cell_k(void);
|
void eis_load_cell_k(void);
|
||||||
|
|
||||||
|
void eis_set_cl_factor(float f);
|
||||||
|
float eis_get_cl_factor(void);
|
||||||
|
void eis_load_cl_factor(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
11
main/eis4.c
11
main/eis4.c
|
|
@ -56,6 +56,7 @@ void app_main(void)
|
||||||
eis_default_config(&cfg);
|
eis_default_config(&cfg);
|
||||||
eis_load_open_cal();
|
eis_load_open_cal();
|
||||||
eis_load_cell_k();
|
eis_load_cell_k();
|
||||||
|
eis_load_cl_factor();
|
||||||
temp_init();
|
temp_init();
|
||||||
|
|
||||||
esp_netif_init();
|
esp_netif_init();
|
||||||
|
|
@ -214,6 +215,16 @@ void app_main(void)
|
||||||
send_cell_k(eis_get_cell_k());
|
send_cell_k(eis_get_cell_k());
|
||||||
break;
|
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_START_CL: {
|
case CMD_START_CL: {
|
||||||
ClConfig cl_cfg;
|
ClConfig cl_cfg;
|
||||||
cl_cfg.v_cond = cmd.cl.v_cond;
|
cl_cfg.v_cond = cmd.cl.v_cond;
|
||||||
|
|
|
||||||
|
|
@ -341,6 +341,18 @@ int send_cell_k(float k)
|
||||||
return send_sysex(sx, p);
|
return send_sysex(sx, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- outbound: chlorine factor ---- */
|
||||||
|
|
||||||
|
int send_cl_factor(float f)
|
||||||
|
{
|
||||||
|
uint8_t sx[12];
|
||||||
|
uint16_t p = 0;
|
||||||
|
sx[p++] = 0xF0; sx[p++] = 0x7D; sx[p++] = RSP_CL_FACTOR;
|
||||||
|
encode_float(f, &sx[p]); p += 5;
|
||||||
|
sx[p++] = 0xF7;
|
||||||
|
return send_sysex(sx, p);
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- outbound: reference collection ---- */
|
/* ---- outbound: reference collection ---- */
|
||||||
|
|
||||||
int send_ref_frame(uint8_t mode, uint8_t rtia_idx)
|
int send_ref_frame(uint8_t mode, uint8_t rtia_idx)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
#define CMD_START_REFS 0x30
|
#define CMD_START_REFS 0x30
|
||||||
#define CMD_GET_REFS 0x31
|
#define CMD_GET_REFS 0x31
|
||||||
#define CMD_CLEAR_REFS 0x32
|
#define CMD_CLEAR_REFS 0x32
|
||||||
|
#define CMD_SET_CL_FACTOR 0x33
|
||||||
|
#define CMD_GET_CL_FACTOR 0x34
|
||||||
|
|
||||||
/* Session sync commands (0x4x) */
|
/* Session sync commands (0x4x) */
|
||||||
#define CMD_SESSION_CREATE 0x40
|
#define CMD_SESSION_CREATE 0x40
|
||||||
|
|
@ -56,6 +58,7 @@
|
||||||
#define RSP_REF_LP_RANGE 0x21
|
#define RSP_REF_LP_RANGE 0x21
|
||||||
#define RSP_REFS_DONE 0x22
|
#define RSP_REFS_DONE 0x22
|
||||||
#define RSP_REF_STATUS 0x23
|
#define RSP_REF_STATUS 0x23
|
||||||
|
#define RSP_CL_FACTOR 0x24
|
||||||
|
|
||||||
/* Session sync responses (0x4x) */
|
/* Session sync responses (0x4x) */
|
||||||
#define RSP_SESSION_CREATED 0x40
|
#define RSP_SESSION_CREATED 0x40
|
||||||
|
|
@ -81,6 +84,7 @@ typedef struct {
|
||||||
struct { float stabilize_s; } ph;
|
struct { float stabilize_s; } ph;
|
||||||
struct { float v_mv; float duration_s; } clean;
|
struct { float v_mv; float duration_s; } clean;
|
||||||
float cell_k;
|
float cell_k;
|
||||||
|
float cl_factor;
|
||||||
struct { uint8_t name_len; char name[MAX_SESSION_NAME]; } session_create;
|
struct { uint8_t name_len; char name[MAX_SESSION_NAME]; } session_create;
|
||||||
struct { uint8_t id; } session_switch;
|
struct { uint8_t id; } session_switch;
|
||||||
struct { uint8_t id; uint8_t name_len; char name[MAX_SESSION_NAME]; } session_rename;
|
struct { uint8_t id; uint8_t name_len; char name[MAX_SESSION_NAME]; } session_rename;
|
||||||
|
|
@ -132,6 +136,9 @@ int send_temp(float temp_c);
|
||||||
/* outbound: cell constant */
|
/* outbound: cell constant */
|
||||||
int send_cell_k(float k);
|
int send_cell_k(float k);
|
||||||
|
|
||||||
|
/* outbound: chlorine factor */
|
||||||
|
int send_cl_factor(float f);
|
||||||
|
|
||||||
/* outbound: reference collection */
|
/* outbound: reference collection */
|
||||||
int send_ref_frame(uint8_t mode, uint8_t rtia_idx);
|
int send_ref_frame(uint8_t mode, uint8_t rtia_idx);
|
||||||
int send_ref_lp_range(uint8_t mode, uint8_t low_idx, uint8_t high_idx);
|
int send_ref_lp_range(uint8_t mode, uint8_t low_idx, uint8_t high_idx);
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,10 @@ static void parse_udp_sysex(const uint8_t *data, uint16_t len)
|
||||||
if (len < 8) return;
|
if (len < 8) return;
|
||||||
cmd.cell_k = decode_float(&data[3]);
|
cmd.cell_k = decode_float(&data[3]);
|
||||||
break;
|
break;
|
||||||
|
case CMD_SET_CL_FACTOR:
|
||||||
|
if (len < 8) return;
|
||||||
|
cmd.cl_factor = decode_float(&data[3]);
|
||||||
|
break;
|
||||||
case CMD_SESSION_CREATE:
|
case CMD_SESSION_CREATE:
|
||||||
if (len < 5) return;
|
if (len < 5) return;
|
||||||
cmd.session_create.name_len = data[3] & 0x7F;
|
cmd.session_create.name_len = data[3] & 0x7F;
|
||||||
|
|
@ -192,6 +196,7 @@ static void parse_udp_sysex(const uint8_t *data, uint16_t len)
|
||||||
case CMD_STOP_AMP:
|
case CMD_STOP_AMP:
|
||||||
case CMD_GET_TEMP:
|
case CMD_GET_TEMP:
|
||||||
case CMD_GET_CELL_K:
|
case CMD_GET_CELL_K:
|
||||||
|
case CMD_GET_CL_FACTOR:
|
||||||
case CMD_START_REFS:
|
case CMD_START_REFS:
|
||||||
case CMD_GET_REFS:
|
case CMD_GET_REFS:
|
||||||
case CMD_CLEAR_REFS:
|
case CMD_CLEAR_REFS:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue