Skip to main content

CustomBuilder

Struct CustomBuilder 

Source
#[non_exhaustive]
pub struct CustomBuilder { pub interfaces: Vec<Interface>, pub all_ctrl_recipient: bool, pub config0_setup: bool, pub ffs_dir: Option<PathBuf>, pub ffs_root_mode: Option<u32>, pub ffs_file_mode: Option<u32>, pub ffs_uid: Option<u32>, pub ffs_gid: Option<u32>, pub ffs_no_disconnect: bool, pub ffs_no_init: bool, pub ffs_no_mount: bool, }
Expand description

Builder for custom USB interface, implemented in user code.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§interfaces: Vec<Interface>

USB interfaces.

§all_ctrl_recipient: bool

Receive control requests that are not explicitly directed to an interface or endpoint.

§config0_setup: bool

Receive control requests in configuration 0.

§ffs_dir: Option<PathBuf>

FunctionFS mount directory.

The parent directory must exist. If unspecified, a directory starting with /dev/ffs-* is created and used.

§ffs_root_mode: Option<u32>

FunctionFS root permissions.

§ffs_file_mode: Option<u32>

FunctionFS file permissions.

§ffs_uid: Option<u32>

FunctionFS user id.

§ffs_gid: Option<u32>

FunctionFS group id.

§ffs_no_disconnect: bool

Do not disconnect USB gadget when interface files are closed.

§ffs_no_init: bool

Do not initialize FunctionFS.

No FunctionFS files are opened. This must then be done externally.

§ffs_no_mount: bool

Do not mount FunctionFS.

Implies ffs_no_init.

Implementations§

Source§

impl CustomBuilder

Source

pub fn build(self) -> (Custom, Handle)

Build the USB function.

The returned handle must be added to a USB gadget configuration.

