1use crate::buffer::Buffer;
4use crate::fmt::{debug, trace, warning};
5use crate::transport::{CommandStatus, Transport, TransportError};
6use core::assert_matches;
7use core::borrow::BorrowMut;
8use core::cmp::min;
9use usb_device::UsbError;
10use usb_device::bus::{UsbBus, UsbBusAllocator};
11use usb_device::class::ControlIn;
12use usb_device::class_prelude::DescriptorWriter;
13use usb_device::control::{Recipient, RequestType};
14use usb_device::endpoint::{Endpoint, In, Out};
15
16pub(crate) const TRANSPORT_BBB: u8 = 0x50;
18
19const CLASS_SPECIFIC_BULK_ONLY_MASS_STORAGE_RESET: u8 = 0xFF;
20const CLASS_SPECIFIC_GET_MAX_LUN: u8 = 0xFE;
21
22const CBW_SIGNATURE_LE: [u8; 4] = 0x43425355u32.to_le_bytes();
23const CSW_SIGNATURE_LE: [u8; 4] = 0x53425355u32.to_le_bytes();
24
25const CBW_LEN: usize = 31;
26const CSW_LEN: usize = 13;
27
28const FILL_BYTE: u8 = 0xFF;
29
30struct InvalidCbwError; #[derive(Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub enum BulkOnlyError {
36 IoBufferOverflow,
38 InvalidMaxLun,
40 InvalidState,
42 FullPacketExpected,
44 BufferTooSmall,
46}
47
48pub struct CommandBlock<'a> {
50 pub bytes: &'a [u8],
52 pub lun: u8,
53}
54
55#[derive(Debug, Copy, Clone)]
56#[cfg_attr(feature = "defmt", derive(defmt::Format))]
57enum State {
58 CommandTransfer,
60 CommandTransferInvalid,
62 DataTransferNoData,
64 StatusTransfer,
67 DataTransferToHost,
69 DataTransferToHostStatusAwait,
71 DataTransferToHostEnding,
73 DataTransferFromHost,
75 DataTransferFromHostEnding,
77}
78
79#[repr(u8)]
80#[derive(Default, Debug, Copy, Clone)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82enum DataDirection {
83 Out,
84 In,
85 #[default]
86 NotExpected,
87}
88
89struct StatusAndResidue {
90 status: CommandStatus,
91 data_residue: u32,
92}
93
94type BulkOnlyTransportResult<T> = Result<T, TransportError<BulkOnlyError>>;
95
96pub struct BulkOnly<'alloc, Bus: UsbBus, Buf: BorrowMut<[u8]>> {
106 in_ep: Endpoint<'alloc, Bus, In>,
107 out_ep: Endpoint<'alloc, Bus, Out>,
108 buf: Buffer<Buf>,
109 state: State,
110 cbw: CommandBlockWrapper,
111 cs: Option<StatusAndResidue>,
112 max_lun: u8,
113 left_to_transfer: u32,
114}
115
116impl<'alloc, Bus, Buf> BulkOnly<'alloc, Bus, Buf>
117where
118 Bus: UsbBus,
119 Buf: BorrowMut<[u8]>,
120{
121 pub fn new(
141 alloc: &'alloc UsbBusAllocator<Bus>,
142 packet_size: u16,
143 max_lun: u8,
144 buf: Buf,
145 ) -> Result<BulkOnly<'alloc, Bus, Buf>, BulkOnlyError> {
146 if max_lun > 0x0F {
147 return Err(BulkOnlyError::InvalidMaxLun);
148 }
149
150 let buf_len = buf.borrow().len();
151 if buf_len < CBW_LEN || buf_len < packet_size as usize {
152 return Err(BulkOnlyError::BufferTooSmall);
153 }
154
155 Ok(BulkOnly {
156 in_ep: alloc.bulk(packet_size),
157 out_ep: alloc.bulk(packet_size),
158 buf: Buffer::new(buf),
159 state: State::CommandTransfer,
160 cbw: Default::default(),
161 cs: Default::default(),
162 max_lun,
163 left_to_transfer: 0,
164 })
165 }
166
167 pub fn set_status(&mut self, status: CommandStatus, data_processed: u32) {
177 assert_matches!(
178 self.state,
179 State::DataTransferToHost
180 | State::DataTransferFromHost
181 | State::DataTransferNoData
182 | State::DataTransferToHostStatusAwait
183 );
184 let data_residue = self.cbw.data_transfer_len.saturating_sub(data_processed);
185 trace!("usb: bbb: Set status: {} residue: {}", status, data_residue);
186 self.cs = Some(StatusAndResidue {
187 status,
188 data_residue,
189 });
190 }
191
192 pub fn get_command(&self) -> Option<CommandBlock<'_>> {
194 if matches!(self.state, State::CommandTransfer) {
195 return None;
196 }
197
198 Some(CommandBlock {
199 bytes: &self.cbw.block[..self.cbw.block_len],
200 lun: self.cbw.lun,
201 })
202 }
203
204 pub fn read_data(&mut self, dst: &mut [u8]) -> BulkOnlyTransportResult<usize> {
215 if !matches!(self.state, State::DataTransferFromHost) {
216 return Err(TransportError::Error(BulkOnlyError::InvalidState));
217 }
218
219 Ok(self
220 .buf
221 .read(|buf| {
222 let size = min(dst.len(), buf.len());
224 dst[..size].copy_from_slice(&buf[..size]);
225 Ok::<usize, core::convert::Infallible>(size)
226 })
227 .unwrap_or(0))
228 }
229
230 pub fn write_data(&mut self, src: &[u8]) -> BulkOnlyTransportResult<usize> {
241 if !matches!(self.state, State::DataTransferToHost) {
242 return Err(TransportError::Error(BulkOnlyError::InvalidState));
243 }
244
245 Ok(self
246 .buf
247 .write(&src[..min(src.len(), self.left_to_transfer as usize)]))
248 }
249
250 pub fn try_write_data_all(&mut self, src: &[u8]) -> BulkOnlyTransportResult<()> {
259 if !matches!(self.state, State::DataTransferToHost) {
260 return Err(TransportError::Error(BulkOnlyError::InvalidState));
261 }
262
263 self.buf
264 .write_all(
265 src.len(),
266 TransportError::Error(BulkOnlyError::IoBufferOverflow),
267 |dst| {
268 dst[..src.len()].copy_from_slice(src);
269 Ok(src.len())
270 },
271 )
272 .map(|bytes_written| debug!("usb: bbb: buf written: {}", bytes_written))
273 }
274
275 pub fn has_status(&self) -> bool {
277 self.cs.is_some()
278 }
279
280 fn enter_state_command_transfer(&mut self) {
281 self.cs = None;
282 self.left_to_transfer = 0;
283 self.in_ep.unstall();
284 self.out_ep.unstall();
285
286 self.state = State::CommandTransfer;
287 trace!("usb: bbb: enter {:?}", self.state);
288 }
289
290 #[inline]
291 fn enter_state_cbw_invalid(&mut self) {
292 self.state = State::CommandTransferInvalid;
293 trace!("usb: bbb: enter {:?}", self.state);
294 }
295
296 #[inline]
297 fn enter_state_data_transfer_no_data(&mut self) {
298 self.state = State::DataTransferNoData;
299 trace!("usb: bbb: enter {:?}", self.state);
300 }
301
302 #[inline]
303 fn enter_state_data_transfer_to_host(&mut self) {
304 self.state = State::DataTransferToHost;
305 trace!("usb: bbb: enter {:?}", self.state);
306 }
307
308 #[inline]
309 fn enter_state_data_transfer_to_host_status_await(&mut self) {
310 self.state = State::DataTransferToHostStatusAwait;
311 trace!("usb: bbb: enter {:?}", self.state);
312 }
313
314 #[inline]
315 fn enter_state_data_transfer_to_host_ending(&mut self) {
316 self.state = State::DataTransferToHostEnding;
317 trace!("usb: bbb: enter {:?}", self.state);
318 }
319
320 #[inline]
321 fn enter_state_data_transfer_from_host_ending(&mut self) {
322 self.state = State::DataTransferFromHostEnding;
323 trace!("usb: bbb: enter {:?}", self.state);
324 }
325
326 #[inline]
327 fn enter_state_data_transfer_from_host(&mut self) {
328 self.state = State::DataTransferFromHost;
329 trace!("usb: bbb: enter {:?}", self.state);
330 }
331
332 fn enter_state_status_transfer(&mut self) {
333 let Some(csw_bytes) = self.build_csw() else {
334 debug!("usb: bbb: UNEXPECTED no CSW");
335 panic!("usb: bbb: UNEXPECTED no CSW");
336 };
337
338 self.buf.clean();
340 self.buf.write(csw_bytes.as_slice());
341
342 self.state = State::StatusTransfer;
343 trace!("usb: bbb: enter {:?}", self.state);
344 }
345
346 fn handle_read_cbw(&mut self) -> BulkOnlyTransportResult<()> {
348 assert_matches!(self.state, State::CommandTransfer);
349
350 self.read_packet()?;
351
352 if self.buf.available_read() >= CBW_LEN {
353 match self.try_parse_cbw() {
355 Ok(cbw) => {
356 trace!("usb: bbb: Recv CBW: {}", cbw);
357 return self.start_data_transfer(cbw);
358 }
359 Err(_) => {
360 self.enter_state_cbw_invalid();
361 return self.handle_cbw_invalid();
362 }
363 }
364 }
365
366 Ok(())
367 }
368
369 fn handle_cbw_invalid(&mut self) -> BulkOnlyTransportResult<()> {
371 assert_matches!(self.state, State::CommandTransferInvalid);
372
373 self.in_ep.stall();
375 self.out_ep.stall();
376
377 Ok(())
378 }
379
380 fn handle_data_transfer_no_data(&mut self) -> BulkOnlyTransportResult<()> {
381 assert_matches!(self.state, State::DataTransferNoData);
382
383 self.enter_state_data_transfer_to_host_status_await();
384 self.handle_data_transfer_to_host_status_await()?;
385
386 Ok(())
387 }
388
389 fn handle_data_transfer_to_host(&mut self) -> BulkOnlyTransportResult<()> {
391 assert_matches!(self.state, State::DataTransferToHost);
392
393 if self.left_to_transfer == 0 {
395 self.enter_state_data_transfer_to_host_status_await();
396 return self.handle_data_transfer_to_host_status_await();
397 }
398
399 if self.has_status() {
401 self.enter_state_data_transfer_to_host_ending();
402 return self.handle_data_transfer_to_host_ending();
403 }
404
405 let bytes_sent = if self.left_to_transfer < self.packet_size() as u32 {
407 self.write_packet()?
408 } else {
409 self.try_write_full_packet()?
410 };
411
412 self.mark_as_transferred(bytes_sent as u32);
413
414 Ok(())
415 }
416
417 fn handle_status_transfer(&mut self) -> BulkOnlyTransportResult<()> {
419 assert_matches!(self.state, State::StatusTransfer);
420
421 if self.buf.available_read() == 0 {
423 self.enter_state_command_transfer();
424 return self.handle_read_cbw();
425 }
426
427 self.write_packet()?;
428
429 Ok(())
430 }
431
432 fn handle_data_transfer_to_host_status_await(&mut self) -> BulkOnlyTransportResult<()> {
434 assert_matches!(self.state, State::DataTransferToHostStatusAwait);
435
436 if self.has_status() {
437 self.enter_state_status_transfer();
438 self.handle_status_transfer()?;
439 }
440
441 Ok(())
442 }
443
444 fn handle_data_transfer_to_host_ending(&mut self) -> BulkOnlyTransportResult<()> {
446 assert_matches!(self.state, State::DataTransferToHostEnding);
447
448 let has_to_send = min(self.left_to_transfer as usize, self.packet_size());
449
450 if has_to_send == 0 {
452 self.enter_state_status_transfer();
453 return self.handle_status_transfer();
454 }
455
456 let available = self.buf.available_read();
457
458 if available >= has_to_send {
459 let bytes_written = self.write_packet()?;
461 self.mark_as_transferred(bytes_written as u32);
462 } else {
463 let to_fill = has_to_send.saturating_sub(available);
465 self.buf.fill_up_to(FILL_BYTE, to_fill);
466
467 let bytes_written = self.write_packet()?;
468 self.mark_as_transferred(bytes_written as u32);
469 }
470
471 Ok(())
472 }
473
474 fn handle_data_transfer_from_host(&mut self) -> BulkOnlyTransportResult<()> {
476 assert_matches!(self.state, State::DataTransferFromHost);
477
478 if self.left_to_transfer == 0 {
480 self.enter_state_data_transfer_to_host_status_await();
481 return self.handle_data_transfer_to_host_status_await();
482 }
483
484 if self.has_status() {
486 self.enter_state_data_transfer_from_host_ending();
487 return self.handle_data_transfer_from_host_ending();
488 }
489
490 let bytes_read = self.read_packet()?;
491 self.mark_as_transferred(bytes_read as u32);
492
493 Ok(())
494 }
495
496 fn handle_data_transfer_from_host_ending(&mut self) -> BulkOnlyTransportResult<()> {
497 assert_matches!(self.state, State::DataTransferFromHostEnding);
498
499 if self.left_to_transfer > 0 {
501 self.buf.clean(); let bytes_read = self.read_packet()?;
504 self.mark_as_transferred(bytes_read as u32);
505 } else {
506 self.enter_state_status_transfer();
508 return self.handle_status_transfer();
509 }
510
511 Ok(())
512 }
513
514 fn build_csw(&mut self) -> Option<[u8; CSW_LEN]> {
515 self.cs.as_ref().map(|status| {
516 let mut csw = [0u8; CSW_LEN];
517 csw[..4].copy_from_slice(CSW_SIGNATURE_LE.as_slice());
518 csw[4..8].copy_from_slice(self.cbw.tag.to_le_bytes().as_slice());
519 csw[8..12].copy_from_slice(status.data_residue.to_le_bytes().as_slice());
520 csw[12..].copy_from_slice(&[status.status as u8]);
521 csw
522 })
523 }
524
525 fn try_parse_cbw(&mut self) -> Result<CommandBlockWrapper, InvalidCbwError> {
527 assert!(self.buf.available_read() >= CBW_LEN);
528
529 let mut raw_cbw = [0u8; CBW_LEN];
531 self.buf
533 .read::<core::convert::Infallible>(|buf| {
534 raw_cbw.copy_from_slice(&buf[..CBW_LEN]); Ok(CBW_LEN)
536 })
537 .unwrap_or(0);
538
539 if !raw_cbw.starts_with(&CBW_SIGNATURE_LE) {
541 return Err(InvalidCbwError);
542 }
543
544 CommandBlockWrapper::from_le_bytes(&raw_cbw[4..]) }
546
547 fn start_data_transfer(&mut self, cbw: CommandBlockWrapper) -> BulkOnlyTransportResult<()> {
548 assert_matches!(self.state, State::CommandTransfer);
549
550 self.cbw = cbw;
551 self.left_to_transfer = cbw.data_transfer_len;
552
553 match cbw.direction {
554 DataDirection::Out => {
555 self.enter_state_data_transfer_from_host();
556 self.handle_data_transfer_from_host()
557 }
558 DataDirection::In => {
559 self.enter_state_data_transfer_to_host();
560 self.handle_data_transfer_to_host()
561 }
562 DataDirection::NotExpected => {
563 self.enter_state_data_transfer_no_data();
564 self.handle_data_transfer_no_data()
565 }
566 }
567 }
568
569 #[inline]
570 fn packet_size(&self) -> usize {
571 self.in_ep.max_packet_size() as usize }
573
574 #[inline]
575 fn mark_as_transferred(&mut self, by: u32) {
576 self.left_to_transfer = self.left_to_transfer.saturating_sub(by);
577 }
578
579 fn read_packet(&mut self) -> BulkOnlyTransportResult<usize> {
581 let bytes_read = self.buf.write_all(
582 self.packet_size(),
583 TransportError::Error(BulkOnlyError::IoBufferOverflow),
584 |buf| match self.out_ep.read(buf) {
585 Ok(bytes_read) => {
586 trace!("usb: bbb: Read bytes: {}", bytes_read);
587 Ok(bytes_read)
588 }
589 Err(UsbError::WouldBlock) => {
590 trace!("usb: bbb: Read bytes: WOULD_BLOCK");
591 Err(TransportError::Usb(UsbError::WouldBlock))
592 }
593 Err(err) => Err(TransportError::Usb(err)),
594 },
595 )?;
596
597 Ok(bytes_read)
598 }
599
600 fn write_packet(&mut self) -> BulkOnlyTransportResult<usize> {
604 let packet_size = self.packet_size();
605
606 let bytes_written = self.buf.read(|buf| {
607 if !buf.is_empty() {
608 match self.in_ep.write(&buf[..min(packet_size, buf.len())]) {
609 Ok(bytes_written) => {
610 trace!("usb: bbb: Wrote bytes: {}", bytes_written);
611 Ok(bytes_written)
612 }
613 Err(UsbError::WouldBlock) => {
614 trace!("usb: bbb: Wrote bytes: WOULD_BLOCK");
615 Err(TransportError::Usb(UsbError::WouldBlock))
616 }
617 Err(err) => Err(TransportError::Usb(err)),
618 }
619 } else {
620 trace!("usb: bbb: Wrote bytes: 0, buf write available: 0",);
621 Ok(0) }
623 })?;
624
625 Ok(bytes_written)
626 }
627
628 fn try_write_full_packet(&mut self) -> BulkOnlyTransportResult<usize> {
630 if self.buf.available_read() < self.packet_size() {
631 return Err(TransportError::Error(BulkOnlyError::FullPacketExpected));
632 }
633
634 self.write_packet()
635 }
636}
637
638impl<Bus, Buf> Transport for BulkOnly<'_, Bus, Buf>
639where
640 Bus: UsbBus,
641 Buf: BorrowMut<[u8]>,
642{
643 const PROTO: u8 = TRANSPORT_BBB;
644
645 type Bus = Bus;
646 type Error = BulkOnlyError;
647
648 fn get_endpoint_descriptors(&self, writer: &mut DescriptorWriter) -> Result<(), UsbError> {
649 writer.endpoint(&self.in_ep)?;
650 writer.endpoint(&self.out_ep)?;
651 Ok(())
652 }
653
654 fn reset(&mut self) {
655 trace!("usb: bbb: Recv reset");
656 self.enter_state_command_transfer();
657 }
658
659 fn control_in(&mut self, xfer: ControlIn<Self::Bus>) {
660 let req = xfer.request();
661
662 if !(req.request_type == RequestType::Class && req.recipient == Recipient::Interface) {
664 return;
665 }
666
667 trace!("usb: bbb: Recv ctrl_in: {}", req);
668
669 match req.request {
670 CLASS_SPECIFIC_BULK_ONLY_MASS_STORAGE_RESET => {
672 self.enter_state_command_transfer();
673 }
674 CLASS_SPECIFIC_GET_MAX_LUN => {
676 if let Err(err) = xfer.accept_with(&[self.max_lun]) {
680 warning!("usb: bbb: Get Max Lun accept failed: {}", err);
681 }
682 }
683 _ => {}
684 }
685 }
686
687 fn poll(&mut self) -> BulkOnlyTransportResult<()> {
689 trace!("usb: bbb: poll");
690
691 match self.state {
696 State::CommandTransfer => self.handle_read_cbw(),
697 State::CommandTransferInvalid => self.handle_cbw_invalid(),
698 State::DataTransferNoData => self.handle_data_transfer_no_data(),
699 State::DataTransferToHost => self.handle_data_transfer_to_host(),
700 State::DataTransferToHostStatusAwait => {
701 self.handle_data_transfer_to_host_status_await()
702 }
703 State::DataTransferToHostEnding => self.handle_data_transfer_to_host_ending(),
704 State::DataTransferFromHost => self.handle_data_transfer_from_host(),
705 State::DataTransferFromHostEnding => self.handle_data_transfer_from_host_ending(),
706 State::StatusTransfer => self.handle_status_transfer(),
707 }
708 }
709}
710
711#[derive(Default, Debug, Copy, Clone)]
712#[cfg_attr(feature = "defmt", derive(defmt::Format))]
713struct CommandBlockWrapper {
714 tag: u32,
715 data_transfer_len: u32,
716 direction: DataDirection,
717 lun: u8,
718 block_len: usize,
719 block: [u8; 16],
720}
721
722impl CommandBlockWrapper {
723 fn from_le_bytes(value: &[u8]) -> Result<Self, InvalidCbwError> {
724 const MIN_CB_LEN: u8 = 1;
725 const MAX_CB_LEN: u8 = 16;
726
727 let block_len = value[10];
728
729 if !(MIN_CB_LEN..=MAX_CB_LEN).contains(&block_len) {
730 return Err(InvalidCbwError);
731 }
732
733 let tag = u32::from_le_bytes(value[..4].try_into().map_err(|_| InvalidCbwError)?);
737 let data_transfer_len =
738 u32::from_le_bytes(value[4..8].try_into().map_err(|_| InvalidCbwError)?);
739 let direction = if data_transfer_len != 0 {
740 if (value[8] & (1 << 7)) > 0 {
741 DataDirection::In
742 } else {
743 DataDirection::Out
744 }
745 } else {
746 DataDirection::NotExpected
747 };
748 let block: [u8; 16] = value[11..].try_into().map_err(|_| InvalidCbwError)?;
749
750 Ok(CommandBlockWrapper {
751 tag,
752 data_transfer_len,
753 direction,
754 lun: value[9] & 0b00001111,
755 block_len: block_len as usize,
756 block,
757 })
758 }
759}
760
761#[cfg(test)]
762mod tests {
763 use super::*;
764 use std::collections::VecDeque;
765 use std::sync::{Arc, Mutex};
766 use usb_device::UsbDirection;
767 use usb_device::bus::{PollResult, UsbBusAllocator};
768 use usb_device::class_prelude::{EndpointAddress, EndpointType};
769 use usb_device::device::{UsbDeviceBuilder, UsbVidPid};
770
771 #[test]
776 fn host_expects_no_data_device_sends_no_data() {
777 for ps in PACKET_SIZES {
779 let (csw, _) = run(ps, 0, Host::ExpectsNoData, |b| {
780 b.set_status(CommandStatus::Passed, 0)
781 });
782 assert_eq!(csw.status, 0, "ps={ps}");
783 assert_eq!(csw.residue, 0, "ps={ps}");
784 }
785 }
786
787 #[test]
788 fn host_expects_no_data_device_wants_to_send() {
789 for ps in PACKET_SIZES {
791 let (csw, data) = run(ps, 0, Host::ExpectsNoData, |b| {
792 assert!(is_invalid_state(b.write_data(&[0xAA; 8])));
793 b.set_status(CommandStatus::PhaseError, 0);
794 });
795 assert_eq!(csw.status, 0x02, "ps={ps}");
796 assert!(data.is_empty(), "ps={ps}");
797 }
798 }
799
800 #[test]
801 fn host_expects_no_data_device_wants_to_receive() {
802 for ps in PACKET_SIZES {
804 let (csw, _) = run(ps, 0, Host::ExpectsNoData, |b| {
805 assert!(is_invalid_state(b.read_data(&mut [0u8; 8])));
806 b.set_status(CommandStatus::PhaseError, 0);
807 });
808 assert_eq!(csw.status, 0x02, "ps={ps}");
809 }
810 }
811
812 #[test]
815 fn host_expects_data_in_device_sends_none() {
816 for ps in PACKET_SIZES {
818 let (csw, data) = run(ps, 32, Host::ExpectsDataIn, |b| {
819 b.set_status(CommandStatus::Passed, 0)
820 });
821 assert_eq!(csw.status, 0, "ps={ps}");
822 assert_eq!(csw.residue, 32, "ps={ps}");
823 assert_eq!(data.len(), 32, "ps={ps}"); }
825 }
826
827 #[test]
828 fn host_expects_more_data_in_than_device_sends() {
829 for ps in PACKET_SIZES {
831 let (csw, data) = run(ps, 32, Host::ExpectsDataIn, |b| {
832 let n = b.write_data(&[0xAA; 16]).unwrap();
833 b.set_status(CommandStatus::Passed, n as u32);
834 });
835 assert_eq!(csw.status, 0, "ps={ps}");
836 assert_eq!(csw.residue, 16, "ps={ps}");
837 assert_eq!(data.len(), 32, "ps={ps}");
838 }
839 }
840
841 #[test]
842 fn host_expects_exactly_what_device_sends() {
843 for ps in PACKET_SIZES {
845 let (csw, data) = run(ps, 32, Host::ExpectsDataIn, |b| {
846 let n = b.write_data(&[0xAA; 32]).unwrap();
847 b.set_status(CommandStatus::Passed, n as u32);
848 });
849 assert_eq!(csw.status, 0, "ps={ps}");
850 assert_eq!(csw.residue, 0, "ps={ps}");
851 assert_eq!(data, vec![0xAA; 32], "ps={ps}");
852 }
853 }
854
855 #[test]
856 fn host_expects_less_data_in_than_device_sends() {
857 for ps in PACKET_SIZES {
859 let (csw, data) = run(ps, 16, Host::ExpectsDataIn, |b| {
860 let n = b.write_data(&[0xAA; 32]).unwrap(); assert_eq!(n, 16); b.set_status(CommandStatus::PhaseError, 0);
863 });
864 assert_eq!(csw.status, 0x02, "ps={ps}");
865 assert_eq!(data.len(), 16, "ps={ps}");
866 }
867 }
868
869 #[test]
870 fn host_expects_data_in_device_wants_to_receive() {
871 for ps in PACKET_SIZES {
873 let (csw, data) = run(ps, 32, Host::ExpectsDataIn, |b| {
874 assert!(is_invalid_state(b.read_data(&mut [0u8; 32])));
875 b.set_status(CommandStatus::PhaseError, 0);
876 });
877 assert_eq!(csw.status, 0x02, "ps={ps}");
878 assert_eq!(data.len(), 32, "ps={ps}");
879 }
880 }
881
882 #[test]
885 fn host_sends_data_device_receives_none() {
886 for ps in PACKET_SIZES {
888 let (csw, _) = run(ps, 32, Host::ExpectsDataOut, |b| {
889 b.set_status(CommandStatus::Passed, 0)
890 });
891 assert_eq!(csw.status, 0, "ps={ps}");
892 assert_eq!(csw.residue, 32, "ps={ps}");
893 }
894 }
895
896 #[test]
897 fn host_sends_data_device_wants_to_send() {
898 for ps in PACKET_SIZES {
900 let (csw, _) = run(ps, 32, Host::ExpectsDataOut, |b| {
901 assert!(is_invalid_state(b.write_data(&[0xAA; 8])));
902 b.set_status(CommandStatus::PhaseError, 0);
903 });
904 assert_eq!(csw.status, 0x02, "ps={ps}");
905 }
906 }
907
908 #[test]
909 fn host_sends_more_data_out_than_device_receives() {
910 for ps in PACKET_SIZES {
912 let (csw, _) = run(ps, 32, Host::ExpectsDataOut, |b| {
913 let n = b.read_data(&mut [0u8; 16]).unwrap();
914 b.set_status(CommandStatus::Passed, n as u32);
915 });
916 assert_eq!(csw.status, 0, "ps={ps}");
917 assert_eq!(csw.residue, 16, "ps={ps}");
918 }
919 }
920
921 #[test]
922 fn host_sends_exactly_what_device_receives() {
923 for ps in PACKET_SIZES {
925 let (csw, _) = run(ps, 32, Host::ExpectsDataOut, |b| {
926 let n = b.read_data(&mut [0u8; 32]).unwrap();
927 b.set_status(CommandStatus::Passed, n as u32);
928 });
929 assert_eq!(csw.status, 0, "ps={ps}");
930 assert_eq!(csw.residue, 0, "ps={ps}");
931 }
932 }
933
934 #[test]
935 fn host_sends_less_data_out_than_device_receives() {
936 for ps in PACKET_SIZES {
938 let (csw, _) = run(ps, 16, Host::ExpectsDataOut, |b| {
939 let n = b.read_data(&mut [0u8; 32]).unwrap(); assert_eq!(n, 16); b.set_status(CommandStatus::PhaseError, 0);
942 });
943 assert_eq!(csw.status, 0x02, "ps={ps}");
944 }
945 }
946
947 #[test]
948 fn should_read_data_into_small_buffer() {
949 const BUF_SIZE: usize = 512;
950 const N: usize = 123;
951
952 let (_shared, mut bbb) = new_bbb(64);
953 bbb.state = State::DataTransferFromHost;
954 bbb.buf.write([0xFFu8; BUF_SIZE].as_slice()); assert_eq!(N, bbb.read_data([0u8; N].as_mut_slice()).unwrap());
957 }
958
959 const PACKET_SIZES: [u16; 4] = [8, 16, 32, 64];
962
963 #[derive(Copy, Clone)]
964 enum Host {
965 ExpectsNoData,
966 ExpectsDataIn, ExpectsDataOut, }
969
970 #[derive(Clone, Default)]
972 struct Shared {
973 out: Arc<Mutex<VecDeque<Vec<u8>>>>, input: Arc<Mutex<Vec<Vec<u8>>>>, }
976
977 struct MockBus {
978 shared: Shared,
979 }
980
981 impl UsbBus for MockBus {
982 fn alloc_ep(
983 &mut self,
984 ep_dir: UsbDirection,
985 _ep_addr: Option<EndpointAddress>,
986 _ep_type: EndpointType,
987 _max_packet_size: u16,
988 _interval: u8,
989 ) -> usb_device::Result<EndpointAddress> {
990 Ok(EndpointAddress::from_parts(1, ep_dir))
991 }
992
993 fn enable(&mut self) {}
994 fn reset(&self) {}
995 fn set_device_address(&self, _addr: u8) {}
996
997 fn write(&self, _ep_addr: EndpointAddress, buf: &[u8]) -> usb_device::Result<usize> {
998 self.shared.input.lock().unwrap().push(buf.to_vec());
999 Ok(buf.len())
1000 }
1001
1002 fn read(&self, _ep_addr: EndpointAddress, buf: &mut [u8]) -> usb_device::Result<usize> {
1003 match self.shared.out.lock().unwrap().pop_front() {
1004 Some(pkt) => {
1005 buf[..pkt.len()].copy_from_slice(&pkt);
1006 Ok(pkt.len())
1007 }
1008 None => Err(UsbError::WouldBlock),
1009 }
1010 }
1011
1012 fn set_stalled(&self, _ep_addr: EndpointAddress, _stalled: bool) {}
1013 fn is_stalled(&self, _ep_addr: EndpointAddress) -> bool {
1014 false
1015 }
1016 fn suspend(&self) {}
1017 fn resume(&self) {}
1018 fn poll(&self) -> PollResult {
1019 PollResult::None
1020 }
1021 }
1022
1023 type MockBbb = BulkOnly<'static, MockBus, Vec<u8>>;
1024
1025 fn new_bbb(packet_size: u16) -> (Shared, MockBbb) {
1026 let shared = Shared::default();
1027 let bus = MockBus {
1028 shared: shared.clone(),
1029 };
1030 let alloc = Box::leak(Box::new(UsbBusAllocator::new(bus)));
1031 let bbb = BulkOnly::new(alloc, packet_size, 0, vec![0u8; 512]).unwrap();
1032 core::mem::forget(UsbDeviceBuilder::new(alloc, UsbVidPid(0xabcd, 0xabcd)).build());
1035 (shared, bbb)
1036 }
1037
1038 fn cbw(data_len: u32, host: Host) -> Vec<u8> {
1040 let mut c = vec![0u8; CBW_LEN];
1041 c[..4].copy_from_slice(&0x43425355u32.to_le_bytes());
1042 c[4..8].copy_from_slice(&1u32.to_le_bytes()); c[8..12].copy_from_slice(&data_len.to_le_bytes());
1044 c[12] = if matches!(host, Host::ExpectsDataIn) {
1045 0x80
1046 } else {
1047 0x00
1048 };
1049 c[14] = 6; c[15] = 0x12; c
1052 }
1053
1054 fn enqueue(shared: &Shared, bytes: &[u8], packet_size: u16) {
1056 let mut out = shared.out.lock().unwrap();
1057 for chunk in bytes.chunks(packet_size as usize) {
1058 out.push_back(chunk.to_vec());
1059 }
1060 }
1061
1062 struct Csw {
1063 status: u8,
1064 residue: u32,
1065 }
1066
1067 fn run(
1069 packet_size: u16,
1070 data_len: u32,
1071 host: Host,
1072 device: impl FnOnce(&mut MockBbb),
1073 ) -> (Csw, Vec<u8>) {
1074 let (shared, mut bbb) = new_bbb(packet_size);
1075
1076 enqueue(&shared, &cbw(data_len, host), packet_size);
1077 if matches!(host, Host::ExpectsDataOut) {
1078 enqueue(&shared, &vec![0xAA; data_len as usize], packet_size);
1079 }
1080
1081 for _ in 0..64 {
1084 let _ = bbb.poll();
1085 let out_drained = !matches!(host, Host::ExpectsDataOut) || bbb.left_to_transfer == 0;
1086 if bbb.get_command().is_some() && out_drained {
1087 break;
1088 }
1089 }
1090
1091 device(&mut bbb);
1092
1093 for _ in 0..64 {
1094 let _ = bbb.poll();
1095 if matches!(bbb.state, State::CommandTransfer) {
1096 break;
1097 }
1098 }
1099
1100 let stream = std::mem::take(&mut *shared.input.lock().unwrap()).concat();
1103 assert!(stream.len() >= CSW_LEN, "no CSW sent");
1104 let (data, raw) = stream.split_at(stream.len() - CSW_LEN);
1105 assert!(raw.starts_with(&CSW_SIGNATURE_LE));
1106 (
1107 Csw {
1108 status: raw[12],
1109 residue: u32::from_le_bytes(raw[8..12].try_into().unwrap()),
1110 },
1111 data.to_vec(),
1112 )
1113 }
1114
1115 fn is_invalid_state<T>(r: Result<T, TransportError<BulkOnlyError>>) -> bool {
1116 matches!(r, Err(TransportError::Error(BulkOnlyError::InvalidState)))
1117 }
1118}