From 0a9f2cca71889e78fb0bad31a63fdb6c8e54e20f Mon Sep 17 00:00:00 2001 From: Guillaume Pinot Date: Sun, 2 Aug 2020 19:49:35 +0200 Subject: first compiling firmware --- firmware/src/main.rs | 213 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 firmware/src/main.rs (limited to 'firmware/src') diff --git a/firmware/src/main.rs b/firmware/src/main.rs new file mode 100644 index 0000000..9c261c0 --- /dev/null +++ b/firmware/src/main.rs @@ -0,0 +1,213 @@ +#![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 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::{self, *}; +use keyberon::layout::Layout; +use keyberon::matrix::{Matrix, PressedKeys}; +use rtfm::app; +use stm32f0xx_hal::gpio::{gpioa, gpiob, Input, Output, PullUp, PushPull}; +use stm32f0xx_hal::prelude::*; +use stm32f0xx_hal::usb; +use stm32f0xx_hal::{stm32, timers}; +use usb_device::bus::UsbBusAllocator; +use usb_device::class::UsbClass as _; + +type UsbClass = keyberon::Class<'static, usb::UsbBusType, ()>; +type UsbDevice = keyberon::Device<'static, usb::UsbBusType>; + +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: 200, + hold: &l(2), + tap: &k(Enter), +}; +const L1_SP: Action = HoldTap { + timeout: 200, + 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]) + }; +} + +// The 13th column is the hardware button of the development board, +// thus all the column is activated when the button is pushed. Because +// of that, only one action is defined in the 13th column. +#[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 = stm32f0xx_hal::stm32, peripherals = true)] +const APP: () = { + struct Resources { + usb_dev: UsbDevice, + usb_class: UsbClass, + matrix: Matrix, + debouncer: Debouncer>, + layout: Layout, + timer: timers::Timer, + } + + #[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 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.unwrap(), + layout: Layout::new(LAYERS), + } + } + + #[task(binds = USB, priority = 2, resources = [usb_dev, usb_class])] + fn usb_rx(mut c: usb_rx::Context) { + usb_poll(&mut c.resources.usb_dev, &mut c.resources.usb_class); + } + + #[task(binds = TIM3, priority = 1, resources = [usb_class, matrix, debouncer, layout, timer])] + fn tick(mut c: tick::Context) { + c.resources.timer.wait().ok(); + + for event in c + .resources + .debouncer + .events(c.resources.matrix.get().unwrap()) + { + send_report(c.resources.layout.event(event), &mut c.resources.usb_class); + } + send_report(c.resources.layout.tick(), &mut c.resources.usb_class); + } +}; + +fn send_report(iter: impl Iterator, usb_class: &mut resources::usb_class<'_>) { + use rtfm::Mutex; + let report: KbHidReport = iter.collect(); + if usb_class.lock(|k| k.device_mut().set_keyboard_report(report.clone())) { + while let Ok(0) = usb_class.lock(|k| k.write(report.as_bytes())) {} + } +} + +fn usb_poll(usb_dev: &mut UsbDevice, keyboard: &mut UsbClass) { + if usb_dev.poll(&mut [keyboard]) { + keyboard.poll(); + } +} -- cgit v1.2.3