Examples found in repository?
examples/custom_interface_device_split.rs (line 53)
25fn main() {
26    env_logger::init();
27
28    let existing = std::env::var("EXISTING_FFS").ok();
29    let register_only = std::env::var("REGISTER_ONLY").ok().is_some();
30
31    let (ep1_rx, ep1_dir) = EndpointDirection::host_to_device();
32    let (ep2_tx, ep2_dir) = EndpointDirection::device_to_host();
33
34    let mut builder = Custom::builder();
35
36    if register_only {
37        // We are only registering and binding the gadget, and leaving the FunctionFS interactions
38        // to another process.
39        builder.ffs_no_init = true;
40        builder.ffs_uid = Some(std::env::var("SUDO_UID").unwrap().parse().unwrap());
41        builder.ffs_gid = Some(std::env::var("SUDO_GID").unwrap().parse().unwrap());
42    } else {
43        builder = builder.with_interface(
44            Interface::new(Class::vendor_specific(1, 2), "custom interface")
45                .with_endpoint(Endpoint::bulk(ep1_dir))
46                .with_endpoint(Endpoint::bulk(ep2_dir)),
47        );
48    }
49
50    let (reg, custom) = if let Some(ref path) = existing {
51        (None, builder.existing(path).unwrap())
52    } else {
53        let (mut custom, handle) = builder.build();
54
55        usb_gadget::remove_all().expect("cannot remove all gadgets");
56
57        let udc = default_udc().expect("cannot get UDC");
58        let gadget = Gadget::new(
59            Class::vendor_specific(255, 3),
60            Id::new(6, 0x11),
61            Strings::new("manufacturer", "custom USB interface", "serial_number"),
62        )
63        .with_config(Config::new("config").with_function(handle))
64        .with_os_descriptor(OsDescriptor::microsoft())
65        .with_web_usb(WebUsb::new(0xf1, "http://webusb.org"));
66
67        let reg = gadget.register().expect("cannot register gadget");
68
69        if register_only {
70            let ffs_dir = custom.ffs_dir().unwrap();
71            println!("FunctionFS dir mounted at {}", ffs_dir.display());
72            println!("You can now run this program again as unprivileged user:");
73            println!("EXISTING_FFS={} {}", ffs_dir.display(), std::env::args().next().unwrap());
74
75            let mut ep1_path = ffs_dir.clone();
76            ep1_path.push("ep1");
77            while std::fs::metadata(&ep1_path).is_err() {
78                thread::sleep(Duration::from_secs(1));
79            }
80
81            println!("Detected ep1 in FunctionFS dir, this means descriptors have been written to ep0.");
82            println!("Now binding gadget to UDC (making it active)...");
83        }
84
85        reg.bind(Some(&udc)).expect("cannot bind to UDC");
86
87        println!("Custom function at {}", custom.status().unwrap().path().unwrap().display());
88        println!();
89
90        (Some(reg), custom)
91    };
92
93    if register_only {
94        println!("Waiting for the gadget to become unbound. If you stop the other process, this will happen automatically.");
95        while reg.as_ref().unwrap().udc().unwrap().is_some() {
96            thread::sleep(Duration::from_secs(1));
97        }
98    } else {
99        if existing.is_some() {
100            println!("The FunctionFS setup is done, you can type 'yes' in the other process and hit <ENTER>");
101        }
102        run(ep1_rx, ep2_tx, custom);
103    }
104
105    if let Some(reg) = reg {
106        println!("Unregistering");
107        reg.remove().unwrap();
108    }
109}
More examples
Hide additional examples
examples/custom_interface_device_async.rs (line 33)
19async fn main() {
20    env_logger::init();
21
22    usb_gadget::remove_all().expect("cannot remove all gadgets");
23
24    let (mut ep1_rx, ep1_dir) = EndpointDirection::host_to_device();
25    let (mut ep2_tx, ep2_dir) = EndpointDirection::device_to_host();
26
27    let (mut custom, handle) = Custom::builder()
28        .with_interface(
29            Interface::new(Class::vendor_specific(1, 2), "custom interface")
30                .with_endpoint(Endpoint::bulk(ep1_dir))
31                .with_endpoint(Endpoint::bulk(ep2_dir)),
32        )
33        .build();
34
35    let udc = default_udc().expect("cannot get UDC");
36    let reg = Gadget::new(
37        Class::vendor_specific(255, 3),
38        Id::new(6, 0x11),
39        Strings::new("manufacturer", "custom USB interface", "serial_number"),
40    )
41    .with_config(Config::new("config").with_function(handle))
42    .with_os_descriptor(OsDescriptor::microsoft())
43    .with_web_usb(WebUsb::new(0xf1, "http://webusb.org"))
44    .bind(&udc)
45    .expect("cannot bind to UDC");
46
47    println!("Custom function at {}", custom.status().unwrap().path().unwrap().display());
48    println!();
49
50    let ep1_control = ep1_rx.control().unwrap();
51    println!("ep1 unclaimed: {:?}", ep1_control.unclaimed_fifo());
52    println!("ep1 real address: {}", ep1_control.real_address().unwrap());
53    println!("ep1 descriptor: {:?}", ep1_control.descriptor().unwrap());
54    println!();
55
56    let ep2_control = ep2_tx.control().unwrap();
57    println!("ep2 unclaimed: {:?}", ep2_control.unclaimed_fifo());
58    println!("ep2 real address: {}", ep2_control.real_address().unwrap());
59    println!("ep2 descriptor: {:?}", ep2_control.descriptor().unwrap());
60    println!();
61
62    let stop = Arc::new(AtomicBool::new(false));
63
64    let stop1 = stop.clone();
65    tokio::spawn(async move {
66        let size = ep1_rx.max_packet_size().unwrap();
67        let mut b = 0;
68        while !stop1.load(Ordering::Relaxed) {
69            let data = ep1_rx.recv_async(BytesMut::with_capacity(size)).await.expect("recv_async failed");
70            match data {
71                Some(data) => {
72                    println!("received {} bytes: {data:x?}", data.len());
73                    if !data.iter().all(|x| *x == b) {
74                        panic!("wrong data received");
75                    }
76                    b = b.wrapping_add(1);
77                }
78                None => {
79                    println!("receive empty");
80                }
81            }
82        }
83    });
84
85    let stop2 = stop.clone();
86    tokio::spawn(async move {
87        let size = ep2_tx.max_packet_size().unwrap();
88        let mut b = 0u8;
89        while !stop2.load(Ordering::Relaxed) {
90            let data = vec![b; size];
91            match ep2_tx.send_async(data.into()).await {
92                Ok(()) => {
93                    println!("sent data {b} of size {size} bytes");
94                    b = b.wrapping_add(1);
95                }
96                Err(err) => panic!("send failed: {err}"),
97            }
98        }
99    });
100
101    let mut ctrl_data = Vec::new();
102    while !stop.load(Ordering::Relaxed) {
103        custom.wait_event().await.expect("wait for event failed");
104        println!("event ready");
105        let event = custom.event().expect("event failed");
106
107        println!("Event: {event:?}");
108        match event {
109            Event::SetupHostToDevice(req) => {
110                if req.ctrl_req().request == 255 {
111                    println!("Stopping");
112                    stop.store(true, Ordering::Relaxed);
113                }
114                ctrl_data = req.recv_all().unwrap();
115                println!("Control data: {ctrl_data:x?}");
116            }
117            Event::SetupDeviceToHost(req) => {
118                println!("Replying with data");
119                req.send(&ctrl_data).unwrap();
120            }
121            _ => (),
122        }
123    }
124
125    tokio::time::sleep(Duration::from_secs(1)).await;
126
127    println!("Unregistering");
128    reg.remove().unwrap();
129}
examples/custom_interface_device.rs (line 34)
20fn main() {
21    env_logger::init();
22
23    usb_gadget::remove_all().expect("cannot remove all gadgets");
24
25    let (mut ep1_rx, ep1_dir) = EndpointDirection::host_to_device();
26    let (mut ep2_tx, ep2_dir) = EndpointDirection::device_to_host();
27
28    let (mut custom, handle) = Custom::builder()
29        .with_interface(
30            Interface::new(Class::vendor_specific(1, 2), "custom interface")
31                .with_endpoint(Endpoint::bulk(ep1_dir))
32                .with_endpoint(Endpoint::bulk(ep2_dir)),
33        )
34        .build();
35
36    let udc = default_udc().expect("cannot get UDC");
37    let reg = Gadget::new(
38        Class::vendor_specific(255, 3),
39        Id::new(6, 0x11),
40        Strings::new("manufacturer", "custom USB interface", "serial_number"),
41    )
42    .with_config(Config::new("config").with_function(handle))
43    .with_os_descriptor(OsDescriptor::microsoft())
44    .with_web_usb(WebUsb::new(0xf1, "http://webusb.org"))
45    .bind(&udc)
46    .expect("cannot bind to UDC");
47
48    println!("Custom function at {}", custom.status().unwrap().path().unwrap().display());
49    println!();
50
51    let ep1_control = ep1_rx.control().unwrap();
52    println!("ep1 unclaimed: {:?}", ep1_control.unclaimed_fifo());
53    println!("ep1 real address: {}", ep1_control.real_address().unwrap());
54    println!("ep1 descriptor: {:?}", ep1_control.descriptor().unwrap());
55    println!();
56
57    let ep2_control = ep2_tx.control().unwrap();
58    println!("ep2 unclaimed: {:?}", ep2_control.unclaimed_fifo());
59    println!("ep2 real address: {}", ep2_control.real_address().unwrap());
60    println!("ep2 descriptor: {:?}", ep2_control.descriptor().unwrap());
61    println!();
62
63    let stop = Arc::new(AtomicBool::new(false));
64
65    thread::scope(|s| {
66        s.spawn(|| {
67            let size = ep1_rx.max_packet_size().unwrap();
68            let mut b = 0;
69            while !stop.load(Ordering::Relaxed) {
70                let data = ep1_rx
71                    .recv_timeout(BytesMut::with_capacity(size), Duration::from_secs(1))
72                    .expect("recv failed");
73                match data {
74                    Some(data) => {
75                        println!("received {} bytes: {data:x?}", data.len());
76                        if !data.iter().all(|x| *x == b) {
77                            panic!("wrong data received");
78                        }
79                        b = b.wrapping_add(1);
80                    }
81                    None => {
82                        println!("receive empty");
83                    }
84                }
85            }
86        });
87
88        s.spawn(|| {
89            let size = ep2_tx.max_packet_size().unwrap();
90            let mut b = 0u8;
91            while !stop.load(Ordering::Relaxed) {
92                let data = vec![b; size];
93                match ep2_tx.send_timeout(data.into(), Duration::from_secs(1)) {
94                    Ok(()) => {
95                        println!("sent data {b} of size {size} bytes");
96                        b = b.wrapping_add(1);
97                    }
98                    Err(err) if err.kind() == ErrorKind::TimedOut => println!("send timeout"),
99                    Err(err) => panic!("send failed: {err}"),
100                }
101            }
102        });
103
104        s.spawn(|| {
105            let mut ctrl_data = Vec::new();
106
107            while !stop.load(Ordering::Relaxed) {
108                if let Some(event) = custom.event_timeout(Duration::from_secs(1)).expect("event failed") {
109                    println!("Event: {event:?}");
110                    match event {
111                        Event::SetupHostToDevice(req) => {
112                            if req.ctrl_req().request == 255 {
113                                println!("Stopping");
114                                stop.store(true, Ordering::Relaxed);
115                            }
116                            ctrl_data = req.recv_all().unwrap();
117                            println!("Control data: {ctrl_data:x?}");
118                        }
119                        Event::SetupDeviceToHost(req) => {
120                            println!("Replying with data");
121                            req.send(&ctrl_data).unwrap();
122                        }
123                        _ => (),
124                    }
125                } else {
126                    println!("no event");
127                }
128            }
129        });
130    });
131
132    thread::sleep(Duration::from_secs(1));
133
134    println!("Unregistering");
135    reg.remove().unwrap();
136}
Source

