Created
August 13, 2025 00:17
-
-
Save agrif/00140d982ab025f52d49c62d0ca5938b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
impl StateMachine for Simplex { | |
type InputAbove = PhysicalIn; | |
type InputBelow = HardwareOut; | |
type OutputAbove = PhysicalOut; | |
type OutputBelow = HardwareIn; | |
fn reset(&mut self) { | |
*self = Self::new_with(self.config.clone()); | |
} | |
fn process( | |
&mut self, | |
out: &mut impl Subscriber<Self>, | |
now: Instant, | |
ev: Event<Self::InputAbove, Self::InputBelow>, | |
) -> Wake { | |
use Event::*; | |
use SimplexState::*; | |
let mut tr = out.tracer(format_args!("PHY"), ev.as_ref()); | |
match self.state { | |
Ready => match ev { | |
Above(a) => { | |
tr.on_internal_out(&a); | |
if let PhysicalIn::ExpeditedData(d) = a { | |
self.priority.push_back(d); | |
self.digipeating = true; | |
self.start_transmitter(out, &mut tr, now); | |
tr.transition(&mut self.state, TransmitterStart); | |
} else { | |
self.normal.push_back(a); | |
} | |
} | |
None if !self.normal.is_empty() => { | |
let a = self.normal.pop_front().unwrap(); | |
tr.on_internal_in(&a); | |
match a { | |
PhysicalIn::Seize => { | |
self.digipeating = false; | |
self.start_transmitter(out, &mut tr, now); | |
tr.transition(&mut self.state, TransmitterStart); | |
} | |
PhysicalIn::Release => (), | |
PhysicalIn::Data(_) => (), | |
PhysicalIn::ExpeditedData(_) => unreachable!(), | |
} | |
} | |
None if tr.expired(&mut self.slot_time, now) => { | |
// T102 expired | |
self.repeater_up = true; | |
} | |
Below(HardwareOut::AOS) => { | |
self.acquisition(out, &mut tr); | |
tr.transition(&mut self.state, Receiving); | |
} | |
Below(_) => (), | |
None => (), | |
}, | |
Receiving => match ev { | |
Above(a) => { | |
tr.on_internal_out(&a); | |
if let PhysicalIn::ExpeditedData(d) = a { | |
self.priority.push_back(d); | |
} else { | |
self.normal.push_back(a); | |
} | |
} | |
Below(HardwareOut::Data(d)) => { | |
tr.send_above(out, PhysicalOut::Data(d)); | |
} | |
Below(HardwareOut::AOS) => (), | |
Below(HardwareOut::LOS) => { | |
// start T100 and T101 | |
tr.start(&mut self.repeater_hang, now); | |
tr.start(&mut self.priority_window, now); | |
tr.send_above(out, PhysicalOut::Quiet); | |
if self.priority.is_empty() { | |
tr.transition(&mut self.state, TransmitterSuppression); | |
} else { | |
self.digipeating = true; | |
self.start_transmitter(out, &mut tr, now); | |
tr.transition(&mut self.state, TransmitterStart); | |
} | |
} | |
None => (), | |
}, | |
TransmitterSuppression => match ev { | |
Above(a) => { | |
tr.on_internal_out(&a); | |
if let PhysicalIn::ExpeditedData(d) = a { | |
self.priority.push_back(d); | |
self.digipeating = true; | |
self.start_transmitter(out, &mut tr, now); | |
tr.transition(&mut self.state, TransmitterStart); | |
} else { | |
self.normal.push_back(a); | |
} | |
} | |
None if tr.expired(&mut self.repeater_hang, now) => { | |
// T100 expired | |
self.repeater_up = false; | |
} | |
Below(HardwareOut::AOS) => { | |
self.acquisition(out, &mut tr); | |
tr.transition(&mut self.state, Receiving); | |
} | |
Below(_) => { | |
tr.transition(&mut self.state, Ready); | |
} | |
None if tr.expired(&mut self.priority_window, now) | |
|| tr.expired(&mut self.slot_time, now) => | |
{ | |
// T101 or T102 expired | |
if self.priority.is_empty() { | |
let r: f32 = rand::random(); | |
if r < self.p { | |
if self.interrupted { | |
self.start_transmitter(out, &mut tr, now); | |
tr.transition(&mut self.state, TransmitterStart); | |
} else { | |
tr.transition(&mut self.state, Ready); | |
} | |
} else { | |
// start T102 | |
tr.start(&mut self.slot_time, now); | |
} | |
} else { | |
self.digipeating = true; | |
self.start_transmitter(out, &mut tr, now); | |
tr.transition(&mut self.state, TransmitterStart); | |
} | |
} | |
None => (), | |
}, | |
TransmitterStart => match ev { | |
Above(a) => { | |
tr.on_internal_out(&a); | |
if let PhysicalIn::ExpeditedData(d) = a { | |
self.priority.push_back(d); | |
} else { | |
self.normal.push_back(a); | |
} | |
} | |
None if tr.expired(&mut self.repeater_hang, now) => { | |
// T100 expired | |
self.repeater_up = false; | |
} | |
None if tr.expired(&mut self.repeater_startup, now) => { | |
// T104 expired | |
self.repeater_up = true; | |
// start T105 | |
tr.start(&mut self.remote_receiver_sync, now); | |
} | |
None if tr.expired(&mut self.transmitter_startup, now) => { | |
// T103 expired | |
if self.repeater_up { | |
// start T105 | |
tr.start(&mut self.remote_receiver_sync, now); | |
} else { | |
// start T104 | |
tr.start(&mut self.repeater_startup, now); | |
} | |
} | |
None if tr.expired(&mut self.remote_receiver_sync, now) => { | |
// T105 expired | |
// start T106 | |
tr.start(&mut self.transmission_limit, now); | |
if self.digipeating { | |
tr.transition(&mut self.state, Digipeating); | |
} else { | |
// start T107 | |
tr.start(&mut self.anti_hogging_limit, now); | |
if !self.interrupted { | |
tr.send_above(out, PhysicalOut::SeizeConfirm); | |
} | |
tr.transition(&mut self.state, Transmitting); | |
} | |
} | |
// tx on, other hardware events should not occur | |
Below(_) => (), | |
None => (), | |
}, | |
Transmitting => match ev { | |
Above(a) => { | |
tr.on_internal_out(&a); | |
if let PhysicalIn::ExpeditedData(d) = a { | |
self.priority.push_back(d); | |
} else { | |
self.normal.push_back(a); | |
} | |
} | |
None if !self.normal.is_empty() => { | |
let a = self.normal.pop_front().unwrap(); | |
tr.on_internal_in(&a); | |
match a { | |
PhysicalIn::Seize => { | |
tr.send_above(out, PhysicalOut::SeizeConfirm); | |
} | |
PhysicalIn::Data(d) => { | |
tr.send_below(out, HardwareIn::Data(d)); | |
} | |
PhysicalIn::Release => { | |
// stop T107 | |
self.anti_hogging_limit.stop(); | |
self.interrupted = false; | |
if self.priority.is_empty() { | |
// stop T106 | |
self.transmission_limit.stop(); | |
tr.send_below(out, HardwareIn::TOff); | |
// start T108 | |
tr.start(&mut self.receiver_startup, now); | |
tr.transition(&mut self.state, ReceiverStart); | |
} else { | |
self.digipeating = true; | |
tr.transition(&mut self.state, Digipeating); | |
} | |
} | |
PhysicalIn::ExpeditedData(_) => unreachable!(), | |
} | |
} | |
None if tr.expired(&mut self.anti_hogging_limit, now) => { | |
// T107 expired | |
self.interrupted = true; | |
if self.priority.is_empty() { | |
// stop T106 | |
self.transmission_limit.stop(); | |
tr.send_below(out, HardwareIn::TOff); | |
// start T108 | |
tr.start(&mut self.receiver_startup, now); | |
tr.transition(&mut self.state, ReceiverStart); | |
} else { | |
self.digipeating = true; | |
tr.transition(&mut self.state, Digipeating); | |
} | |
} | |
None if tr.expired(&mut self.transmission_limit, now) => { | |
// T106 expired | |
// stop T107 | |
self.anti_hogging_limit.stop(); | |
self.interrupted = true; | |
tr.send_below(out, HardwareIn::TOff); | |
// start T108 | |
tr.start(&mut self.receiver_startup, now); | |
tr.transition(&mut self.state, ReceiverStart); | |
} | |
// tx on, other hardware events should not occur | |
Below(_) => (), | |
None => (), | |
}, | |
Digipeating => match ev { | |
Above(a) => { | |
tr.on_internal_out(&a); | |
if let PhysicalIn::ExpeditedData(d) = a { | |
self.priority.push_back(d); | |
} else { | |
self.normal.push_back(a); | |
} | |
} | |
None if !self.priority.is_empty() => { | |
let d = self.priority.pop_front(); | |
tr.on_internal_in(&d); | |
tr.send_below(out, HardwareIn::Data(d.unwrap())); | |
} | |
None if self.priority.is_empty() | |
|| tr.expired(&mut self.transmission_limit, now) => | |
{ | |
// empty queue or T106 expired | |
if self.priority.is_empty() { | |
tr.on_internal_in(&format_args!("None")); | |
} | |
tr.send_below(out, HardwareIn::TOff); | |
self.digipeating = false; | |
// start T108 | |
tr.start(&mut self.receiver_startup, now); | |
tr.transition(&mut self.state, ReceiverStart); | |
} | |
// tx on, other hardware events should not occur | |
Below(_) => (), | |
None => (), | |
}, | |
ReceiverStart => match ev { | |
Above(a) => { | |
tr.on_internal_out(&a); | |
if let PhysicalIn::ExpeditedData(d) = a { | |
self.priority.push_back(d); | |
} else { | |
self.normal.push_back(a); | |
} | |
} | |
None if tr.expired(&mut self.receiver_startup, now) => { | |
// T108 expired | |
// start T100 and T101 | |
tr.start(&mut self.repeater_hang, now); | |
tr.start(&mut self.priority_window, now); | |
tr.send_above(out, PhysicalOut::Quiet); | |
tr.transition(&mut self.state, TransmitterSuppression); | |
} | |
// this is not in spec, but we should handle AOS here | |
Below(HardwareOut::AOS) => { | |
self.acquisition(out, &mut tr); | |
tr.transition(&mut self.state, Receiving); | |
} | |
// ignore other hardware events | |
Below(_) => (), | |
None => (), | |
}, | |
} | |
// check if normal queue needs processing | |
if let Ready | Transmitting = self.state { | |
// normal queue states have only pop events | |
if !self.normal.is_empty() { | |
return Wake::Immediately; | |
} | |
} | |
// check priority queue | |
// priority queue states have pop and empty events | |
if let Digipeating = self.state { | |
return Wake::Immediately; | |
} | |
// otherwise, wake on timer | |
let mut wake = Wake::Never; | |
wake.combine(self.repeater_hang.as_wake()); | |
wake.combine(self.priority_window.as_wake()); | |
wake.combine(self.slot_time.as_wake()); | |
wake.combine(self.transmitter_startup.as_wake()); | |
wake.combine(self.repeater_startup.as_wake()); | |
wake.combine(self.remote_receiver_sync.as_wake()); | |
wake.combine(self.transmission_limit.as_wake()); | |
wake.combine(self.anti_hogging_limit.as_wake()); | |
wake.combine(self.receiver_startup.as_wake()); | |
wake | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment