aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-02-20 00:05:41 +0000
committerGitHub <[email protected]>2024-02-20 00:05:41 +0000
commitce81bb5d533b8f5e2bc953959c95ce3a93350348 (patch)
tree71d8877eadc450af552c27b6906b57a39a262116 /examples
parent69bfcaad42e560b3d52c0e03a761dcedf34cc09f (diff)
parentbae30fb3973e0c35613422b1ecff299961b0dda4 (diff)
Merge pull request #2559 from mchant/main
added usb_hid_mouse example for rp
Diffstat (limited to 'examples')
-rw-r--r--examples/rp/src/bin/usb_hid_mouse.rs182
1 files changed, 182 insertions, 0 deletions
diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs
new file mode 100644
index 000000000..afebd8813
--- /dev/null
+++ b/examples/rp/src/bin/usb_hid_mouse.rs
@@ -0,0 +1,182 @@
1#![no_std]
2#![no_main]
3
4use core::sync::atomic::{AtomicBool, Ordering};
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_futures::join::join;
9use embassy_rp::bind_interrupts;
10use embassy_rp::clocks::RoscRng;
11use embassy_rp::gpio::{Input, Pull};
12use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, InterruptHandler};
14use embassy_time::Timer;
15use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
16use embassy_usb::control::OutResponse;
17use embassy_usb::{Builder, Config, Handler};
18use rand::Rng;
19use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(struct Irqs {
23 USBCTRL_IRQ => InterruptHandler<USB>;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let p = embassy_rp::init(Default::default());
29 // Create the driver, from the HAL.
30 let driver = Driver::new(p.USB, Irqs);
31
32 // Create embassy-usb Config
33 let mut config = Config::new(0xc0de, 0xcafe);
34 config.manufacturer = Some("Embassy");
35 config.product = Some("HID keyboard example");
36 config.serial_number = Some("12345678");
37 config.max_power = 100;
38 config.max_packet_size_0 = 64;
39
40 // Create embassy-usb DeviceBuilder using the driver and config.
41 // It needs some buffers for building the descriptors.
42 let mut device_descriptor = [0; 256];
43 let mut config_descriptor = [0; 256];
44 let mut bos_descriptor = [0; 256];
45 // You can also add a Microsoft OS descriptor.
46 let mut msos_descriptor = [0; 256];
47 let mut control_buf = [0; 64];
48 let request_handler = MyRequestHandler {};
49 let mut device_handler = MyDeviceHandler::new();
50
51 let mut state = State::new();
52
53 let mut builder = Builder::new(
54 driver,
55 config,
56 &mut device_descriptor,
57 &mut config_descriptor,
58 &mut bos_descriptor,
59 &mut msos_descriptor,
60 &mut control_buf,
61 );
62
63 builder.handler(&mut device_handler);
64
65 // Create classes on the builder.
66 let config = embassy_usb::class::hid::Config {
67 report_descriptor: MouseReport::desc(),
68 request_handler: Some(&request_handler),
69 poll_ms: 60,
70 max_packet_size: 64,
71 };
72 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
73
74 // Build the builder.
75 let mut usb = builder.build();
76
77 // Run the USB device.
78 let usb_fut = usb.run();
79
80 // Set up the signal pin that will be used to trigger the keyboard.
81 let mut signal_pin = Input::new(p.PIN_16, Pull::None);
82
83 // Enable the schmitt trigger to slightly debounce.
84 signal_pin.set_schmitt(true);
85
86 let (reader, mut writer) = hid.split();
87
88 // Do stuff with the class!
89 let in_fut = async {
90 let mut rng = RoscRng;
91
92 loop {
93 // every 1 second
94 _ = Timer::after_secs(1).await;
95 let report = MouseReport {
96 buttons: 0,
97 x: rng.gen_range(-100..100), // random small x movement
98 y: rng.gen_range(-100..100), // random small y movement
99 wheel: 0,
100 pan: 0,
101 };
102 // Send the report.
103 match writer.write_serialize(&report).await {
104 Ok(()) => {}
105 Err(e) => warn!("Failed to send report: {:?}", e),
106 }
107 }
108 };
109
110 let out_fut = async {
111 reader.run(false, &request_handler).await;
112 };
113
114 // Run everything concurrently.
115 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
116 join(usb_fut, join(in_fut, out_fut)).await;
117}
118
119struct MyRequestHandler {}
120
121impl RequestHandler for MyRequestHandler {
122 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
123 info!("Get report for {:?}", id);
124 None
125 }
126
127 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
128 info!("Set report for {:?}: {=[u8]}", id, data);
129 OutResponse::Accepted
130 }
131
132 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
133 info!("Set idle rate for {:?} to {:?}", id, dur);
134 }
135
136 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
137 info!("Get idle rate for {:?}", id);
138 None
139 }
140}
141
142struct MyDeviceHandler {
143 configured: AtomicBool,
144}
145
146impl MyDeviceHandler {
147 fn new() -> Self {
148 MyDeviceHandler {
149 configured: AtomicBool::new(false),
150 }
151 }
152}
153
154impl Handler for MyDeviceHandler {
155 fn enabled(&mut self, enabled: bool) {
156 self.configured.store(false, Ordering::Relaxed);
157 if enabled {
158 info!("Device enabled");
159 } else {
160 info!("Device disabled");
161 }
162 }
163
164 fn reset(&mut self) {
165 self.configured.store(false, Ordering::Relaxed);
166 info!("Bus reset, the Vbus current limit is 100mA");
167 }
168
169 fn addressed(&mut self, addr: u8) {
170 self.configured.store(false, Ordering::Relaxed);
171 info!("USB address set to: {}", addr);
172 }
173
174 fn configured(&mut self, configured: bool) {
175 self.configured.store(configured, Ordering::Relaxed);
176 if configured {
177 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
178 } else {
179 info!("Device is no longer configured, the Vbus current limit is 100mA.");
180 }
181 }
182}