Skip to main content

device/
device.rs

1//! Device-side example.
2
3use std::time::{Duration, Instant};
4use tokio::time::sleep;
5use usb_gadget::{default_udc, Config, Gadget, Id, OsDescriptor, Strings};
6use uuid::uuid;
7
8use upc::{
9    device::{InterfaceId, UpcFunction},
10    Class,
11};
12
13mod common;
14use common::*;
15
16const DEVICE_CLASS: Class = Class::vendor_specific(0xff, 0);
17
18#[tokio::main(flavor = "current_thread")]
19async fn main() {
20    init_log();
21
22    usb_gadget::remove_all().expect("cannot remove all USB gadgets");
23    sleep(Duration::from_secs(1)).await;
24
25    println!("Creating UPC function...");
26    let (mut upc, hnd) = UpcFunction::new(
27        InterfaceId::new(CLASS)
28            .with_name("USB PACKET TEST")
29            .with_guid(uuid!("3bf77270-42d2-42c6-a475-490227a9cc89")),
30    );
31    upc.set_info(INFO.to_vec()).await;
32
33    println!("Registering gadget...");
34    let udc = default_udc().expect("cannot get UDC");
35    let mut gadget = Gadget::new(DEVICE_CLASS.into(), Id::new(VID, PID), Strings::new("usb-packet", "test", "0"))
36        .with_config(Config::new("config").with_function(hnd))
37        .with_os_descriptor(OsDescriptor::microsoft());
38    gadget.device_release = 0x0110;
39    let reg = gadget.bind(&udc).expect("cannot bind to UDC");
40    assert!(reg.is_attached());
41
42    loop {
43        println!("Waiting for connection...");
44        let (tx, mut rx) = tokio::select! {
45            res = upc.accept() => res.expect("accept failed"),
46            _ = tokio::signal::ctrl_c() => break,
47        };
48
49        assert_eq!(rx.topic(), TOPIC, "wrong topic");
50
51        let overall_start = Instant::now();
52
53        let rx_task = tokio::spawn(async move {
54            let mut rx_testdata = TestData::new(HOST_SEED, TEST_PACKET_MAX_SIZE);
55            let mut rx_delay = TestDelayer::new(HOST_SEED);
56
57            let start = Instant::now();
58            let mut total = 0usize;
59
60            println!("Receiving...");
61            for n in 0..TEST_PACKETS {
62                let data = rx.recv().await.expect("receive failed").expect("unexpected EOF");
63                eprintln!("Recv {n}: {} bytes", data.len());
64                total += data.len();
65                rx_testdata.validate(&data);
66                rx_delay.delay().await;
67            }
68
69            let elapsed = start.elapsed().as_secs_f32();
70            println!(
71                "Received {total} bytes in {elapsed:.2} seconds: {} MB/s",
72                total as f32 / elapsed / 1_048_576.
73            );
74
75            println!("Waiting for receiver close");
76            assert_eq!(rx.recv().await.unwrap(), None, "receiver not closed");
77            println!("Receiver closed");
78
79            total
80        });
81
82        let mut tx_testdata = TestData::new(DEVICE_SEED, TEST_PACKET_MAX_SIZE);
83        let mut tx_delay = TestDelayer::new(DEVICE_SEED);
84
85        let start = Instant::now();
86        let mut tx_total = 0;
87
88        println!("Sending");
89        for n in 0..TEST_PACKETS {
90            let data = tx_testdata.generate();
91            let len = data.len();
92            tx.send(data.into()).await.expect("send failed");
93            tx_total += len;
94            tx_delay.delay().await;
95
96            eprintln!("Send {n}: {len} bytes");
97        }
98
99        let elapsed = start.elapsed().as_secs_f32();
100        println!(
101            "Sent {tx_total} bytes in {elapsed:.2} seconds: {} MB/s",
102            tx_total as f32 / elapsed / 1_048_576.
103        );
104
105        sleep(Duration::from_secs(3)).await;
106
107        println!("Waiting for receiver...");
108        let rx_total = rx_task.await.unwrap();
109        drop(tx);
110
111        let overall_elapsed = overall_start.elapsed().as_secs_f32();
112        let total_bytes = tx_total + rx_total;
113        println!(
114            "Total throughput: {} bytes in {overall_elapsed:.2} seconds: {:.2} MB/s",
115            total_bytes,
116            total_bytes as f32 / overall_elapsed / 1_048_576.
117        );
118        println!("Disconnected\n");
119    }
120
121    drop(reg);
122    sleep(Duration::from_secs(1)).await;
123}