pub fn existing(self, ffs_dir: impl AsRef<Path>) -> Result<Custom>

Use the specified pre-mounted FunctionFS directory.

Descriptors and strings are written into the ep0 device file.

This allows usage of the custom interface functionality when the USB gadget has been registered externally.

Examples found in repository?
examples/custom_interface_device_split.rs (line 51)
25fn main() {
26    env_logger::init();
27
28    let existing = std::env::var("EXISTING_FFS").ok();
29    let register_only = std::env::var("REGISTER_ONLY").ok().is_some();
30
31    let (ep1_rx, ep1_dir) = EndpointDirection::host_to_device();
32    let (ep2_tx, ep2_dir) = EndpointDirection::device_to_host();
33
34    let mut builder = Custom::builder();
35
36    if register_only {
37        // We are only registering and binding the gadget, and leaving the FunctionFS interactions
38        // to another process.
39        builder.ffs_no_init = true;
40        builder.ffs_uid = Some(std::env::var("SUDO_UID").unwrap().parse().unwrap());
41        builder.ffs_gid = Some(std::env::var("SUDO_GID").unwrap().parse().unwrap());
42    } else {
43        builder = builder.with_interface(
44            Interface::new(Class::vendor_specific(1, 2), "custom interface")
45                .with_endpoint(Endpoint::bulk(ep1_dir))
46                .with_endpoint(Endpoint::bulk(ep2_dir)),
47        );
48    }
49
50    let (reg, custom) = if let Some(ref path) = existing {
51        (None, builder.existing(path).unwrap())
52    } else {
53        let (mut custom, handle) = builder.build();
54
55        usb_gadget::remove_all().expect("cannot remove all gadgets");
56
57        let udc = default_udc().expect("cannot get UDC");
58        let gadget = Gadget::new(
59            Class::vendor_specific(255, 3),
60            Id::new(6, 0x11),
61            Strings::new("manufacturer", "custom USB interface", "serial_number"),
62        )
63        .with_config(Config::new("config").with_function(handle))
64        .with_os_descriptor(OsDescriptor::microsoft())
65        .with_web_usb(WebUsb::new(0xf1, "http://webusb.org"));
66
67        let reg = gadget.register().expect("cannot register gadget");
68
69        if register_only {
70            let ffs_dir = custom.ffs_dir().unwrap();
71            println!("FunctionFS dir mounted at {}", ffs_dir.display());
72            println!("You can now run this program again as unprivileged user:");
73            println!("EXISTING_FFS={} {}", ffs_dir.display(), std::env::args().next().unwrap());
74
75            let mut ep1_path = ffs_dir.clone();
76            ep1_path.push("ep1");
77            while std::fs::metadata(&ep1_path).is_err() {
78                thread::sleep(Duration::from_secs(1));
79            }
80
81            println!("Detected ep1 in FunctionFS dir, this means descriptors have been written to ep0.");
82            println!("Now binding gadget to UDC (making it active)...");
83        }
84
85        reg.bind(Some(&udc)).expect("cannot bind to UDC");
86
87        println!("Custom function at {}", custom.status().unwrap().path().unwrap().display());
88        println!();
89
90        (Some(reg), custom)
91    };
92
93    if register_only {
94        println!("Waiting for the gadget to become unbound. If you stop the other process, this will happen automatically.");
95        while reg.as_ref().unwrap().udc().unwrap().is_some() {
96            thread::sleep(Duration::from_secs(1));
97        }
98    } else {
99        if existing.is_some() {
100            println!("The FunctionFS setup is done, you can type 'yes' in the other process and hit <ENTER>");
101        }
102        run(ep1_rx, ep2_tx, custom);
103    }
104
105    if let Some(reg) = reg {
106        println!("Unregistering");
107        reg.remove().unwrap();
108    }
109}
Source

