extern crate alloc;
use alloc::vec::Vec;
use crate::constants::*;
use crate::wire::{Packet, wire_encode, wire_decode, make_packet};
use crate::transports::Transport;
#[derive(Debug)]
pub enum DeviceError<E: core::fmt::Debug> {
Transport(E),
Nak { code: u8, name: &'static str, seq: u8 },
Timeout { seq: u8 },
WireError(crate::wire::WireError),
NotConnected,
}
impl<E: core::fmt::Debug> core::fmt::Display for DeviceError<E> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Self::Transport(e) => write!(f, "transport error: {:?}", e),
Self::Nak { code, name, seq } => write!(f, "NAK: {} (0x{:02x}, seq={})", name, code, seq),
Self::Timeout { seq } => write!(f, "timeout: seq={}", seq),
Self::WireError(e) => write!(f, "wire: {}", e),
Self::NotConnected => write!(f, "not connected"),
}
}
}
pub struct Device<T: Transport> {
transport: T,
seq: u8,
}
impl<T: Transport> Device<T> {
pub fn new(transport: T) -> Self {
Self { transport, seq: 0 }
}
pub fn connect(&mut self) -> Result<Vec<u8>, DeviceError<T::Error>> {
self.transport.connect().map_err(DeviceError::Transport)?;
let resp = self.send_command(CMD_HELLO, &[])?;
Ok(resp.payload)
}
pub fn ping(&mut self) -> Result<(), DeviceError<T::Error>> {
self.send_command(CMD_PING, &[])?;
Ok(())
}
pub fn reset(&mut self) -> Result<(), DeviceError<T::Error>> {
self.send_command(CMD_RESET, &[])?;
Ok(())
}
pub fn close(&mut self) -> Result<(), DeviceError<T::Error>> {
self.transport.close().map_err(DeviceError::Transport)
}
pub fn pin_mode(&mut self, pin: u8, mode: u8) -> Result<(), DeviceError<T::Error>> {
self.send_command(CMD_PIN_MODE, &[pin, mode])?;
Ok(())
}
pub fn pin_write(&mut self, pin: u8, value: u8) -> Result<(), DeviceError<T::Error>> {
self.send_command(CMD_PIN_WRITE, &[pin, value])?;
Ok(())
}
pub fn pin_read(&mut self, pin: u8) -> Result<u16, DeviceError<T::Error>> {
let resp = self.send_command(CMD_PIN_READ, &[pin])?;
if resp.payload.len() >= 3 {
Ok(u16::from_le_bytes([resp.payload[1], resp.payload[2]]))
} else {
Ok(0)
}
}
pub fn mod_cmd(&mut self, payload: &[u8]) -> Result<Vec<u8>, DeviceError<T::Error>> {
let resp = self.send_command(CMD_MOD_CMD, payload)?;
Ok(resp.payload)
}
fn send_command(&mut self, cmd_type: u8, payload: &[u8]) -> Result<Packet, DeviceError<T::Error>> {
if !self.transport.connected() {
return Err(DeviceError::NotConnected);
}
let seq = self.seq;
self.seq = self.seq.wrapping_add(1);
let pkt = make_packet(cmd_type, seq, payload);
let encoded = wire_encode(&pkt);
self.transport.send(&encoded).map_err(DeviceError::Transport)?;
let raw = self.transport.recv().map_err(DeviceError::Transport)?;
let resp = wire_decode(&raw).map_err(DeviceError::WireError)?;
if resp.pkt_type == EVT_NAK {
let code = if resp.payload.is_empty() { 0 } else { resp.payload[0] };
return Err(DeviceError::Nak {
code,
name: err_name(code),
seq,
});
}
Ok(resp)
}
}