diff --git a/rp2040/Cargo.toml b/rp2040/Cargo.toml index e4205ec..fe65580 100644 --- a/rp2040/Cargo.toml +++ b/rp2040/Cargo.toml @@ -17,6 +17,10 @@ fugit = "0.3.5" nb = "1.0.0" smart-leds = "0.3.0" ws2812-pio = "0.6.0" +usbd-human-interface-device = "0.4.2" +usb-device = "0.2" +packed_struct = { version = "0.10", default-features = false } +keypad = "0.2.2" [features] # This is the set of features we enable by default diff --git a/rp2040/src/main.rs b/rp2040/src/main.rs index b505f00..c864a92 100644 --- a/rp2040/src/main.rs +++ b/rp2040/src/main.rs @@ -1,15 +1,16 @@ -//! Rainbow effect color wheel using the onboard NeoPixel on an Waveshare RP2040 Zero board -//! -//! This flows smoothly through various colors on the onboard NeoPixel. -//! Uses the `ws2812_pio` driver to control the NeoPixel, which in turns uses the -//! RP2040's PIO block. #![no_std] #![no_main] +use core::convert::Infallible; use embedded_hal::timer::CountDown; +use embedded_hal::digital::v2::*; use fugit::ExtU32; use panic_halt as _; use smart_leds::{SmartLedsWrite, RGB8}; +use usb_device::class_prelude::*; +use usb_device::prelude::*; +use usbd_human_interface_device::page::Keyboard; +use usbd_human_interface_device::prelude::*; use waveshare_rp2040_zero::entry; use waveshare_rp2040_zero::{ hal::{ @@ -24,6 +25,7 @@ use waveshare_rp2040_zero::{ }; use ws2812_pio::Ws2812; + #[entry] fn main() -> ! { let mut pac = pac::Peripherals::take().unwrap(); @@ -50,8 +52,27 @@ fn main() -> ! { &mut pac.RESETS, ); + let usb_bus = UsbBusAllocator::new(waveshare_rp2040_zero::hal::usb::UsbBus::new( + pac.USBCTRL_REGS, + pac.USBCTRL_DPRAM, + clocks.usb_clock, + true, + &mut pac.RESETS, + )); + + let mut keyboard = UsbHidClassBuilder::new() + .add_device( + usbd_human_interface_device::device::keyboard::NKROBootKeyboardConfig::default(), + ) + .build(&usb_bus); + + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x1209, 0x0001)) + .manufacturer("usbd-human-interface-device") + .product("CMDR keyboard") + .serial_number("0001") + .build(); + let timer = Timer::new(pac.TIMER, &mut pac.RESETS); - let mut delay = timer.count_down(); // Configure the addressable LED let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); @@ -63,14 +84,146 @@ fn main() -> ! { clocks.peripheral_clock.freq(), timer.count_down(), ); + + let keys: &[&dyn InputPin] = &[ + &pins.gp0.into_pull_up_input(), + &pins.gp1.into_pull_up_input(), + &pins.gp2.into_pull_up_input(), + &pins.gp3.into_pull_up_input(), + &pins.gp4.into_readable_output(), + &pins.gp5.into_readable_output(), + &pins.gp6.into_readable_output(), + &pins.gp7.into_readable_output(), + &pins.gp8.into_readable_output(), + &pins.gp9.into_readable_output(), + &pins.gp10.into_readable_output(), + &pins.gp11.into_readable_output(), + &pins.gp12.into_readable_output(), + &pins.gp13.into_readable_output(), + &pins.gp14.into_readable_output(), + ]; + + let mut input_count_down = timer.count_down(); + input_count_down.start(10.millis()); + + let mut tick_count_down = timer.count_down(); + tick_count_down.start(1.millis()); + + let color_purple: RGB8 = (0, 10, 10).into(); + let color_red: RGB8 = (0, 10, 0).into(); + let color_green: RGB8 = (10, 0, 0).into(); + let color_blue: RGB8 = (0, 0, 10).into(); + let color_none: RGB8 = (0, 0, 0).into(); // Infinite colour wheel loop loop { - let color_green : RGB8 = (0, 10, 10).into(); - ws.write([color_green].iter().copied()).unwrap(); + // ws.write([color_purple].iter().copied()).unwrap(); - delay.start(25.millis()); - let _ = nb::block!(delay.wait()); + if input_count_down.wait().is_ok() { + let keys = get_keys(keys); + + match keyboard.device().write_report(keys) { + Err(UsbHidError::WouldBlock) => {} + Err(UsbHidError::Duplicate) => {} + Ok(_) => {} + Err(e) => { + core::panic!("Failed to write keyboard report: {:?}", e) + } + }; + } + + //Tick once per ms + if tick_count_down.wait().is_ok() { + match keyboard.tick() { + Err(UsbHidError::WouldBlock) => {} + Ok(_) => {} + Err(e) => { + core::panic!("Failed to process keyboard tick: {:?}", e) + } + }; + } + + if usb_dev.poll(&mut [&mut keyboard]) { + match keyboard.device().read_report() { + Err(UsbError::WouldBlock) => { + //do nothing + } + Err(e) => { + core::panic!("Failed to read keyboard report: {:?}", e) + } + Ok(leds) => { + if leds.caps_lock == true { + ws.write([color_red].iter().copied()).unwrap(); + } else { + ws.write([color_none].iter().copied()).unwrap(); + } + } + } + } } } +fn get_keys(keys: &[&dyn InputPin]) -> [Keyboard; 12] { + [ + if keys[0].is_low().unwrap() { + Keyboard::KeypadNumLockAndClear + } else { + Keyboard::NoEventIndicated + }, //Numlock + if keys[1].is_low().unwrap() { + Keyboard::UpArrow + } else { + Keyboard::NoEventIndicated + }, //Up + if keys[2].is_low().unwrap() { + Keyboard::F12 + } else { + Keyboard::NoEventIndicated + }, //F12 + if keys[3].is_low().unwrap() { + Keyboard::LeftArrow + } else { + Keyboard::NoEventIndicated + }, //Left + if keys[4].is_low().unwrap() { + Keyboard::DownArrow + } else { + Keyboard::NoEventIndicated + }, //Down + if keys[5].is_low().unwrap() { + Keyboard::RightArrow + } else { + Keyboard::NoEventIndicated + }, //Right + if keys[6].is_low().unwrap() { + Keyboard::A + } else { + Keyboard::NoEventIndicated + }, //A + if keys[7].is_low().unwrap() { + Keyboard::B + } else { + Keyboard::NoEventIndicated + }, //B + if keys[8].is_low().unwrap() { + Keyboard::C + } else { + Keyboard::NoEventIndicated + }, //C + if keys[9].is_low().unwrap() { + Keyboard::LeftControl + } else { + Keyboard::NoEventIndicated + }, //LCtrl + if keys[10].is_low().unwrap() { + Keyboard::LeftShift + } else { + Keyboard::NoEventIndicated + }, //LShift + if keys[11].is_low().unwrap() { + Keyboard::ReturnEnter + } else { + Keyboard::NoEventIndicated + }, //Enter + ] +}