1#![warn(missing_docs)]
26
27mod quirks;
28
29use std::{
30 fmt,
31 hash::{Hash, Hasher},
32 marker::PhantomData,
33 pin::Pin,
34 task::{ready, Context, Poll},
35};
36
37use futures_core::Stream;
38use futures_util::StreamExt;
39use js_sys::{Reflect, Uint8Array};
40use tokio::sync::broadcast;
41use tokio_stream::wrappers::{errors::BroadcastStreamRecvError, BroadcastStream};
42use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
43use wasm_bindgen_futures::{spawn_local, JsFuture};
44
45unsafe fn uint8_array_for_api(data: &[u8]) -> Uint8Array {
56 let view = unsafe { Uint8Array::view(data) };
58 if view.buffer().is_instance_of::<js_sys::SharedArrayBuffer>() {
59 let copy = Uint8Array::new_with_length(data.len() as u32);
61 copy.set(&view, 0);
62 copy
63 } else {
64 view
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct Error {
71 kind: ErrorKind,
72 msg: String,
73}
74
75impl Error {
76 pub fn kind(&self) -> ErrorKind {
78 self.kind
79 }
80
81 pub fn msg(&self) -> &str {
83 &self.msg
84 }
85}
86
87impl fmt::Display for Error {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 write!(f, "{:?}: {}", self.kind, &self.msg)
90 }
91}
92
93impl std::error::Error for Error {}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
97#[non_exhaustive]
98pub enum ErrorKind {
99 Unsupported,
101 AlreadyOpen,
103 Disconnected,
105 Security,
107 Stall,
111 Babble,
113 Transfer,
115 InvalidAccess,
117 Other,
119}
120
121impl Error {
122 fn new(kind: ErrorKind, msg: impl AsRef<str>) -> Self {
123 Self { kind, msg: msg.as_ref().to_string() }
124 }
125}
126
127impl From<JsValue> for Error {
128 fn from(value: JsValue) -> Self {
129 if let Some(js_error) = value.dyn_ref::<js_sys::Error>() {
130 let msg = js_error.message().as_string().unwrap();
131 let kind = match js_error.name().as_string().unwrap().as_str() {
132 "NotFoundError" => ErrorKind::Disconnected,
133 "SecurityError" => ErrorKind::Security,
134 "InvalidAccessError" => ErrorKind::InvalidAccess,
135 "NetworkError" => ErrorKind::Transfer,
136 _ => ErrorKind::Other,
137 };
138 return Error::new(kind, msg);
139 }
140
141 let msg = value.as_string().unwrap_or_else(|| "unknown error".into());
142 Error::new(ErrorKind::Other, msg)
143 }
144}
145
146impl From<Error> for std::io::Error {
147 fn from(err: Error) -> Self {
148 let kind = match err.kind {
149 ErrorKind::Unsupported => std::io::ErrorKind::Unsupported,
150 ErrorKind::AlreadyOpen => std::io::ErrorKind::ResourceBusy,
151 ErrorKind::Disconnected => std::io::ErrorKind::NotConnected,
152 ErrorKind::Security => std::io::ErrorKind::PermissionDenied,
153 ErrorKind::Stall => std::io::ErrorKind::InvalidData,
154 ErrorKind::Babble => std::io::ErrorKind::UnexpectedEof,
155 ErrorKind::Transfer => std::io::ErrorKind::ConnectionReset,
156 ErrorKind::InvalidAccess => std::io::ErrorKind::InvalidInput,
157 ErrorKind::Other => std::io::ErrorKind::Other,
158 };
159 std::io::Error::new(kind, err)
160 }
161}
162
163pub type Result<T> = std::result::Result<T, Error>;
165
166#[derive(Clone)]
172pub struct UsbData(Uint8Array);
173
174impl UsbData {
175 fn from_data_view(view: &js_sys::DataView) -> Self {
177 Self(Uint8Array::new_with_byte_offset_and_length(
178 &view.buffer(),
179 view.byte_offset() as u32,
180 view.byte_length() as u32,
181 ))
182 }
183
184 pub fn len(&self) -> usize {
186 self.0.length() as usize
187 }
188
189 pub fn is_empty(&self) -> bool {
191 self.len() == 0
192 }
193
194 pub fn copy_to(&self, buf: &mut [u8]) {
199 self.0.copy_to(buf);
200 }
201
202 pub fn to_vec(&self) -> Vec<u8> {
204 self.0.to_vec()
205 }
206}
207
208impl From<UsbData> for Vec<u8> {
209 fn from(data: UsbData) -> Self {
210 data.to_vec()
211 }
212}
213
214impl fmt::Debug for UsbData {
215 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216 f.debug_struct("UsbData").field("len", &self.len()).finish()
217 }
218}
219
220#[derive(Debug, Clone)]
222#[non_exhaustive]
223pub struct UsbConfiguration {
224 pub configuration_value: u8,
229 pub configuration_name: Option<String>,
235 pub interfaces: Vec<UsbInterface>,
237}
238
239impl From<&web_sys::UsbConfiguration> for UsbConfiguration {
240 fn from(conf: &web_sys::UsbConfiguration) -> Self {
241 let iface_list = conf.interfaces();
242 let mut interfaces = Vec::new();
243 for i in 0..iface_list.length() {
244 if let Some(iface) = iface_list.get(i).dyn_ref::<web_sys::UsbInterface>() {
245 interfaces.push(UsbInterface::from(iface));
246 }
247 }
248 Self {
249 configuration_value: conf.configuration_value(),
250 configuration_name: conf.configuration_name(),
251 interfaces,
252 }
253 }
254}
255
256#[derive(Debug, Clone)]
258#[non_exhaustive]
259pub struct UsbInterface {
260 pub interface_number: u8,
262 pub alternate: UsbAlternateInterface,
269 pub alternates: Vec<UsbAlternateInterface>,
274 pub claimed: bool,
276}
277
278impl From<&web_sys::UsbInterface> for UsbInterface {
279 fn from(iface: &web_sys::UsbInterface) -> Self {
280 let alt_list = iface.alternates();
281 let mut alternates = Vec::new();
282 for i in 0..alt_list.length() {
283 if let Some(alt) = alt_list.get(i).dyn_ref::<web_sys::UsbAlternateInterface>() {
284 alternates.push(UsbAlternateInterface::from(alt));
285 }
286 }
287
288 Self {
289 interface_number: iface.interface_number(),
290 alternate: UsbAlternateInterface::from(&iface.alternate()),
291 alternates,
292 claimed: iface.claimed(),
293 }
294 }
295}
296
297#[derive(Debug, Clone)]
299#[non_exhaustive]
300pub struct UsbAlternateInterface {
301 pub alternate_setting: u8,
305 pub interface_class: u8,
309 pub interface_subclass: u8,
313 pub interface_protocol: u8,
317 pub interface_name: Option<String>,
322 pub endpoints: Vec<UsbEndpoint>,
324}
325
326impl From<&web_sys::UsbAlternateInterface> for UsbAlternateInterface {
327 fn from(alt: &web_sys::UsbAlternateInterface) -> Self {
328 let ep_list = alt.endpoints();
329 let mut endpoints = Vec::new();
330 for i in 0..ep_list.length() {
331 if let Some(ep) = ep_list.get(i).dyn_ref::<web_sys::UsbEndpoint>() {
332 endpoints.push(UsbEndpoint::from(ep));
333 }
334 }
335
336 Self {
337 alternate_setting: alt.alternate_setting(),
338 interface_class: alt.interface_class(),
339 interface_subclass: alt.interface_subclass(),
340 interface_protocol: alt.interface_protocol(),
341 interface_name: alt.interface_name(),
342 endpoints,
343 }
344 }
345}
346
347#[derive(Debug, Clone)]
349#[non_exhaustive]
350pub struct UsbEndpoint {
351 pub endpoint_number: u8,
356 pub direction: UsbDirection,
358 pub endpoint_type: UsbEndpointType,
360 pub packet_size: u32,
362}
363
364impl From<&web_sys::UsbEndpoint> for UsbEndpoint {
365 fn from(ep: &web_sys::UsbEndpoint) -> Self {
366 Self {
367 endpoint_number: ep.endpoint_number(),
368 direction: ep.direction().into(),
369 endpoint_type: ep.type_().into(),
370 packet_size: ep.packet_size(),
371 }
372 }
373}
374
375#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
377pub enum UsbEndpointType {
378 Bulk,
383 Interrupt,
389 Isochronous,
394}
395
396impl From<web_sys::UsbEndpointType> for UsbEndpointType {
397 fn from(value: web_sys::UsbEndpointType) -> Self {
398 match value {
399 web_sys::UsbEndpointType::Bulk => Self::Bulk,
400 web_sys::UsbEndpointType::Interrupt => Self::Interrupt,
401 web_sys::UsbEndpointType::Isochronous => Self::Isochronous,
402 other => unreachable!("unsupported UsbEndpointType: {other:?}"),
403 }
404 }
405}
406
407#[derive(Clone, PartialEq, Eq)]
409pub struct UsbDevice {
410 device: web_sys::UsbDevice,
411}
412
413impl UsbDevice {
414 pub fn vendor_id(&self) -> u16 {
416 self.device.vendor_id()
417 }
418
419 pub fn product_id(&self) -> u16 {
421 self.device.product_id()
422 }
423
424 pub fn device_class(&self) -> u8 {
426 self.device.device_class()
427 }
428
429 pub fn device_subclass(&self) -> u8 {
431 self.device.device_subclass()
432 }
433
434 pub fn device_protocol(&self) -> u8 {
436 self.device.device_protocol()
437 }
438
439 pub fn device_version_major(&self) -> u8 {
441 self.device.device_version_major()
442 }
443
444 pub fn device_version_minor(&self) -> u8 {
446 self.device.device_version_minor()
447 }
448
449 pub fn device_version_subminor(&self) -> u8 {
451 self.device.device_version_subminor()
452 }
453
454 pub fn usb_version_major(&self) -> u8 {
456 self.device.usb_version_major()
457 }
458
459 pub fn usb_version_minor(&self) -> u8 {
461 self.device.usb_version_minor()
462 }
463
464 pub fn usb_version_subminor(&self) -> u8 {
466 self.device.usb_version_subminor()
467 }
468
469 pub fn manufacturer_name(&self) -> Option<String> {
471 self.device.manufacturer_name()
472 }
473
474 pub fn product_name(&self) -> Option<String> {
476 self.device.product_name()
477 }
478
479 pub fn serial_number(&self) -> Option<String> {
481 self.device.serial_number()
482 }
483
484 pub fn opened(&self) -> bool {
486 self.device.opened()
487 }
488
489 pub fn configuration(&self) -> Option<UsbConfiguration> {
491 self.device.configuration().map(|cfg| (&cfg).into())
492 }
493
494 pub fn configurations(&self) -> Vec<UsbConfiguration> {
496 let cfg_list = self.device.configurations();
497 let mut configurations = Vec::new();
498 for i in 0..cfg_list.length() {
499 if let Some(conf) = cfg_list.get(i).dyn_ref::<web_sys::UsbConfiguration>() {
500 configurations.push(UsbConfiguration::from(conf));
501 }
502 }
503 configurations
504 }
505
506 pub async fn forget(self) {
509 JsFuture::from(self.device.forget()).await.unwrap();
510 }
511
512 pub async fn open(&self) -> Result<OpenUsbDevice> {
516 if self.opened() {
517 return Err(Error::new(ErrorKind::AlreadyOpen, "USB device is already open"));
518 }
519
520 JsFuture::from(self.device.open()).await?;
521 Ok(OpenUsbDevice { device: self.clone(), closed: false })
522 }
523}
524
525impl std::fmt::Debug for UsbDevice {
526 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
527 f.debug_struct("UsbDevice")
528 .field("vendor_id", &self.vendor_id())
529 .field("product_id", &self.product_id())
530 .field("device_class", &self.device_class())
531 .field("device_subclass", &self.device_subclass())
532 .field("device_protocol", &self.device_protocol())
533 .field("device_version_major", &self.device_version_major())
534 .field("device_version_minor", &self.device_version_minor())
535 .field("device_version_subminor", &self.device_version_subminor())
536 .field("usb_version_major", &self.usb_version_major())
537 .field("usb_version_minor", &self.usb_version_minor())
538 .field("usb_version_subminor", &self.usb_version_subminor())
539 .field("manufacturer_name", &self.manufacturer_name())
540 .field("product_name", &self.product_name())
541 .field("serial_number", &self.serial_number())
542 .field("opened", &self.opened())
543 .field("configuration", &self.configuration())
544 .field("configurations", &self.configurations())
545 .finish()
546 }
547}
548
549impl Hash for UsbDevice {
550 fn hash<H: Hasher>(&self, state: &mut H) {
551 self.vendor_id().hash(state);
552 self.product_id().hash(state);
553 self.device_class().hash(state);
554 self.device_subclass().hash(state);
555 self.device_protocol().hash(state);
556 self.device_version_major().hash(state);
557 self.device_version_minor().hash(state);
558 self.device_version_subminor().hash(state);
559 self.manufacturer_name().hash(state);
560 self.product_name().hash(state);
561 self.serial_number().hash(state);
562 }
563}
564
565impl From<web_sys::UsbDevice> for UsbDevice {
566 fn from(device: web_sys::UsbDevice) -> Self {
567 Self { device }
568 }
569}
570
571impl AsRef<web_sys::UsbDevice> for UsbDevice {
572 fn as_ref(&self) -> &web_sys::UsbDevice {
573 &self.device
574 }
575}
576
577#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
579pub enum UsbDirection {
580 In,
582 Out,
584}
585
586impl From<web_sys::UsbDirection> for UsbDirection {
587 fn from(value: web_sys::UsbDirection) -> Self {
588 match value {
589 web_sys::UsbDirection::In => Self::In,
590 web_sys::UsbDirection::Out => Self::Out,
591 other => unreachable!("unsupported UsbDirection {other:?}"),
592 }
593 }
594}
595
596impl From<UsbDirection> for web_sys::UsbDirection {
597 fn from(direction: UsbDirection) -> Self {
598 match direction {
599 UsbDirection::In => web_sys::UsbDirection::In,
600 UsbDirection::Out => web_sys::UsbDirection::Out,
601 }
602 }
603}
604
605#[derive(Debug, Clone, Default)]
609#[non_exhaustive]
610pub struct UsbDeviceFilter {
611 pub vendor_id: Option<u16>,
613 pub product_id: Option<u16>,
615 pub class_code: Option<u8>,
617 pub subclass_code: Option<u8>,
619 pub protocol_code: Option<u8>,
621 pub serial_number: Option<String>,
623}
624
625impl UsbDeviceFilter {
626 pub const fn new() -> Self {
628 Self {
629 vendor_id: None,
630 product_id: None,
631 class_code: None,
632 subclass_code: None,
633 protocol_code: None,
634 serial_number: None,
635 }
636 }
637
638 pub const fn with_vendor_id(mut self, vendor_id: u16) -> Self {
640 self.vendor_id = Some(vendor_id);
641 self
642 }
643
644 pub const fn with_product_id(mut self, product_id: u16) -> Self {
646 self.product_id = Some(product_id);
647 self
648 }
649
650 pub const fn with_class_code(mut self, class_code: u8) -> Self {
652 self.class_code = Some(class_code);
653 self
654 }
655
656 pub const fn with_subclass_code(mut self, subclass_code: u8) -> Self {
658 self.subclass_code = Some(subclass_code);
659 self
660 }
661
662 pub const fn with_protocol_code(mut self, protocol_code: u8) -> Self {
664 self.protocol_code = Some(protocol_code);
665 self
666 }
667
668 pub fn with_serial_number<S: Into<String>>(mut self, serial_number: S) -> Self {
670 self.serial_number = Some(serial_number.into());
671 self
672 }
673}
674
675impl From<&UsbDeviceFilter> for web_sys::UsbDeviceFilter {
676 fn from(value: &UsbDeviceFilter) -> Self {
677 let filter = web_sys::UsbDeviceFilter::new();
678 if let Some(x) = value.vendor_id {
679 filter.set_vendor_id(x);
680 }
681 if let Some(x) = value.product_id {
682 filter.set_product_id(x);
683 }
684 if let Some(x) = value.class_code {
685 filter.set_class_code(x);
686 }
687 if let Some(x) = value.subclass_code {
688 filter.set_subclass_code(x);
689 }
690 if let Some(x) = value.protocol_code {
691 filter.set_protocol_code(x);
692 }
693 if let Some(x) = &value.serial_number {
694 filter.set_serial_number(x);
695 }
696 filter
697 }
698}
699
700#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
702pub enum UsbRecipient {
703 Device,
705 Interface,
707 Endpoint,
709 Other,
711}
712
713impl From<UsbRecipient> for web_sys::UsbRecipient {
714 fn from(recipient: UsbRecipient) -> Self {
715 match recipient {
716 UsbRecipient::Device => Self::Device,
717 UsbRecipient::Interface => Self::Interface,
718 UsbRecipient::Endpoint => Self::Endpoint,
719 UsbRecipient::Other => Self::Other,
720 }
721 }
722}
723
724#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
726pub enum UsbRequestType {
727 Standard,
729 Class,
731 Vendor,
733}
734
735impl From<UsbRequestType> for web_sys::UsbRequestType {
736 fn from(req_type: UsbRequestType) -> Self {
737 match req_type {
738 UsbRequestType::Standard => Self::Standard,
739 UsbRequestType::Class => Self::Class,
740 UsbRequestType::Vendor => Self::Vendor,
741 }
742 }
743}
744
745#[derive(Clone, Debug)]
747struct UsbDeviceRequestOptions {
748 pub filters: Vec<UsbDeviceFilter>,
750}
751
752impl UsbDeviceRequestOptions {
753 pub fn new(filters: impl IntoIterator<Item = UsbDeviceFilter>) -> Self {
755 Self { filters: filters.into_iter().collect() }
756 }
757}
758
759impl From<&UsbDeviceRequestOptions> for web_sys::UsbDeviceRequestOptions {
760 fn from(value: &UsbDeviceRequestOptions) -> Self {
761 let filters = value.filters.iter().map(web_sys::UsbDeviceFilter::from).collect::<Vec<_>>();
762
763 web_sys::UsbDeviceRequestOptions::new(&filters)
764 }
765}
766
767#[derive(Clone, Debug)]
769#[non_exhaustive]
770pub struct UsbControlRequest {
771 pub request_type: UsbRequestType,
773 pub recipient: UsbRecipient,
775 pub request: u8,
777 pub value: u16,
779 pub index: u16,
781}
782
783impl UsbControlRequest {
784 pub const fn new(
787 request_type: UsbRequestType, recipient: UsbRecipient, request: u8, value: u16, index: u16,
788 ) -> Self {
789 Self { request_type, recipient, request, value, index }
790 }
791}
792
793impl From<&UsbControlRequest> for web_sys::UsbControlTransferParameters {
794 fn from(req: &UsbControlRequest) -> Self {
795 Self::new(req.index, req.recipient.into(), req.request, req.request_type.into(), req.value)
796 }
797}
798
799#[derive(Debug, Clone)]
801#[non_exhaustive]
802pub enum UsbEvent {
803 Connected(UsbDevice),
805 Disconnected(UsbDevice),
807}
808
809#[derive(Debug, Clone)]
811struct SendWrapper<T>(pub T);
812unsafe impl<T> Send for SendWrapper<T> {}
813
814pub struct UsbEvents {
818 rx: BroadcastStream<SendWrapper<UsbEvent>>,
822 _marker: PhantomData<*const ()>,
823}
824
825impl fmt::Debug for UsbEvents {
826 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
827 f.debug_tuple("UsbEvents").finish()
828 }
829}
830
831impl Stream for UsbEvents {
832 type Item = UsbEvent;
833 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
834 loop {
835 match ready!(self.rx.poll_next_unpin(cx)) {
836 Some(Ok(event)) => break Poll::Ready(Some(event.0)),
837 Some(Err(BroadcastStreamRecvError::Lagged(_))) => (),
838 None => break Poll::Ready(None),
839 }
840 }
841 }
842}
843
844pub struct Usb {
846 usb: web_sys::Usb,
847 event_rx: broadcast::Receiver<SendWrapper<UsbEvent>>,
848 on_connect: Closure<dyn Fn(web_sys::UsbConnectionEvent)>,
849 on_disconnect: Closure<dyn Fn(web_sys::UsbConnectionEvent)>,
850}
851
852impl fmt::Debug for Usb {
853 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
854 f.debug_tuple("Usb").finish()
855 }
856}
857
858impl Usb {
859 pub fn new() -> Result<Self> {
861 let usb = Self::browser_usb()?;
862
863 let (event_tx, event_rx) = broadcast::channel(1024);
864
865 let on_connect = {
866 let event_tx = event_tx.clone();
867 Closure::wrap(Box::new(move |event: web_sys::UsbConnectionEvent| {
868 let _ = event_tx.send(SendWrapper(UsbEvent::Connected(event.device().into())));
869 }) as Box<dyn Fn(_)>)
870 };
871 usb.add_event_listener_with_callback("connect", on_connect.as_ref().unchecked_ref()).unwrap();
872
873 let on_disconnect = {
874 let event_tx = event_tx.clone();
875 Closure::wrap(Box::new(move |event: web_sys::UsbConnectionEvent| {
876 let _ = event_tx.send(SendWrapper(UsbEvent::Disconnected(event.device().into())));
877 }) as Box<dyn Fn(_)>)
878 };
879 usb.add_event_listener_with_callback("disconnect", on_disconnect.as_ref().unchecked_ref()).unwrap();
880
881 Ok(Self { usb, event_rx, on_connect, on_disconnect })
882 }
883
884 fn browser_usb() -> Result<web_sys::Usb> {
885 let global = js_sys::global();
886
887 if let Some(window) = global.dyn_ref::<web_sys::Window>() {
888 let navigator = window.navigator();
889 match Reflect::get(&navigator, &JsValue::from_str("usb")) {
890 Ok(usb) if !usb.is_null() && !usb.is_undefined() => return Ok(navigator.usb()),
891 _ => (),
892 }
893 }
894
895 if let Some(worker) = global.dyn_ref::<web_sys::WorkerGlobalScope>() {
896 let navigator = worker.navigator();
897 match Reflect::get(&navigator, &JsValue::from_str("usb")) {
898 Ok(usb) if !usb.is_null() && !usb.is_undefined() => return Ok(navigator.usb()),
899 _ => (),
900 }
901 }
902
903 Err(Error::new(ErrorKind::Unsupported, "browser does not support WebUSB"))
904 }
905
906 pub fn events(&self) -> UsbEvents {
910 UsbEvents { rx: self.event_rx.resubscribe().into(), _marker: PhantomData }
911 }
912
913 pub async fn devices(&self) -> Vec<UsbDevice> {
917 let list = JsFuture::from(self.usb.get_devices()).await.unwrap();
918 js_sys::Array::from(&list)
919 .iter()
920 .map(|dev| UsbDevice::from(dev.unchecked_into::<web_sys::UsbDevice>()))
921 .collect()
922 }
923
924 pub async fn request_device(&self, filters: impl IntoIterator<Item = UsbDeviceFilter>) -> Result<UsbDevice> {
928 let opts = &UsbDeviceRequestOptions::new(filters);
929 let dev = JsFuture::from(self.usb.request_device(&opts.into())).await?;
930 Ok(dev.into())
931 }
932}
933
934impl Drop for Usb {
935 fn drop(&mut self) {
936 self.usb
937 .remove_event_listener_with_callback("connect", self.on_connect.as_ref().unchecked_ref())
938 .unwrap();
939 self.usb
940 .remove_event_listener_with_callback("disconnect", self.on_disconnect.as_ref().unchecked_ref())
941 .unwrap();
942 }
943}
944
945pub struct OpenUsbDevice {
949 device: UsbDevice,
950 closed: bool,
951}
952
953impl fmt::Debug for OpenUsbDevice {
954 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
955 f.debug_struct("OpenUsbDevice").field("device", &self.device).finish()
956 }
957}
958
959impl AsRef<UsbDevice> for OpenUsbDevice {
960 fn as_ref(&self) -> &UsbDevice {
961 &self.device
962 }
963}
964
965impl OpenUsbDevice {
966 fn dev(&self) -> &web_sys::UsbDevice {
967 &self.device.device
968 }
969
970 pub fn device(&self) -> &UsbDevice {
972 &self.device
973 }
974
975 pub async fn close(mut self) -> Result<()> {
980 self.closed = true;
981 JsFuture::from(self.dev().close()).await?;
982 Ok(())
983 }
984
985 pub async fn reset(&self) -> Result<()> {
987 JsFuture::from(self.dev().reset()).await?;
988 Ok(())
989 }
990
991 pub async fn select_configuration(&self, configuration: u8) -> Result<()> {
993 JsFuture::from(self.dev().select_configuration(configuration)).await?;
994 Ok(())
995 }
996
997 pub async fn claim_interface(&self, interface: u8) -> Result<()> {
999 JsFuture::from(self.dev().claim_interface(interface)).await?;
1000 Ok(())
1001 }
1002
1003 pub async fn release_interface(&self, interface: u8) -> Result<()> {
1005 JsFuture::from(self.dev().release_interface(interface)).await?;
1006 Ok(())
1007 }
1008
1009 pub async fn select_alternate_interface(&self, interface: u8, alternate: u8) -> Result<()> {
1011 JsFuture::from(self.dev().select_alternate_interface(interface, alternate)).await?;
1012 Ok(())
1013 }
1014
1015 pub async fn clear_halt(&self, direction: UsbDirection, endpoint: u8) -> Result<()> {
1020 JsFuture::from(self.dev().clear_halt(direction.into(), endpoint)).await?;
1021 Ok(())
1022 }
1023
1024 fn check_status(status: web_sys::UsbTransferStatus) -> Result<()> {
1026 match status {
1027 web_sys::UsbTransferStatus::Ok => Ok(()),
1028 web_sys::UsbTransferStatus::Stall => Err(Error::new(ErrorKind::Stall, "USB device stalled transfer")),
1029 web_sys::UsbTransferStatus::Babble => {
1030 Err(Error::new(ErrorKind::Babble, "USB device sent too much data"))
1031 }
1032 other => unreachable!("unsupported UsbTransferStatus {other:?}"),
1033 }
1034 }
1035
1036 pub async fn control_transfer_in(&self, control_request: &UsbControlRequest, len: u16) -> Result<UsbData> {
1038 let setup = web_sys::UsbControlTransferParameters::from(control_request);
1039 let res = match JsFuture::from(self.dev().control_transfer_in(&setup, len)).await {
1040 Ok(res) => res,
1041 Err(err) => return Err(quirks::network_error_as_stall(err)),
1042 };
1043
1044 Self::check_status(res.status())?;
1045
1046 Ok(UsbData::from_data_view(&res.data().unwrap()))
1047 }
1048
1049 pub async fn control_transfer_out(&self, control_request: &UsbControlRequest, data: &[u8]) -> Result<u32> {
1051 let setup = web_sys::UsbControlTransferParameters::from(control_request);
1052 let arr = unsafe { uint8_array_for_api(data) };
1057 let res = match JsFuture::from(self.dev().control_transfer_out_with_u8_array(&setup, &arr)?).await {
1058 Ok(res) => res,
1059 Err(err) => return Err(quirks::network_error_as_stall(err)),
1060 };
1061
1062 Self::check_status(res.status())?;
1063 Ok(res.bytes_written())
1064 }
1065
1066 pub async fn isochronous_transfer_in(
1068 &self, endpoint: u8, packet_lens: impl IntoIterator<Item = u32>,
1069 ) -> Result<Vec<Result<UsbData>>> {
1070 let packet_lens = packet_lens.into_iter().map(|len| js_sys::Number::from(len as f64)).collect::<Vec<_>>();
1071
1072 let res = JsFuture::from(self.dev().isochronous_transfer_in(endpoint, &packet_lens)).await?;
1073
1074 let mut results = Vec::new();
1075 for packet in res.packets() {
1076 let result = match Self::check_status(packet.status()) {
1077 Ok(()) => Ok(UsbData::from_data_view(&packet.data().unwrap())),
1078 Err(err) => Err(err),
1079 };
1080 results.push(result);
1081 }
1082
1083 Ok(results)
1084 }
1085
1086 pub async fn isochronous_transfer_out(
1090 &self, endpoint: u8, packets: impl IntoIterator<Item = &[u8]>,
1091 ) -> Result<Vec<Result<u32>>> {
1092 let packets: Vec<&[u8]> = packets.into_iter().collect();
1093 let lens: Vec<_> = packets.iter().map(|p| js_sys::Number::from(p.len() as f64)).collect();
1094
1095 let res = if packets.len() == 1 {
1100 let arr = unsafe { uint8_array_for_api(packets[0]) };
1101 JsFuture::from(self.dev().isochronous_transfer_out_with_u8_array(endpoint, &arr, &lens)?).await?
1102 } else {
1103 let total: usize = packets.iter().map(|p| p.len()).sum();
1104 let mut data = Vec::with_capacity(total);
1105 for packet in &packets {
1106 data.extend_from_slice(packet);
1107 }
1108 let arr = unsafe { uint8_array_for_api(&data) };
1109 JsFuture::from(self.dev().isochronous_transfer_out_with_u8_array(endpoint, &arr, &lens)?).await?
1110 };
1111
1112 let mut results = Vec::new();
1113 for packet in res.packets() {
1114 let result = match Self::check_status(packet.status()) {
1115 Ok(()) => Ok(packet.bytes_written()),
1116 Err(err) => Err(err),
1117 };
1118 results.push(result);
1119 }
1120
1121 Ok(results)
1122 }
1123
1124 pub async fn transfer_in(&self, endpoint: u8, len: u32) -> Result<UsbData> {
1126 let res = match JsFuture::from(self.dev().transfer_in(endpoint, len)).await {
1127 Ok(res) => res,
1128 Err(err) => return Err(quirks::network_error_as_stall(err)),
1129 };
1130
1131 Self::check_status(res.status())?;
1132
1133 Ok(UsbData::from_data_view(&res.data().unwrap()))
1134 }
1135
1136 pub async fn transfer_out(&self, endpoint: u8, data: &[u8]) -> Result<u32> {
1140 let arr = unsafe { uint8_array_for_api(data) };
1145 let res = match JsFuture::from(self.dev().transfer_out_with_u8_array(endpoint, &arr)?).await {
1146 Ok(res) => res,
1147 Err(err) => return Err(quirks::network_error_as_stall(err)),
1148 };
1149
1150 Self::check_status(res.status())?;
1151
1152 Ok(res.bytes_written())
1153 }
1154}
1155
1156impl Drop for OpenUsbDevice {
1157 fn drop(&mut self) {
1158 if !self.closed {
1159 let device = self.dev().clone();
1160 let fut = JsFuture::from(device.close());
1161 spawn_local(async move {
1162 let _ = fut.await;
1163 });
1164 }
1165 }
1166}