summaryrefslogtreecommitdiff
path: root/firmware/src/main.rs
diff options
context:
space:
mode:
authorGuillaume Pinot <texitoi@texitoi.eu>2020-08-02 19:49:35 +0200
committerGuillaume Pinot <texitoi@texitoi.eu>2020-08-02 19:49:35 +0200
commit0a9f2cca71889e78fb0bad31a63fdb6c8e54e20f (patch)
tree2bec18262c5d2dedd8ab1c958fdc791011a99ae8 /firmware/src/main.rs
parent4589117f02c7813495719f78e581d7c812664af2 (diff)
first compiling firmware
Diffstat (limited to 'firmware/src/main.rs')
-rw-r--r--firmware/src/main.rs213
1 files changed, 213 insertions, 0 deletions
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<Input<PullUp>>,
+ gpiob::PB3<Input<PullUp>>,
+ gpiob::PB4<Input<PullUp>>,
+ gpiob::PB5<Input<PullUp>>,
+ gpiob::PB8<Input<PullUp>>,
+ gpiob::PB9<Input<PullUp>>,
+);
+impl_heterogenous_array! {
+ Cols,
+ dyn InputPin<Error = Infallible>,
+ U6,
+ [0, 1, 2, 3, 4, 5]
+}
+
+pub struct Rows(
+ gpiob::PB0<Output<PushPull>>,
+ gpiob::PB1<Output<PushPull>>,
+ gpiob::PB2<Output<PushPull>>,
+ gpiob::PB10<Output<PushPull>>,
+);
+impl_heterogenous_array! {
+ Rows,
+ dyn OutputPin<Error = Infallible>,
+ 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<Cols, Rows>,
+ debouncer: Debouncer<PressedKeys<U4, U6>>,
+ layout: Layout,
+ timer: timers::Timer<stm32::TIM3>,
+ }
+
+ #[init]
+ fn init(mut c: init::Context) -> init::LateResources {
+ static mut USB_BUS: Option<UsbBusAllocator<usb::UsbBusType>> = 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<Item = KeyCode>, 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();
+ }
+}