#[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
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.interfaces: Vec<Interface>USB interfaces.
all_ctrl_recipient: boolReceive control requests that are not explicitly directed to an interface or endpoint.
config0_setup: boolReceive 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: boolDo not disconnect USB gadget when interface files are closed.
ffs_no_init: boolDo not initialize FunctionFS.
No FunctionFS files are opened. This must then be done externally.
ffs_no_mount: boolDo not mount FunctionFS.
Implies ffs_no_init.
Implementations§
Source§impl CustomBuilder
impl CustomBuilder
Sourcepub fn build(self) -> (Custom, Handle)
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?
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
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}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}Sourcepub fn existing(self, ffs_dir: impl AsRef<Path>) -> Result<Custom>
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?
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}Sourcepub fn with_interface(self, interface: Interface) -> Self
pub fn with_interface(self, interface: Interface) -> Self
Add an USB interface.
Examples found in repository?
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
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}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}Sourcepub fn ffs_descriptors_and_strings(&self) -> Result<(Vec<u8>, Vec<u8>)>
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.