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