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