use embedded_io::{Error, Read, Write};
use crate::{
base::{communication::TicCommunication, TicBase},
TicCommand, TicHandlerError, TicProduct,
};
pub struct TicSerial<S> {
stream: S,
product: TicProduct,
device_number: u8,
}
impl<S: Write + Read> TicSerial<S> {
pub fn new_default(stream: S, product: TicProduct) -> Self {
Self {
stream,
product,
device_number: 255,
}
}
pub fn new_with_number(stream: S, product: TicProduct, device_number: u8) -> Self {
Self {
stream,
product,
device_number,
}
}
fn send_command_header(&mut self, cmd: TicCommand) -> Result<(), TicHandlerError> {
match self.device_number {
255 => self.stream.write_all(&[cmd as u8])
.map_err(|e| TicHandlerError::StreamError(e.kind()))?,
_ => {
self.stream.write_all(&[0xAA]).map_err(|e| TicHandlerError::StreamError(e.kind()))?;
self.serial_w7(self.device_number)?;
self.serial_w7(cmd as u8)?;
}
}
Ok(())
}
fn serial_w7(&mut self, val: u8) -> Result<(), TicHandlerError> {
self.stream.write_all(&[val & 0x7F])
.map_err(|e| TicHandlerError::StreamError(e.kind()))?;
Ok(())
}
}
impl<S: Write + Read> TicCommunication for TicSerial<S> {
fn command_quick(&mut self, cmd: TicCommand) -> Result<(), TicHandlerError> {
self.send_command_header(cmd)?;
Ok(())
}
fn command_w32(&mut self, cmd: TicCommand, val: u32) -> Result<(), TicHandlerError> {
self.send_command_header(cmd)?;
self.serial_w7(
(((val >> 7) & 1) | ((val >> 14) & 2) | ((val >> 21) & 4) | ((val >> 28) & 8)) as u8,
)?;
self.serial_w7((val) as u8)?; self.serial_w7((val >> 8) as u8)?;
self.serial_w7((val >> 16) as u8)?;
self.serial_w7((val >> 24) as u8)?;
Ok(())
}
fn command_w7(&mut self, cmd: TicCommand, val: u8) -> Result<(), TicHandlerError> {
self.send_command_header(cmd)?;
self.serial_w7(val)?;
Ok(())
}
fn get_segment(
&mut self,
cmd: TicCommand,
offset: u8,
buffer: &mut [u8],
) -> Result<(), TicHandlerError> {
self.send_command_header(cmd)?;
self.serial_w7(offset & 0x7F)?;
self.serial_w7((buffer.len() | offset as usize >> 1 & 0x40) as u8)?;
self.stream
.read_exact(buffer)
.map_err(|_| TicHandlerError::StreamError(embedded_io::ErrorKind::Other))?;
Ok(())
}
}
impl<S: Write + Read> TicBase for TicSerial<S> {
fn product(&self) -> TicProduct {
self.product
}
}
impl From<embedded_io::ErrorKind> for TicHandlerError {
fn from(err: embedded_io::ErrorKind) -> Self {
Self::StreamError(err)
}
}