1use crate::{
10 header::PayloadType,
11 payload::{DiagnosticNackCode, RoutingActivationRequest, RoutingActivationResponse},
12 session::{ActivationAuthProvider, ActivationDenialReason, ActivationStateMachine},
13};
14use ace_core::FrameRead;
15use ace_sim::clock::{Duration, Instant};
16
17#[derive(Debug, Clone)]
23pub struct ConnectionConfig {
24 pub alive_check_timeout: Duration,
26
27 pub idle_timeout: Duration,
29}
30
31impl Default for ConnectionConfig {
32 fn default() -> Self {
33 Self {
34 alive_check_timeout: Duration::from_millis(500),
35 idle_timeout: Duration::from_millis(5_000),
36 }
37 }
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
46pub enum ConnectionPhase {
47 Connected,
49
50 Active,
52
53 AliveCheckPending { sent_at: Instant },
55
56 Closing,
58}
59
60#[derive(Debug, Clone, PartialEq, Eq)]
69pub enum ConnectionEvent<const BUF: usize = 4096> {
70 SendActivationResponse(RoutingActivationResponse),
72
73 ForwardToEcu {
75 source_address: u16,
76 target_address: u16,
77 uds_data: heapless::Vec<u8, BUF>,
78 },
79
80 SendDiagnosticAck {
82 source_address: u16,
83 target_address: u16,
84 },
85
86 SendDiagnosticNack {
88 source_address: u16,
89 target_address: u16,
90 nack_code: DiagnosticNackCode,
91 },
92
93 SendAliveCheckRequest,
95
96 SendAliveCheckResponse,
98
99 Close,
101}
102
103#[derive(Debug)]
112pub struct ConnectionState<A: ActivationAuthProvider, const BUF: usize = 4096> {
113 config: ConnectionConfig,
114 phase: ConnectionPhase,
115 activation: ActivationStateMachine<A>,
116 last_rx: Instant,
117 events: heapless::Vec<ConnectionEvent<BUF>, 8>,
118}
119
120impl<A: ActivationAuthProvider, const BUF: usize> ConnectionState<A, BUF> {
121 pub fn new(
122 config: ConnectionConfig,
123 activation: ActivationStateMachine<A>,
124 now: Instant,
125 ) -> Self {
126 Self {
127 config,
128 phase: ConnectionPhase::Connected,
129 activation,
130 last_rx: now,
131 events: heapless::Vec::new(),
132 }
133 }
134
135 pub fn is_active(&self) -> bool {
138 self.phase == ConnectionPhase::Active
139 }
140
141 pub fn active_source_address(&self) -> Option<u16> {
142 self.activation.state.active_source_address()
143 }
144
145 pub fn handle(&mut self, payload_type: &PayloadType, payload_data: &[u8], now: Instant) {
150 self.last_rx = now;
151
152 match payload_type {
153 PayloadType::RoutingActivationRequest => self.on_routing_activation(payload_data),
154 PayloadType::DiagnosticMessage => self.on_diagnostic_message(payload_data),
155 PayloadType::AliveCheckRequest => self.on_alive_check_request(),
156 PayloadType::AliveCheckResponse => self.on_alive_check_response(),
157
158 _ => {}
160 }
161 }
162
163 pub fn tick(&mut self, now: Instant) {
165 match &self.phase {
166 ConnectionPhase::Active => {
167 let idle = now
168 .checked_duration_since(self.last_rx)
169 .unwrap_or(Duration::ZERO);
170
171 if idle > self.config.idle_timeout {
172 self.phase = ConnectionPhase::AliveCheckPending { sent_at: now };
173 let _ = self.events.push(ConnectionEvent::SendAliveCheckRequest);
174 }
175 }
176 ConnectionPhase::AliveCheckPending { sent_at } => {
177 let elapsed = now
178 .checked_duration_since(*sent_at)
179 .unwrap_or(Duration::ZERO);
180
181 if elapsed > self.config.alive_check_timeout {
182 self.phase = ConnectionPhase::Closing;
183 let _ = self.events.push(ConnectionEvent::Close);
184 }
185 }
186 _ => {}
187 }
188 }
189
190 pub fn drop_activation_line(&mut self, reason: ActivationDenialReason) {
192 self.activation.drop_line(reason);
193 self.phase = ConnectionPhase::Closing;
194 let _ = self.events.push(ConnectionEvent::Close);
195 }
196
197 pub fn drain_events(&mut self) -> impl Iterator<Item = ConnectionEvent<BUF>> + '_ {
199 self.events.drain(..)
200 }
201
202 fn on_routing_activation(&mut self, payload_data: &[u8]) {
207 let mut cursor = payload_data;
208 let req = match RoutingActivationRequest::decode(&mut cursor) {
209 Ok(r) => r,
210 Err(_) => {
211 self.phase = ConnectionPhase::Closing;
213 let _ = self.events.push(ConnectionEvent::Close);
214 return;
215 }
216 };
217
218 let resp = self.activation.process_request(&req);
219
220 let _ = self
221 .events
222 .push(ConnectionEvent::SendActivationResponse(resp));
223
224 if self.activation.state.is_active() {
225 self.phase = ConnectionPhase::Active;
226 } else {
227 self.phase = ConnectionPhase::Closing;
228 let _ = self.events.push(ConnectionEvent::Close);
229 }
230 }
231
232 fn on_diagnostic_message(&mut self, payload_data: &[u8]) {
233 let source = u16::from_be_bytes([
234 payload_data.get(0).copied().unwrap_or(0),
235 payload_data.get(1).copied().unwrap_or(0),
236 ]);
237 let target = u16::from_be_bytes([
238 payload_data.get(2).copied().unwrap_or(0),
239 payload_data.get(3).copied().unwrap_or(0),
240 ]);
241
242 if !self.is_active() {
243 let _ = self.events.push(ConnectionEvent::SendDiagnosticNack {
244 source_address: source,
245 target_address: target,
246 nack_code: DiagnosticNackCode::InvalidSourceAddress,
247 });
248 return;
249 }
250
251 if self.activation.state.active_source_address() != Some(source) {
252 let _ = self.events.push(ConnectionEvent::SendDiagnosticNack {
253 source_address: source,
254 target_address: target,
255 nack_code: DiagnosticNackCode::InvalidSourceAddress,
256 });
257 return;
258 }
259
260 let uds_bytes = payload_data.get(4..).unwrap_or(&[]);
261
262 if uds_bytes.is_empty() {
263 let _ = self.events.push(ConnectionEvent::SendDiagnosticNack {
264 source_address: source,
265 target_address: target,
266 nack_code: DiagnosticNackCode::TransportProtocolError,
267 });
268 return;
269 }
270
271 let mut uds_data: heapless::Vec<u8, BUF> = heapless::Vec::new();
272
273 if uds_data.extend_from_slice(uds_bytes).is_err() {
274 let _ = self.events.push(ConnectionEvent::SendDiagnosticNack {
275 source_address: source,
276 target_address: target,
277 nack_code: DiagnosticNackCode::OutOfMemory,
278 });
279 return;
280 }
281
282 let _ = self.events.push(ConnectionEvent::SendDiagnosticAck {
283 source_address: source,
284 target_address: target,
285 });
286
287 let _ = self.events.push(ConnectionEvent::ForwardToEcu {
288 source_address: source,
289 target_address: target,
290 uds_data,
291 });
292 }
293
294 fn on_alive_check_request(&mut self) {
295 let _ = self.events.push(ConnectionEvent::SendAliveCheckResponse);
296 }
297
298 fn on_alive_check_response(&mut self) {
299 if matches!(self.phase, ConnectionPhase::AliveCheckPending { .. }) {
300 self.phase = ConnectionPhase::Active;
301 }
302 }
303
304 }
306
307