use crate::std;
use std::fmt;
use crate::{crc::crc16, len::METADATA, Error, MessageType, ResponseStatus, Result, SequenceId};
mod variant;
pub use variant::*;
pub const STX: u8 = 0x7f;
pub const STEX: u8 = 0x7f;
pub const STEXN: u8 = 0x7e;
pub mod index {
pub const STX: usize = 0;
pub const SEQ_ID: usize = 1;
pub const LEN: usize = 2;
pub const DATA: usize = 3;
pub const ENCRYPTED_DATA: usize = 5;
pub const COMMAND: usize = 3;
pub const ENCRYPTED_COMMAND: usize = 5;
pub const RESPONSE_STATUS: usize = 3;
pub const ENCRYPTED_RESPONSE_STATUS: usize = 5;
}
pub trait MessageOps {
fn buf(&self) -> &[u8];
fn buf_mut(&mut self) -> &mut [u8];
fn message_type(&self) -> MessageType;
fn is_command(&self) -> bool;
fn is_response(&self) -> bool {
!self.is_command()
}
fn is_variable(&self) -> bool {
false
}
fn len(&self) -> usize {
self.metadata_len() + self.data_len()
}
fn metadata_len(&self) -> usize {
super::len::METADATA
}
fn data_len(&self) -> usize;
fn set_data_len(&mut self, len: u8);
fn is_empty(&self) -> bool {
self.data_len() == 0
}
fn init(&mut self);
fn stx(&self) -> u8 {
self.buf()[index::STX]
}
fn length(&self) -> u8 {
self.buf()[index::LEN]
}
fn sequence_id(&self) -> SequenceId {
let buf = self.buf();
buf[index::SEQ_ID].into()
}
fn set_sequence_id(&mut self, id: SequenceId) {
let buf = self.buf_mut();
buf[index::SEQ_ID] = id.into();
}
fn toggle_sequence_id(&mut self) {
self.set_sequence_id(!self.sequence_id());
}
fn data(&self) -> &[u8] {
let start = index::DATA;
let end = start + self.data_len();
self.buf()[start..end].as_ref()
}
fn data_mut(&mut self) -> &mut [u8] {
let start = index::DATA;
let end = start + self.data_len();
self.buf_mut()[start..end].as_mut()
}
fn set_data(&mut self, data: &[u8]) -> Result<()> {
let len = data.len();
let max_len = self.buf().len() - self.metadata_len();
if self.is_variable() {
if !(1..=max_len).contains(&len) {
return Err(Error::InvalidDataLength((len, max_len)));
}
self.set_data_len(len as u8);
} else if len != self.data_len() {
return Err(Error::InvalidDataLength((len, self.data_len())));
}
self.data_mut().copy_from_slice(data);
Ok(())
}
fn toggle_sequence_flag(&mut self) {
let mut seq_id = SequenceId::from(self.buf()[index::SEQ_ID]);
seq_id.toggle_flag();
self.buf_mut()[index::SEQ_ID] = seq_id.into();
}
fn checksum(&self) -> u16 {
let buf = self.buf();
let len = self.len();
u16::from_le_bytes([buf[len - 2], buf[len - 1]])
}
fn calculate_checksum(&mut self) -> u16 {
let len = self.len();
let buf = self.buf_mut();
let crc = crc16(buf[index::SEQ_ID..len - 2].as_ref());
buf[len - 2..len].copy_from_slice(crc.to_le_bytes().as_ref());
crc
}
fn verify_checksum(&self) -> Result<()> {
let buf = self.buf();
let len = self.len();
let crc = self.checksum();
let exp_crc = crc16(buf[index::SEQ_ID..len - 2].as_ref());
if crc == exp_crc {
Ok(())
} else {
Err(Error::Crc((crc, exp_crc)))
}
}
fn as_bytes(&mut self) -> &[u8] {
self.calculate_checksum();
self.buf()
}
fn as_bytes_mut(&mut self) -> &mut [u8] {
self.calculate_checksum();
self.buf_mut()
}
#[allow(clippy::wrong_self_convention)]
fn from_buf(&mut self, buf: &[u8]) -> Result<()> {
let len = self.len();
let mut buf_len = buf.len();
let is_variable = self.is_variable();
if !is_variable && buf_len < len {
return Err(Error::InvalidLength((buf_len, len)));
}
let stx = buf[index::STX];
if stx != STX {
return Err(Error::InvalidSTX(stx));
}
let buf_data_len = buf[index::LEN] as usize;
if !is_variable {
let data_len = self.data_len();
if buf_data_len != data_len {
return Err(Error::InvalidDataLength((buf_data_len, data_len)));
}
}
let msg_type = self.message_type();
if self.is_command() && !self.is_response() {
let raw_type = buf[index::COMMAND];
let buf_msg_type = MessageType::from(raw_type);
if buf_msg_type != msg_type {
return Err(Error::InvalidMessageRaw((buf_msg_type, raw_type)));
}
}
buf_len = std::cmp::min(buf_len, buf_data_len + METADATA);
let buf_crc = u16::from_le_bytes(buf[buf_len - 2..].try_into().unwrap());
let exp_crc = crc16(buf[index::SEQ_ID..buf_len - 2].as_ref());
if buf_crc != exp_crc && msg_type != MessageType::Encrypted {
return Err(Error::Crc((buf_crc, exp_crc)));
}
self.buf_mut()[..buf_len].copy_from_slice(buf[..buf_len].as_ref());
Ok(())
}
}
impl fmt::Display for &dyn MessageOps {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"STX: 0x{:02x} SEQID: {} Data: {:x?} CRC-16: 0x{:04x}",
self.stx(),
self.sequence_id(),
self.data(),
self.checksum(),
)
}
}
pub trait CommandOps: MessageOps {
fn command(&self) -> MessageType {
let data = self.data();
if data.is_empty() {
MessageType::default()
} else {
data[0].into()
}
}
fn set_command(&mut self, command: MessageType) {
let data = self.data_mut();
if !data.is_empty() {
data[0] = command.into();
}
}
}
impl fmt::Display for &dyn CommandOps {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let stx = self.stx();
let seqid = self.sequence_id();
let len = self.data_len();
let command = self.command();
let crc = self.checksum();
write!(f, "STX: 0x{stx:02x} | SEQID: {seqid} | LEN: 0x{len:02x} | Command: {command} | CRC-16: 0x{crc:04x}")
}
}
pub trait ResponseOps: MessageOps {
fn response_status(&self) -> ResponseStatus {
let data = self.data();
if data.is_empty() {
ResponseStatus::default()
} else {
data[0].into()
}
}
fn set_response_status(&mut self, status: ResponseStatus) {
self.buf_mut()[index::RESPONSE_STATUS] = status.into();
}
}
impl fmt::Display for &dyn ResponseOps {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let stx = self.stx();
let seqid = self.sequence_id();
let len = self.data_len();
let status = self.response_status();
let crc = self.checksum();
write!(f, "STX: 0x{stx:02x} | SEQID: {seqid} | LEN: 0x{len:02x} | Response status: {status} | CRC-16: 0x{crc:04x}")
}
}