Skip to main content

ace_server/
server.rs

1// region: Imports
2
3use ace_proto::uds::UdsFrame;
4use ace_sim::clock::{Duration, Instant};
5use ace_sim::io::NodeAddress;
6use ace_uds::ext::UdsFrameExt;
7use ace_uds::message::service::UdsServiceRequest;
8use ace_uds::message::ServiceIdentifier;
9use heapless::Vec;
10
11use crate::config::{periodic, ServerConfig, SessionConfig};
12use crate::handler::ServerHandler;
13use crate::nrc::NrcError;
14use crate::security_provider::SecurityProvider;
15
16// endregion: Imports
17
18// region: Capacity constants
19
20pub const MAX_OUTBOX: usize = 16;
21pub const MAX_FRAME: usize = 4096;
22pub const MAX_PERIODIC: usize = 8;
23pub const MAX_DATA_BUF: usize = 256;
24pub const MAX_SEED: usize = 16;
25
26// endregion: Capacity constants
27
28// region: ServerError
29
30#[derive(Debug)]
31pub enum ServerError<E: NrcError> {
32    Handler(E),
33    Codec(ace_uds::error::UdsError),
34    OutboxFull,
35}
36
37// endregion: ServerError
38
39// region: SessionState
40
41#[derive(Debug, Clone)]
42struct SessionState {
43    session_type: u8,
44    last_rx: Instant,
45    security_level: u8,
46}
47
48impl SessionState {
49    fn new() -> Self {
50        Self {
51            session_type: 0x01,
52            last_rx: Instant::ZERO,
53            security_level: 0,
54        }
55    }
56
57    fn is_default(&self) -> bool {
58        self.session_type == 0x01
59    }
60}
61
62// endregion: SessionState
63
64// region: SecurityState
65
66#[derive(Debug, Clone)]
67struct SecurityState {
68    pending_seed: Vec<u8, MAX_SEED>,
69    pending_level: u8,
70    failed_attempts: Vec<(u8, u8), 8>,
71    lockout_until: Vec<(u8, Instant), 8>,
72}
73
74impl SecurityState {
75    fn new() -> Self {
76        Self {
77            pending_seed: Vec::new(),
78            pending_level: 0,
79            failed_attempts: Vec::new(),
80            lockout_until: Vec::new(),
81        }
82    }
83
84    fn is_locked(&self, level: u8, now: Instant) -> bool {
85        self.lockout_until
86            .iter()
87            .find(|(l, _)| *l == level)
88            .map(|(_, until)| now < *until)
89            .unwrap_or(false)
90    }
91
92    fn failed_count(&self, level: u8) -> u8 {
93        self.failed_attempts
94            .iter()
95            .find(|(l, _)| *l == level)
96            .map(|(_, c)| *c)
97            .unwrap_or(0)
98    }
99
100    fn increment_failed(&mut self, level: u8) {
101        if let Some(e) = self.failed_attempts.iter_mut().find(|(l, _)| *l == level) {
102            e.1 = e.1.saturating_add(1);
103        } else {
104            let _ = self.failed_attempts.push((level, 1));
105        }
106    }
107
108    fn reset_failed(&mut self, level: u8) {
109        if let Some(e) = self.failed_attempts.iter_mut().find(|(l, _)| *l == level) {
110            e.1 = 0;
111        }
112    }
113
114    fn set_lockout(&mut self, level: u8, until: Instant) {
115        if let Some(e) = self.lockout_until.iter_mut().find(|(l, _)| *l == level) {
116            e.1 = until;
117        } else {
118            let _ = self.lockout_until.push((level, until));
119        }
120    }
121
122    fn clear_pending(&mut self) {
123        self.pending_seed.clear();
124        self.pending_level = 0;
125    }
126}
127
128// endregion: SecurityState
129
130// region: PeriodicEntry / PeriodicState
131
132#[derive(Debug, Clone)]
133struct PeriodicEntry {
134    did: u16,
135    interval: Duration,
136    next_tx: Instant,
137    client: NodeAddress,
138}
139
140#[derive(Debug)]
141struct PeriodicState {
142    entries: Vec<PeriodicEntry, MAX_PERIODIC>,
143}
144
145impl PeriodicState {
146    fn new() -> Self {
147        Self {
148            entries: Vec::new(),
149        }
150    }
151
152    fn register(&mut self, did: u16, interval: Duration, client: NodeAddress, now: Instant) {
153        if let Some(e) = self
154            .entries
155            .iter_mut()
156            .find(|e| e.did == did && e.client == client)
157        {
158            e.interval = interval;
159            e.next_tx = now + interval;
160            return;
161        }
162        let _ = self.entries.push(PeriodicEntry {
163            did,
164            interval,
165            next_tx: now + interval,
166            client,
167        });
168    }
169
170    fn cancel(&mut self, did: u16, client: &NodeAddress) {
171        self.entries
172            .retain(|e| !(e.did == did && &e.client == client));
173    }
174
175    fn collect_due(&self, now: Instant, out: &mut Vec<(u16, NodeAddress), MAX_PERIODIC>) {
176        for e in self.entries.iter().filter(|e| now >= e.next_tx) {
177            let _ = out.push((e.did, e.client.clone()));
178        }
179    }
180
181    fn advance(&mut self, did: u16, client: &NodeAddress, now: Instant) {
182        if let Some(e) = self
183            .entries
184            .iter_mut()
185            .find(|e| e.did == did && &e.client == client)
186        {
187            e.next_tx = now + e.interval;
188        }
189    }
190}
191
192// endregion: PeriodicEntry / PeriodicState
193
194// region: UdsServer
195
196/// Stateful UDS ECU server state machine.
197///
198/// Receives raw UDS frames via [`handle`], uses [`UdsFrameExt`] for
199/// protocol-level decisions (SID dispatch, suppress bit, sub-function),
200/// and decodes typed messages only where structured field access is needed.
201///
202/// All timing is driven by [`tick`] - no blocking, no hardware timers,
203/// no OS calls. Suitable for direct use as a `SimNode` in `ace-sim`.
204#[derive(Debug)]
205pub struct UdsServer<H, S>
206where
207    H: ServerHandler,
208    S: SecurityProvider,
209{
210    config: ServerConfig,
211    handler: H,
212    security_provider: S,
213    address: NodeAddress,
214    session: SessionState,
215    security: SecurityState,
216    periodic: PeriodicState,
217    outbox: Vec<(NodeAddress, Vec<u8, MAX_FRAME>), MAX_OUTBOX>,
218}
219
220impl<H, S> UdsServer<H, S>
221where
222    H: ServerHandler,
223    S: SecurityProvider,
224{
225    pub fn new(
226        config: ServerConfig,
227        handler: H,
228        security_provider: S,
229        address: NodeAddress,
230    ) -> Self {
231        Self {
232            config,
233            handler,
234            security_provider,
235            address,
236            session: SessionState::new(),
237            security: SecurityState::new(),
238            periodic: PeriodicState::new(),
239            outbox: Vec::new(),
240        }
241    }
242
243    // region: SimNode surface
244
245    pub fn address(&self) -> &NodeAddress {
246        &self.address
247    }
248    pub fn session_type(&self) -> u8 {
249        self.session.session_type
250    }
251    pub fn security_level(&self) -> u8 {
252        self.session.security_level
253    }
254
255    /// Receives a raw UDS frame from `src`.
256    ///
257    /// Wraps the bytes in a [`UdsFrame`] and uses [`UdsFrameExt`] for
258    /// protocol-level decisions before dispatching to service handlers.
259    /// Typed message decode via `to_message()` is deferred to individual
260    /// handlers that need structured field access.
261    pub fn handle(
262        &mut self,
263        src: &NodeAddress,
264        data: &[u8],
265        now: Instant,
266    ) -> Result<(), ServerError<H::Error>> {
267        self.session.last_rx = now;
268
269        let frame = UdsFrame::from_slice(data);
270
271        // Validate frame has at minimum a SID byte
272        if let Err(e) = frame.validate() {
273            return Err(ServerError::Codec(e));
274        }
275
276        let sid = match frame.service_identifier() {
277            Some(s) => s,
278            None => return self.nrc_raw(src, 0x00, H::Error::service_not_supported().into(), now),
279        };
280
281        // Guard: service must be supported in the active session
282        let sid_byte = sid.discriminant();
283        if let Err(nrc) = self.guard_service(sid_byte) {
284            return self.nrc_raw(src, sid_byte, nrc, now);
285        }
286
287        // Suppress bit - extracted here at the frame level before any
288        // typed decode. Each handler receives this as a plain bool.
289        let suppressed = frame.is_suppressed();
290
291        match sid {
292            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::TesterPresent) => {
293                self.on_tester_present(src, &frame, suppressed, now)
294            }
295
296            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::DiagnosticSessionControl) => {
297                self.on_session_control(src, &frame, suppressed, now)
298            }
299
300            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::EcuReset) => {
301                self.on_ecu_reset(src, &frame, suppressed, now)
302            }
303
304            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::SecurityAccess) => {
305                self.on_security_access(src, &frame, suppressed, now)
306            }
307
308            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::ReadDataByIdentifier) => {
309                self.on_read_did(src, &frame, suppressed, now)
310            }
311
312            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::WriteDataByIdentifier) => {
313                self.on_write_did(src, &frame, suppressed, now)
314            }
315
316            ServiceIdentifier::UdsServiceRequest(
317                UdsServiceRequest::ReadDataByPeriodicIdentifier,
318            ) => self.on_periodic_did(src, &frame, suppressed, now),
319
320            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::RoutineControl) => {
321                self.on_routine_control(src, &frame, suppressed, now)
322            }
323
324            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::CommunicationControl) => {
325                self.on_communication_control(src, &frame, suppressed, now)
326            }
327
328            ServiceIdentifier::UdsServiceRequest(
329                UdsServiceRequest::InputOutputControlByIdentifier,
330            ) => self.on_io_control(src, &frame, suppressed, now),
331
332            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::RequestDownload) => {
333                self.on_request_download(src, &frame, suppressed, now)
334            }
335
336            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::TransferData) => {
337                self.on_transfer_data(src, &frame, suppressed, now)
338            }
339
340            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::RequestTransferExit) => {
341                self.on_transfer_exit(src, &frame, suppressed, now)
342            }
343
344            ServiceIdentifier::UdsServiceRequest(UdsServiceRequest::RequestFileTransfer) => {
345                self.on_file_transfer(src, &frame, suppressed, now)
346            }
347
348            _ => self.nrc_raw(src, sid_byte, H::Error::service_not_supported().into(), now),
349        }
350    }
351
352    /// Advances internal timers - S3 watchdog and periodic DID scheduling.
353    pub fn tick(&mut self, now: Instant) -> Result<(), ServerError<H::Error>> {
354        self.check_s3(now);
355        self.dispatch_periodic(now)
356    }
357
358    /// Drains pending outbound frames into `out`.
359    pub fn drain_outbox(
360        &mut self,
361        out: &mut Vec<(NodeAddress, Vec<u8, MAX_FRAME>), MAX_OUTBOX>,
362    ) -> usize {
363        let n = self.outbox.len();
364        for item in self.outbox.drain(..) {
365            let _ = out.push(item);
366        }
367        n
368    }
369
370    // endregion: SimNode surface
371
372    // region: Session helpers
373
374    fn current_session(&self) -> Option<&SessionConfig> {
375        self.config.find_session(self.session.session_type)
376    }
377
378    fn check_s3(&mut self, now: Instant) {
379        if self.session.is_default() {
380            return;
381        }
382        let s3 = self
383            .current_session()
384            .map(|s| s.s3_timeout)
385            .unwrap_or(Duration::from_millis(5_000));
386        if let Some(elapsed) = now.checked_duration_since(self.session.last_rx) {
387            if elapsed > s3 {
388                self.session.session_type = 0x01;
389                self.session.security_level = 0;
390                self.security.clear_pending();
391            }
392        }
393    }
394
395    fn guard_service(&self, sid: u8) -> Result<(), u8> {
396        if !self.config.service_allowed(sid, self.session.session_type) {
397            return Err(H::Error::service_not_supported_in_active_session().into());
398        }
399        Ok(())
400    }
401
402    fn guard_security(&self, required: u8) -> Result<(), u8> {
403        if required > 0 && self.session.security_level < required {
404            return Err(H::Error::security_access_denied().into());
405        }
406        Ok(())
407    }
408
409    // endregion: Session helpers
410
411    // region: Response helpers
412
413    fn enqueue(
414        &mut self,
415        dst: NodeAddress,
416        frame: Vec<u8, MAX_FRAME>,
417    ) -> Result<(), ServerError<H::Error>> {
418        self.outbox
419            .push((dst, frame))
420            .map_err(|_| ServerError::OutboxFull)
421    }
422
423    fn pos(
424        &mut self,
425        dst: &NodeAddress,
426        request_sid: u8,
427        payload: &[u8],
428        _now: Instant,
429    ) -> Result<(), ServerError<H::Error>> {
430        let mut frame: Vec<u8, MAX_FRAME> = Vec::new();
431        let _ = frame.push(request_sid | 0x40);
432        let _ = frame.extend_from_slice(payload);
433
434        self.enqueue(dst.clone(), frame)
435    }
436
437    fn nrc(
438        &mut self,
439        dst: &NodeAddress,
440        request_sid: u8,
441        error: H::Error,
442        _now: Instant,
443    ) -> Result<(), ServerError<H::Error>> {
444        let nrc_byte: u8 = error.into();
445        self.nrc_raw(dst, request_sid, nrc_byte, _now)
446    }
447
448    fn nrc_raw(
449        &mut self,
450        dst: &NodeAddress,
451        request_sid: u8,
452        nrc_byte: u8,
453        _now: Instant,
454    ) -> Result<(), ServerError<H::Error>> {
455        let mut frame: Vec<u8, MAX_FRAME> = Vec::new();
456        let _ = frame.push(0x7F);
457        let _ = frame.push(request_sid);
458        let _ = frame.push(nrc_byte);
459        self.enqueue(dst.clone(), frame)
460    }
461
462    // endregion: Response helpers
463
464    // region: Service handlers
465    //
466    // Each handler receives:
467    //   - `frame` - the raw UdsFrame for sub-function/payload access
468    //   - `suppressed` - suppress bit already extracted at dispatch
469    //
470    // Typed decode via `frame.to_message()` is used only where structured
471    // field access is needed. Services that only need the sub-function value
472    // and a payload slice never allocate a typed message.
473
474    fn on_tester_present(
475        &mut self,
476        src: &NodeAddress,
477        frame: &UdsFrame<'_>,
478        suppressed: bool,
479        now: Instant,
480    ) -> Result<(), ServerError<H::Error>> {
481        // TesterPresent: sub-function is always 0x00.
482        // The only meaningful information is the suppress bit.
483        if suppressed {
484            return Ok(());
485        }
486        // Echo sub-function value (suppress bit cleared) in response.
487        let sf = frame.sub_function_value().unwrap_or(0x00);
488        self.pos(src, 0x3E, &[sf], now)
489    }
490
491    fn on_session_control(
492        &mut self,
493        src: &NodeAddress,
494        frame: &UdsFrame<'_>,
495        suppressed: bool,
496        now: Instant,
497    ) -> Result<(), ServerError<H::Error>> {
498        // Sub-function value IS the session type byte.
499        let session_type = match frame.sub_function_value() {
500            Some(v) => v,
501            None => {
502                return self.nrc(
503                    src,
504                    0x10,
505                    H::Error::incorrect_message_length_or_invalid_format(),
506                    now,
507                )
508            }
509        };
510
511        if self.config.find_session(session_type).is_none() {
512            return self.nrc(src, 0x10, H::Error::sub_function_not_supported(), now);
513        }
514
515        self.session.session_type = session_type;
516        self.session.security_level = 0;
517        self.session.last_rx = now;
518        self.security.clear_pending();
519
520        if suppressed {
521            return Ok(());
522        }
523
524        let (p2_ms, p2_ext_ms) = self
525            .config
526            .find_session(session_type)
527            .map(|s| {
528                (
529                    s.p2_timeout.as_millis(),
530                    s.p2_extended_timeout.as_millis() / 10,
531                )
532            })
533            .unwrap_or((50, 500));
534
535        let payload = [
536            session_type,
537            (p2_ms >> 8) as u8,
538            p2_ms as u8,
539            (p2_ext_ms >> 8) as u8,
540            p2_ext_ms as u8,
541        ];
542        self.pos(src, 0x10, &payload, now)
543    }
544
545    fn on_ecu_reset(
546        &mut self,
547        src: &NodeAddress,
548        frame: &UdsFrame<'_>,
549        suppressed: bool,
550        now: Instant,
551    ) -> Result<(), ServerError<H::Error>> {
552        // Sub-function value IS the reset type byte.
553        let reset_type = match frame.sub_function_value() {
554            Some(v) => v,
555            None => {
556                return self.nrc(
557                    src,
558                    0x11,
559                    H::Error::incorrect_message_length_or_invalid_format(),
560                    now,
561                )
562            }
563        };
564
565        if !suppressed {
566            self.pos(src, 0x11, &[reset_type], now)?;
567        }
568
569        self.handler
570            .ecu_reset(reset_type)
571            .map_err(ServerError::Handler)
572    }
573
574    fn on_security_access(
575        &mut self,
576        src: &NodeAddress,
577        frame: &UdsFrame<'_>,
578        _suppressed: bool, // SecurityAccess has no suppress bit
579        now: Instant,
580    ) -> Result<(), ServerError<H::Error>> {
581        // Access type byte: odd = RequestSeed, even = SendKey.
582        let access_type = match frame.sub_function_value() {
583            Some(v) => v,
584            None => {
585                return self.nrc(
586                    src,
587                    0x27,
588                    H::Error::incorrect_message_length_or_invalid_format(),
589                    now,
590                )
591            }
592        };
593
594        let is_request_seed = access_type % 2 != 0;
595
596        if is_request_seed {
597            let level = access_type;
598
599            if self.security.is_locked(level, now) {
600                return self.nrc(src, 0x27, H::Error::required_time_delay_not_expired(), now);
601            }
602            if self.config.find_security_level(level).is_none() {
603                return self.nrc(src, 0x27, H::Error::sub_function_not_supported(), now);
604            }
605
606            let mut seed_buf = [0u8; MAX_SEED];
607            let seed_len = self
608                .security_provider
609                .generate_seed(level, &mut seed_buf)
610                .map_err(|_| ServerError::Handler(H::Error::conditions_not_correct()))?;
611
612            self.security.pending_seed.clear();
613            let _ = self
614                .security
615                .pending_seed
616                .extend_from_slice(&seed_buf[..seed_len]);
617            self.security.pending_level = level;
618
619            let mut payload: Vec<u8, { MAX_SEED + 1 }> = Vec::new();
620            let _ = payload.push(level);
621            let _ = payload.extend_from_slice(&seed_buf[..seed_len]);
622            self.pos(src, 0x27, &payload, now)
623        } else {
624            // SendKey - key bytes are the payload after the sub-function byte.
625            let level = access_type - 1; // RequestSeed level
626
627            if self.security.is_locked(level, now) {
628                return self.nrc(src, 0x27, H::Error::required_time_delay_not_expired(), now);
629            }
630            if self.security.pending_level != level || self.security.pending_seed.is_empty() {
631                return self.nrc(src, 0x27, H::Error::request_sequence_error(), now);
632            }
633
634            // Key bytes are the payload after the access_type byte.
635            // frame.payload() is everything after SID - key starts at payload[1].
636            let key = frame.payload().get(1..).unwrap_or(&[]);
637
638            let level_cfg = self.config.find_security_level(level);
639            let max_attempts = level_cfg.map(|l| l.max_attempts).unwrap_or(3);
640            let lockout_dur = level_cfg
641                .map(|l| l.lockout_duration)
642                .unwrap_or(Duration::from_millis(10_000));
643
644            let seed = self.security.pending_seed.clone();
645
646            match self.security_provider.validate_key(level, &seed, key) {
647                Ok(()) => {
648                    self.security.reset_failed(level);
649                    self.security.clear_pending();
650                    self.session.security_level = level;
651                    self.pos(src, 0x27, &[access_type], now)
652                }
653                Err(_) => {
654                    self.security.increment_failed(level);
655                    if self.security.failed_count(level) >= max_attempts {
656                        self.security.set_lockout(level, now + lockout_dur);
657                        return self.nrc(src, 0x27, H::Error::exceeded_number_of_attempts(), now);
658                    }
659                    self.nrc(src, 0x27, H::Error::invalid_key(), now)
660                }
661            }
662        }
663    }
664
665    fn on_read_did(
666        &mut self,
667        src: &NodeAddress,
668        frame: &UdsFrame<'_>,
669        _suppressed: bool, // ReadDataByIdentifier has no sub-function
670        now: Instant,
671    ) -> Result<(), ServerError<H::Error>> {
672        // Payload is pairs of DID bytes: [DID_high, DID_low, DID_high, DID_low, ...]
673        let payload = frame.payload();
674        if payload.len() < 2 || payload.len() % 2 != 0 {
675            return self.nrc(
676                src,
677                0x22,
678                H::Error::incorrect_message_length_or_invalid_format(),
679                now,
680            );
681        }
682
683        let mut resp: Vec<u8, MAX_FRAME> = Vec::new();
684
685        for chunk in payload.chunks_exact(2) {
686            let did = u16::from_be_bytes([chunk[0], chunk[1]]);
687
688            if !self.config.did_readable(did, self.session.session_type) {
689                return self.nrc(src, 0x22, H::Error::request_out_of_range(), now);
690            }
691            let required_sec = self
692                .config
693                .find_did(did)
694                .map(|d| d.security_level)
695                .unwrap_or(0);
696            if let Err(nrc) = self.guard_security(required_sec) {
697                return self.nrc_raw(src, 0x22, nrc, now);
698            }
699
700            let _ = resp.push(chunk[0]);
701            let _ = resp.push(chunk[1]);
702
703            let mut data_buf = [0u8; MAX_DATA_BUF];
704            let len = self
705                .handler
706                .read_did(did, &mut data_buf)
707                .map_err(ServerError::Handler)?;
708            let _ = resp.extend_from_slice(&data_buf[..len]);
709        }
710
711        self.pos(src, 0x22, &resp, now)
712    }
713
714    fn on_write_did(
715        &mut self,
716        src: &NodeAddress,
717        frame: &UdsFrame<'_>,
718        _suppressed: bool,
719        now: Instant,
720    ) -> Result<(), ServerError<H::Error>> {
721        let payload = frame.payload();
722        if payload.len() < 3 {
723            return self.nrc(
724                src,
725                0x2E,
726                H::Error::incorrect_message_length_or_invalid_format(),
727                now,
728            );
729        }
730
731        let did = u16::from_be_bytes([payload[0], payload[1]]);
732        let data_rec = &payload[2..];
733
734        if !self.config.did_writable(did, self.session.session_type) {
735            return self.nrc(src, 0x2E, H::Error::request_out_of_range(), now);
736        }
737        let required_sec = self
738            .config
739            .find_did(did)
740            .map(|d| d.security_level)
741            .unwrap_or(0);
742        if let Err(nrc) = self.guard_security(required_sec) {
743            return self.nrc_raw(src, 0x2E, nrc, now);
744        }
745
746        self.handler
747            .write_did(did, data_rec)
748            .map_err(ServerError::Handler)?;
749
750        self.pos(src, 0x2E, &payload[..2], now)
751    }
752
753    fn on_periodic_did(
754        &mut self,
755        src: &NodeAddress,
756        frame: &UdsFrame<'_>,
757        _suppressed: bool,
758        now: Instant,
759    ) -> Result<(), ServerError<H::Error>> {
760        let payload = frame.payload();
761        if payload.is_empty() {
762            return self.nrc(
763                src,
764                0x2A,
765                H::Error::incorrect_message_length_or_invalid_format(),
766                now,
767            );
768        }
769
770        // Byte 0 is transmission mode, remaining bytes are periodic DID identifiers.
771        let mode = payload[0];
772        let periodic_ids = payload.get(1..).unwrap_or(&[]);
773
774        match mode {
775            // stopSending
776            0x04 => {
777                for &id in periodic_ids {
778                    self.periodic.cancel(0xF200u16 | id as u16, src);
779                }
780                self.pos(src, 0x2A, &[mode], now)
781            }
782            0x01 | 0x02 | 0x03 => {
783                let requested_interval = match mode {
784                    0x01 => periodic::SLOW,
785                    0x02 => periodic::MEDIUM,
786                    _ => periodic::FAST,
787                };
788
789                for &id in periodic_ids {
790                    let did = 0xF200u16 | id as u16;
791
792                    if !self.config.did_readable(did, self.session.session_type) {
793                        return self.nrc(src, 0x2A, H::Error::request_out_of_range(), now);
794                    }
795
796                    let effective = self
797                        .config
798                        .find_did(did)
799                        .map(|d| requested_interval.max(d.min_periodic_interval))
800                        .unwrap_or(requested_interval);
801
802                    self.periodic.register(did, effective, src.clone(), now);
803                }
804
805                self.pos(src, 0x2A, &[mode], now)
806            }
807            _ => self.nrc(src, 0x2A, H::Error::sub_function_not_supported(), now),
808        }
809    }
810
811    fn on_routine_control(
812        &mut self,
813        src: &NodeAddress,
814        frame: &UdsFrame<'_>,
815        suppressed: bool,
816        now: Instant,
817    ) -> Result<(), ServerError<H::Error>> {
818        // Sub-function value is the routine control type (0x01/0x02/0x03).
819        // Payload after SID: [sub_function, routine_id_high, routine_id_low, option_record...]
820        let payload = frame.payload();
821        if payload.len() < 3 {
822            return self.nrc(
823                src,
824                0x31,
825                H::Error::incorrect_message_length_or_invalid_format(),
826                now,
827            );
828        }
829
830        let sub_function = frame.sub_function_value().unwrap_or(0);
831        let routine_id = u16::from_be_bytes([payload[1], payload[2]]);
832        let option_record = payload.get(3..).unwrap_or(&[]);
833
834        let mut buf = [0u8; MAX_DATA_BUF];
835        let len = self
836            .handler
837            .routine_control(routine_id, sub_function, option_record, &mut buf)
838            .map_err(ServerError::Handler)?;
839
840        if suppressed {
841            return Ok(());
842        }
843
844        let mut resp: Vec<u8, { MAX_DATA_BUF + 3 }> = Vec::new();
845        let _ = resp.push(sub_function);
846        let _ = resp.push(payload[1]);
847        let _ = resp.push(payload[2]);
848        let _ = resp.extend_from_slice(&buf[..len]);
849        self.pos(src, 0x31, &resp, now)
850    }
851
852    fn on_communication_control(
853        &mut self,
854        src: &NodeAddress,
855        frame: &UdsFrame<'_>,
856        suppressed: bool,
857        now: Instant,
858    ) -> Result<(), ServerError<H::Error>> {
859        let payload = frame.payload();
860        if payload.len() < 2 {
861            return self.nrc(
862                src,
863                0x28,
864                H::Error::incorrect_message_length_or_invalid_format(),
865                now,
866            );
867        }
868
869        let control_type = frame.sub_function_value().unwrap_or(0);
870        let comm_type = payload[1];
871
872        self.handler
873            .communication_control(control_type, comm_type)
874            .map_err(ServerError::Handler)?;
875
876        if suppressed {
877            return Ok(());
878        }
879
880        self.pos(src, 0x28, &[control_type], now)
881    }
882
883    fn on_io_control(
884        &mut self,
885        src: &NodeAddress,
886        frame: &UdsFrame<'_>,
887        _suppressed: bool,
888        now: Instant,
889    ) -> Result<(), ServerError<H::Error>> {
890        let payload = frame.payload();
891        if payload.len() < 3 {
892            return self.nrc(
893                src,
894                0x2F,
895                H::Error::incorrect_message_length_or_invalid_format(),
896                now,
897            );
898        }
899
900        let did = u16::from_be_bytes([payload[0], payload[1]]);
901        let control_param = payload[2];
902        let control_state = payload.get(3..).unwrap_or(&[]);
903
904        let mut buf = [0u8; MAX_DATA_BUF];
905        let len = self
906            .handler
907            .io_control(did, control_param, control_state, &mut buf)
908            .map_err(ServerError::Handler)?;
909
910        let mut resp: Vec<u8, { MAX_DATA_BUF + 2 }> = Vec::new();
911        let _ = resp.push(payload[0]);
912        let _ = resp.push(payload[1]);
913        let _ = resp.extend_from_slice(&buf[..len]);
914        self.pos(src, 0x2F, &resp, now)
915    }
916
917    fn on_request_download(
918        &mut self,
919        src: &NodeAddress,
920        frame: &UdsFrame<'_>,
921        _suppressed: bool,
922        now: Instant,
923    ) -> Result<(), ServerError<H::Error>> {
924        // Payload: [data_format_identifier, address_and_length_format,
925        //           memory_address..., memory_size...]
926        let payload = frame.payload();
927        if payload.len() < 3 {
928            return self.nrc(
929                src,
930                0x34,
931                H::Error::incorrect_message_length_or_invalid_format(),
932                now,
933            );
934        }
935
936        let data_format = payload[0];
937        let addr_and_len_format = payload[1];
938        let addr_len = (addr_and_len_format >> 4) as usize;
939        let size_len = (addr_and_len_format & 0x0F) as usize;
940
941        if payload.len() < 2 + addr_len + size_len {
942            return self.nrc(
943                src,
944                0x34,
945                H::Error::incorrect_message_length_or_invalid_format(),
946                now,
947            );
948        }
949
950        let memory_address = &payload[2..2 + addr_len];
951        let memory_size = &payload[2 + addr_len..2 + addr_len + size_len];
952
953        let mut buf = [0u8; 64];
954        let len = self
955            .handler
956            .request_download(memory_address, memory_size, data_format, 0, &mut buf)
957            .map_err(ServerError::Handler)?;
958
959        self.pos(src, 0x34, &buf[..len], now)
960    }
961
962    fn on_transfer_data(
963        &mut self,
964        src: &NodeAddress,
965        frame: &UdsFrame<'_>,
966        _suppressed: bool,
967        now: Instant,
968    ) -> Result<(), ServerError<H::Error>> {
969        let payload = frame.payload();
970        if payload.is_empty() {
971            return self.nrc(
972                src,
973                0x36,
974                H::Error::incorrect_message_length_or_invalid_format(),
975                now,
976            );
977        }
978
979        let block_seq = payload[0];
980        let data = payload.get(1..).unwrap_or(&[]);
981
982        let mut buf = [0u8; MAX_DATA_BUF];
983        let len = self
984            .handler
985            .transfer_data(block_seq, data, &mut buf)
986            .map_err(ServerError::Handler)?;
987
988        let mut resp: Vec<u8, { MAX_DATA_BUF + 1 }> = Vec::new();
989        let _ = resp.push(block_seq);
990        let _ = resp.extend_from_slice(&buf[..len]);
991        self.pos(src, 0x36, &resp, now)
992    }
993
994    fn on_transfer_exit(
995        &mut self,
996        src: &NodeAddress,
997        frame: &UdsFrame<'_>,
998        _suppressed: bool,
999        now: Instant,
1000    ) -> Result<(), ServerError<H::Error>> {
1001        let parameter_record = frame.payload();
1002
1003        let mut buf = [0u8; MAX_DATA_BUF];
1004        let len = self
1005            .handler
1006            .request_transfer_exit(parameter_record, &mut buf)
1007            .map_err(ServerError::Handler)?;
1008
1009        self.pos(src, 0x37, &buf[..len], now)
1010    }
1011
1012    fn on_file_transfer(
1013        &mut self,
1014        src: &NodeAddress,
1015        frame: &UdsFrame<'_>,
1016        _suppressed: bool,
1017        now: Instant,
1018    ) -> Result<(), ServerError<H::Error>> {
1019        let payload = frame.payload();
1020        if payload.len() < 3 {
1021            return self.nrc(
1022                src,
1023                0x38,
1024                H::Error::incorrect_message_length_or_invalid_format(),
1025                now,
1026            );
1027        }
1028
1029        let operation = payload[0];
1030        // Bytes 1-2 are file path length (big-endian u16), rest is path
1031        let path_len = u16::from_be_bytes([payload[1], payload[2]]) as usize;
1032        let path = payload.get(3..3 + path_len).unwrap_or(&[]);
1033
1034        let mut buf = [0u8; MAX_DATA_BUF];
1035        let len = self
1036            .handler
1037            .request_file_transfer(operation, path, &mut buf)
1038            .map_err(ServerError::Handler)?;
1039
1040        self.pos(src, 0x38, &buf[..len], now)
1041    }
1042
1043    // endregion: Service handlers
1044
1045    // region: Periodic dispatch
1046
1047    fn dispatch_periodic(&mut self, now: Instant) -> Result<(), ServerError<H::Error>> {
1048        let mut due: Vec<(u16, NodeAddress), MAX_PERIODIC> = Vec::new();
1049        self.periodic.collect_due(now, &mut due);
1050
1051        for (did, client) in &due {
1052            let mut data_buf = [0u8; MAX_DATA_BUF];
1053            let len = self
1054                .handler
1055                .read_did(*did, &mut data_buf)
1056                .map_err(ServerError::Handler)?;
1057
1058            // [periodic_data_identifier (1 byte), data_record (n bytes)]
1059            let did_low = (*did & 0xFF) as u8;
1060            let mut frame = Vec::new();
1061            let _ = frame.push(did_low);
1062            let _ = frame.extend_from_slice(&data_buf[..len]);
1063
1064            self.enqueue(client.clone(), frame)?;
1065            self.periodic.advance(*did, client, now);
1066        }
1067
1068        Ok(())
1069    }
1070
1071    // endregion: Periodic dispatch
1072}
1073
1074// endregion: UdsServer