1use int_enum::IntEnum;
5
6use crate::messages::{CanId, CanMessage};
7
8enum ServerCommand {
10 SegmentUpload = 0,
11 SegmentDownload = 1,
12 Upload = 2,
13 Download = 3,
14 Abort = 4,
15 BlockDownload = 5,
16 BlockUpload = 6,
17}
18
19impl TryFrom<u8> for ServerCommand {
20 type Error = ();
21
22 fn try_from(value: u8) -> Result<Self, Self::Error> {
23 use ServerCommand::*;
24 match value {
25 0 => Ok(SegmentUpload),
26 1 => Ok(SegmentDownload),
27 2 => Ok(Upload),
28 3 => Ok(Download),
29 4 => Ok(Abort),
30 5 => Ok(BlockDownload),
31 6 => Ok(BlockUpload),
32 _ => Err(()),
33 }
34 }
35}
36
37#[derive(Clone, Copy, Debug, PartialEq, IntEnum)]
41#[repr(u32)]
42pub enum AbortCode {
43 ToggleNotAlternated = 0x0503_0000,
45 SdoTimeout = 0x0504_0000,
47 InvalidCommandSpecifier = 0x0504_0001,
49 InvalidBlockSize = 0x0504_0002,
51 InvalidSequenceNumber = 0x0504_0003,
53 CrcError = 0x0504_0004,
55 OutOfMemory = 0x0504_0005,
57 UnsupportedAccess = 0x0601_0000,
59 WriteOnly = 0x0601_0001,
61 ReadOnly = 0x0601_0002,
63 NoSuchObject = 0x0602_0000,
65 UnnallowedPdo = 0x0604_0041,
67 PdoTooLong = 0x0604_0042,
69 IncompatibleParameter = 0x0604_0043,
71 HardwareError = 0x0606_0000,
73 DataTypeMismatch = 0x0607_0010,
75 DataTypeMismatchLengthHigh = 0x0607_0012,
77 DataTypeMismatchLengthLow = 0x0607_0013,
79 NoSuchSubIndex = 0x0609_0011,
81 InvalidValue = 0x0609_0030,
83 ValueTooHigh = 0x0609_0031,
85 ValueTooLow = 0x0609_0032,
87 ResourceNotAvailable = 0x060A_0023,
89 GeneralError = 0x0800_0000,
91 CantStore = 0x0800_0020,
93 CantStoreLocalControl = 0x0800_0021,
95 CantStoreDeviceState = 0x0800_0022,
97 NoObjectDict = 0x0800_0023,
99 NoData = 0x0800_0024,
101}
102
103#[derive(Clone, Copy, Debug, PartialEq)]
104#[repr(u8)]
105enum ClientCommand {
106 DownloadSegment = 0,
107 InitiateDownload = 1,
108 InitiateUpload = 2,
109 ReqUploadSegment = 3,
110 Abort = 4,
111 BlockUpload = 5,
112 BlockDownload = 6,
113}
114
115impl TryFrom<u8> for ClientCommand {
116 type Error = ();
117
118 fn try_from(value: u8) -> Result<Self, Self::Error> {
119 use ClientCommand::*;
120 match value {
121 0 => Ok(DownloadSegment),
122 1 => Ok(InitiateDownload),
123 2 => Ok(InitiateUpload),
124 3 => Ok(ReqUploadSegment),
125 4 => Ok(Abort),
126 5 => Ok(BlockUpload),
127 6 => Ok(BlockDownload),
128 _ => Err(()),
129 }
130 }
131}
132
133#[derive(Clone, Copy, Debug)]
135pub struct BlockSegment {
136 pub c: bool,
140 pub seqnum: u8,
145 pub data: [u8; 7],
147}
148
149impl TryFrom<&[u8]> for BlockSegment {
150 type Error = ();
151
152 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
153 if value.len() != 8 {
154 return Err(());
155 }
156 let c = (value[0] & (1 << 7)) != 0;
157 let seqnum = value[0] & 0x7f;
158 let data: [u8; 7] = value[1..8].try_into().unwrap();
159 Ok(Self { c, seqnum, data })
160 }
161}
162
163impl BlockSegment {
164 pub fn to_bytes(&self) -> [u8; 8] {
166 let mut bytes = [0; 8];
167 bytes[0] = (self.c as u8) << 7 | self.seqnum & 0x7f;
168 bytes[1..8].copy_from_slice(&self.data);
169 bytes
170 }
171
172 pub fn to_can_message(&self, id: CanId) -> CanMessage {
174 CanMessage {
175 data: self.to_bytes(),
176 dlc: 8,
177 rtr: false,
178 id,
179 }
180 }
181}
182
183#[derive(Clone, Copy, Debug, PartialEq)]
184#[repr(u8)]
185enum BlockDownloadClientSubcommand {
186 InitiateDownload = 0,
187 EndDownload = 1,
188}
189
190impl TryFrom<u8> for BlockDownloadClientSubcommand {
191 type Error = ();
192
193 fn try_from(value: u8) -> Result<Self, Self::Error> {
194 match value {
195 0 => Ok(Self::InitiateDownload),
196 1 => Ok(Self::EndDownload),
197 _ => Err(()),
198 }
199 }
200}
201
202#[derive(Clone, Copy, Debug, PartialEq)]
203#[repr(u8)]
204enum BlockDownloadServerSubcommand {
205 InitiateDownloadAck = 0,
206 EndDownloadAck = 1,
207 ConfirmBlock = 2,
208}
209
210impl TryFrom<u8> for BlockDownloadServerSubcommand {
211 type Error = ();
212
213 fn try_from(value: u8) -> Result<Self, Self::Error> {
214 match value {
215 0 => Ok(Self::InitiateDownloadAck),
216 1 => Ok(Self::EndDownloadAck),
217 2 => Ok(Self::ConfirmBlock),
218 _ => Err(()),
219 }
220 }
221}
222
223#[derive(Clone, Copy, Debug, PartialEq)]
224#[repr(u8)]
225enum BlockUploadClientSubcommand {
226 InitiateUpload = 0,
227 EndUpload = 1,
228 ConfirmBlock = 2,
229 StartUpload = 3,
230}
231
232impl TryFrom<u8> for BlockUploadClientSubcommand {
233 type Error = ();
234
235 fn try_from(value: u8) -> Result<Self, Self::Error> {
236 match value {
237 0 => Ok(Self::InitiateUpload),
238 1 => Ok(Self::EndUpload),
239 2 => Ok(Self::ConfirmBlock),
240 3 => Ok(Self::StartUpload),
241 _ => Err(()),
242 }
243 }
244}
245
246#[derive(Clone, Copy, Debug, PartialEq)]
247#[repr(u8)]
248enum BlockUploadServerSubcommand {
249 InitiateUpload = 0,
250 EndUpload = 1,
251}
252
253impl TryFrom<u8> for BlockUploadServerSubcommand {
254 type Error = ();
255
256 fn try_from(value: u8) -> Result<Self, Self::Error> {
257 match value {
258 0 => Ok(Self::InitiateUpload),
259 1 => Ok(Self::EndUpload),
260 _ => Err(()),
261 }
262 }
263}
264
265#[derive(Clone, Copy, Debug)]
269#[cfg_attr(feature = "defmt", derive(defmt::Format))]
270pub enum SdoRequest {
271 InitiateDownload {
273 n: u8,
275 e: bool,
277 s: bool,
279 index: u16,
281 sub: u8,
283 data: [u8; 4],
285 },
286 DownloadSegment {
288 t: bool,
290 n: u8,
292 c: bool,
294 data: [u8; 7],
296 },
297 InitiateUpload {
299 index: u16,
301 sub: u8,
303 },
304 ReqUploadSegment {
306 t: bool,
308 },
309 InitiateBlockDownload {
311 cc: bool,
313 s: bool,
315 index: u16,
317 sub: u8,
319 size: u32,
321 },
322 EndBlockDownload {
324 n: u8,
327 crc: u16,
329 },
330 InitiateBlockUpload {
332 index: u16,
334 sub: u8,
336 blksize: u8,
338 pst: u8,
344 },
345 EndBlockUpload,
347 StartBlockUpload,
349 ConfirmBlock {
351 ackseq: u8,
353 blksize: u8,
355 },
356
357 Abort {
359 index: u16,
361 sub: u8,
363 abort_code: u32,
365 },
366}
367
368impl SdoRequest {
369 pub fn abort(index: u16, sub: u8, abort_code: AbortCode) -> Self {
371 SdoRequest::Abort {
372 index,
373 sub,
374 abort_code: abort_code as u32,
375 }
376 }
377
378 pub fn initiate_download(index: u16, sub: u8, size: Option<u32>) -> Self {
380 let data = size.unwrap_or(0).to_le_bytes();
381
382 SdoRequest::InitiateDownload {
383 n: 0,
384 e: false,
385 s: size.is_some(),
386 index,
387 sub,
388 data,
389 }
390 }
391
392 pub fn initiate_block_download(index: u16, sub: u8, crc_supported: bool, size: u32) -> Self {
394 SdoRequest::InitiateBlockDownload {
395 cc: crc_supported,
396 s: true,
397 index,
398 sub,
399 size,
400 }
401 }
402
403 pub fn end_block_download(n: u8, crc: u16) -> Self {
410 SdoRequest::EndBlockDownload { n, crc }
411 }
412
413 pub fn download_segment(toggle: bool, last_segment: bool, segment_data: &[u8]) -> Self {
415 let mut data = [0; 7];
416 data[0..segment_data.len()].copy_from_slice(segment_data);
417 SdoRequest::DownloadSegment {
418 t: toggle,
419 n: 7 - segment_data.len() as u8,
420 c: last_segment,
421 data,
422 }
423 }
424
425 pub fn expedited_download(index: u16, sub: u8, data: &[u8]) -> Self {
427 let mut msg_data = [0; 4];
428 msg_data[0..data.len()].copy_from_slice(data);
429
430 SdoRequest::InitiateDownload {
431 n: (4 - data.len()) as u8,
432 e: true,
433 s: true,
434 index,
435 sub,
436 data: msg_data,
437 }
438 }
439
440 pub fn initiate_upload(index: u16, sub: u8) -> Self {
442 SdoRequest::InitiateUpload { index, sub }
443 }
444
445 pub fn upload_segment_request(toggle: bool) -> Self {
447 SdoRequest::ReqUploadSegment { t: toggle }
448 }
449
450 pub fn to_bytes(self) -> [u8; 8] {
452 let mut payload = [0; 8];
453
454 match self {
455 SdoRequest::InitiateDownload {
456 n,
457 e,
458 s,
459 index,
460 sub,
461 data,
462 } => {
463 payload[0] = ((ClientCommand::InitiateDownload as u8) << 5)
464 | (n << 2)
465 | ((e as u8) << 1)
466 | s as u8;
467 payload[1] = (index & 0xff) as u8;
468 payload[2] = (index >> 8) as u8;
469 payload[3] = sub;
470 payload[4..8].copy_from_slice(&data);
471 }
472 SdoRequest::DownloadSegment { t, n, c, data } => {
473 payload[0] = ((ClientCommand::DownloadSegment as u8) << 5)
474 | ((t as u8) << 4)
475 | ((n & 7) << 1)
476 | (c as u8);
477
478 payload[1..8].copy_from_slice(&data);
479 }
480 SdoRequest::InitiateUpload { index, sub } => {
481 payload[0] = (ClientCommand::InitiateUpload as u8) << 5;
482 payload[1] = (index & 0xff) as u8;
483 payload[2] = (index >> 8) as u8;
484 payload[3] = sub;
485 }
486 SdoRequest::ReqUploadSegment { t } => {
487 payload[0] = ((ClientCommand::ReqUploadSegment as u8) << 5) | ((t as u8) << 4);
488 }
489 SdoRequest::Abort {
490 index,
491 sub,
492 abort_code,
493 } => {
494 payload[0] = (ClientCommand::Abort as u8) << 5;
495 payload[1] = (index & 0xff) as u8;
496 payload[2] = (index >> 8) as u8;
497 payload[3] = sub;
498 payload[4..8].copy_from_slice(&abort_code.to_le_bytes());
499 }
500 SdoRequest::InitiateBlockDownload {
501 cc,
502 s,
503 index,
504 sub,
505 size,
506 } => {
507 payload[0] = ((ClientCommand::BlockDownload as u8) << 5)
508 | ((cc as u8) << 2)
509 | ((s as u8) << 1);
510 payload[1] = (index & 0xff) as u8;
511 payload[2] = (index >> 8) as u8;
512 payload[3] = sub;
513 payload[4..8].copy_from_slice(&size.to_le_bytes());
514 }
515 SdoRequest::EndBlockDownload { n, crc } => {
516 payload[0] = ((ClientCommand::BlockDownload as u8) << 5)
517 | (n << 2)
518 | BlockDownloadClientSubcommand::EndDownload as u8;
519 payload[1..3].copy_from_slice(&crc.to_le_bytes());
520 }
521 SdoRequest::InitiateBlockUpload {
522 index: _,
523 sub: _,
524 blksize: _,
525 pst: _,
526 } => todo!(),
527 SdoRequest::EndBlockUpload => todo!(),
528 SdoRequest::StartBlockUpload => todo!(),
529 SdoRequest::ConfirmBlock {
530 ackseq: _,
531 blksize: _,
532 } => todo!(),
533 }
534 payload
535 }
536
537 pub fn to_can_message(self, id: CanId) -> CanMessage {
539 let payload = self.to_bytes();
540 CanMessage::new(id, &payload)
541 }
542}
543
544impl TryFrom<&[u8]> for SdoRequest {
545 type Error = AbortCode;
546
547 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
548 if value.len() < 8 {
549 return Err(AbortCode::DataTypeMismatchLengthLow);
550 }
551 let ccs = value[0] >> 5;
552 let ccs: ClientCommand = match ccs.try_into() {
553 Ok(ccs) => ccs,
554 Err(_) => return Err(AbortCode::InvalidCommandSpecifier),
555 };
556
557 match ccs {
558 ClientCommand::DownloadSegment => {
559 let t = (value[0] & (1 << 4)) != 0;
560 let n = (value[0] >> 1) & 0x7;
561 let c = (value[0] & (1 << 0)) != 0;
562 let data = value[1..8].try_into().unwrap();
563 Ok(SdoRequest::DownloadSegment { t, n, c, data })
564 }
565 ClientCommand::InitiateDownload => {
566 let n = (value[0] >> 2) & 0x3;
567 let e = (value[0] & (1 << 1)) != 0;
568 let s = (value[0] & (1 << 0)) != 0;
569 let index = value[1] as u16 | ((value[2] as u16) << 8);
570 let sub = value[3];
571 let data = value[4..8].try_into().unwrap();
572 Ok(SdoRequest::InitiateDownload {
573 n,
574 e,
575 s,
576 index,
577 sub,
578 data,
579 })
580 }
581 ClientCommand::InitiateUpload => {
582 let index = value[1] as u16 | ((value[2] as u16) << 8);
583 let sub = value[3];
584 Ok(SdoRequest::InitiateUpload { index, sub })
585 }
586 ClientCommand::ReqUploadSegment => {
587 let t = (((value[0]) >> 4) & 1) != 0;
588 Ok(SdoRequest::ReqUploadSegment { t })
589 }
590 ClientCommand::Abort => {
591 let index = value[1] as u16 | ((value[2] as u16) << 8);
592 let sub = value[3];
593 let abort_code = u32::from_le_bytes(value[4..8].try_into().unwrap());
594 Ok(SdoRequest::Abort {
595 index,
596 sub,
597 abort_code,
598 })
599 }
600 ClientCommand::BlockUpload => {
601 let csc = value[0] & 3;
602 let subcommand = match BlockUploadClientSubcommand::try_from(csc) {
603 Ok(subcommand) => subcommand,
604 Err(_) => return Err(AbortCode::InvalidCommandSpecifier),
605 };
606 match subcommand {
607 BlockUploadClientSubcommand::InitiateUpload => {
608 let index = value[1] as u16 | ((value[2] as u16) << 8);
609 let sub = value[3];
610 let blksize = value[4];
611 let pst = value[5];
612 Ok(SdoRequest::InitiateBlockUpload {
613 index,
614 sub,
615 blksize,
616 pst,
617 })
618 }
619 BlockUploadClientSubcommand::EndUpload => Ok(SdoRequest::EndBlockUpload),
620 BlockUploadClientSubcommand::ConfirmBlock => {
621 let ackseq = value[1];
622 let blksize = value[2];
623 Ok(SdoRequest::ConfirmBlock { ackseq, blksize })
624 }
625 BlockUploadClientSubcommand::StartUpload => Ok(SdoRequest::StartBlockUpload),
626 }
627 }
628 ClientCommand::BlockDownload => {
629 let csc = value[0] & 0x1;
630 let subcommand = match BlockDownloadClientSubcommand::try_from(csc) {
631 Ok(subcommand) => subcommand,
632 Err(_) => return Err(AbortCode::InvalidCommandSpecifier),
633 };
634 match subcommand {
635 BlockDownloadClientSubcommand::InitiateDownload => {
636 let cc = (value[0] & (1 << 2)) != 0;
637 let s = (value[0] & (1 << 1)) != 0;
638 let index = value[1] as u16 | ((value[2] as u16) << 8);
639 let sub = value[3];
640 let size = u32::from_le_bytes(value[4..8].try_into().unwrap());
641 Ok(SdoRequest::InitiateBlockDownload {
642 cc,
643 s,
644 index,
645 sub,
646
647 size,
648 })
649 }
650 BlockDownloadClientSubcommand::EndDownload => {
651 let n = (value[0] >> 2) & 7;
652 let crc = u16::from_le_bytes(value[1..3].try_into().unwrap());
653 Ok(SdoRequest::EndBlockDownload { n, crc })
654 }
655 }
656 }
657 }
658 }
659}
660
661#[derive(Copy, Clone, Debug, PartialEq)]
663#[cfg_attr(feature = "defmt", derive(defmt::Format))]
664pub enum SdoResponse {
665 ConfirmUpload {
667 n: u8,
669 e: bool,
671 s: bool,
673 index: u16,
675 sub: u8,
677 data: [u8; 4],
679 },
680 UploadSegment {
682 t: bool,
684 n: u8,
686 c: bool,
688 data: [u8; 7],
690 },
691 ConfirmDownload {
693 index: u16,
695 sub: u8,
697 },
698 ConfirmDownloadSegment {
700 t: bool,
702 },
703 ConfirmBlockDownload {
705 sc: bool,
707 index: u16,
709 sub: u8,
711 blksize: u8,
713 },
714 ConfirmBlock {
716 ackseq: u8,
718 blksize: u8,
720 },
721 ConfirmBlockDownloadEnd,
723 ConfirmBlockUpload {
725 sc: bool,
727 s: bool,
729 index: u16,
731 sub: u8,
733 size: u32,
735 },
736 BlockUploadEnd {
738 n: u8,
740 crc: u16,
743 },
744 Abort {
746 index: u16,
748 sub: u8,
750 abort_code: u32,
752 },
753}
754
755impl TryFrom<CanMessage> for SdoResponse {
756 type Error = ();
757 fn try_from(msg: CanMessage) -> Result<Self, Self::Error> {
758 let scs = msg.data[0] >> 5;
759 let command: ServerCommand = scs.try_into()?;
760 match command {
761 ServerCommand::SegmentUpload => {
762 let t = (msg.data[0] & (1 << 4)) != 0;
763 let n = (msg.data[0] >> 1) & 7;
764 let c = (msg.data[0] & (1 << 0)) != 0;
765 let data: [u8; 7] = msg.data[1..8].try_into().unwrap();
766
767 Ok(SdoResponse::UploadSegment { t, n, c, data })
768 }
769 ServerCommand::SegmentDownload => {
770 let t = (msg.data[0] & (1 << 4)) != 0;
771 Ok(SdoResponse::ConfirmDownloadSegment { t })
772 }
773 ServerCommand::Upload => {
774 let n = (msg.data[0] >> 2) & 0x3;
775 let e = (msg.data[0] & (1 << 1)) != 0;
776 let s = (msg.data[0] & (1 << 0)) != 0;
777 let index = u16::from_le_bytes(msg.data[1..3].try_into().unwrap());
778 let sub = msg.data[3];
779 let data: [u8; 4] = msg.data[4..8].try_into().unwrap();
780 Ok(SdoResponse::ConfirmUpload {
781 n,
782 e,
783 s,
784 index,
785 sub,
786 data,
787 })
788 }
789 ServerCommand::Download => {
790 let index = u16::from_le_bytes(msg.data[1..3].try_into().unwrap());
791 let sub = msg.data[3];
792 Ok(SdoResponse::ConfirmDownload { index, sub })
793 }
794 ServerCommand::BlockDownload => {
795 match BlockDownloadServerSubcommand::try_from(msg.data[0] & 0x3)? {
796 BlockDownloadServerSubcommand::ConfirmBlock => {
797 let ackseq = msg.data[1];
798 let blksize = msg.data[2];
799 Ok(SdoResponse::ConfirmBlock { ackseq, blksize })
800 }
801 BlockDownloadServerSubcommand::InitiateDownloadAck => {
802 let sc = (msg.data[0] & (1 << 2)) != 0;
803 let index = u16::from_le_bytes(msg.data[1..3].try_into().unwrap());
804 let sub = msg.data[3];
805 let blksize = msg.data[4];
806 Ok(SdoResponse::ConfirmBlockDownload {
807 sc,
808 index,
809 sub,
810 blksize,
811 })
812 }
813 BlockDownloadServerSubcommand::EndDownloadAck => {
814 Ok(SdoResponse::ConfirmBlockDownloadEnd)
815 }
816 }
817 }
818 ServerCommand::BlockUpload => {
819 match BlockUploadServerSubcommand::try_from(msg.data[0] & 0x3)? {
820 BlockUploadServerSubcommand::InitiateUpload => {
821 let s = (msg.data[0] & (1 << 1)) != 0;
822 let sc = (msg.data[0] & (1 << 2)) != 0;
823 let index = u16::from_le_bytes(msg.data[1..3].try_into().unwrap());
824 let sub = msg.data[3];
825 let size = u32::from_le_bytes(msg.data[4..8].try_into().unwrap());
826 Ok(SdoResponse::ConfirmBlockUpload {
827 sc,
828 s,
829 index,
830 sub,
831 size,
832 })
833 }
834 BlockUploadServerSubcommand::EndUpload => {
835 let n = (msg.data[0] >> 2) & 7;
836 let crc = u16::from_le_bytes(msg.data[1..3].try_into().unwrap());
837 Ok(SdoResponse::BlockUploadEnd { n, crc })
838 }
839 }
840 }
841 ServerCommand::Abort => {
842 let index = u16::from_le_bytes(msg.data[1..3].try_into().unwrap());
843 let sub = msg.data[3];
844 let abort_code = u32::from_le_bytes(msg.data[4..8].try_into().unwrap());
845 Ok(SdoResponse::Abort {
846 index,
847 sub,
848 abort_code,
849 })
850 }
851 }
852 }
853}
854impl SdoResponse {
855 pub fn expedited_upload(index: u16, sub: u8, data: &[u8]) -> SdoResponse {
857 if data.len() > 4 {
858 panic!("Cannot create expedited upload with more than 4 bytes");
859 }
860
861 let mut msg_data = [0; 4];
862 msg_data[0..data.len()].copy_from_slice(data);
863
864 let s;
865 let n;
866 if data.is_empty() {
869 s = false;
870 n = 0;
871 } else {
872 s = true;
873 n = 4 - data.len() as u8;
874 }
875 SdoResponse::ConfirmUpload {
876 index,
877 sub,
878 e: true,
879 s,
880 n,
881 data: msg_data,
882 }
883 }
884
885 pub fn upload_acknowledge(index: u16, sub: u8, size: Option<u32>) -> SdoResponse {
887 SdoResponse::ConfirmUpload {
888 n: 0,
889 e: false,
890 s: size.is_some(),
891 index,
892 sub,
893 data: size.unwrap_or(0).to_le_bytes(),
894 }
895 }
896
897 pub fn upload_segment(t: bool, c: bool, data: &[u8]) -> SdoResponse {
899 let n = (7 - data.len()) as u8;
900 let mut buf = [0; 7];
901 buf[0..data.len()].copy_from_slice(data);
902 SdoResponse::UploadSegment { t, n, c, data: buf }
903 }
904
905 pub fn download_acknowledge(index: u16, sub: u8) -> SdoResponse {
907 SdoResponse::ConfirmDownload { index, sub }
908 }
909
910 pub fn download_segment_acknowledge(t: bool) -> SdoResponse {
912 SdoResponse::ConfirmDownloadSegment { t }
913 }
914
915 pub fn block_download_acknowledge(sc: bool, index: u16, sub: u8, blksize: u8) -> SdoResponse {
917 SdoResponse::ConfirmBlockDownload {
918 sc,
919 index,
920 sub,
921 blksize,
922 }
923 }
924
925 pub fn confirm_block(ackseq: u8, blksize: u8) -> SdoResponse {
927 SdoResponse::ConfirmBlock { ackseq, blksize }
928 }
929
930 pub fn abort(index: u16, sub: u8, abort_code: AbortCode) -> SdoResponse {
932 let abort_code = abort_code as u32;
933 SdoResponse::Abort {
934 index,
935 sub,
936 abort_code,
937 }
938 }
939
940 pub fn to_can_message(self, id: CanId) -> CanMessage {
942 let mut payload = [0; 8];
943
944 match self {
945 SdoResponse::ConfirmUpload {
946 n,
947 e,
948 s,
949 index,
950 sub,
951 data,
952 } => {
953 payload[0] = ((ServerCommand::Upload as u8) << 5)
954 | ((n & 0x3) << 2)
955 | ((e as u8) << 1)
956 | (s as u8);
957 payload[1] = (index & 0xff) as u8;
958 payload[2] = (index >> 8) as u8;
959 payload[3] = sub;
960 payload[4..8].copy_from_slice(&data);
961 }
962 SdoResponse::ConfirmDownload { index, sub } => {
963 payload[0] = (ServerCommand::Download as u8) << 5;
964 payload[1] = (index & 0xff) as u8;
965 payload[2] = (index >> 8) as u8;
966 payload[3] = sub;
967 }
968 SdoResponse::UploadSegment { t, n, c, data } => {
969 payload[0] = ((ServerCommand::SegmentUpload as u8) << 5)
970 | ((t as u8) << 4)
971 | (n << 1)
972 | c as u8;
973 payload[1..8].copy_from_slice(&data);
974 }
975 SdoResponse::ConfirmBlockDownload {
976 sc,
977 index,
978 sub,
979 blksize,
980 } => {
981 payload[0] = ((ServerCommand::BlockDownload as u8) << 5)
982 | ((sc as u8) << 2)
983 | (BlockDownloadServerSubcommand::InitiateDownloadAck as u8);
984 payload[1] = (index & 0xff) as u8;
985 payload[2] = (index >> 8) as u8;
986 payload[3] = sub;
987 payload[4] = blksize;
988 }
989 SdoResponse::ConfirmBlock { ackseq, blksize } => {
990 payload[0] = ((ServerCommand::BlockDownload as u8) << 5)
991 | (BlockDownloadServerSubcommand::ConfirmBlock as u8);
992 payload[1] = ackseq;
993 payload[2] = blksize;
994 }
995 SdoResponse::ConfirmBlockDownloadEnd => {
996 payload[0] = ((ServerCommand::BlockDownload as u8) << 5)
997 | (BlockDownloadServerSubcommand::EndDownloadAck as u8);
998 }
999 SdoResponse::ConfirmDownloadSegment { t } => {
1000 payload[0] = ((ServerCommand::SegmentDownload as u8) << 5) | ((t as u8) << 4);
1001 }
1002 SdoResponse::Abort {
1003 index,
1004 sub,
1005 abort_code,
1006 } => {
1007 payload[0] = (ServerCommand::Abort as u8) << 5;
1008 payload[1] = (index & 0xff) as u8;
1009 payload[2] = (index >> 8) as u8;
1010 payload[3] = sub;
1011 payload[4..8].copy_from_slice(&abort_code.to_le_bytes());
1012 }
1013 SdoResponse::ConfirmBlockUpload {
1014 sc: _,
1015 s: _,
1016 index: _,
1017 sub: _,
1018 size: _,
1019 } => todo!(),
1020 SdoResponse::BlockUploadEnd { n: _, crc: _ } => todo!(),
1021 }
1022 CanMessage::new(id, &payload)
1023 }
1024}