#![no_std] #![no_main] use core::convert::Infallible; use cortex_m::delay::Delay; use embedded_hal::digital::v2::*; use embedded_hal::timer::CountDown; 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::{ clocks::{init_clocks_and_plls, Clock}, pac, pio::PIOExt, timer::Timer, watchdog::Watchdog, Sio, }, Pins, XOSC_CRYSTAL_FREQ, }; use ws2812_pio::Ws2812; pub const NUMBER_OF_KEYS: usize = 42; #[derive(Copy, Clone)] struct MatrixKey { current_state: bool, previous_state: bool, fn_mode: u8, } impl MatrixKey { fn default() -> Self { Self { current_state: false, previous_state: false, fn_mode: 0, } } } #[entry] fn main() -> ! { let mut pac = pac::Peripherals::take().unwrap(); let core = pac::CorePeripherals::take().unwrap(); let mut watchdog = Watchdog::new(pac.WATCHDOG); let clocks = init_clocks_and_plls( XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, pac.PLL_USB, &mut pac.RESETS, &mut watchdog, ) .ok() .unwrap(); let sio = Sio::new(pac.SIO); let pins = Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &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 = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); // Configure the status LED let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let mut status_led = Ws2812::new( pins.neopixel.into_mode(), &mut pio, sm0, clocks.peripheral_clock.freq(), timer.count_down(), ); let mut matrix_keys: [MatrixKey; NUMBER_OF_KEYS] = [MatrixKey::default(); NUMBER_OF_KEYS]; let matrix_rows: &[&dyn InputPin] = &[ &pins.gp0.into_pull_up_input(), &pins.gp1.into_pull_up_input(), &pins.gp29.into_pull_up_input(), &pins.gp28.into_pull_up_input(), ]; let matrix_cols: &mut [&mut dyn OutputPin] = &mut [ &mut pins.gp12.into_push_pull_output(), &mut pins.gp13.into_push_pull_output(), &mut pins.gp14.into_push_pull_output(), &mut pins.gp15.into_push_pull_output(), &mut pins.gp26.into_push_pull_output(), &mut pins.gp27.into_push_pull_output(), &mut pins.gp7.into_push_pull_output(), &mut pins.gp8.into_push_pull_output(), &mut pins.gp6.into_push_pull_output(), &mut pins.gp9.into_push_pull_output(), &mut pins.gp10.into_push_pull_output(), &mut pins.gp11.into_push_pull_output(), ]; // ------------------------------------- ------------------------------------- // | 0 | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 10 | 11 | // | 12 | 13 | 14 | 15 | 16 | 17 | | 18 | 19 | 20 | 21 | 22 | 23 | // | 24 | 25 | 26 | 27 | 28 | 29 | | 30 | 31 | 32 | 33 | 34 | 35 | // ------------------| 36 | 37 | 38 | | 39 | 40 | 41 |------------------ // ------------------- ------------------- // GRAVE = § // SEMICOLON = ö // APOSTROPHE = ä // LEFT_BRACE = å // FORWARDSLASH = - // NON_US_BACKSLASH = < // EQUAL = ´ // BACKSLASH = ' // RIGHT_BRACE = ^ // MINUS = + // LEFT_ALT = Alt // RIGHT_ALT = AltGr let layout: [[Keyboard; NUMBER_OF_KEYS]; 3] = [ [ // Function layer 0 Keyboard::Tab, Keyboard::Q, Keyboard::W, Keyboard::E, Keyboard::R, Keyboard::T, Keyboard::Y, Keyboard::U, Keyboard::I, Keyboard::O, Keyboard::P, Keyboard::LeftBrace, Keyboard::LeftControl, Keyboard::A, Keyboard::S, Keyboard::D, Keyboard::F, Keyboard::G, Keyboard::H, Keyboard::J, Keyboard::K, Keyboard::L, Keyboard::Semicolon, Keyboard::Apostrophe, Keyboard::LeftShift, Keyboard::Z, Keyboard::X, Keyboard::C, Keyboard::V, Keyboard::B, Keyboard::N, Keyboard::M, Keyboard::Comma, Keyboard::Dot, Keyboard::ForwardSlash, Keyboard::RightShift, Keyboard::LeftAlt, Keyboard::NoEventIndicated, Keyboard::Space, Keyboard::Space, Keyboard::NoEventIndicated, Keyboard::RightAlt, ], [ // Function layer 1 Keyboard::Escape, Keyboard::F1, Keyboard::F2, Keyboard::F3, Keyboard::F4, Keyboard::F5, Keyboard::F6, Keyboard::F7, Keyboard::F8, Keyboard::F9, Keyboard::F10, Keyboard::DeleteBackspace, Keyboard::LeftControl, Keyboard::Keyboard1, Keyboard::Keyboard2, Keyboard::Keyboard3, Keyboard::Keyboard4, Keyboard::Keyboard5, Keyboard::Keyboard6, Keyboard::Keyboard7, Keyboard::Keyboard8, Keyboard::Keyboard9, Keyboard::Keyboard0, Keyboard::ReturnEnter, Keyboard::LeftShift, Keyboard::Keyboard6, Keyboard::Keyboard7, Keyboard::Keyboard8, Keyboard::Keyboard9, Keyboard::Keyboard0, Keyboard::NonUSBackslash, Keyboard::Equal, Keyboard::Backslash, Keyboard::RightBrace, Keyboard::Minus, Keyboard::RightShift, Keyboard::LeftAlt, Keyboard::NoEventIndicated, Keyboard::DeleteBackspace, Keyboard::DeleteBackspace, Keyboard::NoEventIndicated, Keyboard::RightAlt, ], [ // Function layer 2 Keyboard::F11, Keyboard::F12, Keyboard::F13, Keyboard::F14, Keyboard::F15, Keyboard::F16, Keyboard::Grave, Keyboard::NoEventIndicated, Keyboard::LeftGUI, Keyboard::NoEventIndicated, Keyboard::CapsLock, Keyboard::DeleteBackspace, Keyboard::LeftControl, Keyboard::NoEventIndicated, Keyboard::NoEventIndicated, Keyboard::F17, Keyboard::F18, Keyboard::F19, Keyboard::LeftArrow, Keyboard::DownArrow, Keyboard::UpArrow, Keyboard::RightArrow, Keyboard::DeleteForward, Keyboard::ReturnEnter, Keyboard::LeftShift, Keyboard::F20, Keyboard::F21, Keyboard::F22, Keyboard::F23, Keyboard::F24, Keyboard::Home, Keyboard::PageDown, Keyboard::PageUp, Keyboard::End, Keyboard::Insert, Keyboard::RightShift, Keyboard::LeftAlt, Keyboard::NoEventIndicated, Keyboard::LeftGUI, Keyboard::DeleteBackspace, Keyboard::NoEventIndicated, Keyboard::RightAlt, ], ]; 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_none: RGB8 = (0, 0, 0).into(); init_keyboard_matrix_pins(matrix_cols, &mut delay); // Infinite colour wheel loop loop { if input_count_down.wait().is_ok() { // Scan keyboard matrix let pressed_keys = get_pressed_keys(matrix_rows, matrix_cols, &mut delay); // Get current function layer let fn_mode = get_fn_mode(pressed_keys); // Copy result from scanned keys to matrix struct for (index, key) in pressed_keys.iter().enumerate() { matrix_keys[index].current_state = *key; } // Generate keyboard report let keyboard_report = get_keyboard_report(matrix_keys, layout, fn_mode); match keyboard.device().write_report(keyboard_report) { Err(UsbHidError::WouldBlock) => {} Err(UsbHidError::Duplicate) => {} Ok(_) => {} Err(e) => { status_led.write([color_red].iter().copied()).unwrap(); 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) => { status_led.write([color_red].iter().copied()).unwrap(); 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) => { status_led.write([color_red].iter().copied()).unwrap(); core::panic!("Failed to read keyboard report: {:?}", e) } Ok(leds) => { if leds.caps_lock == true { status_led.write([color_purple].iter().copied()).unwrap(); } else { status_led.write([color_none].iter().copied()).unwrap(); } } } } } } // Initialise keyboard matrix pins fn init_keyboard_matrix_pins( cols: &mut [&mut dyn OutputPin], delay: &mut Delay, ) { for col in cols.iter_mut() { col.set_high().unwrap(); } delay.delay_us(10); } // Scan keyboard matrix for pressed keys and return a bool array // representing the state of each key (true = pressed) // TODO: This is a bit of a mess, needs refactoring fn get_pressed_keys( rows: &[&dyn InputPin], cols: &mut [&mut dyn OutputPin], delay: &mut Delay, ) -> [bool; NUMBER_OF_KEYS] { // Scan keyboard matrix for pressed keys let mut pressed_keys: [bool; NUMBER_OF_KEYS] = [false; NUMBER_OF_KEYS]; let mut key_index: usize = 0; for (col_index, col) in cols.iter_mut().enumerate() { col.set_low().unwrap(); delay.delay_us(10); for (row_index, row) in rows.iter().enumerate() { if col_index == 3 && (row_index == 0 || row_index == 1 || row_index == 2 || row_index == 9 || row_index == 10 || row_index == 11) { continue; } if row.is_low().unwrap() { pressed_keys[key_index] = true; } key_index += 1; } col.set_high().unwrap(); delay.delay_us(10); } // Return scan result pressed_keys } // Get current Fn mode (0, 1 or 2) fn get_fn_mode(pressed_keys: [bool; NUMBER_OF_KEYS]) -> u8 { // Check Fn mode let mut fn_mode: u8 = 0; if pressed_keys[37] == true && pressed_keys[40] == true { fn_mode = 2; } else if pressed_keys[37] == true || pressed_keys[40] == true { fn_mode = 1; } fn_mode } // Generate keyboard report based on pressed keys and Fn mode (0, 1 or 2) fn get_keyboard_report( mut matrix_keys: [MatrixKey; NUMBER_OF_KEYS], layout: [[Keyboard; NUMBER_OF_KEYS]; 3], fn_mode: u8, ) -> [Keyboard; NUMBER_OF_KEYS] { // Create default report let mut keyboard_report: [Keyboard; NUMBER_OF_KEYS] = [Keyboard::NoEventIndicated; NUMBER_OF_KEYS]; // Filter report based on Fn mode and pressed keys for (index, key) in matrix_keys.iter_mut().enumerate() { if key.current_state != key.previous_state && key.current_state == true { key.fn_mode = fn_mode; } if key.current_state == true { keyboard_report[index] = layout[index][usize::from(key.fn_mode)]; } } // Return report keyboard_report }