use core::mem;
use std::time::{Instant};
#[allow(unused_imports)]
use log::{error, warn, info, debug, trace};
use spectrusty_core::clock::{FTs, TimestampOps};
pub use super::zxnet_udp::*;
const CPU_HZ: f32 = 3_500_000.0;
pub trait ZxNetSocket {
fn packet_data(&self) -> &[u8];
fn begin_packet(&mut self);
fn push_byte(&mut self, byte: u8) -> usize;
fn outbound_index(&self) -> usize;
fn send_packet(&mut self);
fn recv_accept(&mut self) -> bool;
fn recv_packet(&mut self) -> bool;
fn pull_byte(&mut self) -> Option<u8>;
fn inbound_index(&self) -> usize;
fn send_accept(&mut self);
}
#[derive(Debug)]
pub struct ZxNet<T, S> {
pub socket: S,
event_ts: T,
dir_io: NetDir,
io: NetState,
net_state: bool
}
#[repr(C, packed)]
pub struct ZxNetHead {
pub dest: u8,
pub ours: u8,
pub serial: [u8;2],
pub eof: u8,
pub size: u8,
pub dchk: u8,
pub hchk: u8,
}
pub(super) const HEAD_SIZE: usize = mem::size_of::<ZxNetHead>();
pub trait DataAsZxNetHead {
fn as_zxnet_header(&self) -> &ZxNetHead;
}
impl DataAsZxNetHead for [u8] {
fn as_zxnet_header(&self) -> &ZxNetHead {
let head = &self[..mem::size_of::<ZxNetHead>()];
let ptr = head.as_ptr() as *const ZxNetHead;
unsafe { &*ptr }
}
}
const INPAK_WAIT_MAX: FTs = 8925;
const OUTPAK_START_DELAY: FTs = 110;
const BIT_DELAY: FTs = 60;
const REST_DELAY_THRESHOLD: FTs = 64;
const PROBE_DELAY_MIN: FTs = 65;
const PROBE_DELAY_MAX: FTs = 130;
const BYTE_DELAY: FTs = 120;
const BROADCAST_DATA_DELAY: i32 = 530;
#[derive(Clone, Copy, Debug, PartialEq)]
enum NetDir {
Inbound,
Outbound
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum NetState {
Idle(u8),
InputScout,
InputStart,
InputData(u8),
OutputScout,
OutputStart,
OutputData(u8),
OutputStop(u8),
OutputEnd
}
impl<T: TimestampOps, S: ZxNetSocket> ZxNet<T, S> {
pub fn send_state(&mut self, net: bool, timestamp: T) {
match self.io {
NetState::Idle(..) => {
self.net_state = net;
self.io = NetState::OutputScout;
}
NetState::OutputScout if net && !self.net_state => { self.socket.begin_packet();
self.dir_io = NetDir::Outbound;
self.event_ts = timestamp + OUTPAK_START_DELAY;
self.io = NetState::OutputStart;
}
NetState::OutputScout => {
self.net_state = false;
self.io = NetState::Idle(0);
}
NetState::InputData(0) if net && timestamp >= self.event_ts => { self.event_ts = timestamp + OUTPAK_START_DELAY;
self.io = NetState::OutputStart;
}
NetState::OutputStart if !net && timestamp < self.event_ts => {
self.event_ts = timestamp + BIT_DELAY;
self.io = NetState::OutputData(0x80);
}
NetState::OutputData(bits) if timestamp < self.event_ts => {
let next_bits = ((bits & !1)| u8::from(net)).rotate_right(1);
self.event_ts = timestamp + BIT_DELAY;
self.io = if bits & 1 == 1 {
NetState::OutputStop(next_bits)
}
else {
NetState::OutputData(next_bits)
};
}
NetState::OutputStop(byte) if net && timestamp < self.event_ts => {
match self.dir_io {
NetDir::Inbound if byte == 1 => {
if self.socket.inbound_index() == HEAD_SIZE {
self.socket.send_accept();
}
self.io = NetState::OutputEnd;
}
NetDir::Inbound => {
self.net_state = false;
self.io = NetState::Idle(0); }
NetDir::Outbound => {
let len = self.socket.push_byte(byte);
self.io = if len == HEAD_SIZE {
NetState::OutputEnd
}
else if len > HEAD_SIZE
&& len - HEAD_SIZE == self.socket.packet_data().as_zxnet_header().size as usize {
self.socket.send_packet();
NetState::OutputEnd
}
else {
NetState::OutputStart
}
}
}
self.event_ts = timestamp + BYTE_DELAY;
}
NetState::OutputEnd if !net && timestamp < self.event_ts => { self.event_ts = timestamp; let head = self.socket.packet_data().as_zxnet_header();
match self.dir_io {
NetDir::Inbound => { self.io = if self.socket.inbound_index() == head.size as usize + HEAD_SIZE {
self.net_state = false;
NetState::Idle(0) }
else {
self.net_state = true;
NetState::InputScout }
}
NetDir::Outbound => {
self.io = if self.socket.outbound_index() == head.size as usize + HEAD_SIZE {
if head.dest == 0 { self.net_state = false;
NetState::Idle(0) }
else {
self.net_state = false;
NetState::InputScout }
}
else if head.dest == 0 { self.net_state = false;
NetState::InputData(0) }
else {
self.net_state = true;
NetState::InputScout }
}
}
}
_ => { self.io = NetState::Idle(0);
self.net_state = false;
}
}
}
pub fn poll_state(&mut self, timestamp: T) -> bool {
match self.io {
NetState::Idle(cnt) => {
if timestamp >= self.event_ts {
match timestamp.diff_from(self.event_ts) as FTs {
0..=REST_DELAY_THRESHOLD => {
self.event_ts = timestamp;
self.io = NetState::Idle(cnt.saturating_add(1));
}
PROBE_DELAY_MIN..=PROBE_DELAY_MAX if cnt < 191 => { if self.socket.recv_packet() {
self.event_ts = timestamp;
self.io = NetState::InputScout;
self.dir_io = NetDir::Inbound;
self.net_state = true;
}
else {
self.event_ts = timestamp;
}
}
_ => {
self.event_ts = timestamp;
self.io = NetState::Idle(0);
self.net_state = false;
}
}
}
else if cnt != 0 {
self.io = NetState::Idle(0);
}
}
NetState::OutputScout => {
self.io = NetState::Idle(0);
}
NetState::InputScout if self.net_state => { self.event_ts = timestamp;
self.io = NetState::InputStart;
}
NetState::InputScout => {
let now = Instant::now();
if self.socket.recv_accept() {
self.event_ts = timestamp;
self.io = NetState::InputStart;
self.net_state = true;
}
else {
self.setup_event_time(timestamp, now);
self.io = NetState::Idle(0);
}
}
NetState::InputStart => { self.event_ts = timestamp + INPAK_WAIT_MAX;
self.io = NetState::Idle(0);
self.net_state = false;
}
NetState::InputData(byte) => {
self.net_state = if timestamp < self.event_ts {
self.event_ts = timestamp + BIT_DELAY;
self.io = NetState::InputData(byte >> 1);
byte & 1 == 1
}
else if timestamp.diff_from(self.event_ts) <= BROADCAST_DATA_DELAY {
self.event_ts = timestamp;
self.io = NetState::InputStart;
true
}
else {
self.io = NetState::Idle(0);
false
};
}
_ => { self.io = NetState::Idle(0);
self.net_state = false;
}
}
self.net_state }
pub fn wait_data(&mut self, timestamp: T) {
if let Some(byte) = match (self.io, self.dir_io) { (NetState::InputStart, NetDir::Outbound) => Some(1),
(NetState::InputStart, NetDir::Inbound) => self.socket.pull_byte(),
(NetState::InputData(0), NetDir::Inbound) if timestamp > self.event_ts &&
timestamp < self.event_ts + BIT_DELAY => {
self.socket.pull_byte()
}
_ => None
}
{
self.event_ts = timestamp + 2*BIT_DELAY;
self.io = NetState::InputData(byte);
}
else {
self.event_ts = timestamp + INPAK_WAIT_MAX;
self.io = NetState::Idle(0);
self.net_state = false;
}
}
pub fn next_frame(&mut self, eof_timestamp: T) {
self.event_ts = self.event_ts.saturating_sub(eof_timestamp);
}
fn setup_event_time(&mut self, timestamp: T, start: Instant) {
let elapsed = start.elapsed().as_secs_f32();
let elapsed_ts = (elapsed * CPU_HZ).round() as FTs;
self.event_ts = timestamp + elapsed_ts;
}
}
impl<T: Default, S: Default> Default for ZxNet<T, S> {
fn default() -> Self {
let socket = S::default();
let event_ts = T::default();
let net_state = false;
let dir_io = NetDir::Inbound;
let io = NetState::Idle(0);
ZxNet { socket, event_ts, net_state, dir_io, io }
}
}