1#![warn(missing_docs)]
26
27use std::{
28 fmt,
29 hash::{Hash, Hasher},
30 marker::PhantomData,
31 pin::Pin,
32 task::{ready, Context, Poll},
33};
34
35use futures_core::Stream;
36use futures_util::StreamExt;
37use js_sys::{Reflect, Uint8Array};
38use tokio::sync::broadcast;
39use tokio_stream::wrappers::{errors::BroadcastStreamRecvError, BroadcastStream};
40use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
41use wasm_bindgen_futures::{spawn_local, JsFuture};
42
43#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct Error {
46 kind: ErrorKind,
47 msg: String,
48}
49
50impl Error {
51 pub fn kind(&self) -> ErrorKind {
53 self.kind
54 }
55
56 pub fn msg(&self) -> &str {
58 &self.msg
59 }
60}
61
62impl fmt::Display for Error {
63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64 write!(f, "{:?}: {}", self.kind, &self.msg)
65 }
66}
67
68impl std::error::Error for Error {}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
72#[non_exhaustive]
73pub enum ErrorKind {
74 Unsupported,
76 AlreadyOpen,
78 Disconnected,
80 Security,
82 Stall,
86 Babble,
88 Transfer,
90 InvalidAccess,
92 Other,
94}
95
96impl Error {
97 fn new(kind: ErrorKind, msg: impl AsRef<str>) -> Self {
98 Self { kind, msg: msg.as_ref().to_string() }
99 }
100}
101
102impl From<JsValue> for Error {
103 fn from(value: JsValue) -> Self {
104 if let Some(js_error) = value.dyn_ref::<js_sys::Error>() {
105 let msg = js_error.message().as_string().unwrap();
106 let kind = match js_error.name().as_string().unwrap().as_str() {
107 "NotFoundError" => ErrorKind::Disconnected,
108 "SecurityError" => ErrorKind::Security,
109 "InvalidAccessError" => ErrorKind::InvalidAccess,
110 "NetworkError" => ErrorKind::Transfer,
111 _ => ErrorKind::Other,
112 };
113 return Error::new(kind, msg);
114 }
115
116 let msg = value.as_string().unwrap_or_else(|| "unknown error".into());
117 Error::new(ErrorKind::Other, msg)
118 }
119}
120
121impl From<Error> for std::io::Error {
122 fn from(err: Error) -> Self {
123 let kind = match err.kind {
124 ErrorKind::Unsupported => std::io::ErrorKind::Unsupported,
125 ErrorKind::AlreadyOpen => std::io::ErrorKind::ResourceBusy,
126 ErrorKind::Disconnected => std::io::ErrorKind::NotConnected,
127 ErrorKind::Security => std::io::ErrorKind::PermissionDenied,
128 ErrorKind::Stall => std::io::ErrorKind::InvalidData,
129 ErrorKind::Babble => std::io::ErrorKind::UnexpectedEof,
130 ErrorKind::Transfer => std::io::ErrorKind::ConnectionReset,
131 ErrorKind::InvalidAccess => std::io::ErrorKind::InvalidInput,
132 ErrorKind::Other => std::io::ErrorKind::Other,
133 };
134 std::io::Error::new(kind, err)
135 }
136}
137
138pub type Result<T> = std::result::Result<T, Error>;
140
141#[derive(Debug, Clone)]
143#[non_exhaustive]
144pub struct UsbConfiguration {
145 pub configuration_value: u8,
150 pub configuration_name: Option<String>,
156 pub interfaces: Vec<UsbInterface>,
158}
159
160impl From<&web_sys::UsbConfiguration> for UsbConfiguration {
161 fn from(conf: &web_sys::UsbConfiguration) -> Self {
162 let iface_list = conf.interfaces();
163 let mut interfaces = Vec::new();
164 for i in 0..iface_list.length() {
165 if let Some(iface) = iface_list.get(i).dyn_ref::<web_sys::UsbInterface>() {
166 interfaces.push(UsbInterface::from(iface));
167 }
168 }
169 Self {
170 configuration_value: conf.configuration_value(),
171 configuration_name: conf.configuration_name(),
172 interfaces,
173 }
174 }
175}
176
177#[derive(Debug, Clone)]
179#[non_exhaustive]
180pub struct UsbInterface {
181 pub interface_number: u8,
183 pub alternate: UsbAlternateInterface,
190 pub alternates: Vec<UsbAlternateInterface>,
195 pub claimed: bool,
197}
198
199impl From<&web_sys::UsbInterface> for UsbInterface {
200 fn from(iface: &web_sys::UsbInterface) -> Self {
201 let alt_list = iface.alternates();
202 let mut alternates = Vec::new();
203 for i in 0..alt_list.length() {
204 if let Some(alt) = alt_list.get(i).dyn_ref::<web_sys::UsbAlternateInterface>() {
205 alternates.push(UsbAlternateInterface::from(alt));
206 }
207 }
208
209 Self {
210 interface_number: iface.interface_number(),
211 alternate: UsbAlternateInterface::from(&iface.alternate()),
212 alternates,
213 claimed: iface.claimed(),
214 }
215 }
216}
217
218#[derive(Debug, Clone)]
220#[non_exhaustive]
221pub struct UsbAlternateInterface {
222 pub alternate_setting: u8,
226 pub interface_class: u8,
230 pub interface_subclass: u8,
234 pub interface_protocol: u8,
238 pub interface_name: Option<String>,
243 pub endpoints: Vec<UsbEndpoint>,
245}
246
247impl From<&web_sys::UsbAlternateInterface> for UsbAlternateInterface {
248 fn from(alt: &web_sys::UsbAlternateInterface) -> Self {
249 let ep_list = alt.endpoints();
250 let mut endpoints = Vec::new();
251 for i in 0..ep_list.length() {
252 if let Some(ep) = ep_list.get(i).dyn_ref::<web_sys::UsbEndpoint>() {
253 endpoints.push(UsbEndpoint::from(ep));
254 }
255 }
256
257 Self {
258 alternate_setting: alt.alternate_setting(),
259 interface_class: alt.interface_class(),
260 interface_subclass: alt.interface_subclass(),
261 interface_protocol: alt.interface_protocol(),
262 interface_name: alt.interface_name(),
263 endpoints,
264 }
265 }
266}
267
268#[derive(Debug, Clone)]
270#[non_exhaustive]
271pub struct UsbEndpoint {
272 pub endpoint_number: u8,
277 pub direction: UsbDirection,
279 pub endpoint_type: UsbEndpointType,
281 pub packet_size: u32,
283}
284
285impl From<&web_sys::UsbEndpoint> for UsbEndpoint {
286 fn from(ep: &web_sys::UsbEndpoint) -> Self {
287 Self {
288 endpoint_number: ep.endpoint_number(),
289 direction: ep.direction().into(),
290 endpoint_type: ep.type_().into(),
291 packet_size: ep.packet_size(),
292 }
293 }
294}
295
296#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
298pub enum UsbEndpointType {
299 Bulk,
304 Interrupt,
310 Isochronous,
315}
316
317impl From<web_sys::UsbEndpointType> for UsbEndpointType {
318 fn from(value: web_sys::UsbEndpointType) -> Self {
319 match value {
320 web_sys::UsbEndpointType::Bulk => Self::Bulk,
321 web_sys::UsbEndpointType::Interrupt => Self::Interrupt,
322 web_sys::UsbEndpointType::Isochronous => Self::Isochronous,
323 other => unreachable!("unsupported UsbEndpointType: {other:?}"),
324 }
325 }
326}
327
328#[derive(Clone, PartialEq, Eq)]
330pub struct UsbDevice {
331 device: web_sys::UsbDevice,
332}
333
334impl UsbDevice {
335 pub fn vendor_id(&self) -> u16 {
337 self.device.vendor_id()
338 }
339
340 pub fn product_id(&self) -> u16 {
342 self.device.product_id()
343 }
344
345 pub fn device_class(&self) -> u8 {
347 self.device.device_class()
348 }
349
350 pub fn device_subclass(&self) -> u8 {
352 self.device.device_subclass()
353 }
354
355 pub fn device_protocol(&self) -> u8 {
357 self.device.device_protocol()
358 }
359
360 pub fn device_version_major(&self) -> u8 {
362 self.device.device_version_major()
363 }
364
365 pub fn device_version_minor(&self) -> u8 {
367 self.device.device_version_minor()
368 }
369
370 pub fn device_version_subminor(&self) -> u8 {
372 self.device.device_version_subminor()
373 }
374
375 pub fn usb_version_major(&self) -> u8 {
377 self.device.usb_version_major()
378 }
379
380 pub fn usb_version_minor(&self) -> u8 {
382 self.device.usb_version_minor()
383 }
384
385 pub fn usb_version_subminor(&self) -> u8 {
387 self.device.usb_version_subminor()
388 }
389
390 pub fn manufacturer_name(&self) -> Option<String> {
392 self.device.manufacturer_name()
393 }
394
395 pub fn product_name(&self) -> Option<String> {
397 self.device.product_name()
398 }
399
400 pub fn serial_number(&self) -> Option<String> {
402 self.device.serial_number()
403 }
404
405 pub fn opened(&self) -> bool {
407 self.device.opened()
408 }
409
410 pub fn configuration(&self) -> Option<UsbConfiguration> {
412 self.device.configuration().map(|cfg| (&cfg).into())
413 }
414
415 pub fn configurations(&self) -> Vec<UsbConfiguration> {
417 let cfg_list = self.device.configurations();
418 let mut configurations = Vec::new();
419 for i in 0..cfg_list.length() {
420 if let Some(conf) = cfg_list.get(i).dyn_ref::<web_sys::UsbConfiguration>() {
421 configurations.push(UsbConfiguration::from(conf));
422 }
423 }
424 configurations
425 }
426
427 pub async fn forget(self) {
430 JsFuture::from(self.device.forget()).await.unwrap();
431 }
432
433 pub async fn open(&self) -> Result<OpenUsbDevice> {
437 if self.opened() {
438 return Err(Error::new(ErrorKind::AlreadyOpen, "USB device is already open"));
439 }
440
441 JsFuture::from(self.device.open()).await?;
442 Ok(OpenUsbDevice { device: self.clone(), closed: false })
443 }
444}
445
446impl std::fmt::Debug for UsbDevice {
447 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
448 f.debug_struct("UsbDevice")
449 .field("vendor_id", &self.vendor_id())
450 .field("product_id", &self.product_id())
451 .field("device_class", &self.device_class())
452 .field("device_subclass", &self.device_subclass())
453 .field("device_protocol", &self.device_protocol())
454 .field("device_version_major", &self.device_version_major())
455 .field("device_version_minor", &self.device_version_minor())
456 .field("device_version_subminor", &self.device_version_subminor())
457 .field("usb_version_major", &self.usb_version_major())
458 .field("usb_version_minor", &self.usb_version_minor())
459 .field("usb_version_subminor", &self.usb_version_subminor())
460 .field("manufacturer_name", &self.manufacturer_name())
461 .field("product_name", &self.product_name())
462 .field("serial_number", &self.serial_number())
463 .field("opened", &self.opened())
464 .field("configuration", &self.configuration())
465 .field("configurations", &self.configurations())
466 .finish()
467 }
468}
469
470impl Hash for UsbDevice {
471 fn hash<H: Hasher>(&self, state: &mut H) {
472 self.vendor_id().hash(state);
473 self.product_id().hash(state);
474 self.device_class().hash(state);
475 self.device_subclass().hash(state);
476 self.device_protocol().hash(state);
477 self.device_version_major().hash(state);
478 self.device_version_minor().hash(state);
479 self.device_version_subminor().hash(state);
480 self.manufacturer_name().hash(state);
481 self.product_name().hash(state);
482 self.serial_number().hash(state);
483 }
484}
485
486impl From<web_sys::UsbDevice> for UsbDevice {
487 fn from(device: web_sys::UsbDevice) -> Self {
488 Self { device }
489 }
490}
491
492impl AsRef<web_sys::UsbDevice> for UsbDevice {
493 fn as_ref(&self) -> &web_sys::UsbDevice {
494 &self.device
495 }
496}
497
498#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
500pub enum UsbDirection {
501 In,
503 Out,
505}
506
507impl From<web_sys::UsbDirection> for UsbDirection {
508 fn from(value: web_sys::UsbDirection) -> Self {
509 match value {
510 web_sys::UsbDirection::In => Self::In,
511 web_sys::UsbDirection::Out => Self::Out,
512 other => unreachable!("unsupported UsbDirection {other:?}"),
513 }
514 }
515}
516
517impl From<UsbDirection> for web_sys::UsbDirection {
518 fn from(direction: UsbDirection) -> Self {
519 match direction {
520 UsbDirection::In => web_sys::UsbDirection::In,
521 UsbDirection::Out => web_sys::UsbDirection::Out,
522 }
523 }
524}
525
526#[derive(Debug, Clone, Default)]
530#[non_exhaustive]
531pub struct UsbDeviceFilter {
532 pub vendor_id: Option<u16>,
534 pub product_id: Option<u16>,
536 pub class_code: Option<u8>,
538 pub subclass_code: Option<u8>,
540 pub protocol_code: Option<u8>,
542 pub serial_number: Option<String>,
544}
545
546impl UsbDeviceFilter {
547 pub const fn new() -> Self {
549 Self {
550 vendor_id: None,
551 product_id: None,
552 class_code: None,
553 subclass_code: None,
554 protocol_code: None,
555 serial_number: None,
556 }
557 }
558
559 pub const fn with_vendor_id(mut self, vendor_id: u16) -> Self {
561 self.vendor_id = Some(vendor_id);
562 self
563 }
564
565 pub const fn with_product_id(mut self, product_id: u16) -> Self {
567 self.product_id = Some(product_id);
568 self
569 }
570
571 pub const fn with_class_code(mut self, class_code: u8) -> Self {
573 self.class_code = Some(class_code);
574 self
575 }
576
577 pub const fn with_subclass_code(mut self, subclass_code: u8) -> Self {
579 self.subclass_code = Some(subclass_code);
580 self
581 }
582
583 pub const fn with_protocol_code(mut self, protocol_code: u8) -> Self {
585 self.protocol_code = Some(protocol_code);
586 self
587 }
588
589 pub fn with_serial_number<S: Into<String>>(mut self, serial_number: S) -> Self {
591 self.serial_number = Some(serial_number.into());
592 self
593 }
594}
595
596impl From<&UsbDeviceFilter> for web_sys::UsbDeviceFilter {
597 fn from(value: &UsbDeviceFilter) -> Self {
598 let filter = web_sys::UsbDeviceFilter::new();
599 if let Some(x) = value.vendor_id {
600 filter.set_vendor_id(x);
601 }
602 if let Some(x) = value.product_id {
603 filter.set_product_id(x);
604 }
605 if let Some(x) = value.class_code {
606 filter.set_class_code(x);
607 }
608 if let Some(x) = value.subclass_code {
609 filter.set_subclass_code(x);
610 }
611 if let Some(x) = value.protocol_code {
612 filter.set_protocol_code(x);
613 }
614 if let Some(x) = &value.serial_number {
615 filter.set_serial_number(x);
616 }
617 filter
618 }
619}
620
621#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
623pub enum UsbRecipient {
624 Device,
626 Interface,
628 Endpoint,
630 Other,
632}
633
634impl From<UsbRecipient> for web_sys::UsbRecipient {
635 fn from(recipient: UsbRecipient) -> Self {
636 match recipient {
637 UsbRecipient::Device => Self::Device,
638 UsbRecipient::Interface => Self::Interface,
639 UsbRecipient::Endpoint => Self::Endpoint,
640 UsbRecipient::Other => Self::Other,
641 }
642 }
643}
644
645#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
647pub enum UsbRequestType {
648 Standard,
650 Class,
652 Vendor,
654}
655
656impl From<UsbRequestType> for web_sys::UsbRequestType {
657 fn from(req_type: UsbRequestType) -> Self {
658 match req_type {
659 UsbRequestType::Standard => Self::Standard,
660 UsbRequestType::Class => Self::Class,
661 UsbRequestType::Vendor => Self::Vendor,
662 }
663 }
664}
665
666#[derive(Clone, Debug)]
668struct UsbDeviceRequestOptions {
669 pub filters: Vec<UsbDeviceFilter>,
671}
672
673impl UsbDeviceRequestOptions {
674 pub fn new(filters: impl IntoIterator<Item = UsbDeviceFilter>) -> Self {
676 Self { filters: filters.into_iter().collect() }
677 }
678}
679
680impl From<&UsbDeviceRequestOptions> for web_sys::UsbDeviceRequestOptions {
681 fn from(value: &UsbDeviceRequestOptions) -> Self {
682 let filters = value.filters.iter().map(web_sys::UsbDeviceFilter::from).collect::<Vec<_>>();
683
684 web_sys::UsbDeviceRequestOptions::new(&filters)
685 }
686}
687
688#[derive(Clone, Debug)]
690#[non_exhaustive]
691pub struct UsbControlRequest {
692 pub request_type: UsbRequestType,
694 pub recipient: UsbRecipient,
696 pub request: u8,
698 pub value: u16,
700 pub index: u16,
702}
703
704impl UsbControlRequest {
705 pub const fn new(
708 request_type: UsbRequestType, recipient: UsbRecipient, request: u8, value: u16, index: u16,
709 ) -> Self {
710 Self { request_type, recipient, request, value, index }
711 }
712}
713
714impl From<&UsbControlRequest> for web_sys::UsbControlTransferParameters {
715 fn from(req: &UsbControlRequest) -> Self {
716 Self::new(req.index, req.recipient.into(), req.request, req.request_type.into(), req.value)
717 }
718}
719
720#[derive(Debug, Clone)]
722#[non_exhaustive]
723pub enum UsbEvent {
724 Connected(UsbDevice),
726 Disconnected(UsbDevice),
728}
729
730#[derive(Debug, Clone)]
732struct SendWrapper<T>(pub T);
733unsafe impl<T> Send for SendWrapper<T> {}
734
735pub struct UsbEvents {
739 rx: BroadcastStream<SendWrapper<UsbEvent>>,
743 _marker: PhantomData<*const ()>,
744}
745
746impl fmt::Debug for UsbEvents {
747 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
748 f.debug_tuple("UsbEvents").finish()
749 }
750}
751
752impl Stream for UsbEvents {
753 type Item = UsbEvent;
754 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
755 loop {
756 match ready!(self.rx.poll_next_unpin(cx)) {
757 Some(Ok(event)) => break Poll::Ready(Some(event.0)),
758 Some(Err(BroadcastStreamRecvError::Lagged(_))) => (),
759 None => break Poll::Ready(None),
760 }
761 }
762 }
763}
764
765pub struct Usb {
767 usb: web_sys::Usb,
768 event_rx: broadcast::Receiver<SendWrapper<UsbEvent>>,
769 on_connect: Closure<dyn Fn(web_sys::UsbConnectionEvent)>,
770 on_disconnect: Closure<dyn Fn(web_sys::UsbConnectionEvent)>,
771}
772
773impl fmt::Debug for Usb {
774 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
775 f.debug_tuple("Usb").finish()
776 }
777}
778
779impl Usb {
780 pub fn new() -> Result<Self> {
782 let usb = Self::browser_usb()?;
783
784 let (event_tx, event_rx) = broadcast::channel(1024);
785
786 let on_connect = {
787 let event_tx = event_tx.clone();
788 Closure::wrap(Box::new(move |event: web_sys::UsbConnectionEvent| {
789 let _ = event_tx.send(SendWrapper(UsbEvent::Connected(event.device().into())));
790 }) as Box<dyn Fn(_)>)
791 };
792 usb.add_event_listener_with_callback("connect", on_connect.as_ref().unchecked_ref()).unwrap();
793
794 let on_disconnect = {
795 let event_tx = event_tx.clone();
796 Closure::wrap(Box::new(move |event: web_sys::UsbConnectionEvent| {
797 let _ = event_tx.send(SendWrapper(UsbEvent::Disconnected(event.device().into())));
798 }) as Box<dyn Fn(_)>)
799 };
800 usb.add_event_listener_with_callback("disconnect", on_disconnect.as_ref().unchecked_ref()).unwrap();
801
802 Ok(Self { usb, event_rx, on_connect, on_disconnect })
803 }
804
805 fn browser_usb() -> Result<web_sys::Usb> {
806 let global = js_sys::global();
807
808 if let Some(window) = global.dyn_ref::<web_sys::Window>() {
809 let navigator = window.navigator();
810 match Reflect::get(&navigator, &JsValue::from_str("usb")) {
811 Ok(usb) if !usb.is_null() && !usb.is_undefined() => return Ok(navigator.usb()),
812 _ => (),
813 }
814 }
815
816 if let Some(worker) = global.dyn_ref::<web_sys::WorkerGlobalScope>() {
817 let navigator = worker.navigator();
818 match Reflect::get(&navigator, &JsValue::from_str("usb")) {
819 Ok(usb) if !usb.is_null() && !usb.is_undefined() => return Ok(navigator.usb()),
820 _ => (),
821 }
822 }
823
824 Err(Error::new(ErrorKind::Unsupported, "browser does not support WebUSB"))
825 }
826
827 pub fn events(&self) -> UsbEvents {
831 UsbEvents { rx: self.event_rx.resubscribe().into(), _marker: PhantomData }
832 }
833
834 pub async fn devices(&self) -> Vec<UsbDevice> {
838 let list = JsFuture::from(self.usb.get_devices()).await.unwrap();
839 js_sys::Array::from(&list)
840 .iter()
841 .map(|dev| UsbDevice::from(dev.dyn_into::<web_sys::UsbDevice>().unwrap()))
842 .collect()
843 }
844
845 pub async fn request_device(&self, filters: impl IntoIterator<Item = UsbDeviceFilter>) -> Result<UsbDevice> {
849 let opts = &UsbDeviceRequestOptions::new(filters);
850 let dev = JsFuture::from(self.usb.request_device(&opts.into())).await?;
851 Ok(dev.dyn_into::<web_sys::UsbDevice>().unwrap().into())
852 }
853}
854
855impl Drop for Usb {
856 fn drop(&mut self) {
857 self.usb
858 .remove_event_listener_with_callback("connect", self.on_connect.as_ref().unchecked_ref())
859 .unwrap();
860 self.usb
861 .remove_event_listener_with_callback("disconnect", self.on_disconnect.as_ref().unchecked_ref())
862 .unwrap();
863 }
864}
865
866pub struct OpenUsbDevice {
870 device: UsbDevice,
871 closed: bool,
872}
873
874impl fmt::Debug for OpenUsbDevice {
875 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
876 f.debug_struct("OpenUsbDevice").field("device", &self.device).finish()
877 }
878}
879
880impl AsRef<UsbDevice> for OpenUsbDevice {
881 fn as_ref(&self) -> &UsbDevice {
882 &self.device
883 }
884}
885
886impl OpenUsbDevice {
887 fn dev(&self) -> &web_sys::UsbDevice {
888 &self.device.device
889 }
890
891 pub fn device(&self) -> &UsbDevice {
893 &self.device
894 }
895
896 pub async fn close(mut self) -> Result<()> {
901 self.closed = true;
902 JsFuture::from(self.dev().close()).await?;
903 Ok(())
904 }
905
906 pub async fn reset(&self) -> Result<()> {
908 JsFuture::from(self.dev().reset()).await?;
909 Ok(())
910 }
911
912 pub async fn select_configuration(&self, configuration: u8) -> Result<()> {
914 JsFuture::from(self.dev().select_configuration(configuration)).await?;
915 Ok(())
916 }
917
918 pub async fn claim_interface(&self, interface: u8) -> Result<()> {
920 JsFuture::from(self.dev().claim_interface(interface)).await?;
921 Ok(())
922 }
923
924 pub async fn release_interface(&self, interface: u8) -> Result<()> {
926 JsFuture::from(self.dev().release_interface(interface)).await?;
927 Ok(())
928 }
929
930 pub async fn select_alternate_interface(&self, interface: u8, alternate: u8) -> Result<()> {
932 JsFuture::from(self.dev().select_alternate_interface(interface, alternate)).await?;
933 Ok(())
934 }
935
936 pub async fn clear_halt(&self, direction: UsbDirection, endpoint: u8) -> Result<()> {
941 JsFuture::from(self.dev().clear_halt(direction.into(), endpoint)).await?;
942 Ok(())
943 }
944
945 fn check_status(status: web_sys::UsbTransferStatus) -> Result<()> {
947 match status {
948 web_sys::UsbTransferStatus::Ok => Ok(()),
949 web_sys::UsbTransferStatus::Stall => Err(Error::new(ErrorKind::Stall, "USB device stalled transfer")),
950 web_sys::UsbTransferStatus::Babble => {
951 Err(Error::new(ErrorKind::Babble, "USB device sent too much data"))
952 }
953 other => unreachable!("unsupported UsbTransferStatus {other:?}"),
954 }
955 }
956
957 pub async fn control_transfer_in(&self, control_request: &UsbControlRequest, len: u16) -> Result<Vec<u8>> {
959 let setup = web_sys::UsbControlTransferParameters::from(control_request);
960 let res = JsFuture::from(self.dev().control_transfer_in(&setup, len)).await?;
961 let res = res.dyn_into::<web_sys::UsbInTransferResult>().unwrap();
962
963 Self::check_status(res.status())?;
964
965 let data = Uint8Array::new(&res.data().unwrap().buffer()).to_vec();
966 Ok(data)
967 }
968
969 pub async fn control_transfer_out(&self, control_request: &UsbControlRequest, data: &[u8]) -> Result<u32> {
971 let setup = web_sys::UsbControlTransferParameters::from(control_request);
972 let data = Uint8Array::from(data);
973 let res = JsFuture::from(self.dev().control_transfer_out_with_u8_array(&setup, &data)?).await?;
974 let res = res.dyn_into::<web_sys::UsbOutTransferResult>().unwrap();
975
976 Self::check_status(res.status())?;
977 Ok(res.bytes_written())
978 }
979
980 pub async fn isochronous_transfer_in(
982 &self, endpoint: u8, packet_lens: impl IntoIterator<Item = u32>,
983 ) -> Result<Vec<Result<Vec<u8>>>> {
984 let packet_lens = packet_lens.into_iter().map(|len| js_sys::Number::from(len as f64)).collect::<Vec<_>>();
985
986 let res = JsFuture::from(self.dev().isochronous_transfer_in(endpoint, &packet_lens)).await?;
987 let res = res.dyn_into::<web_sys::UsbIsochronousInTransferResult>().unwrap();
988
989 let mut results = Vec::new();
990 for packet in res.packets() {
991 let packet = packet.dyn_into::<web_sys::UsbIsochronousInTransferPacket>().unwrap();
992 let result = match Self::check_status(packet.status()) {
993 Ok(()) => Ok(Uint8Array::new(&res.data().unwrap().buffer()).to_vec()),
994 Err(err) => Err(err),
995 };
996 results.push(result);
997 }
998
999 Ok(results)
1000 }
1001
1002 pub async fn isochronous_transfer_out(
1006 &self, endpoint: u8, packets: impl IntoIterator<Item = &[u8]>,
1007 ) -> Result<Vec<Result<u32>>> {
1008 let mut data = Vec::new();
1009 let mut lens = Vec::new();
1010
1011 for packet in packets {
1012 data.extend_from_slice(packet);
1013 lens.push(data.len());
1014 }
1015
1016 let data = Uint8Array::from(&data[..]);
1017 let lens = lens.into_iter().map(|len| js_sys::Number::from(len as f64)).collect::<Vec<_>>();
1018
1019 let res =
1020 JsFuture::from(self.dev().isochronous_transfer_out_with_u8_array(endpoint, &data, &lens)?).await?;
1021 let res = res.dyn_into::<web_sys::UsbIsochronousOutTransferResult>().unwrap();
1022
1023 let mut results = Vec::new();
1024 for packet in res.packets() {
1025 let packet = packet.dyn_into::<web_sys::UsbIsochronousOutTransferPacket>().unwrap();
1026 let result = match Self::check_status(packet.status()) {
1027 Ok(()) => Ok(packet.bytes_written()),
1028 Err(err) => Err(err),
1029 };
1030 results.push(result);
1031 }
1032
1033 Ok(results)
1034 }
1035
1036 pub async fn transfer_in(&self, endpoint: u8, len: u32) -> Result<Vec<u8>> {
1038 let res = JsFuture::from(self.dev().transfer_in(endpoint, len)).await?;
1039 let res = res.dyn_into::<web_sys::UsbInTransferResult>().unwrap();
1040
1041 Self::check_status(res.status())?;
1042
1043 let data = Uint8Array::new(&res.data().unwrap().buffer()).to_vec();
1044 Ok(data)
1045 }
1046
1047 pub async fn transfer_out(&self, endpoint: u8, data: &[u8]) -> Result<u32> {
1051 let data = Uint8Array::from(data);
1052 let res = JsFuture::from(self.dev().transfer_out_with_u8_array(endpoint, &data)?).await?;
1053 let res = res.dyn_into::<web_sys::UsbOutTransferResult>().unwrap();
1054
1055 Self::check_status(res.status())?;
1056
1057 Ok(res.bytes_written())
1058 }
1059}
1060
1061impl Drop for OpenUsbDevice {
1062 fn drop(&mut self) {
1063 if !self.closed {
1064 let device = self.dev().clone();
1065 let fut = JsFuture::from(device.close());
1066 spawn_local(async move {
1067 let _ = fut.await;
1068 });
1069 }
1070 }
1071}