use std::fmt;
pub const BATTERY_VOLTAGE_MIN_MV: u32 = 3600;
pub const BATTERY_VOLTAGE_MAX_MV: u32 = 4100;
pub const ACCEL_SCALE: f32 = 2.0 / 32768.0;
pub const GYRO_SCALE: f32 = 125.0 / 32768.0;
#[derive(Debug, Clone, PartialEq)]
pub struct FrameReading {
pub timestamp: f64,
pub acc_x: i32,
pub acc_y: i32,
pub acc_z: i32,
pub ang_x: i32,
pub ang_y: i32,
pub ang_z: i32,
pub temperature: f32,
pub ir_left: i32,
pub red_left: i32,
pub amb_left: i32,
pub ir_right: i32,
pub red_right: i32,
pub amb_right: i32,
pub ir_pulse: i32,
pub red_pulse: i32,
pub amb_pulse: i32,
}
impl FrameReading {
pub fn accel_x_g(&self) -> f32 {
self.acc_x as f32 * ACCEL_SCALE
}
pub fn accel_y_g(&self) -> f32 {
self.acc_y as f32 * ACCEL_SCALE
}
pub fn accel_z_g(&self) -> f32 {
self.acc_z as f32 * ACCEL_SCALE
}
pub fn gyro_x_dps(&self) -> f32 {
self.ang_x as f32 * GYRO_SCALE
}
pub fn gyro_y_dps(&self) -> f32 {
self.ang_y as f32 * GYRO_SCALE
}
pub fn gyro_z_dps(&self) -> f32 {
self.ang_z as f32 * GYRO_SCALE
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct BatteryReading {
pub timestamp: f64,
pub voltage_mv: u32,
pub charging: bool,
pub usb_connected: bool,
}
impl BatteryReading {
pub fn voltage(&self) -> f32 {
self.voltage_mv as f32 / 1000.0
}
pub fn percentage(&self) -> u8 {
if self.voltage_mv <= BATTERY_VOLTAGE_MIN_MV {
return 0;
}
if self.voltage_mv >= BATTERY_VOLTAGE_MAX_MV {
return 100;
}
let range = (BATTERY_VOLTAGE_MAX_MV - BATTERY_VOLTAGE_MIN_MV) as f32;
let pct = (self.voltage_mv - BATTERY_VOLTAGE_MIN_MV) as f32 / range * 100.0;
pct.round() as u8
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct CalibrationReading {
pub timestamp: f64,
pub offset_left: f32,
pub offset_right: f32,
pub offset_pulse: f32,
pub auto_calibration: bool,
pub low_power_mode: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DiagnosticsReading {
pub timestamp: f64,
pub adc: Option<BatteryReading>,
pub imu_ok: bool,
pub sensor_ok: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SensorReading {
pub timestamp: f64,
pub address: u32,
pub data: u32,
}
pub const MENDI_FCC_ID: &str = "RYYEYSHJN";
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct DeviceInfo {
pub firmware_version: Option<String>,
pub hardware_version: Option<String>,
pub id: String,
pub name: String,
pub fcc_id: String,
}
impl fmt::Display for DeviceInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} [{}]", self.name, self.id)?;
if let Some(fw) = &self.firmware_version {
write!(f, " fw={fw}")?;
}
if let Some(hw) = &self.hardware_version {
write!(f, " hw={hw}")?;
}
if !self.fcc_id.is_empty() {
write!(f, " fcc={}", self.fcc_id)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum MendiEvent {
Connected(DeviceInfo),
Frame(FrameReading),
Battery(BatteryReading),
Calibration(CalibrationReading),
Diagnostics(DiagnosticsReading),
SensorRead(SensorReading),
Disconnected,
}