Skip to content

Instantly share code, notes, and snippets.

@agrif
Created August 13, 2025 00:17
Show Gist options
  • Save agrif/00140d982ab025f52d49c62d0ca5938b to your computer and use it in GitHub Desktop.
Save agrif/00140d982ab025f52d49c62d0ca5938b to your computer and use it in GitHub Desktop.
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