use futures::{SinkExt, StreamExt};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_util::codec::Framed;
pub mod codec;
pub use codec::{TashTalkCodec, TashTalkCommand, TashTalkError};
pub mod crc;
pub use crc::{lt_crc, CrcCalculator};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct TashTalkFeatures {
crc_calculation: bool,
crc_checking: bool,
}
impl TashTalkFeatures {
pub fn new() -> Self {
Self::default()
}
pub fn with_crc_calculation(mut self) -> Self {
self.crc_calculation = true;
self
}
pub fn with_crc_checking(mut self) -> Self {
self.crc_checking = true;
self
}
pub fn with_crc(self) -> Self {
self.with_crc_calculation().with_crc_checking()
}
}
impl From<TashTalkFeatures> for u8 {
fn from(features: TashTalkFeatures) -> u8 {
let mut val = 0;
if features.crc_calculation {
val |= 0x80;
}
if features.crc_checking {
val |= 0x40;
}
val
}
}
pub struct TashTalk<T> {
framed: Framed<T, TashTalkCodec>,
}
impl<T: AsyncRead + AsyncWrite + Unpin> TashTalk<T> {
pub fn new(io: T) -> Self {
Self {
framed: Framed::new(io, TashTalkCodec),
}
}
pub async fn send_frame(&mut self, frame: &[u8]) -> Result<(), std::io::Error> {
tracing::info!("sending frame of len: {}", frame.len());
self.framed
.send(TashTalkCommand::TransmitFrame(frame.to_vec()))
.await
}
pub async fn reset(&mut self) -> Result<(), std::io::Error> {
for _ in 0..1024 {
self.framed.send(TashTalkCommand::Noop).await?;
}
Ok(())
}
pub async fn set_node_ids(&mut self, nodes: [u8; 32]) -> Result<(), std::io::Error> {
self.framed.send(TashTalkCommand::SetNodeIds(nodes)).await
}
pub async fn set_features(&mut self, features: impl Into<u8>) -> Result<(), std::io::Error> {
self.framed
.send(TashTalkCommand::SetFeatures(features.into()))
.await
}
pub async fn receive_frame(&mut self) -> Result<Option<Vec<u8>>, TashTalkError> {
self.framed.next().await.transpose()
}
}