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, PartialEq)]
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 cc: bool,
334 index: u16,
336 sub: u8,
338 blksize: u8,
340 pst: u8,
346 },
347 EndBlockUpload,
349 StartBlockUpload,
351 ConfirmBlock {
353 ackseq: u8,
355 blksize: u8,
357 },
358
359 Abort {
361 index: u16,
363 sub: u8,
365 abort_code: u32,
367 },
368}
369
370impl SdoRequest {
371 pub fn abort(index: u16, sub: u8, abort_code: AbortCode) -> Self {
373 SdoRequest::Abort {
374 index,
375 sub,
376 abort_code: abort_code as u32,
377 }
378 }
379
380 pub fn initiate_download(index: u16, sub: u8, size: Option<u32>) -> Self {
382 let data = size.unwrap_or(0).to_le_bytes();
383
384 SdoRequest::InitiateDownload {
385 n: 0,
386 e: false,
387 s: size.is_some(),
388 index,
389 sub,
390 data,
391 }
392 }
393
394 pub fn initiate_block_download(index: u16, sub: u8, crc_supported: bool, size: u32) -> Self {
396 SdoRequest::InitiateBlockDownload {
397 cc: crc_supported,
398 s: true,
399 index,
400 sub,
401 size,
402 }
403 }
404
405 pub fn end_block_download(n: u8, crc: u16) -> Self {
412 SdoRequest::EndBlockDownload { n, crc }
413 }
414
415 pub fn download_segment(toggle: bool, last_segment: bool, segment_data: &[u8]) -> Self {
417 let mut data = [0; 7];
418 data[0..segment_data.len()].copy_from_slice(segment_data);
419 SdoRequest::DownloadSegment {
420 t: toggle,
421 n: 7 - segment_data.len() as u8,
422 c: last_segment,
423 data,
424 }
425 }
426
427 pub fn expedited_download(index: u16, sub: u8, data: &[u8]) -> Self {
429 let mut msg_data = [0; 4];
430 msg_data[0..data.len()].copy_from_slice(data);
431
432 SdoRequest::InitiateDownload {
433 n: (4 - data.len()) as u8,
434 e: true,
435 s: true,
436 index,
437 sub,
438 data: msg_data,
439 }
440 }
441
442 pub fn initiate_upload(index: u16, sub: u8) -> Self {
444 SdoRequest::InitiateUpload { index, sub }
445 }
446
447 pub fn initiate_block_upload(index: u16, sub: u8, cc: bool, blksize: u8, pst: u8) -> Self {
449 SdoRequest::InitiateBlockUpload {
450 index,
451 sub,
452 cc,
453 blksize,
454 pst,
455 }
456 }
457
458 pub fn upload_segment_request(toggle: bool) -> Self {
460 SdoRequest::ReqUploadSegment { t: toggle }
461 }
462
463 pub fn to_bytes(self) -> [u8; 8] {
465 let mut payload = [0; 8];
466
467 match self {
468 SdoRequest::InitiateDownload {
469 n,
470 e,
471 s,
472 index,
473 sub,
474 data,
475 } => {
476 payload[0] = ((ClientCommand::InitiateDownload as u8) << 5)
477 | (n << 2)
478 | ((e as u8) << 1)
479 | s as u8;
480 payload[1] = (index & 0xff) as u8;
481 payload[2] = (index >> 8) as u8;
482 payload[3] = sub;
483 payload[4..8].copy_from_slice(&data);
484 }
485 SdoRequest::DownloadSegment { t, n, c, data } => {
486 payload[0] = ((ClientCommand::DownloadSegment as u8) << 5)
487 | ((t as u8) << 4)
488 | ((n & 7) << 1)
489 | (c as u8);
490
491 payload[1..8].copy_from_slice(&data);
492 }
493 SdoRequest::InitiateUpload { index, sub } => {
494 payload[0] = (ClientCommand::InitiateUpload as u8) << 5;
495 payload[1] = (index & 0xff) as u8;
496 payload[2] = (index >> 8) as u8;
497 payload[3] = sub;
498 }
499 SdoRequest::ReqUploadSegment { t } => {
500 payload[0] = ((ClientCommand::ReqUploadSegment as u8) << 5) | ((t as u8) << 4);
501 }
502 SdoRequest::Abort {
503 index,
504 sub,
505 abort_code,
506 } => {
507 payload[0] = (ClientCommand::Abort as u8) << 5;
508 payload[1] = (index & 0xff) as u8;
509 payload[2] = (index >> 8) as u8;
510 payload[3] = sub;
511 payload[4..8].copy_from_slice(&abort_code.to_le_bytes());
512 }
513 SdoRequest::InitiateBlockDownload {
514 cc,
515 s,
516 index,
517 sub,
518 size,
519 } => {
520 payload[0] = ((ClientCommand::BlockDownload as u8) << 5)
521 | ((cc as u8) << 2)
522 | ((s as u8) << 1);
523 payload[1] = (index & 0xff) as u8;
524 payload[2] = (index >> 8) as u8;
525 payload[3] = sub;
526 payload[4..8].copy_from_slice(&size.to_le_bytes());
527 }
528 SdoRequest::EndBlockDownload { n, crc } => {
529 payload[0] = ((ClientCommand::BlockDownload as u8) << 5)
530 | (n << 2)
531 | BlockDownloadClientSubcommand::EndDownload as u8;
532 payload[1..3].copy_from_slice(&crc.to_le_bytes());
533 }
534 SdoRequest::InitiateBlockUpload {
535 index,
536 sub,
537 cc,
538 blksize,
539 pst,
540 } => {
541 payload[0] = ((ClientCommand::BlockUpload as u8) << 5)
542 | ((cc as u8) << 2)
543 | (BlockUploadClientSubcommand::InitiateUpload as u8);
544 payload[1] = (index & 0xff) as u8;
545 payload[2] = (index >> 8) as u8;
546 payload[3] = sub;
547 payload[4] = blksize;
548 payload[5] = pst;
549 }
550 SdoRequest::EndBlockUpload => {
551 payload[0] = ((ClientCommand::BlockUpload as u8) << 5)
552 | (BlockUploadClientSubcommand::EndUpload as u8);
553 }
554 SdoRequest::StartBlockUpload => {
555 payload[0] = ((ClientCommand::BlockUpload as u8) << 5)
556 | (BlockUploadClientSubcommand::StartUpload as u8);
557 }
558 SdoRequest::ConfirmBlock { ackseq, blksize } => {
559 payload[0] = ((ClientCommand::BlockUpload as u8) << 5)
560 | (BlockUploadClientSubcommand::ConfirmBlock as u8);
561 payload[1] = ackseq;
562 payload[2] = blksize;
563 }
564 }
565 payload
566 }
567
568 pub fn to_can_message(self, id: CanId) -> CanMessage {
570 let payload = self.to_bytes();
571 CanMessage::new(id, &payload)
572 }
573}
574
575impl TryFrom<&[u8]> for SdoRequest {
576 type Error = AbortCode;
577
578 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
579 if value.len() < 8 {
580 return Err(AbortCode::DataTypeMismatchLengthLow);
581 }
582 let ccs = value[0] >> 5;
583 let ccs: ClientCommand = match ccs.try_into() {
584 Ok(ccs) => ccs,
585 Err(_) => return Err(AbortCode::InvalidCommandSpecifier),
586 };
587
588 match ccs {
589 ClientCommand::DownloadSegment => {
590 let t = (value[0] & (1 << 4)) != 0;
591 let n = (value[0] >> 1) & 0x7;
592 let c = (value[0] & (1 << 0)) != 0;
593 let data = value[1..8].try_into().unwrap();
594 Ok(SdoRequest::DownloadSegment { t, n, c, data })
595 }
596 ClientCommand::InitiateDownload => {
597 let n = (value[0] >> 2) & 0x3;
598 let e = (value[0] & (1 << 1)) != 0;
599 let s = (value[0] & (1 << 0)) != 0;
600 let index = value[1] as u16 | ((value[2] as u16) << 8);
601 let sub = value[3];
602 let data = value[4..8].try_into().unwrap();
603 Ok(SdoRequest::InitiateDownload {
604 n,
605 e,
606 s,
607 index,
608 sub,
609 data,
610 })
611 }
612 ClientCommand::InitiateUpload => {
613 let index = value[1] as u16 | ((value[2] as u16) << 8);
614 let sub = value[3];
615 Ok(SdoRequest::InitiateUpload { index, sub })
616 }
617 ClientCommand::ReqUploadSegment => {
618 let t = (((value[0]) >> 4) & 1) != 0;
619 Ok(SdoRequest::ReqUploadSegment { t })
620 }
621 ClientCommand::Abort => {
622 let index = value[1] as u16 | ((value[2] as u16) << 8);
623 let sub = value[3];
624 let abort_code = u32::from_le_bytes(value[4..8].try_into().unwrap());
625 Ok(SdoRequest::Abort {
626 index,
627 sub,
628 abort_code,
629 })
630 }
631 ClientCommand::BlockUpload => {
632 let csc = value[0] & 3;
633 let subcommand = match BlockUploadClientSubcommand::try_from(csc) {
634 Ok(subcommand) => subcommand,
635 Err(_) => return Err(AbortCode::InvalidCommandSpecifier),
636 };
637 match subcommand {
638 BlockUploadClientSubcommand::InitiateUpload => {
639 let cc = value[0] & (1 << 2) != 0;
640 let index = value[1] as u16 | ((value[2] as u16) << 8);
641 let sub = value[3];
642 let blksize = value[4];
643 let pst = value[5];
644 Ok(SdoRequest::InitiateBlockUpload {
645 index,
646 sub,
647 cc,
648 blksize,
649 pst,
650 })
651 }
652 BlockUploadClientSubcommand::EndUpload => Ok(SdoRequest::EndBlockUpload),
653 BlockUploadClientSubcommand::ConfirmBlock => {
654 let ackseq = value[1];
655 let blksize = value[2];
656 Ok(SdoRequest::ConfirmBlock { ackseq, blksize })
657 }
658 BlockUploadClientSubcommand::StartUpload => Ok(SdoRequest::StartBlockUpload),
659 }
660 }
661 ClientCommand::BlockDownload => {
662 let csc = value[0] & 0x1;
663 let subcommand = match BlockDownloadClientSubcommand::try_from(csc) {
664 Ok(subcommand) => subcommand,
665 Err(_) => return Err(AbortCode::InvalidCommandSpecifier),
666 };
667 match subcommand {
668 BlockDownloadClientSubcommand::InitiateDownload => {
669 let cc = (value[0] & (1 << 2)) != 0;
670 let s = (value[0] & (1 << 1)) != 0;
671 let index = value[1] as u16 | ((value[2] as u16) << 8);
672 let sub = value[3];
673 let size = u32::from_le_bytes(value[4..8].try_into().unwrap());
674 Ok(SdoRequest::InitiateBlockDownload {
675 cc,
676 s,
677 index,
678 sub,
679
680 size,
681 })
682 }
683 BlockDownloadClientSubcommand::EndDownload => {
684 let n = (value[0] >> 2) & 7;
685 let crc = u16::from_le_bytes(value[1..3].try_into().unwrap());
686 Ok(SdoRequest::EndBlockDownload { n, crc })
687 }
688 }
689 }
690 }
691 }
692}
693
694#[derive(Copy, Clone, Debug, PartialEq)]
696#[cfg_attr(feature = "defmt", derive(defmt::Format))]
697pub enum SdoResponse {
698 ConfirmUpload {
700 n: u8,
702 e: bool,
704 s: bool,
706 index: u16,
708 sub: u8,
710 data: [u8; 4],
712 },
713 UploadSegment {
715 t: bool,
717 n: u8,
719 c: bool,
721 data: [u8; 7],
723 },
724 ConfirmDownload {
726 index: u16,
728 sub: u8,
730 },
731 ConfirmDownloadSegment {
733 t: bool,
735 },
736 ConfirmBlockDownload {
738 sc: bool,
740 index: u16,
742 sub: u8,
744 blksize: u8,
746 },
747 ConfirmBlock {
749 ackseq: u8,
751 blksize: u8,
753 },
754 ConfirmBlockDownloadEnd,
756 ConfirmBlockUpload {
758 sc: bool,
760 s: bool,
762 index: u16,
764 sub: u8,
766 size: u32,
768 },
769 BlockUploadEnd {
771 n: u8,
773 crc: u16,
776 },
777 Abort {
779 index: u16,
781 sub: u8,
783 abort_code: u32,
785 },
786}
787
788impl TryFrom<[u8; 8]> for SdoResponse {
789 type Error = ();
790
791 fn try_from(value: [u8; 8]) -> Result<Self, Self::Error> {
792 let scs = value[0] >> 5;
793 let command: ServerCommand = scs.try_into()?;
794 match command {
795 ServerCommand::SegmentUpload => {
796 let t = (value[0] & (1 << 4)) != 0;
797 let n = (value[0] >> 1) & 7;
798 let c = (value[0] & (1 << 0)) != 0;
799 let data: [u8; 7] = value[1..8].try_into().unwrap();
800
801 Ok(SdoResponse::UploadSegment { t, n, c, data })
802 }
803 ServerCommand::SegmentDownload => {
804 let t = (value[0] & (1 << 4)) != 0;
805 Ok(SdoResponse::ConfirmDownloadSegment { t })
806 }
807 ServerCommand::Upload => {
808 let n = (value[0] >> 2) & 0x3;
809 let e = (value[0] & (1 << 1)) != 0;
810 let s = (value[0] & (1 << 0)) != 0;
811 let index = u16::from_le_bytes(value[1..3].try_into().unwrap());
812 let sub = value[3];
813 let data: [u8; 4] = value[4..8].try_into().unwrap();
814 Ok(SdoResponse::ConfirmUpload {
815 n,
816 e,
817 s,
818 index,
819 sub,
820 data,
821 })
822 }
823 ServerCommand::Download => {
824 let index = u16::from_le_bytes(value[1..3].try_into().unwrap());
825 let sub = value[3];
826 Ok(SdoResponse::ConfirmDownload { index, sub })
827 }
828 ServerCommand::BlockDownload => {
829 match BlockDownloadServerSubcommand::try_from(value[0] & 0x3)? {
830 BlockDownloadServerSubcommand::ConfirmBlock => {
831 let ackseq = value[1];
832 let blksize = value[2];
833 Ok(SdoResponse::ConfirmBlock { ackseq, blksize })
834 }
835 BlockDownloadServerSubcommand::InitiateDownloadAck => {
836 let sc = (value[0] & (1 << 2)) != 0;
837 let index = u16::from_le_bytes(value[1..3].try_into().unwrap());
838 let sub = value[3];
839 let blksize = value[4];
840 Ok(SdoResponse::ConfirmBlockDownload {
841 sc,
842 index,
843 sub,
844 blksize,
845 })
846 }
847 BlockDownloadServerSubcommand::EndDownloadAck => {
848 Ok(SdoResponse::ConfirmBlockDownloadEnd)
849 }
850 }
851 }
852 ServerCommand::BlockUpload => {
853 match BlockUploadServerSubcommand::try_from(value[0] & 0x3)? {
854 BlockUploadServerSubcommand::InitiateUpload => {
855 let s = (value[0] & (1 << 1)) != 0;
856 let sc = (value[0] & (1 << 2)) != 0;
857 let index = u16::from_le_bytes(value[1..3].try_into().unwrap());
858 let sub = value[3];
859 let size = u32::from_le_bytes(value[4..8].try_into().unwrap());
860 Ok(SdoResponse::ConfirmBlockUpload {
861 sc,
862 s,
863 index,
864 sub,
865 size,
866 })
867 }
868 BlockUploadServerSubcommand::EndUpload => {
869 let n = (value[0] >> 2) & 7;
870 let crc = u16::from_le_bytes(value[1..3].try_into().unwrap());
871 Ok(SdoResponse::BlockUploadEnd { n, crc })
872 }
873 }
874 }
875 ServerCommand::Abort => {
876 let index = u16::from_le_bytes(value[1..3].try_into().unwrap());
877 let sub = value[3];
878 let abort_code = u32::from_le_bytes(value[4..8].try_into().unwrap());
879 Ok(SdoResponse::Abort {
880 index,
881 sub,
882 abort_code,
883 })
884 }
885 }
886 }
887}
888
889impl TryFrom<CanMessage> for SdoResponse {
890 type Error = ();
891 fn try_from(msg: CanMessage) -> Result<Self, Self::Error> {
892 msg.data.try_into()
893 }
894}
895impl SdoResponse {
896 pub fn expedited_upload(index: u16, sub: u8, data: &[u8]) -> SdoResponse {
898 if data.len() > 4 {
899 panic!("Cannot create expedited upload with more than 4 bytes");
900 }
901
902 let mut msg_data = [0; 4];
903 msg_data[0..data.len()].copy_from_slice(data);
904
905 let s;
906 let n;
907 if data.is_empty() {
910 s = false;
911 n = 0;
912 } else {
913 s = true;
914 n = 4 - data.len() as u8;
915 }
916 SdoResponse::ConfirmUpload {
917 index,
918 sub,
919 e: true,
920 s,
921 n,
922 data: msg_data,
923 }
924 }
925
926 pub fn upload_acknowledge(index: u16, sub: u8, size: Option<u32>) -> SdoResponse {
928 SdoResponse::ConfirmUpload {
929 n: 0,
930 e: false,
931 s: size.is_some(),
932 index,
933 sub,
934 data: size.unwrap_or(0).to_le_bytes(),
935 }
936 }
937
938 pub fn block_upload_acknowledge(
940 index: u16,
941 sc: bool,
942 sub: u8,
943 size: Option<u32>,
944 ) -> SdoResponse {
945 SdoResponse::ConfirmBlockUpload {
946 sc,
947 s: size.is_some(),
948 index,
949 sub,
950 size: size.unwrap_or(0),
951 }
952 }
953
954 pub fn upload_segment(t: bool, c: bool, data: &[u8]) -> SdoResponse {
956 let n = (7 - data.len()) as u8;
957 let mut buf = [0; 7];
958 buf[0..data.len()].copy_from_slice(data);
959 SdoResponse::UploadSegment { t, n, c, data: buf }
960 }
961
962 pub fn download_acknowledge(index: u16, sub: u8) -> SdoResponse {
964 SdoResponse::ConfirmDownload { index, sub }
965 }
966
967 pub fn download_segment_acknowledge(t: bool) -> SdoResponse {
969 SdoResponse::ConfirmDownloadSegment { t }
970 }
971
972 pub fn block_download_acknowledge(sc: bool, index: u16, sub: u8, blksize: u8) -> SdoResponse {
974 SdoResponse::ConfirmBlockDownload {
975 sc,
976 index,
977 sub,
978 blksize,
979 }
980 }
981
982 pub fn confirm_block(ackseq: u8, blksize: u8) -> SdoResponse {
984 SdoResponse::ConfirmBlock { ackseq, blksize }
985 }
986
987 pub fn abort(index: u16, sub: u8, abort_code: AbortCode) -> SdoResponse {
989 let abort_code = abort_code as u32;
990 SdoResponse::Abort {
991 index,
992 sub,
993 abort_code,
994 }
995 }
996
997 pub fn to_bytes(&self) -> [u8; 8] {
999 let mut payload = [0; 8];
1000
1001 match self {
1002 SdoResponse::ConfirmUpload {
1003 n,
1004 e,
1005 s,
1006 index,
1007 sub,
1008 data,
1009 } => {
1010 payload[0] = ((ServerCommand::Upload as u8) << 5)
1011 | ((n & 0x3) << 2)
1012 | ((*e as u8) << 1)
1013 | (*s as u8);
1014 payload[1] = (index & 0xff) as u8;
1015 payload[2] = (index >> 8) as u8;
1016 payload[3] = *sub;
1017 payload[4..8].copy_from_slice(data);
1018 }
1019 SdoResponse::ConfirmDownload { index, sub } => {
1020 payload[0] = (ServerCommand::Download as u8) << 5;
1021 payload[1] = (index & 0xff) as u8;
1022 payload[2] = (index >> 8) as u8;
1023 payload[3] = *sub;
1024 }
1025 SdoResponse::UploadSegment { t, n, c, data } => {
1026 payload[0] = ((ServerCommand::SegmentUpload as u8) << 5)
1027 | ((*t as u8) << 4)
1028 | (n << 1)
1029 | *c as u8;
1030 payload[1..8].copy_from_slice(data);
1031 }
1032 SdoResponse::ConfirmBlockDownload {
1033 sc,
1034 index,
1035 sub,
1036 blksize,
1037 } => {
1038 payload[0] = ((ServerCommand::BlockDownload as u8) << 5)
1039 | ((*sc as u8) << 2)
1040 | (BlockDownloadServerSubcommand::InitiateDownloadAck as u8);
1041 payload[1] = (index & 0xff) as u8;
1042 payload[2] = (index >> 8) as u8;
1043 payload[3] = *sub;
1044 payload[4] = *blksize;
1045 }
1046 SdoResponse::ConfirmBlock { ackseq, blksize } => {
1047 payload[0] = ((ServerCommand::BlockDownload as u8) << 5)
1048 | (BlockDownloadServerSubcommand::ConfirmBlock as u8);
1049 payload[1] = *ackseq;
1050 payload[2] = *blksize;
1051 }
1052 SdoResponse::ConfirmBlockDownloadEnd => {
1053 payload[0] = ((ServerCommand::BlockDownload as u8) << 5)
1054 | (BlockDownloadServerSubcommand::EndDownloadAck as u8);
1055 }
1056 SdoResponse::ConfirmDownloadSegment { t } => {
1057 payload[0] = ((ServerCommand::SegmentDownload as u8) << 5) | ((*t as u8) << 4);
1058 }
1059 SdoResponse::Abort {
1060 index,
1061 sub,
1062 abort_code,
1063 } => {
1064 payload[0] = (ServerCommand::Abort as u8) << 5;
1065 payload[1] = (index & 0xff) as u8;
1066 payload[2] = (index >> 8) as u8;
1067 payload[3] = *sub;
1068 payload[4..8].copy_from_slice(&abort_code.to_le_bytes());
1069 }
1070 SdoResponse::ConfirmBlockUpload {
1071 sc,
1072 s,
1073 index,
1074 sub,
1075 size,
1076 } => {
1077 payload[0] = ((ServerCommand::BlockUpload as u8) << 5)
1078 | ((*sc as u8) << 2)
1079 | ((*s as u8) << 1)
1080 | (BlockUploadServerSubcommand::InitiateUpload as u8);
1081 payload[1] = (index & 0xff) as u8;
1082 payload[2] = (index >> 8) as u8;
1083 payload[3] = *sub;
1084 payload[4..8].copy_from_slice(&size.to_le_bytes());
1085 }
1086 SdoResponse::BlockUploadEnd { n, crc } => {
1087 payload[0] = ((ServerCommand::BlockUpload as u8) << 5)
1088 | (*n << 2)
1089 | (BlockUploadServerSubcommand::EndUpload as u8);
1090 payload[1..3].copy_from_slice(&crc.to_le_bytes());
1091 }
1092 }
1093 payload
1094 }
1095 pub fn to_can_message(self, id: CanId) -> CanMessage {
1097 CanMessage::new(id, &self.to_bytes())
1098 }
1099}