#![no_main] #![no_std] // set the panic handler use panic_halt as _; use core::convert::Infallible; use embedded_hal::digital::v2::{InputPin, OutputPin}; use generic_array::typenum::{U4, U6}; use hal::gpio::{gpioa, gpiob, Floating, Input, Output, PullUp, PushPull}; use hal::prelude::*; use hal::serial; use hal::usb; use hal::{stm32, timers}; use keyberon::action::{k, l, m, Action, Action::*}; use keyberon::debounce::Debouncer; use keyberon::impl_heterogenous_array; use keyberon::key_code::KbHidReport; use keyberon::key_code::KeyCode::*; use keyberon::layout::{Event, Layout}; use keyberon::matrix::{Matrix, PressedKeys}; use nb::block; use rtic::app; use stm32f0xx_hal as hal; use usb_device::bus::UsbBusAllocator; use usb_device::class::UsbClass as _; use usb_device::device::UsbDeviceState; type UsbClass = keyberon::Class<'static, usb::UsbBusType, ()>; type UsbDevice = keyberon::Device<'static, usb::UsbBusType>; trait ResultExt { fn get(self) -> T; } impl ResultExt for Result { fn get(self) -> T { match self { Ok(v) => v, Err(e) => match e {}, } } } pub struct Cols( gpioa::PA15>, gpiob::PB3>, gpiob::PB4>, gpiob::PB5>, gpiob::PB8>, gpiob::PB9>, ); impl_heterogenous_array! { Cols, dyn InputPin, U6, [0, 1, 2, 3, 4, 5] } pub struct Rows( gpiob::PB0>, gpiob::PB1>, gpiob::PB2>, gpiob::PB10>, ); impl_heterogenous_array! { Rows, dyn OutputPin, U4, [0, 1, 2, 3] } const CUT: Action = m(&[LShift, Delete]); const COPY: Action = m(&[LCtrl, Insert]); const PASTE: Action = m(&[LShift, Insert]); const L2_ENTER: Action = HoldTap { timeout: 160, hold: &l(2), tap: &k(Enter), }; const L1_SP: Action = HoldTap { timeout: 160, hold: &l(1), tap: &k(Space), }; const CSPACE: Action = m(&[LCtrl, Space]); macro_rules! s { ($k:ident) => { m(&[LShift, $k]) }; } macro_rules! a { ($k:ident) => { m(&[RAlt, $k]) }; } #[rustfmt::skip] pub static LAYERS: keyberon::layout::Layers = &[ &[ &[k(Tab), k(Q), k(W), k(E), k(R), k(T), k(Y), k(U), k(I), k(O), k(P), k(LBracket)], &[k(RBracket),k(A), k(S), k(D), k(F), k(G), k(H), k(J), k(K), k(L), k(SColon),k(Quote) ], &[k(Equal), k(Z), k(X), k(C), k(V), k(B), k(N), k(M), k(Comma),k(Dot), k(Slash), k(Bslash) ], &[Trans, Trans,k(LGui),k(LAlt),L1_SP,k(LCtrl),k(RShift),L2_ENTER,k(RAlt),k(BSpace),Trans, Trans ], ], &[ &[Trans, k(Pause),Trans, k(PScreen),Trans, Trans,Trans, Trans, k(Delete),Trans, Trans, Trans ], &[Trans, Trans, k(NumLock),k(Insert), k(Escape),Trans,k(CapsLock),k(Left),k(Down), k(Up), k(Right),Trans ], &[k(NonUsBslash),k(Undo), CUT, COPY, PASTE, Trans,Trans, k(Home),k(PgDown),k(PgUp),k(End), Trans ], &[Trans, Trans, Trans, Trans, Trans, Trans,Trans, Trans, Trans, Trans, Trans, Trans ], ], &[ &[s!(Grave),s!(Kb1),s!(Kb2),s!(Kb3),s!(Kb4),s!(Kb5),s!(Kb6),s!(Kb7),s!(Kb8),s!(Kb9),s!(Kb0),s!(Minus)], &[ k(Grave), k(Kb1), k(Kb2), k(Kb3), k(Kb4), k(Kb5), k(Kb6), k(Kb7), k(Kb8), k(Kb9), k(Kb0), k(Minus)], &[a!(Grave),a!(Kb1),a!(Kb2),a!(Kb3),a!(Kb4),a!(Kb5),a!(Kb6),a!(Kb7),a!(Kb8),a!(Kb9),a!(Kb0),a!(Minus)], &[Trans, Trans, Trans, Trans, CSPACE, Trans, Trans, Trans, Trans, Trans, Trans, Trans ], ], &[ &[k(F1),k(F2),k(F3),k(F4),k(F5),k(F6),k(F7),k(F8),k(F9),k(F10),k(F11),k(F12)], &[Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans, Trans, Trans ], &[Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans, Trans, Trans ], &[Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans, Trans, Trans ], ], ]; #[app(device = crate::hal::pac, peripherals = true)] const APP: () = { struct Resources { usb_dev: UsbDevice, usb_class: UsbClass, matrix: Matrix, debouncer: Debouncer>, layout: Layout, timer: timers::Timer, transpose: fn(Event) -> Event, tx: serial::Tx, rx: serial::Rx, } #[init] fn init(mut c: init::Context) -> init::LateResources { static mut USB_BUS: Option> = None; let mut rcc = c .device .RCC .configure() .hsi48() .enable_crs(c.device.CRS) .sysclk(48.mhz()) .pclk(24.mhz()) .freeze(&mut c.device.FLASH); let gpioa = c.device.GPIOA.split(&mut rcc); let gpiob = c.device.GPIOB.split(&mut rcc); let usb = usb::Peripheral { usb: c.device.USB, pin_dm: gpioa.pa11, pin_dp: gpioa.pa12, }; *USB_BUS = Some(usb::UsbBusType::new(usb)); let usb_bus = USB_BUS.as_ref().unwrap(); let usb_class = keyberon::new_class(usb_bus, ()); let usb_dev = keyberon::new_device(usb_bus); let mut timer = timers::Timer::tim3(c.device.TIM3, 1.khz(), &mut rcc); timer.listen(timers::Event::TimeOut); let pb12: &gpiob::PB12> = &gpiob.pb12; let is_left = pb12.is_low().get(); let transpose = if is_left { transpose_left } else { transpose_right }; let (pa9, pa10) = (gpioa.pa9, gpioa.pa10); let pins = cortex_m::interrupt::free(move |cs| { (pa9.into_alternate_af1(cs), pa10.into_alternate_af1(cs)) }); let mut serial = serial::Serial::usart1(c.device.USART1, pins, 115_200.bps(), &mut rcc); serial.listen(serial::Event::Rxne); let (tx, rx) = serial.split(); let pa15 = gpioa.pa15; let matrix = cortex_m::interrupt::free(move |cs| { Matrix::new( Cols( pa15.into_pull_up_input(cs), gpiob.pb3.into_pull_up_input(cs), gpiob.pb4.into_pull_up_input(cs), gpiob.pb5.into_pull_up_input(cs), gpiob.pb8.into_pull_up_input(cs), gpiob.pb9.into_pull_up_input(cs), ), Rows( gpiob.pb0.into_push_pull_output(cs), gpiob.pb1.into_push_pull_output(cs), gpiob.pb2.into_push_pull_output(cs), gpiob.pb10.into_push_pull_output(cs), ), ) }); init::LateResources { usb_dev, usb_class, timer, debouncer: Debouncer::new(PressedKeys::default(), PressedKeys::default(), 5), matrix: matrix.get(), layout: Layout::new(LAYERS), transpose, tx, rx, } } #[task(binds = USB, priority = 4, resources = [usb_dev, usb_class])] fn usb_rx(c: usb_rx::Context) { if c.resources.usb_dev.poll(&mut [c.resources.usb_class]) { c.resources.usb_class.poll(); } } #[task(priority = 3, capacity = 3, resources = [usb_dev, usb_class])] fn handle_report(mut c: handle_report::Context, report: KbHidReport) { if !c .resources .usb_class .lock(|k| k.device_mut().set_keyboard_report(report.clone())) { return; } if c.resources.usb_dev.lock(|d| d.state()) != UsbDeviceState::Configured { return; } while let Ok(0) = c.resources.usb_class.lock(|k| k.write(report.as_bytes())) {} } #[task( binds = TIM3, priority = 2, spawn = [handle_report], resources = [matrix, debouncer, layout, timer, &transpose, tx], )] fn tick(mut c: tick::Context) { c.resources.timer.wait().ok(); for event in c .resources .debouncer .events(c.resources.matrix.get().get()) .map(c.resources.transpose) { for &b in &ser(event) { block!(c.resources.tx.write(b)).get(); } c.spawn .handle_report(c.resources.layout.lock(|l| l.event(event).collect())) .unwrap(); } c.spawn .handle_report(c.resources.layout.lock(|l| l.tick().collect())) .unwrap(); } #[task(binds = USART1, priority = 5, spawn = [handle_report], resources = [layout, rx])] fn rx(c: rx::Context) { static mut BUF: [u8; 4] = [0; 4]; if let Ok(b) = c.resources.rx.read() { BUF.rotate_left(1); BUF[3] = b; } if BUF[3] == b'\n' { if let Ok(event) = de(&BUF[..]) { c.spawn .handle_report(c.resources.layout.event(event).collect()) .unwrap(); } } } extern "C" { fn CEC_CAN(); } }; fn transpose_left(e: Event) -> Event { e } fn transpose_right(e: Event) -> Event { match e { Event::Press(i, j) => Event::Press(i, 11 - j), Event::Release(i, j) => Event::Release(i, 11 - j), } } fn de(bytes: &[u8]) -> Result { match *bytes { [b'P', i, j, b'\n'] => Ok(Event::Press(i as usize, j as usize)), [b'R', i, j, b'\n'] => Ok(Event::Release(i as usize, j as usize)), _ => Err(()), } } fn ser(e: Event) -> [u8; 4] { match e { Event::Press(i, j) => [b'P', i as u8, j as u8, b'\n'], Event::Release(i, j) => [b'R', i as u8, j as u8, b'\n'], } }