Skip to content

Commit

Permalink
USB Composite Device Support (#58)
Browse files Browse the repository at this point in the history
* Change WireStorage::init() return type from UsbDevice to Builder for enhanced flexibility in USB class construction

* Added a closure parameter to new_raw_nusb() function for interface identification.

* Revert "Added a closure parameter to new_raw_nusb() function for interface identification."

This reverts commit ba2ac52.

* Interface identification from the interface class

* Refactor init() by introducing init_without_build()

* add try_new_raw_nusb_with_interface()
  • Loading branch information
Dicklessgreat authored Nov 27, 2024
1 parent d504e61 commit 41fe2a5
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 6 deletions.
87 changes: 85 additions & 2 deletions source/postcard-rpc/src/host_client/raw_nusb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::future::Future;

use nusb::{
transfer::{Queue, RequestBuffer, TransferError},
DeviceInfo,
DeviceInfo, InterfaceInfo,
};
use postcard_schema::Schema;
use serde::de::DeserializeOwned;
Expand Down Expand Up @@ -85,11 +85,94 @@ where
.map_err(|e| format!("Error listing devices: {e:?}"))?
.find(func)
.ok_or_else(|| String::from("Failed to find matching nusb device!"))?;
let interface_id = x
.interfaces()
.position(|i| i.class() == 0xFF)
.ok_or_else(|| String::from("Failed to find matching interface!!"))?;
let dev = x
.open()
.map_err(|e| format!("Failed opening device: {e:?}"))?;
let interface = dev
.claim_interface(0)
.claim_interface(interface_id as u8)
.map_err(|e| format!("Failed claiming interface: {e:?}"))?;

let boq = interface.bulk_out_queue(BULK_OUT_EP);
let biq = interface.bulk_in_queue(BULK_IN_EP);

Ok(HostClient::new_with_wire(
NusbWireTx { boq },
NusbWireRx {
biq,
consecutive_errs: 0,
},
NusbSpawn,
seq_no_kind,
err_uri_path,
outgoing_depth,
))
}
/// Try to create a new link using [`nusb`] for connectivity
///
/// The provided function will be used to find a matching device. The first
/// matching device will be connected to. `err_uri_path` is
/// the path associated with the `WireErr` message type.
///
/// Returns an error if no device or interface could be found, or if there was an error
/// connecting to the device or interface.
///
/// This constructor is available when the `raw-nusb` feature is enabled.
///
/// ## Example
///
/// ```rust,no_run
/// use postcard_rpc::host_client::HostClient;
/// use postcard_rpc::header::VarSeqKind;
/// use serde::{Serialize, Deserialize};
/// use postcard_schema::Schema;
///
/// /// A "wire error" type your server can use to respond to any
/// /// kind of request, for example if deserializing a request fails
/// #[derive(Debug, PartialEq, Schema, Serialize, Deserialize)]
/// pub enum Error {
/// SomethingBad
/// }
///
/// let client = HostClient::<Error>::try_new_raw_nusb_with_interface(
/// // Find the first device with the serial 12345678
/// |d| d.serial_number() == Some("12345678"),
/// // Find the "Vendor Specific" interface
/// |i| i.class() == 0xFF,
/// // the URI/path for `Error` messages
/// "error",
/// // Outgoing queue depth in messages
/// 8,
/// // Use one-byte sequence numbers
/// VarSeqKind::Seq1,
/// ).unwrap();
/// ```
pub fn try_new_raw_nusb_with_interface<
F1: FnMut(&DeviceInfo) -> bool,
F2: FnMut(&InterfaceInfo) -> bool,
>(
device_func: F1,
interface_func: F2,
err_uri_path: &str,
outgoing_depth: usize,
seq_no_kind: VarSeqKind,
) -> Result<Self, String> {
let x = nusb::list_devices()
.map_err(|e| format!("Error listing devices: {e:?}"))?
.find(device_func)
.ok_or_else(|| String::from("Failed to find matching nusb device!"))?;
let interface_id = x
.interfaces()
.position(interface_func)
.ok_or_else(|| String::from("Failed to find matching interface!!"))?;
let dev = x
.open()
.map_err(|e| format!("Failed opening device: {e:?}"))?;
let interface = dev
.claim_interface(interface_id as u8)
.map_err(|e| format!("Failed claiming interface: {e:?}"))?;

let boq = interface.bulk_out_queue(BULK_OUT_EP);
Expand Down
18 changes: 14 additions & 4 deletions source/postcard-rpc/src/server/impls/embassy_usb_v0_3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,19 @@ pub mod dispatch_impl {
config: Config<'static>,
tx_buf: &'static mut [u8],
) -> (UsbDevice<'static, D>, WireTxImpl<M, D>, WireRxImpl<D>) {
let (builder, wtx, wrx) = self.init_without_build(driver, config, tx_buf);
let usb = builder.build();
(usb, wtx, wrx)
}
/// Initialize the static storage, without building `Builder`
///
/// This must only be called once.
pub fn init_without_build(
&'static self,
driver: D,
config: Config<'static>,
tx_buf: &'static mut [u8],
) -> (Builder<'static, D>, WireTxImpl<M, D>, WireRxImpl<D>) {
let bufs = self.bufs_usb.take();

let mut builder = Builder::new(
Expand Down Expand Up @@ -204,10 +217,7 @@ pub mod dispatch_impl {
pending_frame: false,
}));

// Build the builder.
let usb = builder.build();

(usb, EUsbWireTx { inner: wtx }, EUsbWireRx { ep_out })
(builder, EUsbWireTx { inner: wtx }, EUsbWireRx { ep_out })
}
}
}
Expand Down

0 comments on commit 41fe2a5

Please sign in to comment.