1use num::FromPrimitive;
35use num_derive::FromPrimitive;
36
37use crate::error::{Error, ErrorCode};
38use crate::sc::{self, GeneralCode, StatusReport};
39use crate::transport::exchange::{Exchange, MessageMeta};
40use crate::transport::{MAX_RX_PAYLOAD_SIZE, MAX_TX_PAYLOAD_SIZE};
41use crate::utils::storage::{ReadBuf, WriteBuf};
42
43mod handler;
44mod nego;
45mod read;
46mod write;
47
48pub use handler::*;
49pub use read::*;
50pub use write::*;
51
52pub type BdxBuffer = crate::transport::exchange::Buffer;
59
60pub const PROTO_ID_BDX: u16 = 0x0002;
62
63pub const BDX_VERSION: u8 = 0;
66
67#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70#[repr(u8)]
71pub enum OpCode {
72 SendInit = 0x01,
74 SendAccept = 0x02,
76 ReceiveInit = 0x04,
78 ReceiveAccept = 0x05,
80 BlockQuery = 0x10,
82 Block = 0x11,
84 BlockEof = 0x12,
86 BlockAck = 0x13,
88 BlockAckEof = 0x14,
90 BlockQueryWithSkip = 0x15,
92}
93
94impl OpCode {
95 pub fn meta(self) -> MessageMeta {
98 MessageMeta {
99 proto_id: PROTO_ID_BDX,
100 proto_opcode: self as u8,
101 reliable: true,
102 }
103 }
104}
105
106impl From<OpCode> for MessageMeta {
107 fn from(op: OpCode) -> Self {
108 op.meta()
109 }
110}
111
112#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq)]
114#[cfg_attr(feature = "defmt", derive(defmt::Format))]
115#[repr(u16)]
116pub enum BdxStatus {
117 LengthTooLarge = 0x0012,
118 LengthTooShort = 0x0013,
119 LengthMismatch = 0x0014,
120 LengthRequired = 0x0015,
121 BadMessageContents = 0x0016,
122 BadBlockCounter = 0x0017,
123 UnexpectedMessage = 0x0018,
124 ResponderBusy = 0x0019,
125 TransferFailedUnknownError = 0x001F,
126 TransferMethodNotSupported = 0x0050,
127 FileDesignatorUnknown = 0x0051,
128 StartOffsetNotSupported = 0x0052,
129 VersionNotSupported = 0x0053,
130 Unknown = 0x005F,
131}
132
133impl BdxStatus {
134 pub fn as_report(self) -> StatusReport<'static> {
137 StatusReport {
138 general_code: GeneralCode::Failure,
139 proto_id: PROTO_ID_BDX as u32,
140 proto_code: self as u16,
141 proto_data: &[],
142 }
143 }
144}
145
146#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
153#[cfg_attr(feature = "defmt", derive(defmt::Format))]
154pub struct TransferControl {
155 pub version: u8,
157 pub sender_drive: bool,
159 pub receiver_drive: bool,
161 pub async_mode: bool,
163}
164
165impl TransferControl {
166 const SENDER_DRIVE: u8 = 1 << 4;
167 const RECEIVER_DRIVE: u8 = 1 << 5;
168 const ASYNC: u8 = 1 << 6;
169 const VERSION_MASK: u8 = 0x0f;
170
171 pub(crate) const fn select(sender_drive: bool) -> Self {
175 Self {
176 version: BDX_VERSION,
177 sender_drive,
178 receiver_drive: !sender_drive,
179 async_mode: false,
180 }
181 }
182
183 fn from_byte(b: u8) -> Self {
184 Self {
185 version: b & Self::VERSION_MASK,
186 sender_drive: b & Self::SENDER_DRIVE != 0,
187 receiver_drive: b & Self::RECEIVER_DRIVE != 0,
188 async_mode: b & Self::ASYNC != 0,
189 }
190 }
191
192 fn to_byte(self) -> u8 {
193 let mut b = self.version & Self::VERSION_MASK;
194
195 if self.sender_drive {
196 b |= Self::SENDER_DRIVE;
197 }
198
199 if self.receiver_drive {
200 b |= Self::RECEIVER_DRIVE;
201 }
202
203 if self.async_mode {
204 b |= Self::ASYNC;
205 }
206
207 b
208 }
209}
210
211#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
213#[cfg_attr(feature = "defmt", derive(defmt::Format))]
214pub struct RangeControl {
215 pub def_len: bool,
217 pub start_offset: bool,
219 pub wide_range: bool,
221}
222
223impl RangeControl {
224 const DEF_LEN: u8 = 1 << 0;
225 const START_OFFSET: u8 = 1 << 1;
226 const WIDE_RANGE: u8 = 1 << 4;
227
228 fn from_byte(b: u8) -> Self {
229 Self {
230 def_len: b & Self::DEF_LEN != 0,
231 start_offset: b & Self::START_OFFSET != 0,
232 wide_range: b & Self::WIDE_RANGE != 0,
233 }
234 }
235
236 fn to_byte(self) -> u8 {
237 let mut b = 0;
238
239 if self.def_len {
240 b |= Self::DEF_LEN;
241 }
242
243 if self.start_offset {
244 b |= Self::START_OFFSET;
245 }
246
247 if self.wide_range {
248 b |= Self::WIDE_RANGE;
249 }
250
251 b
252 }
253}
254
255#[derive(Debug, Clone)]
261pub struct TransferInit<'a> {
262 pub transfer_control: TransferControl,
264 pub range_control: RangeControl,
266 pub max_block_size: u16,
268 pub start_offset: u64,
271 pub length: u64,
274 pub file_designator: &'a [u8],
276 pub metadata: &'a [u8],
278}
279
280impl<'a> TransferInit<'a> {
281 pub fn parse(payload: &'a [u8]) -> Result<Self, Error> {
283 let mut rb = ReadBuf::new(payload);
284
285 let transfer_control = TransferControl::from_byte(rb.le_u8()?);
286 let range_control = RangeControl::from_byte(rb.le_u8()?);
287 let max_block_size = rb.le_u16()?;
288
289 let start_offset = if range_control.start_offset {
290 if range_control.wide_range {
291 rb.le_u64()?
292 } else {
293 rb.le_u32()? as u64
294 }
295 } else {
296 0
297 };
298 let length = if range_control.def_len {
299 if range_control.wide_range {
300 rb.le_u64()?
301 } else {
302 rb.le_u32()? as u64
303 }
304 } else {
305 0
306 };
307
308 let fdl = rb.le_u16()? as usize;
309 let off = rb.read_off();
312 let end = off.checked_add(fdl).ok_or(ErrorCode::TruncatedPacket)?;
313 let file_designator = payload.get(off..end).ok_or(ErrorCode::TruncatedPacket)?;
314 let metadata = &payload[end..];
315
316 Ok(Self {
317 transfer_control,
318 range_control,
319 max_block_size,
320 start_offset,
321 length,
322 file_designator,
323 metadata,
324 })
325 }
326
327 pub fn write(&self, wb: &mut WriteBuf) -> Result<(), Error> {
329 wb.le_u8(self.transfer_control.to_byte())?;
330 wb.le_u8(self.range_control.to_byte())?;
331 wb.le_u16(self.max_block_size)?;
332
333 if self.range_control.start_offset {
334 if self.range_control.wide_range {
335 wb.le_u64(self.start_offset)?;
336 } else {
337 wb.le_u32(self.start_offset as u32)?;
338 }
339 }
340
341 if self.range_control.def_len {
342 if self.range_control.wide_range {
343 wb.le_u64(self.length)?;
344 } else {
345 wb.le_u32(self.length as u32)?;
346 }
347 }
348
349 wb.le_u16(self.file_designator.len() as u16)?;
350 wb.append(self.file_designator)?;
351 wb.append(self.metadata)?;
352
353 Ok(())
354 }
355}
356
357#[derive(Debug, Clone)]
364pub struct TransferAccept<'a> {
365 pub receive: bool,
368 pub transfer_control: TransferControl,
370 pub range_control: RangeControl,
372 pub max_block_size: u16,
374 pub length: u64,
377 pub metadata: &'a [u8],
379}
380
381impl<'a> TransferAccept<'a> {
382 pub fn parse(receive: bool, payload: &'a [u8]) -> Result<Self, Error> {
385 let mut rb = ReadBuf::new(payload);
386
387 let transfer_control = TransferControl::from_byte(rb.le_u8()?);
388
389 let (range_control, max_block_size, length) = if receive {
390 let range_control = RangeControl::from_byte(rb.le_u8()?);
391 let max_block_size = rb.le_u16()?;
393 let length = if range_control.def_len {
394 if range_control.wide_range {
395 rb.le_u64()?
396 } else {
397 rb.le_u32()? as u64
398 }
399 } else {
400 0
401 };
402 (range_control, max_block_size, length)
403 } else {
404 (RangeControl::default(), rb.le_u16()?, 0)
405 };
406
407 let metadata = &payload[rb.read_off()..];
409
410 Ok(Self {
411 receive,
412 transfer_control,
413 range_control,
414 max_block_size,
415 length,
416 metadata,
417 })
418 }
419
420 pub fn write(&self, wb: &mut WriteBuf) -> Result<(), Error> {
422 wb.le_u8(self.transfer_control.to_byte())?;
423
424 if self.receive {
425 wb.le_u8(self.range_control.to_byte())?;
426 wb.le_u16(self.max_block_size)?;
427
428 if self.range_control.def_len {
429 if self.range_control.wide_range {
430 wb.le_u64(self.length)?;
431 } else {
432 wb.le_u32(self.length as u32)?;
433 }
434 }
435 } else {
436 wb.le_u16(self.max_block_size)?;
437 }
438
439 wb.append(self.metadata)?;
440
441 Ok(())
442 }
443}
444
445#[derive(Debug, Clone)]
448pub struct Block<'a> {
449 pub block_counter: u32,
451 pub data: &'a [u8],
454}
455
456impl<'a> Block<'a> {
457 pub fn parse(payload: &'a [u8]) -> Result<Self, Error> {
459 let mut rb = ReadBuf::new(payload);
460 let block_counter = rb.le_u32()?;
461 let data = &payload[rb.read_off()..];
463
464 Ok(Self {
465 block_counter,
466 data,
467 })
468 }
469
470 pub fn write(&self, wb: &mut WriteBuf) -> Result<(), Error> {
472 wb.le_u32(self.block_counter)?;
473 wb.append(self.data)?;
474
475 Ok(())
476 }
477}
478
479#[derive(Debug, Clone, Copy, Eq, PartialEq)]
485pub struct BlockQuery {
486 pub block_counter: u32,
488}
489
490impl BlockQuery {
491 pub fn parse(payload: &[u8]) -> Result<Self, Error> {
493 let mut rb = ReadBuf::new(payload);
494
495 Ok(Self {
496 block_counter: rb.le_u32()?,
497 })
498 }
499
500 pub fn write(&self, wb: &mut WriteBuf) -> Result<(), Error> {
502 wb.le_u32(self.block_counter)
503 }
504}
505
506#[derive(Debug, Clone, Copy, Eq, PartialEq)]
509pub struct BlockQueryWithSkip {
510 pub block_counter: u32,
512 pub bytes_to_skip: u64,
514}
515
516impl BlockQueryWithSkip {
517 pub fn parse(payload: &[u8]) -> Result<Self, Error> {
519 let mut rb = ReadBuf::new(payload);
520
521 Ok(Self {
522 block_counter: rb.le_u32()?,
523 bytes_to_skip: rb.le_u64()?,
524 })
525 }
526
527 pub fn write(&self, wb: &mut WriteBuf) -> Result<(), Error> {
529 wb.le_u32(self.block_counter)?;
530 wb.le_u64(self.bytes_to_skip)?;
531
532 Ok(())
533 }
534}
535
536pub(crate) fn opcode(meta: &MessageMeta) -> Option<OpCode> {
538 (meta.proto_id == PROTO_ID_BDX).then(|| OpCode::from_u8(meta.proto_opcode))?
539}
540
541const BLOCK_HEADER_LEN: usize = 4;
551
552const fn max_block_size(payload: usize) -> u16 {
556 let data = payload - BLOCK_HEADER_LEN;
557
558 if data > u16::MAX as usize {
559 u16::MAX
560 } else {
561 data as u16
562 }
563}
564
565const MAX_RX_BLOCK_SIZE: u16 = max_block_size(MAX_RX_PAYLOAD_SIZE);
569
570const MAX_TX_BLOCK_SIZE: u16 = max_block_size(MAX_TX_PAYLOAD_SIZE);
574
575#[derive(Debug, Clone, Copy, Eq, PartialEq)]
581enum Drive {
582 Driver,
585 Follower,
588}
589
590#[cfg(test)]
591mod tests {
592 use crate::utils::storage::WriteBuf;
593
594 use super::*;
595
596 fn roundtrip_init(msg: &TransferInit) {
597 let mut buf = [0u8; 256];
598 let mut wb = WriteBuf::new(&mut buf);
599 msg.write(&mut wb).unwrap();
600 let bytes = wb.as_slice().to_vec();
601
602 let parsed = TransferInit::parse(&bytes).unwrap();
603 assert_eq!(parsed.transfer_control, msg.transfer_control);
604 assert_eq!(parsed.range_control, msg.range_control);
605 assert_eq!(parsed.max_block_size, msg.max_block_size);
606 assert_eq!(parsed.start_offset, msg.start_offset);
607 assert_eq!(parsed.length, msg.length);
608 assert_eq!(parsed.file_designator, msg.file_designator);
609 assert_eq!(parsed.metadata, msg.metadata);
610 }
611
612 #[test]
613 fn transfer_control_flags_roundtrip() {
614 for tc in [
615 TransferControl {
616 version: 0,
617 sender_drive: true,
618 receiver_drive: false,
619 async_mode: false,
620 },
621 TransferControl {
622 version: 0,
623 sender_drive: false,
624 receiver_drive: true,
625 async_mode: false,
626 },
627 TransferControl {
628 version: 0,
629 sender_drive: true,
630 receiver_drive: true,
631 async_mode: true,
632 },
633 ] {
634 assert_eq!(TransferControl::from_byte(tc.to_byte()), tc);
635 }
636 assert_eq!(
638 TransferControl {
639 version: 0,
640 sender_drive: true,
641 ..Default::default()
642 }
643 .to_byte(),
644 0x10
645 );
646 assert_eq!(
647 TransferControl {
648 version: 0,
649 receiver_drive: true,
650 ..Default::default()
651 }
652 .to_byte(),
653 0x20
654 );
655 }
656
657 #[test]
658 fn transfer_control_select_picks_one_drive() {
659 let sender = TransferControl::select(true);
660 assert!(sender.sender_drive && !sender.receiver_drive && !sender.async_mode);
661 assert_eq!(sender.version, BDX_VERSION);
662
663 let receiver = TransferControl::select(false);
664 assert!(receiver.receiver_drive && !receiver.sender_drive && !receiver.async_mode);
665 }
666
667 #[test]
668 fn range_control_flags_roundtrip() {
669 let rc = RangeControl {
670 def_len: true,
671 start_offset: true,
672 wide_range: true,
673 };
674 assert_eq!(RangeControl::from_byte(rc.to_byte()), rc);
675 assert_eq!(rc.to_byte(), 0x13); }
677
678 #[test]
679 fn receive_init_minimal_roundtrip() {
680 roundtrip_init(&TransferInit {
681 transfer_control: TransferControl {
682 version: 0,
683 sender_drive: true,
684 receiver_drive: true,
685 async_mode: false,
686 },
687 range_control: RangeControl::default(),
688 max_block_size: 1024,
689 start_offset: 0,
690 length: 0,
691 file_designator: b"firmware.bin",
692 metadata: &[],
693 });
694 }
695
696 #[test]
697 fn receive_init_with_offset_and_length_roundtrip() {
698 roundtrip_init(&TransferInit {
699 transfer_control: TransferControl {
700 version: 0,
701 receiver_drive: true,
702 ..Default::default()
703 },
704 range_control: RangeControl {
705 def_len: true,
706 start_offset: true,
707 wide_range: false,
708 },
709 max_block_size: 1024,
710 start_offset: 0x1234,
711 length: 0x5_6789,
712 file_designator: b"img",
713 metadata: &[0xde, 0xad],
714 });
715 }
716
717 #[test]
718 fn wide_range_uses_8_octets() {
719 let msg = TransferInit {
720 transfer_control: TransferControl {
721 version: 0,
722 sender_drive: true,
723 ..Default::default()
724 },
725 range_control: RangeControl {
726 def_len: true,
727 start_offset: false,
728 wide_range: true,
729 },
730 max_block_size: 512,
731 start_offset: 0,
732 length: 0x1_0000_0000, file_designator: b"x",
734 metadata: &[],
735 };
736 roundtrip_init(&msg);
737 let mut buf = [0u8; 64];
739 let mut wb = WriteBuf::new(&mut buf);
740 msg.write(&mut wb).unwrap();
741 assert_eq!(wb.as_slice().len(), 15);
742 }
743
744 #[test]
745 fn send_accept_roundtrip() {
746 let msg = TransferAccept {
747 receive: false,
748 transfer_control: TransferControl {
749 version: 0,
750 sender_drive: true,
751 ..Default::default()
752 },
753 range_control: RangeControl::default(),
754 max_block_size: 1024,
755 length: 0,
756 metadata: &[],
757 };
758 let mut buf = [0u8; 64];
759 let mut wb = WriteBuf::new(&mut buf);
760 msg.write(&mut wb).unwrap();
761 assert_eq!(wb.as_slice().len(), 3);
763 let bytes = wb.as_slice().to_vec();
764 let parsed = TransferAccept::parse(false, &bytes).unwrap();
765 assert!(parsed.transfer_control.sender_drive);
766 assert_eq!(parsed.max_block_size, 1024);
767 }
768
769 #[test]
770 fn receive_accept_roundtrip() {
771 let msg = TransferAccept {
772 receive: true,
773 transfer_control: TransferControl {
774 version: 0,
775 sender_drive: true,
776 ..Default::default()
777 },
778 range_control: RangeControl {
779 def_len: true,
780 start_offset: false,
781 wide_range: false,
782 },
783 max_block_size: 1024,
784 length: 123_456,
785 metadata: &[],
786 };
787 let mut buf = [0u8; 64];
788 let mut wb = WriteBuf::new(&mut buf);
789 msg.write(&mut wb).unwrap();
790 let bytes = wb.as_slice().to_vec();
791 let parsed = TransferAccept::parse(true, &bytes).unwrap();
792 assert!(parsed.transfer_control.sender_drive);
793 assert_eq!(parsed.max_block_size, 1024);
794 assert!(parsed.range_control.def_len);
795 assert_eq!(parsed.length, 123_456);
796 }
797
798 #[test]
799 fn block_roundtrip() {
800 let msg = Block {
801 block_counter: 7,
802 data: b"hello world",
803 };
804 let mut buf = [0u8; 64];
805 let mut wb = WriteBuf::new(&mut buf);
806 msg.write(&mut wb).unwrap();
807 let bytes = wb.as_slice().to_vec();
808 let parsed = Block::parse(&bytes).unwrap();
809 assert_eq!(parsed.block_counter, 7);
810 assert_eq!(parsed.data, b"hello world");
811 }
812
813 #[test]
814 fn block_eof_empty_roundtrip() {
815 let msg = Block {
816 block_counter: 0,
817 data: &[],
818 };
819 let mut buf = [0u8; 8];
820 let mut wb = WriteBuf::new(&mut buf);
821 msg.write(&mut wb).unwrap();
822 assert_eq!(wb.as_slice().len(), 4); let bytes = wb.as_slice().to_vec();
824 let parsed = Block::parse(&bytes).unwrap();
825 assert_eq!(parsed.block_counter, 0);
826 assert!(parsed.data.is_empty());
827 }
828
829 #[test]
830 fn block_query_and_skip_roundtrip() {
831 let mut buf = [0u8; 32];
832
833 let mut wb = WriteBuf::new(&mut buf);
834 BlockQuery { block_counter: 5 }.write(&mut wb).unwrap();
835 assert_eq!(wb.as_slice().len(), 4);
836 let bytes = wb.as_slice().to_vec();
837 assert_eq!(BlockQuery::parse(&bytes).unwrap().block_counter, 5);
838
839 let mut wb = WriteBuf::new(&mut buf);
840 BlockQueryWithSkip {
841 block_counter: 9,
842 bytes_to_skip: 0x1_0000,
843 }
844 .write(&mut wb)
845 .unwrap();
846 assert_eq!(wb.as_slice().len(), 12); let bytes = wb.as_slice().to_vec();
848 let parsed = BlockQueryWithSkip::parse(&bytes).unwrap();
849 assert_eq!(parsed.block_counter, 9);
850 assert_eq!(parsed.bytes_to_skip, 0x1_0000);
851 }
852
853 #[test]
854 fn truncated_is_rejected() {
855 assert!(BlockQuery::parse(&[1, 2, 3]).is_err()); assert!(TransferInit::parse(&[0x00]).is_err()); }
858
859 #[test]
860 fn opcode_meta_is_bdx_and_reliable() {
861 let meta = OpCode::ReceiveInit.meta();
862 assert_eq!(meta.proto_id, PROTO_ID_BDX);
863 assert_eq!(meta.proto_opcode, 0x04);
864 assert!(meta.reliable);
865 assert_eq!(opcode(&meta), Some(OpCode::ReceiveInit));
866 }
867}