#[cfg(not(feature = "std"))]
use crate::consts::{ASK_MAX_BUF_LEN_USIZE, ASK_MAX_MESSAGE_LEN_USIZE};
use crate::consts::{ASK_HEADER_LEN, ASK_MAX_MESSAGE_LEN, ASK_PREAMBLE_LEN, BROADCAST_ADDRESS};
use crate::crc::crc_ccitt_update;
use crate::encoding::{SYMBOLS, encode_4b6b};
use crate::pll::SoftwarePLL;
use embedded_hal::digital::{InputPin, OutputPin};
use nb::block;
use core::convert::Infallible;
#[cfg(not(feature = "std"))]
use heapless::Vec;
#[cfg(feature = "std")]
use std::vec::Vec;
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug)]
pub enum AskMode {
Sleep,
#[default]
Idle,
Tx,
Rx,
Cad,
}
#[derive(Debug)]
pub struct AskDriver<TX, RX, PTT>
where
TX: OutputPin,
RX: InputPin,
PTT: OutputPin,
{
pub mode: AskMode,
pub tx: TX,
pub rx: RX,
pub ptt: Option<PTT>,
pub pll: SoftwarePLL,
ticks_per_bit: u8,
tick_counter: u8,
#[cfg(feature = "std")]
pub tx_buf: Vec<u8>,
#[cfg(not(feature = "std"))]
pub tx_buf: Vec<u8, ASK_MAX_BUF_LEN_USIZE>,
this_address: u8,
promiscuous: bool,
pub tx_header_to: u8,
pub tx_header_from: u8,
pub tx_header_id: u8,
pub tx_header_flags: u8,
pub rx_header_to: u8,
pub rx_header_from: u8,
pub rx_header_id: u8,
pub rx_header_flags: u8,
ptt_inverted: bool,
pub(crate) tx_index: u8,
pub(crate) tx_bit: u8,
tx_sample: u8,
tx_buf_len: u8,
pub tx_good: u16,
pub rx_bad: u16,
pub rx_good: u16,
rx_buf_valid: bool,
}
impl<TX, RX, PTT> AskDriver<TX, RX, PTT>
where
TX: OutputPin,
RX: InputPin,
PTT: OutputPin,
{
const PREAMBLE: [u8; ASK_PREAMBLE_LEN as usize] =
[0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x38, 0x2c];
pub fn new(
tx: TX,
rx: RX,
ptt: Option<PTT>,
ticks_per_bit: u8,
ptt_inverted: Option<bool>,
rx_inverted: Option<bool>,
) -> Self {
let ptt_invert = match ptt_inverted {
Some(ptt) => ptt,
None => false,
};
#[allow(unused_mut)]
let mut tx = tx;
let _ = tx.set_low(); let mut tx_buf = Vec::new();
let _ = tx_buf.extend_from_slice(&Self::PREAMBLE);
let rx_invert = match rx_inverted {
Some(rxi) => rxi,
None => false,
};
let mut cls = Self {
mode: AskMode::Idle,
tx,
rx,
pll: SoftwarePLL::new(ticks_per_bit, rx_invert),
ticks_per_bit,
tick_counter: 0,
tx_buf,
tx_header_to: BROADCAST_ADDRESS,
tx_header_from: BROADCAST_ADDRESS,
tx_header_id: 0,
tx_header_flags: 0,
rx_header_to: 0,
rx_header_from: 0,
rx_header_id: 0,
rx_header_flags: 0,
this_address: BROADCAST_ADDRESS,
promiscuous: false,
tx_good: 0,
ptt,
ptt_inverted: ptt_invert,
tx_index: 0,
tx_bit: 0,
tx_sample: 0,
tx_buf_len: 0,
rx_good: 0,
rx_bad: 0,
rx_buf_valid: false,
};
cls.set_mode_idle();
cls
}
pub fn set_address(&mut self, addr: u8) {
self.this_address = addr;
}
fn write_tx(&mut self, mode: bool) {
if mode {
self.tx.set_high().unwrap();
} else {
self.tx.set_low().unwrap();
}
}
fn write_ptt(&mut self, mode: bool) {
let state = if self.ptt_inverted { !mode } else { mode };
if let Some(ref mut ptt) = self.ptt {
if state {
let _ = ptt.set_high();
} else {
let _ = ptt.set_low();
}
}
}
pub fn set_mode_idle(&mut self) {
if self.mode != AskMode::Idle {
self.write_ptt(false);
self.write_tx(false);
self.mode = AskMode::Idle;
}
}
pub fn set_mode_rx(&mut self) {
if self.mode != AskMode::Rx {
self.write_ptt(false);
self.write_tx(false);
self.mode = AskMode::Rx;
}
}
pub fn set_mode_tx(&mut self) {
if self.mode != AskMode::Tx {
self.tx_index = 0;
self.tx_bit = 0;
self.tx_sample = 0;
self.write_ptt(true);
self.mode = AskMode::Tx;
}
}
pub fn availabile(&mut self) -> bool {
if self.mode == AskMode::Tx {
return false;
}
self.set_mode_rx();
if self.pll.full {
self.validate_rx_buf();
self.pll.full = false;
}
return self.rx_buf_valid;
}
pub fn validate_rx_buf(&mut self) {
let mut crc: u16 = 0xffff;
for b in &self.pll.buf {
crc = crc_ccitt_update(crc, b);
}
if crc != 0xf0b8 {
self.rx_bad += 1;
self.rx_buf_valid = false;
return;
}
self.rx_header_to = self.pll.buf[1];
self.rx_header_from = self.pll.buf[2];
self.rx_header_id = self.pll.buf[3];
self.rx_header_flags = self.pll.buf[4];
if self.promiscuous
|| self.rx_header_to == self.this_address
|| self.rx_header_to == BROADCAST_ADDRESS
{
self.rx_good += 1;
self.rx_buf_valid = true;
}
}
#[cfg(not(feature = "std"))]
pub fn receive(&mut self) -> Option<Vec<u8, ASK_MAX_MESSAGE_LEN_USIZE>> {
if !self.availabile() {
return None;
}
let message_len: u8 = self.pll.buf_len - 2;
self.rx_buf_valid = false;
let message =
Vec::from_slice(&self.pll.buf[((ASK_HEADER_LEN + 1) as usize)..(message_len as usize)])
.unwrap();
Some(message)
}
#[cfg(feature = "std")]
pub fn receive(&mut self) -> Option<Vec<u8>> {
if !self.availabile() {
return None;
}
let message_len: u8 = self.pll.buf_len - 2;
self.rx_buf_valid = false;
let message =
Vec::from(&self.pll.buf[(ASK_HEADER_LEN + 1) as usize..(message_len as usize)]);
Some(message)
}
pub fn tick(&mut self) {
if self.mode == AskMode::Rx {
self.pll.update(&mut self.rx);
if self.pll.full && !self.pll.active {
self.validate_rx_buf();
}
} else if self.mode == AskMode::Tx {
self.tick_counter += 1;
if self.tick_counter >= self.ticks_per_bit {
self.tick_counter = 0;
self.transmit_bit(); }
}
}
fn wait_packet_sent(&self) -> nb::Result<(), Infallible> {
if self.mode == AskMode::Tx {
Err(nb::Error::WouldBlock)
} else {
Ok(())
}
}
#[cfg(feature = "std")]
pub fn send(&mut self, bytes: Vec<u8>) -> bool {
let mut crc: u16 = 0xffff;
let count: u8 = bytes.len() as u8 + 3 + ASK_HEADER_LEN;
if bytes.len() as u8 > ASK_MAX_MESSAGE_LEN {
return false;
}
let _ = block!(self.wait_packet_sent());
crc = crc_ccitt_update(crc, &count);
let _ = self.tx_buf.extend(encode_4b6b(count));
crc = crc_ccitt_update(crc, &self.tx_header_to);
let _ = self.tx_buf.extend(encode_4b6b(self.tx_header_to));
crc = crc_ccitt_update(crc, &self.tx_header_from);
let _ = self.tx_buf.extend(encode_4b6b(self.tx_header_from));
crc = crc_ccitt_update(crc, &self.tx_header_id);
let _ = self.tx_buf.extend(encode_4b6b(self.tx_header_id));
crc = crc_ccitt_update(crc, &self.tx_header_flags);
let _ = self.tx_buf.extend(encode_4b6b(self.tx_header_flags));
for b in bytes {
crc = crc_ccitt_update(crc, &b);
let _ = self.tx_buf.extend(encode_4b6b(b));
}
crc = !crc;
let _ = self.tx_buf.push(SYMBOLS[((crc >> 4) & 0xf) as usize]);
let _ = self.tx_buf.push(SYMBOLS[(crc & 0xf) as usize]);
let _ = self.tx_buf.push(SYMBOLS[((crc >> 12) & 0xf) as usize]);
let _ = self.tx_buf.push(SYMBOLS[((crc >> 8) & 0xf) as usize]);
self.tx_buf_len = self.tx_buf.len() as u8;
self.set_mode_tx();
return true;
}
#[cfg(not(feature = "std"))]
pub fn send(&mut self, bytes: Vec<u8, ASK_MAX_MESSAGE_LEN_USIZE>) -> bool {
let mut crc: u16 = 0xffff;
let count: u8 = bytes.len() as u8 + 3 + ASK_HEADER_LEN;
if bytes.len() as u8 > ASK_MAX_MESSAGE_LEN {
return false;
}
let _ = block!(self.wait_packet_sent());
crc = crc_ccitt_update(crc, &count);
let _ = self.tx_buf.extend(encode_4b6b(count));
crc = crc_ccitt_update(crc, &self.tx_header_to);
let _ = self.tx_buf.extend(encode_4b6b(self.tx_header_to));
crc = crc_ccitt_update(crc, &self.tx_header_from);
let _ = self.tx_buf.extend(encode_4b6b(self.tx_header_from));
crc = crc_ccitt_update(crc, &self.tx_header_id);
let _ = self.tx_buf.extend(encode_4b6b(self.tx_header_id));
crc = crc_ccitt_update(crc, &self.tx_header_flags);
let _ = self.tx_buf.extend(encode_4b6b(self.tx_header_flags));
for b in bytes {
crc = crc_ccitt_update(crc, &b);
let _ = self.tx_buf.extend(encode_4b6b(b));
}
crc = !crc;
let _ = self.tx_buf.push(SYMBOLS[((crc >> 4) & 0xf) as usize]);
let _ = self.tx_buf.push(SYMBOLS[(crc & 0xf) as usize]);
let _ = self.tx_buf.push(SYMBOLS[((crc >> 12) & 0xf) as usize]);
let _ = self.tx_buf.push(SYMBOLS[((crc >> 8) & 0xf) as usize]);
self.tx_buf_len = self.tx_buf.len() as u8;
self.set_mode_tx();
return true;
}
fn transmit_bit(&mut self) {
if self.tx_index >= self.tx_buf_len {
self.tx_good += 1;
self.set_mode_idle();
} else {
let bit = self.tx_buf[self.tx_index as usize] & (1 << self.tx_bit);
self.tx_bit += 1;
self.write_tx(bit != 0);
if self.tx_bit >= 6 {
self.tx_bit = 0;
self.tx_index += 1;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use embedded_hal_mock::eh1::digital::{
Mock as PinMock, State as PinState, Transaction as PinTransaction,
};
#[test]
fn test_driver_initialization() {
let tx = PinMock::new(&[PinTransaction::set(PinState::Low)]);
let rx = PinMock::new(&[]);
let ptt = PinMock::new(&[]);
let mut driver = AskDriver::new(tx, rx, Some(ptt), 8, Some(false), Some(false));
assert_eq!(driver.mode, AskMode::Idle);
driver.tx.done();
driver.rx.done();
let _ = driver.ptt.as_mut().map(|ptt| ptt.done());
}
#[test]
fn test_set_address() {
let tx = PinMock::new(&[PinTransaction::set(PinState::Low)]);
let rx = PinMock::new(&[]);
let ptt = PinMock::new(&[]);
let mut driver = AskDriver::new(tx, rx, Some(ptt), 8, Some(false), Some(false));
driver.set_address(0x42);
assert_eq!(driver.this_address, 0x42);
driver.tx.done();
driver.rx.done();
let _ = driver.ptt.as_mut().map(|ptt| ptt.done());
}
#[test]
fn test_send_message_starts_transmission() {
#[cfg(not(feature = "std"))]
use heapless::Vec;
#[cfg(feature = "std")]
use std::vec::Vec;
let tx = PinMock::new(&[PinTransaction::set(PinState::Low)]);
let rx = PinMock::new(&[]);
let ptt = PinMock::new(&[PinTransaction::set(PinState::High)]);
let mut driver = AskDriver::new(tx, rx, Some(ptt), 8, Some(false), Some(false));
let mut message = Vec::new();
#[cfg(feature = "std")]
message.extend_from_slice(b"Hi");
#[cfg(not(feature = "std"))]
let _ = message.extend_from_slice(b"Hi");
assert!(driver.send(message));
assert_eq!(driver.mode, AskMode::Tx);
assert_eq!(driver.tx_buf.len(), 26); driver.tx.done();
driver.rx.done();
let _ = driver.ptt.as_mut().map(|ptt| ptt.done());
}
#[cfg(feature = "std")]
#[test]
fn test_tick_transmit_advances_tx_state() {
let tx_states = vec![
0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1,
0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0,
1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0,
1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0,
0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0,
];
let tx = PinMock::new(
&tx_states
.iter()
.map(|&s| {
PinTransaction::set(if s == 0 {
PinState::Low
} else {
PinState::High
})
})
.collect::<Vec<_>>(),
);
let rx = PinMock::new(&[]);
let ptt = PinMock::new(&[
PinTransaction::set(PinState::High),
PinTransaction::set(PinState::Low),
]);
let mut driver = AskDriver::new(tx, rx, Some(ptt), 2, Some(false), Some(false));
let mut message: Vec<u8> = Vec::new();
message.extend_from_slice(b"AB");
assert!(driver.send(message));
assert_eq!(
driver.tx_buf,
vec![
42, 42, 42, 42, 42, 42, 56, 44, 13, 37, 52, 52, 52, 52, 13, 13, 13, 13, 22, 14, 22,
19, 37, 14, 52, 41
]
);
assert!(driver.mode == AskMode::Tx);
for _ in 0..(tx_states.len() * 3) {
driver.tick();
}
assert_eq!(driver.tx_buf_len, 26);
assert_eq!(driver.tx_good, 1);
assert_eq!(driver.tx_index, 26);
driver.tx.done();
driver.rx.done();
let _ = driver.ptt.as_mut().map(|ptt| ptt.done());
}
#[test]
fn test_receive_no_data_returns_none() {
let tx = PinMock::new(&[
PinTransaction::set(PinState::Low),
PinTransaction::set(PinState::Low),
]);
let rx = PinMock::new(&[]);
let ptt = PinMock::new(&[PinTransaction::set(PinState::Low)]);
let mut driver = AskDriver::new(tx, rx, Some(ptt), 8, Some(false), Some(false));
assert!(!driver.availabile());
assert!(driver.receive().is_none());
driver.tx.done();
driver.rx.done();
let _ = driver.ptt.as_mut().map(|ptt| ptt.done());
}
}