From 88d1976e812af995028025407872bf64264c4f94 Mon Sep 17 00:00:00 2001 From: maximedeboeck <119764381+maximedeboeck@users.noreply.github.com> Date: Sun, 16 Jul 2023 12:31:56 +0200 Subject: Added usb-hid keyboard example for rp pico. --- examples/rp/Cargo.toml | 1 + examples/rp/src/bin/usb_hid_keyboard.rs | 188 ++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 examples/rp/src/bin/usb_hid_keyboard.rs (limited to 'examples') diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 7c5a9dfbc..c812cb3ee 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -40,6 +40,7 @@ display-interface = "0.4.1" byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.3.0" heapless = "0.7.15" +usbd-hid = "0.6.1" embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } embedded-hal-async = "0.2.0-alpha.2" diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs new file mode 100644 index 000000000..99af1f02f --- /dev/null +++ b/examples/rp/src/bin/usb_hid_keyboard.rs @@ -0,0 +1,188 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use core::sync::atomic::{AtomicBool, Ordering}; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_rp::bind_interrupts; +use embassy_rp::gpio::{Input, Pull}; +use embassy_rp::peripherals::USB; +use embassy_rp::usb::{Driver, InterruptHandler}; +use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; +use embassy_usb::control::OutResponse; +use embassy_usb::{Builder, Config, Handler}; +use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + // Create the driver, from the HAL. + let driver = Driver::new(p.USB, Irqs); + + // Create embassy-usb Config + let mut config = Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("HID keyboard example"); + config.serial_number = Some("12345678"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + // You can also add a Microsoft OS descriptor. + // let mut msos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + let request_handler = MyRequestHandler {}; + let mut device_handler = MyDeviceHandler::new(); + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + // &mut msos_descriptor, + &mut control_buf, + ); + + builder.handler(&mut device_handler); + + // Create classes on the builder. + let config = embassy_usb::class::hid::Config { + report_descriptor: KeyboardReport::desc(), + request_handler: Some(&request_handler), + poll_ms: 60, + max_packet_size: 64, + }; + let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Set up the signal pin that will be used to trigger the keyboard. + let mut signal_pin = Input::new(p.PIN_16, Pull::None); + + let (reader, mut writer) = hid.split(); + + // Do stuff with the class! + let in_fut = async { + loop { + info!("Waiting for HIGH on pin 16"); + signal_pin.wait_for_high().await; + info!("HIGH DETECTED"); + // Create a report with the A key pressed. (no shift modifier) + let report = KeyboardReport { + keycodes: [4, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + // Send the report. + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + signal_pin.wait_for_low().await; + info!("LOW DETECTED"); + let report = KeyboardReport { + keycodes: [0, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } + }; + + let out_fut = async { + reader.run(false, &request_handler).await; + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, join(in_fut, out_fut)).await; +} + +struct MyRequestHandler {} + +impl RequestHandler for MyRequestHandler { + fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + info!("Get report for {:?}", id); + None + } + + fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + info!("Set report for {:?}: {=[u8]}", id, data); + OutResponse::Accepted + } + + fn set_idle_ms(&self, id: Option, dur: u32) { + info!("Set idle rate for {:?} to {:?}", id, dur); + } + + fn get_idle_ms(&self, id: Option) -> Option { + info!("Get idle rate for {:?}", id); + None + } +} + +struct MyDeviceHandler { + configured: AtomicBool, +} + +impl MyDeviceHandler { + fn new() -> Self { + MyDeviceHandler { + configured: AtomicBool::new(false), + } + } +} + +impl Handler for MyDeviceHandler { + fn enabled(&mut self, enabled: bool) { + self.configured.store(false, Ordering::Relaxed); + if enabled { + info!("Device enabled"); + } else { + info!("Device disabled"); + } + } + + fn reset(&mut self) { + self.configured.store(false, Ordering::Relaxed); + info!("Bus reset, the Vbus current limit is 100mA"); + } + + fn addressed(&mut self, addr: u8) { + self.configured.store(false, Ordering::Relaxed); + info!("USB address set to: {}", addr); + } + + fn configured(&mut self, configured: bool) { + self.configured.store(configured, Ordering::Relaxed); + if configured { + info!("Device configured, it may now draw up to the configured current limit from Vbus.") + } else { + info!("Device is no longer configured, the Vbus current limit is 100mA."); + } + } +} -- cgit From e95a7dc555f367534d3b8bc7a9b6f2d361b0d951 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 16 Jul 2023 12:41:57 -0500 Subject: wpan/mac: use slice view to avoid copy --- examples/stm32wb/src/bin/mac_ffd.rs | 5 ++++- examples/stm32wb/src/bin/mac_rfd.rs | 35 +++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 17 deletions(-) (limited to 'examples') diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs index e4d81997e..f8c8ba288 100644 --- a/examples/stm32wb/src/bin/mac_ffd.rs +++ b/examples/stm32wb/src/bin/mac_ffd.rs @@ -67,7 +67,10 @@ async fn main(spawner: Spawner) { info!("resetting"); mbox.mac_subsystem - .send_command(&ResetRequest { set_default_pib: true }) + .send_command(&ResetRequest { + set_default_pib: true, + ..Default::default() + }) .await .unwrap(); let evt = mbox.mac_subsystem.read().await; diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs index b2dac72cc..b0eb91061 100644 --- a/examples/stm32wb/src/bin/mac_rfd.rs +++ b/examples/stm32wb/src/bin/mac_rfd.rs @@ -69,7 +69,10 @@ async fn main(spawner: Spawner) { info!("resetting"); mbox.mac_subsystem - .send_command(&ResetRequest { set_default_pib: true }) + .send_command(&ResetRequest { + set_default_pib: true, + ..Default::default() + }) .await .unwrap(); let evt = mbox.mac_subsystem.read().await; @@ -91,6 +94,7 @@ async fn main(spawner: Spawner) { mbox.mac_subsystem .send_command(&GetRequest { pib_attribute: PibId::ExtendedAddress, + ..Default::default() }) .await .unwrap(); @@ -141,23 +145,22 @@ async fn main(spawner: Spawner) { info!("{:#x}", evt); info!("sending data"); - let mut data_buffer = [0u8; 256]; let data = b"Hello from embassy!"; - data_buffer[..data.len()].copy_from_slice(data); mbox.mac_subsystem - .send_command(&DataRequest { - src_addr_mode: AddressMode::Short, - dst_addr_mode: AddressMode::Short, - dst_pan_id: PanId([0x1A, 0xAA]), - dst_address: MacAddress::BROADCAST, - msdu_handle: 0x02, - ack_tx: 0x00, - gts_tx: false, - msdu_ptr: &data_buffer as *const _ as *const u8, - msdu_length: data.len() as u8, - security_level: SecurityLevel::Unsecure, - ..Default::default() - }) + .send_command( + DataRequest { + src_addr_mode: AddressMode::Short, + dst_addr_mode: AddressMode::Short, + dst_pan_id: PanId([0x1A, 0xAA]), + dst_address: MacAddress::BROADCAST, + msdu_handle: 0x02, + ack_tx: 0x00, + gts_tx: false, + security_level: SecurityLevel::Unsecure, + ..Default::default() + } + .set_buffer(data), + ) .await .unwrap(); let evt = mbox.mac_subsystem.read().await; -- cgit From 28b419d65ede6ff29c79dbcaa27145f1c3458a57 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 16 Jul 2023 15:09:30 -0500 Subject: wpan/mac: use lifetimes to control events --- examples/stm32wb/src/bin/mac_ffd.rs | 46 ++++++++++++++++++++----------- examples/stm32wb/src/bin/mac_rfd.rs | 55 +++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 37 deletions(-) (limited to 'examples') diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs index f8c8ba288..86413ea0f 100644 --- a/examples/stm32wb/src/bin/mac_ffd.rs +++ b/examples/stm32wb/src/bin/mac_ffd.rs @@ -73,8 +73,10 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } info!("setting extended address"); let extended_address: u64 = 0xACDE480000000001; @@ -85,8 +87,10 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } info!("setting short address"); let short_address: u16 = 0x1122; @@ -97,8 +101,10 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } info!("setting association permit"); let association_permit: bool = true; @@ -109,8 +115,10 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } info!("setting TX power"); let transmit_power: i8 = 2; @@ -121,8 +129,10 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } info!("starting FFD device"); mbox.mac_subsystem @@ -137,8 +147,10 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } info!("setting RX on when idle"); let rx_on_while_idle: bool = true; @@ -149,14 +161,16 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } loop { let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt); + defmt::info!("{:#x}", evt.mac_event()); - if let Ok(evt) = evt { + if let Ok(evt) = evt.mac_event() { match evt { MacEvent::MlmeAssociateInd(association) => mbox .mac_subsystem diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs index b0eb91061..7cb401d89 100644 --- a/examples/stm32wb/src/bin/mac_rfd.rs +++ b/examples/stm32wb/src/bin/mac_rfd.rs @@ -75,8 +75,10 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } info!("setting extended address"); let extended_address: u64 = 0xACDE480000000002; @@ -87,8 +89,10 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + defmt::info!("{:#x}", evt.mac_event()); + } info!("getting extended address"); mbox.mac_subsystem @@ -98,14 +102,17 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt); - if let Ok(MacEvent::MlmeGetCnf(evt)) = evt { - if evt.pib_attribute_value_len == 8 { - let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) }; + { + let evt = mbox.mac_subsystem.read().await; + info!("{:#x}", evt.mac_event()); + + if let Ok(MacEvent::MlmeGetCnf(evt)) = evt.mac_event() { + if evt.pib_attribute_value_len == 8 { + let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) }; - info!("value {:#x}", value) + info!("value {:#x}", value) + } } } @@ -124,13 +131,15 @@ async fn main(spawner: Spawner) { }; info!("{}", a); mbox.mac_subsystem.send_command(&a).await.unwrap(); - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt); + let short_addr = { + let evt = mbox.mac_subsystem.read().await; + info!("{:#x}", evt.mac_event()); - let short_addr = if let Ok(MacEvent::MlmeAssociateCnf(conf)) = evt { - conf.assoc_short_address - } else { - defmt::panic!() + if let Ok(MacEvent::MlmeAssociateCnf(conf)) = evt.mac_event() { + conf.assoc_short_address + } else { + defmt::panic!() + } }; info!("setting short address"); @@ -141,8 +150,10 @@ async fn main(spawner: Spawner) { }) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + info!("{:#x}", evt.mac_event()); + } info!("sending data"); let data = b"Hello from embassy!"; @@ -163,11 +174,13 @@ async fn main(spawner: Spawner) { ) .await .unwrap(); - let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt); + { + let evt = mbox.mac_subsystem.read().await; + info!("{:#x}", evt.mac_event()); + } loop { let evt = mbox.mac_subsystem.read().await; - info!("{:#x}", evt); + info!("{:#x}", evt.mac_event()); } } -- cgit From 34217ea797c6bbea6219bb2bc2b611a99212e14b Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 16 Jul 2023 17:28:34 -0500 Subject: wpan: add slice data view --- examples/stm32wb/src/bin/mac_ffd.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs index 86413ea0f..bc71e29aa 100644 --- a/examples/stm32wb/src/bin/mac_ffd.rs +++ b/examples/stm32wb/src/bin/mac_ffd.rs @@ -168,9 +168,10 @@ async fn main(spawner: Spawner) { loop { let evt = mbox.mac_subsystem.read().await; - defmt::info!("{:#x}", evt.mac_event()); - if let Ok(evt) = evt.mac_event() { + defmt::info!("parsed mac event"); + defmt::info!("{:#x}", evt); + match evt { MacEvent::MlmeAssociateInd(association) => mbox .mac_subsystem @@ -184,17 +185,22 @@ async fn main(spawner: Spawner) { .await .unwrap(), MacEvent::McpsDataInd(data_ind) => { - let data_addr = data_ind.msdu_ptr; - let mut data = [0u8; 256]; - unsafe { data_addr.copy_to(&mut data as *mut _, data_ind.msdu_length as usize) } - info!("{}", data[..data_ind.msdu_length as usize]); + let payload = data_ind.payload(); + let ref_payload = b"Hello from embassy!"; + info!("{}", payload); - if &data[..data_ind.msdu_length as usize] == b"Hello from embassy!" { + if payload == ref_payload { info!("success"); + } else { + info!("ref payload: {}", ref_payload); } } - _ => {} + _ => { + defmt::info!("other mac event"); + } } + } else { + defmt::info!("failed to parse mac event"); } } } -- cgit