pub fn with_interface(self, interface: Interface) -> Self

Add an USB interface.

Examples found in repository?
examples/custom_interface_device_split.rs (lines 43-47)
25fn main() {
26    env_logger::init();
27
28    let existing = std::env::var("EXISTING_FFS").ok();
29    let register_only = std::env::var("REGISTER_ONLY").ok().is_some();
30
31    let (ep1_rx, ep1_dir) = EndpointDirection::host_to_device();
32    let (ep2_tx, ep2_dir) = EndpointDirection::device_to_host();
33
34    let mut builder = Custom::builder();
35
36    if register_only {
37        // We are only registering and binding the gadget, and leaving the FunctionFS interactions
38        // to another process.
39        builder.ffs_no_init = true;
40        builder.ffs_uid = Some(std::env::var("SUDO_UID").unwrap().parse().unwrap());
41        builder.ffs_gid = Some(std::env::var("SUDO_GID").unwrap().parse().unwrap());
42    } else {
43        builder = builder.with_interface(
44            Interface::new(Class::vendor_specific(1, 2), "custom interface")
45                .with_endpoint(Endpoint::bulk(ep1_dir))
46                .with_endpoint(Endpoint::bulk(ep2_dir)),
47        );
48    }
49
50    let (reg, custom) = if let Some(ref path) = existing {
51        (None, builder.existing(path).unwrap())
52    } else {
53        let (mut custom, handle) = builder.build();
54
55        usb_gadget::remove_all().expect("cannot remove all gadgets");
56
57        let udc = default_udc().expect("cannot get UDC");
58        let gadget = Gadget::new(
59            Class::vendor_specific(255, 3),
60            Id::new(6, 0x11),
61            Strings::new("manufacturer", "custom USB interface", "serial_number"),
62        )
63        .with_config(Config::new("config").with_function(handle))
64        .with_os_descriptor(OsDescriptor::microsoft())
65        .with_web_usb(WebUsb::new(0xf1, "http://webusb.org"));
66
67        let reg = gadget.register().expect("cannot register gadget");
68
69        if register_only {
70            let ffs_dir = custom.ffs_dir().unwrap();
71            println!("FunctionFS dir mounted at {}", ffs_dir.display());
72            println!("You can now run this program again as unprivileged user:");
73            println!("EXISTING_FFS={} {}", ffs_dir.display(), std::env::args().next().unwrap());
74
75            let mut ep1_path = ffs_dir.clone();
76            ep1_path.push("ep1");
77            while std::fs::metadata(&ep1_path).is_err() {
78                thread::sleep(Duration::from_secs(1));
79            }
80
81            println!("Detected ep1 in FunctionFS dir, this means descriptors have been written to ep0.");
82            println!("Now binding gadget to UDC (making it active)...");
83        }
84
85        reg.bind(Some(&udc)).expect("cannot bind to UDC");
86
87        println!("Custom function at {}", custom.status().unwrap().path().unwrap().display());
88        println!();
89
90        (Some(reg), custom)
91    };
92
93    if register_only {
94        println!("Waiting for the gadget to become unbound. If you stop the other process, this will happen automatically.");
95        while reg.as_ref().unwrap().udc().unwrap().is_some() {
96            thread::sleep(Duration::from_secs(1));
97        }
98    } else {
99        if existing.is_some() {
100            println!("The FunctionFS setup is done, you can type 'yes' in the other process and hit <ENTER>");
101        }
102        run(ep1_rx, ep2_tx, custom);
103    }
104
105    if let Some(reg) = reg {
106        println!("Unregistering");
107        reg.remove().unwrap();
108    }
109}
More examples
Hide additional examples
examples/custom_interface_device_async.rs (lines 28-32)
19async fn main() {
20    env_logger::init();
21
22    usb_gadget::remove_all().expect("cannot remove all gadgets");
23
24    let (mut ep1_rx, ep1_dir) = EndpointDirection::host_to_device();
25    let (mut ep2_tx, ep2_dir) = EndpointDirection::device_to_host();
26
27    let (mut custom, handle) = Custom::builder()
28        .with_interface(
29            Interface::new(Class::vendor_specific(1, 2), "custom interface")
30                .with_endpoint(Endpoint::bulk(ep1_dir))
31                .with_endpoint(Endpoint::bulk(ep2_dir)),
32        )
33        .build();
34
35    let udc = default_udc().expect("cannot get UDC");
36    let reg = Gadget::new(
37        Class::vendor_specific(255, 3),
38        Id::new(6, 0x11),
39        Strings::new("manufacturer", "custom USB interface", "serial_number"),
40    )
41    .with_config(Config::new("config").with_function(handle))
42    .with_os_descriptor(OsDescriptor::microsoft())
43    .with_web_usb(WebUsb::new(0xf1, "http://webusb.org"))
44    .bind(&udc)
45    .expect("cannot bind to UDC");
46
47    println!("Custom function at {}", custom.status().unwrap().path().unwrap().display());
48    println!();
49
50    let ep1_control = ep1_rx.control().unwrap();
51    println!("ep1 unclaimed: {:?}", ep1_control.unclaimed_fifo());
52    println!("ep1 real address: {}", ep1_control.real_address().unwrap());
53    println!("ep1 descriptor: {:?}", ep1_control.descriptor().unwrap());
54    println!();
55
56    let ep2_control = ep2_tx.control().unwrap();
57    println!("ep2 unclaimed: {:?}", ep2_control.unclaimed_fifo());
58    println!("ep2 real address: {}", ep2_control.real_address().unwrap());
59    println!("ep2 descriptor: {:?}", ep2_control.descriptor().unwrap());
60    println!();
61
62    let stop = Arc::new(AtomicBool::new(false));
63
64    let stop1 = stop.clone();
65    tokio::spawn(async move {
66        let size = ep1_rx.max_packet_size().unwrap();
67        let mut b = 0;
68        while !stop1.load(Ordering::Relaxed) {
69            let data = ep1_rx.recv_async(BytesMut::with_capacity(size)).await.expect("recv_async failed");
70            match data {
71                Some(data) => {
72                    println!("received {} bytes: {data:x?}", data.len());
73                    if !data.iter().all(|x| *x == b) {
74                        panic!("wrong data received");
75                    }
76                    b = b.wrapping_add(1);
77                }
78                None => {
79                    println!("receive empty");
80                }
81            }
82        }
83    });
84
85    let stop2 = stop.clone();
86    tokio::spawn(async move {
87        let size = ep2_tx.max_packet_size().unwrap();
88        let mut b = 0u8;
89        while !stop2.load(Ordering::Relaxed) {
90            let data = vec![b; size];
91            match ep2_tx.send_async(data.into()).await {
92                Ok(()) => {
93                    println!("sent data {b} of size {size} bytes");
94                    b = b.wrapping_add(1);
95                }
96                Err(err) => panic!("send failed: {err}"),
97            }
98        }
99    });
100
101    let mut ctrl_data = Vec::new();
102    while !stop.load(Ordering::Relaxed) {
103        custom.wait_event().await.expect("wait for event failed");
104        println!("event ready");
105        let event = custom.event().expect("event failed");
106
107        println!("Event: {event:?}");
108        match event {
109            Event::SetupHostToDevice(req) => {
110                if req.ctrl_req().request == 255 {
111                    println!("Stopping");
112                    stop.store(true, Ordering::Relaxed);
113                }
114                ctrl_data = req.recv_all().unwrap();
115                println!("Control data: {ctrl_data:x?}");
116            }
117            Event::SetupDeviceToHost(req) => {
118                println!("Replying with data");
119                req.send(&ctrl_data).unwrap();
120            }
121            _ => (),
122        }
123    }
124
125    tokio::time::sleep(Duration::from_secs(1)).await;
126
127    println!("Unregistering");
128    reg.remove().unwrap();
129}
examples/custom_interface_device.rs (lines 29-33)
20fn main() {
21    env_logger::init();
22
23    usb_gadget::remove_all().expect("cannot remove all gadgets");
24
25    let (mut ep1_rx, ep1_dir) = EndpointDirection::host_to_device();
26    let (mut ep2_tx, ep2_dir) = EndpointDirection::device_to_host();
27
28    let (mut custom, handle) = Custom::builder()
29        .with_interface(
30            Interface::new(Class::vendor_specific(1, 2), "custom interface")
31                .with_endpoint(Endpoint::bulk(ep1_dir))
32                .with_endpoint(Endpoint::bulk(ep2_dir)),
33        )
34        .build();
35
36    let udc = default_udc().expect("cannot get UDC");
37    let reg = Gadget::new(
38        Class::vendor_specific(255, 3),
39        Id::new(6, 0x11),
40        Strings::new("manufacturer", "custom USB interface", "serial_number"),
41    )
42    .with_config(Config::new("config").with_function(handle))
43    .with_os_descriptor(OsDescriptor::microsoft())
44    .with_web_usb(WebUsb::new(0xf1, "http://webusb.org"))
45    .bind(&udc)
46    .expect("cannot bind to UDC");
47
48    println!("Custom function at {}", custom.status().unwrap().path().unwrap().display());
49    println!();
50
51    let ep1_control = ep1_rx.control().unwrap();
52    println!("ep1 unclaimed: {:?}", ep1_control.unclaimed_fifo());
53    println!("ep1 real address: {}", ep1_control.real_address().unwrap());
54    println!("ep1 descriptor: {:?}", ep1_control.descriptor().unwrap());
55    println!();
56
57    let ep2_control = ep2_tx.control().unwrap();
58    println!("ep2 unclaimed: {:?}", ep2_control.unclaimed_fifo());
59    println!("ep2 real address: {}", ep2_control.real_address().unwrap());
60    println!("ep2 descriptor: {:?}", ep2_control.descriptor().unwrap());
61    println!();
62
63    let stop = Arc::new(AtomicBool::new(false));
64
65    thread::scope(|s| {
66        s.spawn(|| {
67            let size = ep1_rx.max_packet_size().unwrap();
68            let mut b = 0;
69            while !stop.load(Ordering::Relaxed) {
70                let data = ep1_rx
71                    .recv_timeout(BytesMut::with_capacity(size), Duration::from_secs(1))
72                    .expect("recv failed");
73                match data {
74                    Some(data) => {
75                        println!("received {} bytes: {data:x?}", data.len());
76                        if !data.iter().all(|x| *x == b) {
77                            panic!("wrong data received");
78                        }
79                        b = b.wrapping_add(1);
80                    }
81                    None => {
82                        println!("receive empty");
83                    }
84                }
85            }
86        });
87
88        s.spawn(|| {
89            let size = ep2_tx.max_packet_size().unwrap();
90            let mut b = 0u8;
91            while !stop.load(Ordering::Relaxed) {
92                let data = vec![b; size];
93                match ep2_tx.send_timeout(data.into(), Duration::from_secs(1)) {
94                    Ok(()) => {
95                        println!("sent data {b} of size {size} bytes");
96                        b = b.wrapping_add(1);
97                    }
98                    Err(err) if err.kind() == ErrorKind::TimedOut => println!("send timeout"),
99                    Err(err) => panic!("send failed: {err}"),
100                }
101            }
102        });
103
104        s.spawn(|| {
105            let mut ctrl_data = Vec::new();
106
107            while !stop.load(Ordering::Relaxed) {
108                if let Some(event) = custom.event_timeout(Duration::from_secs(1)).expect("event failed") {
109                    println!("Event: {event:?}");
110                    match event {
111                        Event::SetupHostToDevice(req) => {
112                            if req.ctrl_req().request == 255 {
113                                println!("Stopping");
114                                stop.store(true, Ordering::Relaxed);
115                            }
116                            ctrl_data = req.recv_all().unwrap();
117                            println!("Control data: {ctrl_data:x?}");
118                        }
119                        Event::SetupDeviceToHost(req) => {
120                            println!("Replying with data");
121                            req.send(&ctrl_data).unwrap();
122                        }
123                        _ => (),
124                    }
125                } else {
126                    println!("no event");
127                }
128            }
129        });
130    });
131
132    thread::sleep(Duration::from_secs(1));
133
134    println!("Unregistering");
135    reg.remove().unwrap();
136}
Source

pub fn ffs_descriptors_and_strings(&self) -> Result<(Vec<u8>, Vec<u8>)>

Gets the descriptor and string data for writing into ep0 of FunctionFS.

Normally, this is done automatically when the custom function is registered. This function is only useful when descriptors and strings should be written to ep0 by other means.

Trait Implementations§

Source§

impl Debug for CustomBuilder

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.