1use crate::clock::{Clock, Duration, Instant, SimClock};
4use crate::fault::FaultConfig;
5use crate::io::NodeAddress;
6use crate::rng::{Rng, Xorshift64};
7
8#[derive(Debug, Clone)]
14pub struct Envelope<const N: usize> {
15 pub src: NodeAddress,
16 pub dst: NodeAddress,
17 pub data: heapless::Vec<u8, N>,
18 pub deliver_at: Instant,
20}
21
22#[derive(Debug)]
34pub struct SimBus<const N: usize, const Q: usize> {
35 clock: SimClock,
36 rng: Xorshift64,
37 faults: FaultConfig,
38 queue: heapless::Vec<Envelope<N>, Q>,
39}
40
41impl<const N: usize, const Q: usize> SimBus<N, Q> {
42 pub fn new(seed: u64, faults: FaultConfig) -> Self {
43 Self {
44 clock: SimClock::new(),
45 rng: Xorshift64::new(seed),
46 faults,
47 queue: heapless::Vec::new(),
48 }
49 }
50
51 pub fn now(&self) -> Instant {
53 self.clock.now()
54 }
55
56 pub fn tick(&mut self, duration: Duration) -> heapless::Vec<Envelope<N>, Q> {
59 self.clock.advance(duration);
60 let now = self.clock.now();
61
62 let mut delivered = heapless::Vec::new();
63 let mut remaining = heapless::Vec::new();
64
65 for envelope in self.queue.drain(..) {
66 if envelope.deliver_at <= now {
67 let _ = delivered.push(envelope);
68 } else {
69 let _ = remaining.push(envelope);
70 }
71 }
72
73 if delivered.len() > 1 {
74 for i in 0..delivered.len() - 1 {
75 if self
76 .rng
77 .chance(self.faults.message_reorder.0, self.faults.message_reorder.1)
78 {
79 delivered.swap(i, i + 1);
80 }
81 }
82 }
83
84 self.queue = remaining;
85 delivered
86 }
87
88 pub fn send(&mut self, src: NodeAddress, dst: NodeAddress, data: &[u8]) -> bool {
93 let r = self
94 .rng
95 .chance(self.faults.message_loss.0, self.faults.message_loss.1);
96
97 if r {
98 return false;
99 }
100
101 if self
102 .rng
103 .chance(self.faults.timeout.0, self.faults.timeout.1)
104 {
105 return false;
106 }
107
108 let mut payload = heapless::Vec::new();
109
110 for &byte in data {
111 if self
112 .rng
113 .chance(self.faults.corruption.0, self.faults.corruption.1)
114 {
115 let _ = payload.push(byte ^ self.rng.next_u8());
116 } else {
117 let _ = payload.push(byte);
118 }
119 }
120
121 let deliver_at = if self
122 .rng
123 .chance(self.faults.message_delay.0, self.faults.message_delay.1)
124 {
125 let delay_us = self.rng.next_u64() % self.faults.max_delay.as_micros().max(1);
126 self.clock.now() + Duration::from_micros(delay_us)
127 } else {
128 self.clock.now()
129 };
130
131 let envelope = Envelope {
132 src,
133 dst,
134 data: payload,
135 deliver_at,
136 };
137
138 self.queue.push(envelope).is_ok()
139 }
140
141 pub fn faults(&self) -> &FaultConfig {
143 &self.faults
144 }
145
146 pub fn set_faults(&mut self, faults: FaultConfig) {
148 self.faults = faults;
149 }
150
151 pub fn next_u8(&mut self) -> u8 {
154 self.rng.next_u8()
155 }
156
157 pub fn chance(&mut self, numerator: u32, denominator: u32) -> bool {
158 self.rng.chance(numerator, denominator)
159 }
160}
161
162