use core::fmt::Debug;
#[cfg(feature = "snapshot")]
use serde::{Serialize, Deserialize};
use crate::serial::{SerialPortDevice, DataState, ControlState};
use super::AyIoPort;
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "snapshot", serde(rename_all = "camelCase"))]
pub struct SerialPorts128<S1,S2> {
#[cfg_attr(feature = "snapshot", serde(default))]
pub serial1: S1,
#[cfg_attr(feature = "snapshot", serde(default))]
pub serial2: S2,
io_state: Serial128Io,
}
bitflags! {
#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "snapshot", serde(from = "u8", into = "u8"))]
struct Serial128Io: u8 {
const SER1_CTS = 0b0000_0001;
const SER1_RXD = 0b0000_0010;
const SER2_CTS = 0b0000_0100;
const SER2_RXD = 0b0000_1000;
const SER1_OUT_MASK = 0b0000_0011;
const SER2_OUT_MASK = 0b0000_1100;
const OUTPUT_MASK = Self::SER1_OUT_MASK.bits()|Self::SER2_OUT_MASK.bits();
const SER1_DTR = 0b0001_0000;
const SER1_TXD = 0b0010_0000;
const SER2_DTR = 0b0100_0000;
const SER2_TXD = 0b1000_0000;
const SER1_INP_MASK = 0b0011_0000;
const SER2_INP_MASK = 0b1100_0000;
}
}
impl Default for Serial128Io {
fn default() -> Self {
Serial128Io::all()
}
}
impl From<u8> for Serial128Io {
fn from(keys: u8) -> Self {
Serial128Io::from_bits_truncate(keys)
}
}
impl From<Serial128Io> for u8 {
fn from(keys: Serial128Io) -> Self {
keys.bits()
}
}
impl Serial128Io {
#[inline]
fn is_ser_any_cts(self) -> bool {
self.intersects(Serial128Io::SER1_CTS|Serial128Io::SER2_CTS)
}
#[inline]
fn is_ser1_cts(self) -> bool {
self.intersects(Serial128Io::SER1_CTS)
}
#[inline]
fn is_ser2_cts(self) -> bool {
self.intersects(Serial128Io::SER2_CTS)
}
#[inline]
fn ser1_cts_state(self) -> ControlState {
self.intersects(Serial128Io::SER1_CTS).into()
}
#[inline]
fn ser2_cts_state(self) -> ControlState {
self.intersects(Serial128Io::SER2_CTS).into()
}
#[inline]
fn ser1_rxd_state(self) -> DataState {
self.intersects(Serial128Io::SER1_RXD).into()
}
#[inline]
fn ser2_rxd_state(self) -> DataState {
self.intersects(Serial128Io::SER2_RXD).into()
}
#[inline]
fn set_ser1_txd(&mut self, txd: DataState) {
self.set(Serial128Io::SER1_TXD, txd.into());
}
#[inline]
fn set_ser2_txd(&mut self, txd: DataState) {
self.set(Serial128Io::SER2_TXD, txd.into());
}
#[inline]
fn set_ser1_dtr(&mut self, dtr: ControlState) {
self.set(Serial128Io::SER1_DTR, dtr.into());
}
#[inline]
fn set_ser2_dtr(&mut self, dtr: ControlState) {
self.set(Serial128Io::SER2_DTR, dtr.into());
}
}
impl<S1, S2> AyIoPort for SerialPorts128<S1, S2>
where S1: SerialPortDevice,
S2: SerialPortDevice<Timestamp=S1::Timestamp>,
S1::Timestamp: Copy
{
type Timestamp = S1::Timestamp;
#[inline]
fn ay_io_reset(&mut self, _timestamp: Self::Timestamp) {}
#[inline]
fn ay_io_write(&mut self, _addr: u16, data: u8, timestamp: Self::Timestamp) {
let mut io_state = self.io_state;
let io_diff = (io_state ^ Serial128Io::from_bits_truncate(data)) & Serial128Io::OUTPUT_MASK;
io_state ^= io_diff;
if io_diff.is_ser1_cts() {
self.serial1.update_cts(io_state.ser1_cts_state(), timestamp);
}
if io_diff.is_ser2_cts() {
self.serial2.update_cts(io_state.ser2_cts_state(), timestamp);
}
if !io_diff.is_ser_any_cts() {
io_state.set_ser1_dtr(
self.serial1.write_data(io_state.ser1_rxd_state(), timestamp)
);
io_state.set_ser2_dtr(
self.serial2.write_data(io_state.ser2_rxd_state(), timestamp)
);
}
self.io_state = io_state;
}
#[inline]
fn ay_io_read(&mut self, _addr: u16, timestamp: Self::Timestamp) -> u8 {
let mut io_state = self.io_state;
io_state.set_ser1_txd(self.serial1.read_data(timestamp));
io_state.set_ser2_txd(self.serial2.read_data(timestamp));
self.io_state = io_state;
(io_state | Serial128Io::OUTPUT_MASK).bits()
}
#[inline]
fn end_frame(&mut self, timestamp: Self::Timestamp) {
self.io_state.set_ser1_dtr(self.serial1.poll_ready(timestamp));
self.io_state.set_ser2_dtr(self.serial2.poll_ready(timestamp));
self.serial1.next_frame(timestamp);
self.serial2.next_frame(timestamp);
}
}
#[cfg(test)]
mod tests {
#[test]
fn serial_ports_128_work() {
}
}