pub const INVALID_DIST_TEMP: u16 = 0xFFFF;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Command {
Temperature = 0x11,
Distance = 0x22,
EepromRead = 0x33,
EepromWrite = 0x44,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum EepromRegister {
LargerDist = 0x00,
LessDist = 0x01,
MeasureMode = 0x02,
SerialLevelMode = 0x03,
AutoMeasureTime = 0x04,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum MeasureMode {
Auto = 0xAA,
Passive = 0xBB,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum SerialLevelMode {
Ttl = 0x00,
Rs232 = 0x01,
}
#[inline]
pub fn encode_threshold(distance_cm: u16) -> (u8, u8) {
((distance_cm >> 8) as u8, (distance_cm & 0xFF) as u8)
}
#[inline]
pub fn decode_threshold(high: u8, low: u8) -> u16 {
u16::from_be_bytes([high, low])
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Frame([u8; 4]);
impl Frame {
const INDEX_CMD: usize = 0;
const INDEX_DATA0: usize = 1;
const INDEX_DATA1: usize = 2;
const INDEX_CHECKSUM: usize = 3;
#[inline]
pub fn checksum(cmd: u8, data0: u8, data1: u8) -> u8 {
cmd.wrapping_add(data0).wrapping_add(data1)
}
#[inline]
pub fn build(cmd: Command, data0: u8, data1: u8) -> Self {
let cmd_byte = cmd as u8;
let sum = Self::checksum(cmd_byte, data0, data1);
Self([cmd_byte, data0, data1, sum])
}
#[inline]
pub fn distance_request() -> Self {
Self::build(Command::Distance, 0x00, 0x00)
}
#[inline]
pub fn temperature_request() -> Self {
Self::build(Command::Temperature, 0x00, 0x00)
}
#[inline]
pub fn eeprom_read_request(register: EepromRegister) -> Self {
Self::build(Command::EepromRead, register as u8, 0x00)
}
#[inline]
pub fn eeprom_write_request(register: EepromRegister, value: u8) -> Self {
Self::build(Command::EepromWrite, register as u8, value)
}
#[inline]
pub fn parse(raw: [u8; 4]) -> Result<Self, (u8, u8)> {
let expected = Self::checksum(raw[Self::INDEX_CMD], raw[Self::INDEX_DATA0], raw[Self::INDEX_DATA1]);
let got = raw[Self::INDEX_CHECKSUM];
if expected == got {
Ok(Self(raw))
} else {
Err((expected, got))
}
}
#[inline]
pub fn decode_distance(&self) -> Option<u16> {
let raw = u16::from_be_bytes([self.0[Self::INDEX_DATA0], self.0[Self::INDEX_DATA1]]);
if raw == INVALID_DIST_TEMP {
None
} else {
Some(raw)
}
}
#[inline]
pub fn decode_temperature(&self) -> Option<f32> {
let is_negative = (self.0[Self::INDEX_DATA0] & 0xF0) != 0;
let raw = u16::from_be_bytes([self.0[Self::INDEX_DATA0] & 0x0F, self.0[Self::INDEX_DATA1]]);
if raw == INVALID_DIST_TEMP {
None
} else {
let value = raw as i16;
if is_negative {
Some(-value as f32 / 10.0)
} else {
Some(value as f32 / 10.0)
}
}
}
#[inline]
pub fn raw_data(&self) -> &[u8; 4] {
&self.0
}
}