Skip to main content

ace_server/
server.rs

1// region: Imports
2
3use ace_core::Vec;
4use ace_proto::uds::UdsFrame;
5use ace_sim::clock::{Duration, Instant};
6use ace_sim::io::NodeAddress;
7use ace_uds::ext::UdsFrameExt;
8use ace_uds::message::service::UdsServiceRequest;
9use ace_uds::message::ServiceIdentifier;
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        if self.outbox.len() >= MAX_OUTBOX {
457            return Err(ServerError::OutboxFull);
458        } else {
459            self.outbox.push((dst, frame));
460
461            Ok(())
462        }
463    }
464
465    fn pos(
466        &mut self,
467        dst: &NodeAddress,
468        request_sid: u8,
469        payload: &[u8],
470        _now: Instant,
471    ) -> Result<(), ServerError<H::Error>> {
472        let mut frame: Vec<u8, MAX_FRAME> = Vec::new();
473        let _ = frame.push(request_sid | 0x40);
474        let _ = frame.extend_from_slice(payload);
475
476        self.enqueue(dst.clone(), frame)
477    }
478
479    fn nrc(
480        &mut self,
481        dst: &NodeAddress,
482        request_sid: u8,
483        error: H::Error,
484        _now: Instant,
485    ) -> Result<(), ServerError<H::Error>> {
486        let nrc_byte: u8 = error.into();
487        self.nrc_raw(dst, request_sid, nrc_byte, _now)
488    }
489
490    fn nrc_raw(
491        &mut self,
492        dst: &NodeAddress,
493        request_sid: u8,
494        nrc_byte: u8,
495        _now: Instant,
496    ) -> Result<(), ServerError<H::Error>> {
497        let mut frame: Vec<u8, MAX_FRAME> = Vec::new();
498        let _ = frame.push(0x7F);
499        let _ = frame.push(request_sid);
500        let _ = frame.push(nrc_byte);
501        self.enqueue(dst.clone(), frame)
502    }
503
504    // endregion: Response helpers
505
506    // region: Service handlers
507    //
508    // Each handler receives:
509    //   - `frame` - the raw UdsFrame for sub-function/payload access
510    //   - `suppressed` - suppress bit already extracted at dispatch
511    //
512    // Typed decode via `frame.to_message()` is used only where structured
513    // field access is needed. Services that only need the sub-function value
514    // and a payload slice never allocate a typed message.
515
516    fn on_tester_present(
517        &mut self,
518        src: &NodeAddress,
519        frame: &UdsFrame<'_>,
520        suppressed: bool,
521        now: Instant,
522    ) -> Result<(), ServerError<H::Error>> {
523        // TesterPresent: sub-function is always 0x00.
524        // The only meaningful information is the suppress bit.
525        if suppressed {
526            return Ok(());
527        }
528        // Echo sub-function value (suppress bit cleared) in response.
529        let sf = frame.sub_function_value().unwrap_or(0x00);
530        self.pos(src, 0x3E, &[sf], now)
531    }
532
533    fn on_session_control(
534        &mut self,
535        src: &NodeAddress,
536        frame: &UdsFrame<'_>,
537        suppressed: bool,
538        now: Instant,
539    ) -> Result<(), ServerError<H::Error>> {
540        // Sub-function value IS the session type byte.
541        let session_type = match frame.sub_function_value() {
542            Some(v) => v,
543            None => {
544                return self.nrc(
545                    src,
546                    0x10,
547                    H::Error::incorrect_message_length_or_invalid_format(),
548                    now,
549                )
550            }
551        };
552
553        if self.config.find_session(session_type).is_none() {
554            return self.nrc(src, 0x10, H::Error::sub_function_not_supported(), now);
555        }
556
557        self.session.session_type = session_type;
558        self.session.security_level = 0;
559        self.session.last_rx = now;
560        self.security.clear_pending();
561
562        if suppressed {
563            return Ok(());
564        }
565
566        let (p2_ms, p2_ext_ms) = self
567            .config
568            .find_session(session_type)
569            .map(|s| {
570                (
571                    s.p2_timeout.as_millis(),
572                    s.p2_extended_timeout.as_millis() / 10,
573                )
574            })
575            .unwrap_or((DEFAULT_P2, DEFAULT_P2_EXT));
576
577        let payload = [
578            session_type,
579            (p2_ms >> 8) as u8,
580            p2_ms as u8,
581            (p2_ext_ms >> 8) as u8,
582            p2_ext_ms as u8,
583        ];
584        self.pos(src, 0x10, &payload, now)
585    }
586
587    fn on_ecu_reset(
588        &mut self,
589        src: &NodeAddress,
590        frame: &UdsFrame<'_>,
591        suppressed: bool,
592        now: Instant,
593    ) -> Result<(), ServerError<H::Error>> {
594        // Sub-function value IS the reset type byte.
595        let reset_type = match frame.sub_function_value() {
596            Some(v) => v,
597            None => {
598                return self.nrc(
599                    src,
600                    0x11,
601                    H::Error::incorrect_message_length_or_invalid_format(),
602                    now,
603                )
604            }
605        };
606
607        if !suppressed {
608            self.pos(src, 0x11, &[reset_type], now)?;
609        }
610
611        self.handler
612            .ecu_reset(reset_type)
613            .map_err(ServerError::Handler)
614    }
615
616    fn on_security_access(
617        &mut self,
618        src: &NodeAddress,
619        frame: &UdsFrame<'_>,
620        _suppressed: bool, // SecurityAccess has no suppress bit
621        now: Instant,
622    ) -> Result<(), ServerError<H::Error>> {
623        // Access type byte: odd = RequestSeed, even = SendKey.
624        let access_type = match frame.sub_function_value() {
625            Some(v) => v,
626            None => {
627                return self.nrc(
628                    src,
629                    0x27,
630                    H::Error::incorrect_message_length_or_invalid_format(),
631                    now,
632                )
633            }
634        };
635
636        let is_request_seed = access_type % 2 != 0;
637
638        if is_request_seed {
639            let level = access_type;
640
641            if self.security.is_locked(level, now) {
642                return self.nrc(src, 0x27, H::Error::required_time_delay_not_expired(), now);
643            }
644            if self.config.find_security_level(level).is_none() {
645                return self.nrc(src, 0x27, H::Error::sub_function_not_supported(), now);
646            }
647
648            let mut seed_buf = [0u8; MAX_SEED];
649            let seed_len = self
650                .security_provider
651                .generate_seed(level, &mut seed_buf)
652                .map_err(|_| ServerError::Handler(H::Error::conditions_not_correct()))?;
653
654            self.security.pending_seed.clear();
655            let _ = self
656                .security
657                .pending_seed
658                .extend_from_slice(&seed_buf[..seed_len]);
659            self.security.pending_level = level;
660
661            let mut payload: Vec<u8, MAX_SEED> = Vec::new();
662            let _ = payload.push(level);
663            let _ = payload.extend_from_slice(&seed_buf[..seed_len]);
664            self.pos(src, 0x27, &payload, now)
665        } else {
666            // SendKey - key bytes are the payload after the sub-function byte.
667            let level = access_type - 1; // RequestSeed level
668
669            if self.security.is_locked(level, now) {
670                return self.nrc(src, 0x27, H::Error::required_time_delay_not_expired(), now);
671            }
672            if self.security.pending_level != level || self.security.pending_seed.is_empty() {
673                return self.nrc(src, 0x27, H::Error::request_sequence_error(), now);
674            }
675
676            // Key bytes are the payload after the access_type byte.
677            // frame.payload() is everything after SID - key starts at payload[1].
678            let key = frame.payload().get(1..).unwrap_or(&[]);
679
680            let level_cfg = self.config.find_security_level(level);
681            let max_attempts = level_cfg
682                .map(|l| l.max_attempts)
683                .unwrap_or(DEFAULT_MAX_SECURITY_ATTEMPTS);
684            let lockout_dur = level_cfg
685                .map(|l| l.lockout_duration)
686                .unwrap_or(Duration::from_millis(DEFAULT_LOCKOUT));
687
688            let seed = self.security.pending_seed.clone();
689
690            match self.security_provider.validate_key(level, &seed, key) {
691                Ok(()) => {
692                    self.security.reset_failed(level);
693                    self.security.clear_pending();
694                    self.session.security_level = level;
695                    self.pos(src, 0x27, &[access_type], now)
696                }
697                Err(_) => {
698                    self.security.increment_failed(level);
699                    if self.security.failed_count(level) >= max_attempts {
700                        self.security.set_lockout(level, now + lockout_dur);
701                        return self.nrc(src, 0x27, H::Error::exceeded_number_of_attempts(), now);
702                    }
703                    self.nrc(src, 0x27, H::Error::invalid_key(), now)
704                }
705            }
706        }
707    }
708
709    fn on_read_did(
710        &mut self,
711        src: &NodeAddress,
712        frame: &UdsFrame<'_>,
713        _suppressed: bool, // ReadDataByIdentifier has no sub-function
714        now: Instant,
715    ) -> Result<(), ServerError<H::Error>> {
716        // Payload is pairs of DID bytes: [DID_high, DID_low, DID_high, DID_low, ...]
717        let payload = frame.payload();
718        if payload.len() < 2 || payload.len() % 2 != 0 {
719            return self.nrc(
720                src,
721                0x22,
722                H::Error::incorrect_message_length_or_invalid_format(),
723                now,
724            );
725        }
726
727        let mut resp: Vec<u8, MAX_FRAME> = Vec::new();
728
729        for chunk in payload.chunks_exact(2) {
730            let did = u16::from_be_bytes([chunk[0], chunk[1]]);
731
732            if !self.config.did_readable(did, self.session.session_type) {
733                return self.nrc(src, 0x22, 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, 0x22, nrc, now);
742            }
743
744            let _ = resp.push(chunk[0]);
745            let _ = resp.push(chunk[1]);
746
747            let mut data_buf = [0u8; MAX_FRAME];
748            let len = self
749                .handler
750                .read_did(did, &mut data_buf)
751                .map_err(ServerError::Handler)?;
752            let _ = resp.extend_from_slice(&data_buf[..len]);
753        }
754
755        self.pos(src, 0x22, &resp, now)
756    }
757
758    fn on_write_did(
759        &mut self,
760        src: &NodeAddress,
761        frame: &UdsFrame<'_>,
762        _suppressed: bool,
763        now: Instant,
764    ) -> Result<(), ServerError<H::Error>> {
765        let payload = frame.payload();
766        if payload.len() < 3 {
767            return self.nrc(
768                src,
769                0x2E,
770                H::Error::incorrect_message_length_or_invalid_format(),
771                now,
772            );
773        }
774
775        let did = u16::from_be_bytes([payload[0], payload[1]]);
776        let data_rec = &payload[2..];
777
778        if !self.config.did_writable(did, self.session.session_type) {
779            return self.nrc(src, 0x2E, H::Error::request_out_of_range(), now);
780        }
781        let required_sec = self
782            .config
783            .find_did(did)
784            .map(|d| d.security_level)
785            .unwrap_or(0);
786        if let Err(nrc) = self.guard_security(required_sec) {
787            return self.nrc_raw(src, 0x2E, nrc, now);
788        }
789
790        self.handler
791            .write_did(did, data_rec)
792            .map_err(ServerError::Handler)?;
793
794        self.pos(src, 0x2E, &payload[..2], now)
795    }
796
797    fn on_periodic_did(
798        &mut self,
799        src: &NodeAddress,
800        frame: &UdsFrame<'_>,
801        _suppressed: bool,
802        now: Instant,
803    ) -> Result<(), ServerError<H::Error>> {
804        let payload = frame.payload();
805        if payload.is_empty() {
806            return self.nrc(
807                src,
808                0x2A,
809                H::Error::incorrect_message_length_or_invalid_format(),
810                now,
811            );
812        }
813
814        // Byte 0 is transmission mode, remaining bytes are periodic DID identifiers.
815        let mode = payload[0];
816        let periodic_ids = payload.get(1..).unwrap_or(&[]);
817
818        match mode {
819            // stopSending
820            0x04 => {
821                for &id in periodic_ids {
822                    self.periodic.cancel(0xF200u16 | id as u16, src);
823                }
824                self.pos(src, 0x2A, &[mode], now)
825            }
826            0x01 | 0x02 | 0x03 => {
827                let requested_interval = match mode {
828                    0x01 => periodic::SLOW,
829                    0x02 => periodic::MEDIUM,
830                    _ => periodic::FAST,
831                };
832
833                for &id in periodic_ids {
834                    let did = 0xF200u16 | id as u16;
835
836                    if !self.config.did_readable(did, self.session.session_type) {
837                        return self.nrc(src, 0x2A, H::Error::request_out_of_range(), now);
838                    }
839
840                    let effective = self
841                        .config
842                        .find_did(did)
843                        .map(|d| requested_interval.max(d.min_periodic_interval))
844                        .unwrap_or(requested_interval);
845
846                    self.periodic.register(did, effective, src.clone(), now);
847                }
848
849                self.pos(src, 0x2A, &[mode], now)
850            }
851            _ => self.nrc(src, 0x2A, H::Error::sub_function_not_supported(), now),
852        }
853    }
854
855    fn on_routine_control(
856        &mut self,
857        src: &NodeAddress,
858        frame: &UdsFrame<'_>,
859        suppressed: bool,
860        now: Instant,
861    ) -> Result<(), ServerError<H::Error>> {
862        // Sub-function value is the routine control type (0x01/0x02/0x03).
863        // Payload after SID: [sub_function, routine_id_high, routine_id_low, option_record...]
864        let payload = frame.payload();
865        if payload.len() < 3 {
866            return self.nrc(
867                src,
868                0x31,
869                H::Error::incorrect_message_length_or_invalid_format(),
870                now,
871            );
872        }
873
874        let sub_function = frame.sub_function_value().unwrap_or(0);
875        let routine_id = u16::from_be_bytes([payload[1], payload[2]]);
876        let option_record = payload.get(3..).unwrap_or(&[]);
877
878        let mut buf = [0u8; MAX_FRAME];
879        let len = self
880            .handler
881            .routine_control(routine_id, sub_function, option_record, &mut buf)
882            .map_err(ServerError::Handler)?;
883
884        if suppressed {
885            return Ok(());
886        }
887
888        let mut resp: Vec<u8, MAX_FRAME> = Vec::new();
889        let _ = resp.push(sub_function);
890        let _ = resp.push(payload[1]);
891        let _ = resp.push(payload[2]);
892        let _ = resp.extend_from_slice(&buf[..len]);
893        self.pos(src, 0x31, &resp, now)
894    }
895
896    fn on_communication_control(
897        &mut self,
898        src: &NodeAddress,
899        frame: &UdsFrame<'_>,
900        suppressed: bool,
901        now: Instant,
902    ) -> Result<(), ServerError<H::Error>> {
903        let payload = frame.payload();
904        if payload.len() < 2 {
905            return self.nrc(
906                src,
907                0x28,
908                H::Error::incorrect_message_length_or_invalid_format(),
909                now,
910            );
911        }
912
913        let control_type = frame.sub_function_value().unwrap_or(0);
914        let comm_type = payload[1];
915
916        self.handler
917            .communication_control(control_type, comm_type)
918            .map_err(ServerError::Handler)?;
919
920        if suppressed {
921            return Ok(());
922        }
923
924        self.pos(src, 0x28, &[control_type], now)
925    }
926
927    fn on_io_control(
928        &mut self,
929        src: &NodeAddress,
930        frame: &UdsFrame<'_>,
931        _suppressed: bool,
932        now: Instant,
933    ) -> Result<(), ServerError<H::Error>> {
934        let payload = frame.payload();
935        if payload.len() < 3 {
936            return self.nrc(
937                src,
938                0x2F,
939                H::Error::incorrect_message_length_or_invalid_format(),
940                now,
941            );
942        }
943
944        let did = u16::from_be_bytes([payload[0], payload[1]]);
945        let control_param = payload[2];
946        let control_state = payload.get(3..).unwrap_or(&[]);
947
948        let mut buf = [0u8; MAX_FRAME];
949        let len = self
950            .handler
951            .io_control(did, control_param, control_state, &mut buf)
952            .map_err(ServerError::Handler)?;
953
954        let mut resp: Vec<u8, MAX_FRAME> = Vec::new();
955        let _ = resp.push(payload[0]);
956        let _ = resp.push(payload[1]);
957        let _ = resp.extend_from_slice(&buf[..len]);
958        self.pos(src, 0x2F, &resp, now)
959    }
960
961    fn on_request_download(
962        &mut self,
963        src: &NodeAddress,
964        frame: &UdsFrame<'_>,
965        _suppressed: bool,
966        now: Instant,
967    ) -> Result<(), ServerError<H::Error>> {
968        // Payload: [data_format_identifier, address_and_length_format,
969        //           memory_address..., memory_size...]
970        let payload = frame.payload();
971        if payload.len() < 3 {
972            return self.nrc(
973                src,
974                0x34,
975                H::Error::incorrect_message_length_or_invalid_format(),
976                now,
977            );
978        }
979
980        let data_format = payload[0];
981        let addr_and_len_format = payload[1];
982        let addr_len = (addr_and_len_format >> 4) as usize;
983        let size_len = (addr_and_len_format & 0x0F) as usize;
984
985        if payload.len() < 2 + addr_len + size_len {
986            return self.nrc(
987                src,
988                0x34,
989                H::Error::incorrect_message_length_or_invalid_format(),
990                now,
991            );
992        }
993
994        let memory_address = &payload[2..2 + addr_len];
995        let memory_size = &payload[2 + addr_len..2 + addr_len + size_len];
996
997        let mut buf = [0u8; 64];
998        let len = self
999            .handler
1000            .request_download(memory_address, memory_size, data_format, 0, &mut buf)
1001            .map_err(ServerError::Handler)?;
1002
1003        self.pos(src, 0x34, &buf[..len], now)
1004    }
1005
1006    fn on_transfer_data(
1007        &mut self,
1008        src: &NodeAddress,
1009        frame: &UdsFrame<'_>,
1010        _suppressed: bool,
1011        now: Instant,
1012    ) -> Result<(), ServerError<H::Error>> {
1013        let payload = frame.payload();
1014        if payload.is_empty() {
1015            return self.nrc(
1016                src,
1017                0x36,
1018                H::Error::incorrect_message_length_or_invalid_format(),
1019                now,
1020            );
1021        }
1022
1023        let block_seq = payload[0];
1024        let data = payload.get(1..).unwrap_or(&[]);
1025
1026        let mut buf = [0u8; MAX_FRAME];
1027        let len = self
1028            .handler
1029            .transfer_data(block_seq, data, &mut buf)
1030            .map_err(ServerError::Handler)?;
1031
1032        let mut resp: Vec<u8, MAX_FRAME> = Vec::new();
1033        let _ = resp.push(block_seq);
1034        let _ = resp.extend_from_slice(&buf[..len]);
1035        self.pos(src, 0x36, &resp, now)
1036    }
1037
1038    fn on_transfer_exit(
1039        &mut self,
1040        src: &NodeAddress,
1041        frame: &UdsFrame<'_>,
1042        _suppressed: bool,
1043        now: Instant,
1044    ) -> Result<(), ServerError<H::Error>> {
1045        let parameter_record = frame.payload();
1046
1047        let mut buf = [0u8; MAX_FRAME];
1048        let len = self
1049            .handler
1050            .request_transfer_exit(parameter_record, &mut buf)
1051            .map_err(ServerError::Handler)?;
1052
1053        self.pos(src, 0x37, &buf[..len], now)
1054    }
1055
1056    fn on_file_transfer(
1057        &mut self,
1058        src: &NodeAddress,
1059        frame: &UdsFrame<'_>,
1060        _suppressed: bool,
1061        now: Instant,
1062    ) -> Result<(), ServerError<H::Error>> {
1063        let payload = frame.payload();
1064        if payload.len() < 3 {
1065            return self.nrc(
1066                src,
1067                0x38,
1068                H::Error::incorrect_message_length_or_invalid_format(),
1069                now,
1070            );
1071        }
1072
1073        let operation = payload[0];
1074        // Bytes 1-2 are file path length (big-endian u16), rest is path
1075        let path_len = u16::from_be_bytes([payload[1], payload[2]]) as usize;
1076        let path = payload.get(3..3 + path_len).unwrap_or(&[]);
1077
1078        let mut buf = [0u8; MAX_FRAME];
1079        let len = self
1080            .handler
1081            .request_file_transfer(operation, path, &mut buf)
1082            .map_err(ServerError::Handler)?;
1083
1084        self.pos(src, 0x38, &buf[..len], now)
1085    }
1086
1087    // endregion: Service handlers
1088
1089    // region: Periodic dispatch
1090
1091    fn dispatch_periodic(&mut self, now: Instant) -> Result<(), ServerError<H::Error>> {
1092        let mut due: Vec<(u16, NodeAddress), MAX_PERIODIC> = Vec::new();
1093        self.periodic.collect_due(now, &mut due);
1094
1095        for (did, client) in &due {
1096            let mut data_buf = [0u8; MAX_FRAME];
1097            let len = self
1098                .handler
1099                .read_did(*did, &mut data_buf)
1100                .map_err(ServerError::Handler)?;
1101
1102            // [periodic_data_identifier (1 byte), data_record (n bytes)]
1103            let did_low = (*did & 0xFF) as u8;
1104            let mut frame = Vec::new();
1105            let _ = frame.push(did_low);
1106            let _ = frame.extend_from_slice(&data_buf[..len]);
1107
1108            self.enqueue(client.clone(), frame)?;
1109            self.periodic.advance(*did, client, now);
1110        }
1111
1112        Ok(())
1113    }
1114
1115    // endregion: Periodic dispatch
1116}
1117
1118// endregion: UdsServer