#![no_std] use core::marker::PhantomData; use arduino_hal::{ delay_us, port::{ mode::{Input, PullUp}, Pin, PinOps, }, }; use avr_device::asm::delay_cycles; use static_pins::StaticPinOps; mod structures; pub type PollResult = Result<(), PollError>; pub type ReadByteResult = Result; pub type CorruptedData = (u8, u8); const SERIAL_DELAY: u32 = 4; const FIRST_HALF_SERIAL_DELAY: u32 = SERIAL_DELAY / 2; const SECOND_HALF_SERIAL_DELAY: u32 = SERIAL_DELAY - FIRST_HALF_SERIAL_DELAY; const READING_ADJUST: u32 = 16; const FIRST_ENTRY_READING: u32 = 30; const MSB: u16 = 0x0200; #[inline(always)] fn crc_calculate(value: u8) -> u8 { ((value >> 6) | (value >> 4) | (value >> 2) | value) & 0x0F } pub enum PollError { NotFound, NotReady, } pub struct HalfDuplexSerial

{ _pin: PhantomData, P>>, } impl

HalfDuplexSerial

where P: PinOps + StaticPinOps, { #[inline] pub fn new(_pin: Pin, P>) -> Self { Self { _pin: PhantomData {}, } } pub fn poll(&self) -> PollResult { P::into_output(); delay_cycles(4); P::into_pull_up_input(); delay_us(SERIAL_DELAY); if P::is_low() { return PollResult::Err(PollError::NotFound); } delay_us(SERIAL_DELAY); if P::is_high() { return PollResult::Err(PollError::NotReady); } while P::is_low() {} PollResult::Ok(()) } pub fn response(&self) { P::into_output_high(); delay_us(FIRST_HALF_SERIAL_DELAY); P::set_low(); delay_us(SERIAL_DELAY); P::into_pull_up_input(); } #[inline(never)] pub fn sync_transmitter(&self) { P::into_output(); delay_us(SERIAL_DELAY); P::set_high(); } #[inline(never)] pub fn sync_reciever(&self) { while P::is_high() {} while P::is_low() {} } #[inline] pub fn reset(&self) { P::into_pull_up_input(); } } pub trait SoftSerialWriter: SoftSerialByteWriter

where P: PinOps + StaticPinOps, { fn write_bytes(&self, transmit_data: T); } pub trait SoftSerialReader: SoftSerialByteReader

where P: PinOps + StaticPinOps, { fn read_bytes(&self, recieve_data: T); } pub trait SoftSerialByteWriter

where P: PinOps + StaticPinOps, { #[inline(never)] fn write_byte(&self, transmit_data: u8) { let mut data = ((transmit_data as u16) << 4) | (crc_calculate(transmit_data) as u16); for _ in 0..(u8::BITS + 4) { if data & MSB == 0 { P::set_high(); } else { P::set_low(); } delay_us(SERIAL_DELAY); data <<= 1; } } } pub trait SoftSerialByteReader

where P: PinOps + StaticPinOps, { #[inline(never)] fn read_byte(&self) -> ReadByteResult { let mut packet = 0u16; delay_cycles(FIRST_ENTRY_READING); for _ in 0..(u8::BITS + 4) { delay_us(FIRST_HALF_SERIAL_DELAY); packet <<= 1; if P::is_low() { packet |= 1; } else { packet |= 0; } delay_cycles(READING_ADJUST); delay_us(SECOND_HALF_SERIAL_DELAY); } let received_crc = (packet & 0x000F) as u8; let data = packet.overflowing_shr(4).0 as u8; let calculated_crc = crc_calculate(data); if received_crc != calculated_crc { return Err((received_crc, calculated_crc)); } Ok(data) } } impl SoftSerialByteWriter

for HalfDuplexSerial

{} impl SoftSerialByteReader

for HalfDuplexSerial

{} impl

SoftSerialWriter for HalfDuplexSerial

where P: PinOps + StaticPinOps, { fn write_bytes(&self, transmit_data: &[u8]) { for byte in transmit_data { self.write_byte(*byte); self.sync_transmitter(); } } } impl

SoftSerialReader for HalfDuplexSerial

where P: PinOps + StaticPinOps, { fn read_bytes(&self, recieve_data: &mut [u8]) { for byte in recieve_data { if let Ok(data) = self.read_byte() { *byte = data; } self.sync_reciever(); } } }