#![no_std] #![no_main] use core::sync::atomic::{AtomicBool, Ordering}; use defmt::{info, warn}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::{bind_interrupts, gpio::{Input, Level, Output, Pull}, peripherals::USB, usb::{Driver, InterruptHandler}}; use embassy_time::{Duration, Timer}; use embassy_usb::{Builder, Config, Handler, class::hid::{HidReaderWriter, ReportId, RequestHandler, State}, control::OutResponse}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; pub struct Debouncer<'a> { input: Input<'a>, debounce: Duration, } impl<'a> Debouncer<'a> { pub fn new(input: Input<'a>, debounce: Duration) -> Self { Self { input, debounce } } pub async fn debounce_low(&mut self) -> Level { loop { let l1 = self.input.get_level(); self.input.wait_for_low().await; Timer::after(self.debounce).await; let l2 = self.input.get_level(); if l1 != l2 { break l2; } } } pub async fn debounce_high(&mut self) -> Level { loop { let l1 = self.input.get_level(); self.input.wait_for_high().await; Timer::after(self.debounce).await; let l2 = self.input.get_level(); if l1 != l2 { break l2; } } } } bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; }); #[embassy_executor::main] async fn main(_spawner: Spawner) -> () { let p = embassy_rp::init(Default::default()); let driver = Driver::new(p.USB, Irqs); let mut config = Config::new(0x1234, 0xabcd); config.manufacturer = Some("Lukrecja"); config.product = Some("kb-prototype"); config.serial_number = Some("00000000"); config.composite_with_iads = false; config.device_class = 0x00; config.device_sub_class = 0x00; config.device_protocol = 0x00; let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut msos_descriptor = [0; 256]; let mut control_buf = [0; 64]; let mut request_handler = KbRequestHandler {}; let mut device_handler = KbDeviceHandler::new(); let mut state = State::new(); let mut builder = Builder::new( driver, config, &mut config_descriptor, &mut bos_descriptor, &mut msos_descriptor, &mut control_buf, ); builder.handler(&mut device_handler); let config = embassy_usb::class::hid::Config { report_descriptor: KeyboardReport::desc(), request_handler: None, poll_ms: 60, max_packet_size: 64, }; let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); let mut usb = builder.build(); let usb_fut = usb.run(); let mut led = Output::new(p.PIN_25, Level::Low); let mut switch_input = Debouncer::new(Input::new(p.PIN_0, Pull::Up), Duration::from_millis(20)); switch_input.input.set_schmitt(true); let (reader, mut writer) = hid.split(); let in_fut = async { loop { defmt::info!("waiting for low"); led.set_low(); switch_input.debounce_low().await; info!("got low"); led.set_high(); let report = KeyboardReport { keycodes: [4, 0, 0, 0, 0, 0], leds: 0, modifier: 0, reserved: 0, }; match writer.write_serialize(&report).await { Ok(()) => info!("report sent"), Err(e) => warn!("failed to send: {:?}", e), }; switch_input.debounce_high().await; info!("got high"); let report = KeyboardReport { keycodes: [0, 0, 0, 0, 0, 0], leds: 0, modifier: 0, reserved: 0, }; match writer.write_serialize(&report).await { Ok(()) => info!("report sent"), Err(e) => warn!("failed to send: {:?}", e), }; } }; let out_fut = async { reader.run(false, &mut request_handler).await; }; join(usb_fut, join(in_fut, out_fut)).await; } struct KbRequestHandler {} impl RequestHandler for KbRequestHandler { fn get_report(&mut self, _id: ReportId, _buf: &mut [u8]) -> Option { info!("get report"); None } fn set_report(&mut self, _id: ReportId, data: &[u8]) -> OutResponse { info!("set report: {=[u8]}", data); OutResponse::Accepted } fn set_idle_ms(&mut self, _id: Option, dur: u32) { info!("set idle rate to {}", dur); } fn get_idle_ms(&mut self, _id: Option) -> Option { info!("get idle rate"); None } } struct KbDeviceHandler { configured: AtomicBool, } impl KbDeviceHandler { fn new() -> Self { Self { configured: AtomicBool::new(false), } } } impl Handler for KbDeviceHandler { 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, 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") } else { info!("device no longer configured"); } } }