use std::error::Error;
use std::thread;
use std::time::Duration;
use log::debug;
use serial_core::prelude::*;
use flipdot_core::{Frame, Message, SignBus, State};
use crate::serial_port;
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct SerialSignBus<P: SerialPort> {
port: P,
}
impl<P: SerialPort> SerialSignBus<P> {
pub fn try_new(mut port: P) -> Result<Self, serial_core::Error> {
serial_port::configure_port(&mut port, Duration::from_secs(5))?;
Ok(SerialSignBus { port })
}
pub fn port(&self) -> &P {
&self.port
}
}
impl<P: SerialPort> SignBus for SerialSignBus<P> {
fn process_message<'a>(&mut self, message: Message<'_>) -> Result<Option<Message<'a>>, Box<dyn Error + Send + Sync>> {
debug!("Bus message: {}", message);
let response_expected = response_expected(&message);
let delay = delay_after_send(&message);
let frame = Frame::from(message);
frame.write(&mut self.port)?;
if let Some(duration) = delay {
thread::sleep(duration);
}
if response_expected {
let frame = Frame::read(&mut self.port)?;
let message = Message::from(frame);
debug!(" Sign reply: {}", message);
if let Some(duration) = delay_after_receive(&message) {
thread::sleep(duration);
}
Ok(Some(message))
} else {
Ok(None)
}
}
}
fn response_expected(message: &Message<'_>) -> bool {
matches!(
*message,
Message::Hello(_) | Message::QueryState(_) | Message::RequestOperation(_, _)
)
}
fn delay_after_send(message: &Message<'_>) -> Option<Duration> {
match *message {
Message::SendData(_, _) => Some(Duration::from_millis(30)),
_ => None,
}
}
fn delay_after_receive(message: &Message<'_>) -> Option<Duration> {
match *message {
Message::ReportState(_, State::PageLoadInProgress) | Message::ReportState(_, State::PageShowInProgress) => {
Some(Duration::from_millis(100))
}
_ => None,
}
}