aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorMick Chanthaseth <[email protected]>2024-02-11 16:04:06 -0800
committerGitHub <[email protected]>2024-02-11 16:04:06 -0800
commit58fa5e57b67935d2a81f4fd708d6829afb8112b0 (patch)
tree22aa12c90e42e14dbe9bc072c62f52d0bfa187b0 /examples
parentedb3989b577a15bed3d0434f25edc20b6f24bf52 (diff)
added usb_hid_mouse example for rp
Diffstat (limited to 'examples')
-rw-r--r--examples/rp/src/bin/usb_hid_mouse.rs183
1 files changed, 183 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..ec125a47e
--- /dev/null
+++ b/examples/rp/src/bin/usb_hid_mouse.rs
@@ -0,0 +1,183 @@
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_time::Timer;
14use embassy_rp::usb::{Driver, InterruptHandler};
15use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
16use embassy_usb::control::OutResponse;
17use embassy_usb::{Builder, Config, Handler};
18use rand::{Rng, RngCore};
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 match writer.write_serialize(&report).await{
103 Ok(())=>{},
104 Err(e)=>{
105 warn!("Failed to send report: {:?}", e);
106 },
107 }
108 }
109 };
110
111 let out_fut = async {
112 reader.run(false, &request_handler).await;
113 };
114
115 // Run everything concurrently.
116 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
117 join(usb_fut, join(in_fut, out_fut)).await;
118}
119
120struct MyRequestHandler {}
121
122impl RequestHandler for MyRequestHandler {
123 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
124 info!("Get report for {:?}", id);
125 None
126 }
127
128 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
129 info!("Set report for {:?}: {=[u8]}", id, data);
130 OutResponse::Accepted
131 }
132
133 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
134 info!("Set idle rate for {:?} to {:?}", id, dur);
135 }
136
137 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
138 info!("Get idle rate for {:?}", id);
139 None
140 }
141}
142
143struct MyDeviceHandler {
144 configured: AtomicBool,
145}
146
147impl MyDeviceHandler {
148 fn new() -> Self {
149 MyDeviceHandler {
150 configured: AtomicBool::new(false),
151 }
152 }
153}
154
155impl Handler for MyDeviceHandler {
156 fn enabled(&mut self, enabled: bool) {
157 self.configured.store(false, Ordering::Relaxed);
158 if enabled {
159 info!("Device enabled");
160 } else {
161 info!("Device disabled");
162 }
163 }
164
165 fn reset(&mut self) {
166 self.configured.store(false, Ordering::Relaxed);
167 info!("Bus reset, the Vbus current limit is 100mA");
168 }
169
170 fn addressed(&mut self, addr: u8) {
171 self.configured.store(false, Ordering::Relaxed);
172 info!("USB address set to: {}", addr);
173 }
174
175 fn configured(&mut self, configured: bool) {
176 self.configured.store(configured, Ordering::Relaxed);
177 if configured {
178 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
179 } else {
180 info!("Device is no longer configured, the Vbus current limit is 100mA.");
181 }
182 }
183}