607 lines
20 KiB
Rust
607 lines
20 KiB
Rust
/// EIS4 SysEx Protocol — manufacturer ID 0x7D (non-commercial)
|
|
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
pub const SYSEX_MFR: u8 = 0x7D;
|
|
|
|
/* ESP32 → Cue */
|
|
pub const RSP_SWEEP_START: u8 = 0x01;
|
|
pub const RSP_DATA_POINT: u8 = 0x02;
|
|
pub const RSP_SWEEP_END: u8 = 0x03;
|
|
pub const RSP_CONFIG: u8 = 0x04;
|
|
pub const RSP_LSV_START: u8 = 0x05;
|
|
pub const RSP_LSV_POINT: u8 = 0x06;
|
|
pub const RSP_LSV_END: u8 = 0x07;
|
|
pub const RSP_AMP_START: u8 = 0x08;
|
|
pub const RSP_AMP_POINT: u8 = 0x09;
|
|
pub const RSP_AMP_END: u8 = 0x0A;
|
|
pub const RSP_CL_START: u8 = 0x0B;
|
|
pub const RSP_CL_POINT: u8 = 0x0C;
|
|
pub const RSP_CL_RESULT: u8 = 0x0D;
|
|
pub const RSP_CL_END: u8 = 0x0E;
|
|
pub const RSP_PH_RESULT: u8 = 0x0F;
|
|
pub const RSP_TEMP: u8 = 0x10;
|
|
pub const RSP_REF_FRAME: u8 = 0x20;
|
|
pub const RSP_REF_LP_RANGE: u8 = 0x21;
|
|
pub const RSP_REFS_DONE: u8 = 0x22;
|
|
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;
|
|
pub const CMD_SET_RTIA: u8 = 0x11;
|
|
pub const CMD_SET_RCAL: u8 = 0x12;
|
|
pub const CMD_START_SWEEP: u8 = 0x13;
|
|
pub const CMD_GET_CONFIG: u8 = 0x14;
|
|
pub const CMD_SET_ELECTRODE: u8 = 0x15;
|
|
pub const CMD_START_LSV: u8 = 0x20;
|
|
pub const CMD_START_AMP: u8 = 0x21;
|
|
pub const CMD_STOP_AMP: u8 = 0x22;
|
|
|
|
pub const CMD_GET_TEMP: u8 = 0x17;
|
|
pub const CMD_START_CL: u8 = 0x23;
|
|
pub const CMD_START_PH: u8 = 0x24;
|
|
pub const CMD_START_CLEAN: u8 = 0x25;
|
|
pub const CMD_SET_CELL_K: u8 = 0x28;
|
|
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_SET_PH_CAL: u8 = 0x35;
|
|
pub const CMD_GET_PH_CAL: u8 = 0x36;
|
|
pub const CMD_START_REFS: u8 = 0x30;
|
|
pub const CMD_GET_REFS: u8 = 0x31;
|
|
pub const CMD_CLEAR_REFS: u8 = 0x32;
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum Rtia {
|
|
R200, R1K, R5K, R10K, R20K, R40K, R80K, R160K, ExtDe0,
|
|
}
|
|
|
|
impl Rtia {
|
|
pub fn from_byte(b: u8) -> Option<Self> {
|
|
Some(match b {
|
|
0 => Self::R200, 1 => Self::R1K, 2 => Self::R5K, 3 => Self::R10K,
|
|
4 => Self::R20K, 5 => Self::R40K, 6 => Self::R80K, 7 => Self::R160K,
|
|
8 => Self::ExtDe0,
|
|
_ => return None,
|
|
})
|
|
}
|
|
pub fn as_byte(self) -> u8 { self as u8 }
|
|
pub fn label(self) -> &'static str {
|
|
match self {
|
|
Self::R200 => "200Ω", Self::R1K => "1kΩ", Self::R5K => "5kΩ",
|
|
Self::R10K => "10kΩ", Self::R20K => "20kΩ", Self::R40K => "40kΩ",
|
|
Self::R80K => "80kΩ", Self::R160K => "160kΩ", Self::ExtDe0 => "Ext 3kΩ (DE0)",
|
|
}
|
|
}
|
|
pub const ALL: &[Self] = &[
|
|
Self::R200, Self::R1K, Self::R5K, Self::R10K,
|
|
Self::R20K, Self::R40K, Self::R80K, Self::R160K, Self::ExtDe0,
|
|
];
|
|
}
|
|
|
|
impl std::fmt::Display for Rtia {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str(self.label())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum Rcal {
|
|
R200, R3K,
|
|
}
|
|
|
|
impl Rcal {
|
|
pub fn from_byte(b: u8) -> Option<Self> {
|
|
Some(match b { 0 => Self::R200, 1 => Self::R3K, _ => return None })
|
|
}
|
|
pub fn as_byte(self) -> u8 { self as u8 }
|
|
pub fn label(self) -> &'static str {
|
|
match self { Self::R200 => "200Ω (RCAL0↔RCAL1)", Self::R3K => "3kΩ (RCAL0↔AIN0)" }
|
|
}
|
|
pub const ALL: &[Self] = &[Self::R200, Self::R3K];
|
|
}
|
|
|
|
impl std::fmt::Display for Rcal {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str(self.label())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum Electrode {
|
|
FourWire, ThreeWire,
|
|
}
|
|
|
|
impl Electrode {
|
|
pub fn from_byte(b: u8) -> Option<Self> {
|
|
Some(match b { 0 => Self::FourWire, 1 => Self::ThreeWire, _ => return None })
|
|
}
|
|
pub fn as_byte(self) -> u8 { self as u8 }
|
|
pub fn label(self) -> &'static str {
|
|
match self {
|
|
Self::FourWire => "4-wire (AIN)",
|
|
Self::ThreeWire => "3-wire (CE0/RE0/SE0)",
|
|
}
|
|
}
|
|
pub const ALL: &[Self] = &[Self::FourWire, Self::ThreeWire];
|
|
}
|
|
|
|
impl std::fmt::Display for Electrode {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str(self.label())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum LpRtia {
|
|
R200, R1K, R2K, R3K, R4K, R6K, R8K, R10K, R12K, R16K,
|
|
R20K, R24K, R30K, R32K, R40K, R48K, R64K, R85K, R96K,
|
|
R100K, R120K, R128K, R160K, R196K, R256K, R512K,
|
|
}
|
|
|
|
impl LpRtia {
|
|
#[allow(dead_code)]
|
|
pub fn from_byte(b: u8) -> Option<Self> {
|
|
Some(match b {
|
|
0 => Self::R200, 1 => Self::R1K, 2 => Self::R2K, 3 => Self::R3K,
|
|
4 => Self::R4K, 5 => Self::R6K, 6 => Self::R8K, 7 => Self::R10K,
|
|
8 => Self::R12K, 9 => Self::R16K, 10 => Self::R20K, 11 => Self::R24K,
|
|
12 => Self::R30K, 13 => Self::R32K, 14 => Self::R40K, 15 => Self::R48K,
|
|
16 => Self::R64K, 17 => Self::R85K, 18 => Self::R96K, 19 => Self::R100K,
|
|
20 => Self::R120K, 21 => Self::R128K, 22 => Self::R160K, 23 => Self::R196K,
|
|
24 => Self::R256K, 25 => Self::R512K,
|
|
_ => return None,
|
|
})
|
|
}
|
|
pub fn as_byte(self) -> u8 { self as u8 }
|
|
pub fn label(self) -> &'static str {
|
|
match self {
|
|
Self::R200 => "200Ω", Self::R1K => "1kΩ", Self::R2K => "2kΩ",
|
|
Self::R3K => "3kΩ", Self::R4K => "4kΩ", Self::R6K => "6kΩ",
|
|
Self::R8K => "8kΩ", Self::R10K => "10kΩ", Self::R12K => "12kΩ",
|
|
Self::R16K => "16kΩ", Self::R20K => "20kΩ", Self::R24K => "24kΩ",
|
|
Self::R30K => "30kΩ", Self::R32K => "32kΩ", Self::R40K => "40kΩ",
|
|
Self::R48K => "48kΩ", Self::R64K => "64kΩ", Self::R85K => "85kΩ",
|
|
Self::R96K => "96kΩ", Self::R100K => "100kΩ", Self::R120K => "120kΩ",
|
|
Self::R128K => "128kΩ", Self::R160K => "160kΩ", Self::R196K => "196kΩ",
|
|
Self::R256K => "256kΩ", Self::R512K => "512kΩ",
|
|
}
|
|
}
|
|
pub const ALL: &[Self] = &[
|
|
Self::R200, Self::R1K, Self::R2K, Self::R3K, Self::R4K,
|
|
Self::R6K, Self::R8K, Self::R10K, Self::R12K, Self::R16K,
|
|
Self::R20K, Self::R24K, Self::R30K, Self::R32K, Self::R40K,
|
|
Self::R48K, Self::R64K, Self::R85K, Self::R96K, Self::R100K,
|
|
Self::R120K, Self::R128K, Self::R160K, Self::R196K, Self::R256K, Self::R512K,
|
|
];
|
|
}
|
|
|
|
impl std::fmt::Display for LpRtia {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str(self.label())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct EisPoint {
|
|
pub freq_hz: f32,
|
|
pub mag_ohms: f32,
|
|
pub phase_deg: f32,
|
|
pub z_real: f32,
|
|
pub z_imag: f32,
|
|
pub rtia_mag_before: f32,
|
|
pub rtia_mag_after: f32,
|
|
pub rev_mag: f32,
|
|
pub rev_phase: f32,
|
|
pub pct_err: f32,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct LsvPoint {
|
|
pub v_mv: f32,
|
|
pub i_ua: f32,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AmpPoint {
|
|
pub t_ms: f32,
|
|
pub i_ua: f32,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ClPoint {
|
|
pub t_ms: f32,
|
|
pub i_ua: f32,
|
|
pub phase: u8,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ClResult {
|
|
pub i_free_ua: f32,
|
|
pub i_total_ua: f32,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct PhResult {
|
|
pub v_ocp_mv: f32,
|
|
pub ph: f32,
|
|
pub temp_c: f32,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct EisConfig {
|
|
pub freq_start: f32,
|
|
pub freq_stop: f32,
|
|
pub ppd: u16,
|
|
pub rtia: Rtia,
|
|
pub rcal: Rcal,
|
|
pub electrode: Electrode,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum EisMessage {
|
|
SweepStart { num_points: u16, freq_start: f32, freq_stop: f32,
|
|
esp_timestamp: Option<u32>, meas_id: Option<u16> },
|
|
DataPoint { _index: u16, point: EisPoint },
|
|
SweepEnd,
|
|
Config(EisConfig),
|
|
LsvStart { num_points: u16, v_start: f32, v_stop: f32,
|
|
esp_timestamp: Option<u32>, meas_id: Option<u16> },
|
|
LsvPoint { _index: u16, point: LsvPoint },
|
|
LsvEnd,
|
|
AmpStart { v_hold: f32, esp_timestamp: Option<u32>, meas_id: Option<u16> },
|
|
AmpPoint { _index: u16, point: AmpPoint },
|
|
AmpEnd,
|
|
ClStart { num_points: u16, esp_timestamp: Option<u32>, meas_id: Option<u16> },
|
|
ClPoint { _index: u16, point: ClPoint },
|
|
ClResult(ClResult),
|
|
ClEnd,
|
|
PhResult(PhResult, Option<u32>, Option<u16>),
|
|
Temperature(f32),
|
|
RefFrame { mode: u8, rtia_idx: u8 },
|
|
RefLpRange { mode: u8, low_idx: u8, high_idx: u8 },
|
|
RefsDone,
|
|
RefStatus { has_refs: bool },
|
|
CellK(f32),
|
|
ClFactor(f32),
|
|
PhCal { slope: f32, offset: f32 },
|
|
Keepalive,
|
|
}
|
|
|
|
fn decode_u16(data: &[u8]) -> u16 {
|
|
let b0 = data[1] | ((data[0] & 1) << 7);
|
|
let b1 = data[2] | ((data[0] & 2) << 6);
|
|
u16::from_le_bytes([b0, b1])
|
|
}
|
|
|
|
fn decode_float(data: &[u8]) -> f32 {
|
|
let m = data[0];
|
|
let b0 = data[1] | ((m & 1) << 7);
|
|
let b1 = data[2] | ((m & 2) << 6);
|
|
let b2 = data[3] | ((m & 4) << 5);
|
|
let b3 = data[4] | ((m & 8) << 4);
|
|
f32::from_le_bytes([b0, b1, b2, b3])
|
|
}
|
|
|
|
fn decode_u32(data: &[u8]) -> u32 {
|
|
let b = [
|
|
data[1] | ((data[0] & 1) << 7),
|
|
data[2] | ((data[0] & 2) << 6),
|
|
data[3] | ((data[0] & 4) << 5),
|
|
data[4] | ((data[0] & 8) << 4),
|
|
];
|
|
u32::from_le_bytes(b)
|
|
}
|
|
|
|
fn encode_float(val: f32) -> [u8; 5] {
|
|
let p = val.to_le_bytes();
|
|
[
|
|
((p[0] >> 7) & 1) | ((p[1] >> 6) & 2) | ((p[2] >> 5) & 4) | ((p[3] >> 4) & 8),
|
|
p[0] & 0x7F, p[1] & 0x7F, p[2] & 0x7F, p[3] & 0x7F,
|
|
]
|
|
}
|
|
|
|
fn encode_u16(val: u16) -> [u8; 3] {
|
|
let p = val.to_le_bytes();
|
|
[((p[0] >> 7) & 1) | ((p[1] >> 6) & 2), p[0] & 0x7F, p[1] & 0x7F]
|
|
}
|
|
|
|
pub fn parse_sysex(data: &[u8]) -> Option<EisMessage> {
|
|
if data.len() < 2 || data[0] != SYSEX_MFR { return None; }
|
|
match data[1] {
|
|
RSP_SWEEP_START if data.len() >= 15 => {
|
|
let p = &data[2..];
|
|
let (ts, mid) = if p.len() >= 21 {
|
|
(Some(decode_u32(&p[13..18])), Some(decode_u16(&p[18..21])))
|
|
} else { (None, None) };
|
|
Some(EisMessage::SweepStart {
|
|
num_points: decode_u16(&p[0..3]),
|
|
freq_start: decode_float(&p[3..8]),
|
|
freq_stop: decode_float(&p[8..13]),
|
|
esp_timestamp: ts, meas_id: mid,
|
|
})
|
|
}
|
|
RSP_DATA_POINT if data.len() >= 30 => {
|
|
let p = &data[2..];
|
|
let ext = p.len() >= 53;
|
|
Some(EisMessage::DataPoint {
|
|
_index: decode_u16(&p[0..3]),
|
|
point: EisPoint {
|
|
freq_hz: decode_float(&p[3..8]),
|
|
mag_ohms: decode_float(&p[8..13]),
|
|
phase_deg: decode_float(&p[13..18]),
|
|
z_real: decode_float(&p[18..23]),
|
|
z_imag: decode_float(&p[23..28]),
|
|
rtia_mag_before: if ext { decode_float(&p[28..33]) } else { 0.0 },
|
|
rtia_mag_after: if ext { decode_float(&p[33..38]) } else { 0.0 },
|
|
rev_mag: if ext { decode_float(&p[38..43]) } else { 0.0 },
|
|
rev_phase: if ext { decode_float(&p[43..48]) } else { 0.0 },
|
|
pct_err: if ext { decode_float(&p[48..53]) } else { 0.0 },
|
|
},
|
|
})
|
|
}
|
|
RSP_SWEEP_END => Some(EisMessage::SweepEnd),
|
|
RSP_CONFIG if data.len() >= 18 => {
|
|
let p = &data[2..];
|
|
Some(EisMessage::Config(EisConfig {
|
|
freq_start: decode_float(&p[0..5]),
|
|
freq_stop: decode_float(&p[5..10]),
|
|
ppd: decode_u16(&p[10..13]),
|
|
rtia: Rtia::from_byte(p[13]).unwrap_or(Rtia::R5K),
|
|
rcal: Rcal::from_byte(p[14]).unwrap_or(Rcal::R3K),
|
|
electrode: Electrode::from_byte(p[15]).unwrap_or(Electrode::FourWire),
|
|
}))
|
|
}
|
|
RSP_LSV_START if data.len() >= 15 => {
|
|
let p = &data[2..];
|
|
let (ts, mid) = if p.len() >= 21 {
|
|
(Some(decode_u32(&p[13..18])), Some(decode_u16(&p[18..21])))
|
|
} else { (None, None) };
|
|
Some(EisMessage::LsvStart {
|
|
num_points: decode_u16(&p[0..3]),
|
|
v_start: decode_float(&p[3..8]),
|
|
v_stop: decode_float(&p[8..13]),
|
|
esp_timestamp: ts, meas_id: mid,
|
|
})
|
|
}
|
|
RSP_LSV_POINT if data.len() >= 15 => {
|
|
let p = &data[2..];
|
|
Some(EisMessage::LsvPoint {
|
|
_index: decode_u16(&p[0..3]),
|
|
point: LsvPoint {
|
|
v_mv: decode_float(&p[3..8]),
|
|
i_ua: decode_float(&p[8..13]),
|
|
},
|
|
})
|
|
}
|
|
RSP_LSV_END => Some(EisMessage::LsvEnd),
|
|
RSP_AMP_START if data.len() >= 7 => {
|
|
let p = &data[2..];
|
|
let (ts, mid) = if p.len() >= 13 {
|
|
(Some(decode_u32(&p[5..10])), Some(decode_u16(&p[10..13])))
|
|
} else { (None, None) };
|
|
Some(EisMessage::AmpStart { v_hold: decode_float(&p[0..5]),
|
|
esp_timestamp: ts, meas_id: mid })
|
|
}
|
|
RSP_AMP_POINT if data.len() >= 15 => {
|
|
let p = &data[2..];
|
|
Some(EisMessage::AmpPoint {
|
|
_index: decode_u16(&p[0..3]),
|
|
point: AmpPoint {
|
|
t_ms: decode_float(&p[3..8]),
|
|
i_ua: decode_float(&p[8..13]),
|
|
},
|
|
})
|
|
}
|
|
RSP_AMP_END => Some(EisMessage::AmpEnd),
|
|
RSP_CL_START if data.len() >= 5 => {
|
|
let p = &data[2..];
|
|
let (ts, mid) = if p.len() >= 11 {
|
|
(Some(decode_u32(&p[3..8])), Some(decode_u16(&p[8..11])))
|
|
} else { (None, None) };
|
|
Some(EisMessage::ClStart { num_points: decode_u16(&p[0..3]),
|
|
esp_timestamp: ts, meas_id: mid })
|
|
}
|
|
RSP_CL_POINT if data.len() >= 16 => {
|
|
let p = &data[2..];
|
|
Some(EisMessage::ClPoint {
|
|
_index: decode_u16(&p[0..3]),
|
|
point: ClPoint {
|
|
t_ms: decode_float(&p[3..8]),
|
|
i_ua: decode_float(&p[8..13]),
|
|
phase: p[13],
|
|
},
|
|
})
|
|
}
|
|
RSP_CL_RESULT if data.len() >= 12 => {
|
|
let p = &data[2..];
|
|
Some(EisMessage::ClResult(ClResult {
|
|
i_free_ua: decode_float(&p[0..5]),
|
|
i_total_ua: decode_float(&p[5..10]),
|
|
}))
|
|
}
|
|
RSP_CL_END => Some(EisMessage::ClEnd),
|
|
RSP_TEMP if data.len() >= 7 => {
|
|
let p = &data[2..];
|
|
Some(EisMessage::Temperature(decode_float(&p[0..5])))
|
|
}
|
|
RSP_PH_RESULT if data.len() >= 17 => {
|
|
let p = &data[2..];
|
|
let (ts, mid) = if p.len() >= 23 {
|
|
(Some(decode_u32(&p[15..20])), Some(decode_u16(&p[20..23])))
|
|
} else { (None, None) };
|
|
Some(EisMessage::PhResult(PhResult {
|
|
v_ocp_mv: decode_float(&p[0..5]),
|
|
ph: decode_float(&p[5..10]),
|
|
temp_c: decode_float(&p[10..15]),
|
|
}, ts, mid))
|
|
}
|
|
RSP_REF_FRAME if data.len() >= 4 => {
|
|
Some(EisMessage::RefFrame { mode: data[2], rtia_idx: data[3] })
|
|
}
|
|
RSP_REF_LP_RANGE if data.len() >= 5 => {
|
|
Some(EisMessage::RefLpRange { mode: data[2], low_idx: data[3], high_idx: data[4] })
|
|
}
|
|
RSP_REFS_DONE => Some(EisMessage::RefsDone),
|
|
RSP_REF_STATUS if data.len() >= 3 => {
|
|
Some(EisMessage::RefStatus { has_refs: data[2] != 0 })
|
|
}
|
|
RSP_CELL_K if data.len() >= 7 => {
|
|
let p = &data[2..];
|
|
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])))
|
|
}
|
|
RSP_PH_CAL if data.len() >= 12 => {
|
|
let p = &data[2..];
|
|
Some(EisMessage::PhCal {
|
|
slope: decode_float(&p[0..5]),
|
|
offset: decode_float(&p[5..10]),
|
|
})
|
|
}
|
|
RSP_KEEPALIVE => Some(EisMessage::Keepalive),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn build_sysex_set_sweep(freq_start: f32, freq_stop: f32, ppd: u16) -> Vec<u8> {
|
|
let mut sx = vec![0xF0, SYSEX_MFR, CMD_SET_SWEEP];
|
|
sx.extend_from_slice(&encode_float(freq_start));
|
|
sx.extend_from_slice(&encode_float(freq_stop));
|
|
sx.extend_from_slice(&encode_u16(ppd));
|
|
sx.push(0xF7);
|
|
sx
|
|
}
|
|
|
|
pub fn build_sysex_set_rtia(rtia: Rtia) -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_SET_RTIA, rtia.as_byte(), 0xF7]
|
|
}
|
|
|
|
pub fn build_sysex_set_rcal(rcal: Rcal) -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_SET_RCAL, rcal.as_byte(), 0xF7]
|
|
}
|
|
|
|
pub fn build_sysex_set_electrode(e: Electrode) -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_SET_ELECTRODE, e.as_byte(), 0xF7]
|
|
}
|
|
|
|
pub fn build_sysex_start_sweep() -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_START_SWEEP, 0xF7]
|
|
}
|
|
|
|
pub fn build_sysex_get_config() -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_GET_CONFIG, 0xF7]
|
|
}
|
|
|
|
pub fn build_sysex_start_lsv(v_start: f32, v_stop: f32, scan_rate: f32, lp_rtia: LpRtia, num_points: u16) -> Vec<u8> {
|
|
let mut sx = vec![0xF0, SYSEX_MFR, CMD_START_LSV];
|
|
sx.extend_from_slice(&encode_float(v_start));
|
|
sx.extend_from_slice(&encode_float(v_stop));
|
|
sx.extend_from_slice(&encode_float(scan_rate));
|
|
sx.push(lp_rtia.as_byte());
|
|
sx.extend_from_slice(&encode_u16(num_points));
|
|
sx.push(0xF7);
|
|
sx
|
|
}
|
|
|
|
pub fn build_sysex_start_amp(v_hold: f32, interval_ms: f32, duration_s: f32, lp_rtia: LpRtia) -> Vec<u8> {
|
|
let mut sx = vec![0xF0, SYSEX_MFR, CMD_START_AMP];
|
|
sx.extend_from_slice(&encode_float(v_hold));
|
|
sx.extend_from_slice(&encode_float(interval_ms));
|
|
sx.extend_from_slice(&encode_float(duration_s));
|
|
sx.push(lp_rtia.as_byte());
|
|
sx.push(0xF7);
|
|
sx
|
|
}
|
|
|
|
pub fn build_sysex_stop_amp() -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_STOP_AMP, 0xF7]
|
|
}
|
|
|
|
pub fn build_sysex_start_cl(
|
|
v_cond: f32, t_cond_ms: f32, v_free: f32, v_total: f32,
|
|
t_dep_ms: f32, t_meas_ms: f32, lp_rtia: LpRtia,
|
|
) -> Vec<u8> {
|
|
let mut sx = vec![0xF0, SYSEX_MFR, CMD_START_CL];
|
|
sx.extend_from_slice(&encode_float(v_cond));
|
|
sx.extend_from_slice(&encode_float(t_cond_ms));
|
|
sx.extend_from_slice(&encode_float(v_free));
|
|
sx.extend_from_slice(&encode_float(v_total));
|
|
sx.extend_from_slice(&encode_float(t_dep_ms));
|
|
sx.extend_from_slice(&encode_float(t_meas_ms));
|
|
sx.push(lp_rtia.as_byte());
|
|
sx.push(0xF7);
|
|
sx
|
|
}
|
|
|
|
pub fn build_sysex_get_temp() -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_GET_TEMP, 0xF7]
|
|
}
|
|
|
|
pub fn build_sysex_start_ph(stabilize_s: f32) -> Vec<u8> {
|
|
let mut sx = vec![0xF0, SYSEX_MFR, CMD_START_PH];
|
|
sx.extend_from_slice(&encode_float(stabilize_s));
|
|
sx.push(0xF7);
|
|
sx
|
|
}
|
|
|
|
pub fn build_sysex_start_clean(v_mv: f32, duration_s: f32) -> Vec<u8> {
|
|
let mut sx = vec![0xF0, SYSEX_MFR, CMD_START_CLEAN];
|
|
sx.extend_from_slice(&encode_float(v_mv));
|
|
sx.extend_from_slice(&encode_float(duration_s));
|
|
sx.push(0xF7);
|
|
sx
|
|
}
|
|
|
|
pub fn build_sysex_start_refs() -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_START_REFS, 0xF7]
|
|
}
|
|
|
|
pub fn build_sysex_get_refs() -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_GET_REFS, 0xF7]
|
|
}
|
|
|
|
pub fn build_sysex_clear_refs() -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_CLEAR_REFS, 0xF7]
|
|
}
|
|
|
|
pub fn build_sysex_set_cell_k(k: f32) -> Vec<u8> {
|
|
let mut sx = vec![0xF0, SYSEX_MFR, CMD_SET_CELL_K];
|
|
sx.extend_from_slice(&encode_float(k));
|
|
sx.push(0xF7);
|
|
sx
|
|
}
|
|
|
|
pub fn build_sysex_get_cell_k() -> Vec<u8> {
|
|
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]
|
|
}
|
|
|
|
pub fn build_sysex_set_ph_cal(slope: f32, offset: f32) -> Vec<u8> {
|
|
let mut sx = vec![0xF0, SYSEX_MFR, CMD_SET_PH_CAL];
|
|
sx.extend_from_slice(&encode_float(slope));
|
|
sx.extend_from_slice(&encode_float(offset));
|
|
sx.push(0xF7);
|
|
sx
|
|
}
|
|
|
|
pub fn build_sysex_get_ph_cal() -> Vec<u8> {
|
|
vec![0xF0, SYSEX_MFR, CMD_GET_PH_CAL, 0xF7]
|
|
}
|