1use crate::{
16 bus::{Envelope, SimBus},
17 clock::{Duration, Instant},
18 fault::FaultConfig,
19 io::NodeAddress,
20 rng::{Rng, Xorshift64},
21};
22use acex_core::Vec;
23
24#[derive(Debug, Clone)]
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub struct CanFaultConfig {
32 pub message: FaultConfig,
34
35 pub arbitration_loss: (u32, u32),
37
38 pub bit_error: (u32, u32),
40
41 pub bus_off: (u32, u32),
44}
45
46impl CanFaultConfig {
47 pub fn none() -> Self {
48 Self {
49 message: FaultConfig::none(),
50 arbitration_loss: (0, 1),
51 bit_error: (0, 1),
52 bus_off: (0, 1),
53 }
54 }
55
56 pub fn light() -> Self {
57 Self {
58 message: FaultConfig::light(),
59 arbitration_loss: (1, 200),
60 bit_error: (1, 200),
61 bus_off: (1, 200),
62 }
63 }
64
65 pub fn chaos() -> Self {
66 Self {
67 message: FaultConfig::chaos(),
68 arbitration_loss: (1, 10),
69 bit_error: (1, 10),
70 bus_off: (1, 10),
71 }
72 }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub enum CanBusState {
83 Active,
85
86 ErrorPassive,
89
90 BusOff { since: Instant },
92}
93
94impl CanBusState {
95 pub fn is_operational(&self) -> bool {
96 matches!(self, Self::Active | Self::ErrorPassive)
97 }
98}
99
100#[derive(Debug, Clone, PartialEq, Eq)]
106#[cfg_attr(feature = "defmt", derive(defmt::Format))]
107pub enum CanEvent {
108 BusOff,
110
111 BusRecovered,
113
114 BitError { src: NodeAddress },
116}
117
118#[derive(Debug)]
130#[cfg_attr(all(feature = "defmt", not(feature = "alloc")), derive(defmt::Format))]
131pub struct CanSimBus<const MAX_DATA: usize, const MAX_QUEUED: usize> {
132 inner: SimBus<MAX_DATA, MAX_QUEUED>,
134
135 can_faults: CanFaultConfig,
137
138 bus_state: CanBusState,
140
141 events: Vec<CanEvent, 16>,
143
144 rng: Xorshift64,
146}
147
148impl<const MAX_DATA: usize, const MAX_QUEUED: usize> CanSimBus<MAX_DATA, MAX_QUEUED> {
149 pub fn new(seed: u64, faults: CanFaultConfig) -> Self {
154 Self {
155 inner: SimBus::new(seed, faults.message.clone()),
156 can_faults: faults,
157 bus_state: CanBusState::Active,
158 events: Vec::new(),
159 rng: Xorshift64::new(seed.wrapping_add(2)),
160 }
161 }
162
163 pub fn send(&mut self, src: NodeAddress, dst: NodeAddress, data: &[u8]) -> bool {
170 if !self.bus_state.is_operational() {
171 return false;
172 }
173
174 if self.rng.chance(
175 self.can_faults.arbitration_loss.0,
176 self.can_faults.arbitration_loss.1,
177 ) {
178 return false;
179 }
180
181 if self
182 .rng
183 .chance(self.can_faults.bit_error.0, self.can_faults.bit_error.1)
184 {
185 let _ = self.events.push(CanEvent::BitError { src: src.clone() });
186 return false;
187 }
188
189 self.inner.send(src, dst, data)
190 }
191
192 pub fn trigger_bus_off(&mut self) {
198 let now = self.inner.now();
199
200 self.bus_state = CanBusState::BusOff { since: now };
201
202 let _ = self.events.push(CanEvent::BusOff);
203 }
204
205 pub fn reset_bus_off(&mut self) {
207 if matches!(self.bus_state, CanBusState::BusOff { .. }) {
208 self.bus_state = CanBusState::Active;
209 let _ = self.events.push(CanEvent::BusRecovered);
210 }
211 }
212
213 pub fn bus_state(&self) -> &CanBusState {
214 &self.bus_state
215 }
216
217 pub fn tick(&mut self, duration: Duration) -> Vec<Envelope<MAX_DATA>, MAX_QUEUED> {
223 if self.bus_state.is_operational() {
224 if self
225 .rng
226 .chance(self.can_faults.bus_off.0, self.can_faults.bus_off.1)
227 {
228 let now = self.inner.now();
229
230 self.bus_state = CanBusState::BusOff { since: now };
231
232 let _ = self.events.push(CanEvent::BusOff);
233 }
234 }
235
236 if !self.bus_state.is_operational() {
237 let _ = self.inner.tick(duration);
238 return Vec::new();
239 }
240
241 self.inner.tick(duration)
242 }
243
244 pub fn now(&self) -> Instant {
249 self.inner.now()
250 }
251
252 pub fn drain_events(&mut self) -> impl Iterator<Item = CanEvent> + '_ {
254 self.events.drain(..)
255 }
256
257 pub fn set_faults(&mut self, faults: CanFaultConfig) {
258 self.inner.set_faults(faults.message.clone());
259 self.can_faults = faults;
260 }
261
262 pub fn inner_mut(&mut self) -> &mut SimBus<MAX_DATA, MAX_QUEUED> {
263 &mut self.inner
264 }
265
266 }
268
269