#![no_std]
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
use embedded_hal_nb::{
nb::block,
serial::{Read as UartRead, Write as UartWrite},
};
use embedded_hal_async::delay::DelayNs as AsyncDelayNs;
use embedded_io_async::Read as AsyncUartRead;
use embedded_io_async::Write as AsyncUartWrite;
pub mod config;
use config::*;
#[derive(Debug)]
pub enum Mcp2003aError<E> {
UartError(embedded_hal_nb::nb::Error<E>),
AsyncUartError(E),
UartWriteNotReady,
SyncByteNotReceivedBack,
IdByteNotReceivedBack,
LinReadDeviceTimeoutNoResponse,
LinReadOnlyPartialResponse(usize),
LinReadNoChecksumReceived,
LinReadInvalidChecksum(u8),
}
pub struct Mcp2003a<UART, GPIO, DELAY> {
uart: UART,
break_pin: GPIO,
delay: DELAY,
config: LinBusConfig,
}
impl<UART, GPIO, DELAY, E> Mcp2003a<UART, GPIO, DELAY>
where
UART: UartRead<Error = E> + UartWrite<Error = E>,
GPIO: OutputPin,
DELAY: DelayNs,
{
pub fn new(uart: UART, break_pin: GPIO, delay: DELAY) -> Self {
Mcp2003a {
uart,
break_pin,
delay,
config: LinBusConfig::default(),
}
}
pub fn init(&mut self, config: LinBusConfig) {
self.config = config;
}
fn send_break(&mut self) {
let bit_period_ns = self.config.speed.get_bit_period_ns();
let break_duration_ns = self.config.break_duration.get_duration_ns(bit_period_ns);
self.break_pin.set_high().unwrap();
self.delay.delay_ns(break_duration_ns);
self.break_pin.set_low().unwrap();
self.delay.delay_ns(bit_period_ns);
}
pub fn send_wakeup(&mut self) {
let wakeup_duration_ns = self.config.wakeup_duration.get_duration_ns();
assert!(
wakeup_duration_ns <= 5_000_000,
"Wakeup duration must be less than 5 milliseconds"
);
self.break_pin.set_high().unwrap();
self.delay.delay_ns(wakeup_duration_ns);
self.break_pin.set_low().unwrap();
self.delay.delay_ns(wakeup_duration_ns);
}
pub fn send_frame(&mut self, id: u8, data: &[u8], checksum: u8) -> Result<[u8; 11], Mcp2003aError<E>> {
assert!(
1 <= data.len() && data.len() <= 8,
"Data length must be between 1 and 8 bytes"
);
let data_len = data.len();
let mut frame = [0; 11];
frame[0] = 0x55;
frame[1] = id;
frame[2..2 + data_len].copy_from_slice(data);
frame[2 + data_len] = checksum;
self.send_break();
for byte in frame.iter() {
match self.uart.write(*byte) {
Ok(_) => (),
Err(e) => return Err(Mcp2003aError::UartError(e)),
}
}
match block!(self.uart.flush()) {
Ok(_) => (),
Err(_) => return Err(Mcp2003aError::UartWriteNotReady),
}
self.delay.delay_ns(self.config.inter_frame_space.get_duration_ns());
Ok(frame)
}
pub fn read_frame(&mut self, id: u8, buffer: &mut [u8]) -> Result<u8, Mcp2003aError<E>> {
self.delay.delay_ns(self.config.inter_frame_space.get_duration_ns());
self.send_break();
let header = [0x55, id];
for byte in header.iter() {
match self.uart.write(*byte) {
Ok(_) => (),
Err(e) => return Err(Mcp2003aError::UartError(e)),
}
}
self.delay
.delay_ns(self.config.read_device_response_timeout.get_duration_ns());
let mut len = 0;
let mut sync_byte_received = false;
let mut id_byte_received = false;
let mut data_bytes_received = 0;
let mut checksum_received = false;
let mut checksum = 0;
loop {
match self.uart.read() {
Ok(byte) => {
if !sync_byte_received {
if byte == 0x55 {
sync_byte_received = true;
}
}
else if !id_byte_received {
if byte == id {
id_byte_received = true;
} else {
sync_byte_received = false;
}
}
else if data_bytes_received < buffer.len() {
buffer[len] = byte;
len += 1;
data_bytes_received += 1;
}
else if !checksum_received {
checksum = byte;
checksum_received = true;
break;
}
}
Err(embedded_hal_nb::nb::Error::WouldBlock) => {
break;
}
Err(e) => return Err(Mcp2003aError::UartError(e)),
}
}
self.delay.delay_ns(self.config.inter_frame_space.get_duration_ns());
if !sync_byte_received {
return Err(Mcp2003aError::SyncByteNotReceivedBack);
}
if !id_byte_received {
return Err(Mcp2003aError::IdByteNotReceivedBack);
}
if data_bytes_received == 0 {
return Err(Mcp2003aError::LinReadDeviceTimeoutNoResponse);
}
if data_bytes_received < buffer.len() {
return Err(Mcp2003aError::LinReadOnlyPartialResponse(data_bytes_received));
}
if !checksum_received {
return Err(Mcp2003aError::LinReadNoChecksumReceived);
}
Ok(checksum)
}
}
impl<UART, GPIO, DELAY, E> Mcp2003a<UART, GPIO, DELAY>
where
UART: AsyncUartRead<Error = E> + AsyncUartWrite<Error = E>,
GPIO: OutputPin,
DELAY: AsyncDelayNs,
{
async fn send_break_async(&mut self) {
let bit_period_ns = self.config.speed.get_bit_period_ns();
let break_duration_ns = self.config.break_duration.get_duration_ns(bit_period_ns);
self.break_pin.set_high().unwrap();
self.delay.delay_ns(break_duration_ns).await;
self.break_pin.set_low().unwrap();
self.delay.delay_ns(bit_period_ns).await;
}
pub async fn send_wakeup_async(&mut self) {
let wakeup_duration_ns = self.config.wakeup_duration.get_duration_ns();
assert!(
wakeup_duration_ns <= 5_000_000,
"Wakeup duration must be less than 5 milliseconds"
);
self.break_pin.set_high().unwrap();
self.delay.delay_ns(wakeup_duration_ns).await;
self.break_pin.set_low().unwrap();
self.delay.delay_ns(wakeup_duration_ns).await;
}
pub async fn send_frame_async(&mut self, id: u8, data: &[u8], checksum: u8) -> Result<[u8; 11], Mcp2003aError<E>> {
assert!(
1 <= data.len() && data.len() <= 8,
"Data length must be between 1 and 8 bytes"
);
let data_len = data.len();
let mut frame = [0; 11];
frame[0] = 0x55;
frame[1] = id;
frame[2..2 + data_len].copy_from_slice(data);
frame[2 + data_len] = checksum;
self.send_break_async().await;
match self.uart.write(&frame).await {
Ok(_) => (),
Err(e) => return Err(Mcp2003aError::AsyncUartError(e)),
}
self.delay
.delay_ns(self.config.inter_frame_space.get_duration_ns())
.await;
Ok(frame)
}
pub async fn read_frame_async(&mut self, id: u8, buffer: &mut [u8]) -> Result<u8, Mcp2003aError<E>> {
self.delay
.delay_ns(self.config.inter_frame_space.get_duration_ns())
.await;
self.send_break_async().await;
let header = [0x55, id];
match self.uart.write(&header).await {
Ok(_) => (),
Err(e) => return Err(Mcp2003aError::AsyncUartError(e)),
}
self.delay
.delay_ns(self.config.read_device_response_timeout.get_duration_ns())
.await;
let mut len = 0;
let mut sync_byte_received = false;
let mut id_byte_received = false;
let mut data_bytes_received = 0;
let mut checksum_received = false;
let checksum;
loop {
match self.uart.read(buffer).await {
Ok(len_read) => {
if !sync_byte_received {
if buffer[0] == 0x55 {
sync_byte_received = true;
}
}
else if !id_byte_received {
if buffer[1] == id {
id_byte_received = true;
} else {
sync_byte_received = false;
}
}
else if data_bytes_received < buffer.len() {
len += len_read;
data_bytes_received += len_read;
}
else if !checksum_received {
checksum = buffer[len - 1];
checksum_received = true;
break;
}
}
Err(e) => return Err(Mcp2003aError::AsyncUartError(e)),
}
}
self.delay
.delay_ns(self.config.inter_frame_space.get_duration_ns())
.await;
if !sync_byte_received {
return Err(Mcp2003aError::SyncByteNotReceivedBack);
}
if !id_byte_received {
return Err(Mcp2003aError::IdByteNotReceivedBack);
}
if data_bytes_received == 0 {
return Err(Mcp2003aError::LinReadDeviceTimeoutNoResponse);
}
if data_bytes_received < buffer.len() {
return Err(Mcp2003aError::LinReadOnlyPartialResponse(data_bytes_received));
}
if !checksum_received {
return Err(Mcp2003aError::LinReadNoChecksumReceived);
}
Ok(checksum)
}
}