1use crate::operation::{OperationSteps, UsbStep};
2pub use nusb::transfer::TransferError;
3use nusb::{
4 DeviceInfo,
5 transfer::{ControlOut, ControlType, Recipient, RequestBuffer},
6};
7use thiserror::Error;
8
9#[derive(Debug, Error)]
11#[error("Device is not available: {error}")]
12pub struct DeviceUnavalable {
13 #[from]
14 pub error: nusb::Error,
15}
16
17pub fn devices() -> std::result::Result<impl Iterator<Item = DeviceInfo>, nusb::Error> {
19 Ok(nusb::list_devices()?.filter(|d| d.vendor_id() == 0x2207))
20}
21
22impl From<TransferError> for crate::device::Error<TransferError> {
23 fn from(value: TransferError) -> Self {
24 Self::UsbError(value)
25 }
26}
27
28pub struct Transport {
30 interface: nusb::Interface,
31 ep_in: u8,
32 ep_out: u8,
33}
34
35impl crate::device::TransportAsync for Transport {
36 type TransportError = TransferError;
37 async fn handle_operation<O, T>(
38 &mut self,
39 mut operation: O,
40 ) -> crate::device::DeviceResultAsync<T, Self>
41 where
42 O: OperationSteps<T>,
43 {
44 loop {
45 let step = operation.step();
46 match step {
47 UsbStep::WriteBulk { data } => {
48 let _written = self
49 .interface
50 .bulk_out(self.ep_out, data.to_vec())
51 .await
52 .into_result()?;
53 }
54 UsbStep::ReadBulk { data } => {
55 let req = RequestBuffer::new(data.len());
56 let read = self
57 .interface
58 .bulk_in(self.ep_in, req)
59 .await
60 .into_result()?;
61 data.copy_from_slice(&read);
62 }
63 UsbStep::WriteControl {
64 request_type,
65 request,
66 value,
67 index,
68 data,
69 } => {
70 let (control_type, recipient) = (
71 match (request_type >> 5) & 0x03 {
72 0 => ControlType::Standard,
73 1 => ControlType::Class,
74 2 => ControlType::Vendor,
75 _ => ControlType::Standard,
76 },
77 match request_type & 0x1f {
78 0 => Recipient::Device,
79 1 => Recipient::Interface,
80 2 => Recipient::Endpoint,
81 3 => Recipient::Other,
82 _ => Recipient::Device,
83 },
84 );
85 let data = ControlOut {
86 control_type,
87 recipient,
88 request,
89 value,
90 index,
91 data,
92 };
93 self.interface.control_out(data).await.into_result()?;
94 }
95 UsbStep::Finished(r) => break r.map_err(|e| e.into()),
96 }
97 }
98 }
99}
100
101impl Transport {
102 fn new(
103 device: nusb::Device,
104 interface: u8,
105 ep_in: u8,
106 ep_out: u8,
107 ) -> std::result::Result<Self, DeviceUnavalable> {
108 let interface = device.claim_interface(interface)?;
109 Ok(Self {
110 interface,
111 ep_in,
112 ep_out,
113 })
114 }
115}
116
117pub type Device = crate::device::DeviceAsync<Transport>;
118impl Device {
119 pub fn from_usb_device_info(
121 info: nusb::DeviceInfo,
122 ) -> std::result::Result<Self, DeviceUnavalable> {
123 let device = info.open()?;
124 Self::from_usb_device(device)
125 }
126
127 pub fn from_usb_device(device: nusb::Device) -> std::result::Result<Self, DeviceUnavalable> {
129 for config in device.clone().configurations() {
130 for interface in config.interface_alt_settings() {
131 let output = interface.endpoints().find(|e| {
132 e.direction() == nusb::transfer::Direction::Out
133 && e.transfer_type() == nusb::transfer::EndpointType::Bulk
134 });
135 let input = interface.endpoints().find(|e| {
136 e.direction() == nusb::transfer::Direction::In
137 && e.transfer_type() == nusb::transfer::EndpointType::Bulk
138 });
139
140 if let (Some(input), Some(output)) = (input, output) {
141 return Ok(Device::new(Transport::new(
142 device,
143 interface.interface_number(),
144 input.address(),
145 output.address(),
146 )?));
147 }
148 }
149 }
150 Err(DeviceUnavalable {
151 error: nusb::Error::new(std::io::ErrorKind::NotFound, "Device not found"),
152 })
153 }
154}