Compare commits

...

3 Commits

  1. 14
      firmware/Cargo.toml
  2. 236
      firmware/src/main.rs

14
firmware/Cargo.toml

@ -8,16 +8,16 @@ edition = "2018"
stm32f0xx-hal = { git = "https://github.com/dkm/stm32f0xx-hal/", features = ["rt", "stm32f072", "stm32-usbd"] }
##{ version = "0.17.0", features = ["rt", "stm32f072", "stm32-usbd"] }
cortex-m = "0.6"
cortex-m-rt = { version = "0.6.10", features = ["device"] }
panic-halt = "0.2.0"
keyberon = { git = "https://github.com/TeXitoi/keyberon" }
cortex-m-rt = { version = "0.6", features = ["device"] }
panic-halt = "0.2"
keyberon = { git = "https://github.com/dkm/keyberon" }
cortex-m-rtic = "0.5"
generic-array = "0.13"
embedded-hal = "0.2"
usb-device = "0.2.0"
nb = "1.0.0"
ws2812-spi = "0.3.0"
smart-leds = "0.3.0"
usb-device = "0.2"
nb = "1.0"
ws2812-spi = "0.3"
smart-leds = "0.3"
[profile.release]
lto = true

236
firmware/src/main.rs

@ -12,9 +12,13 @@ use smart_leds::{brightness, colors, SmartLedsWrite, RGB8};
use ws2812_spi as ws2812;
use core::convert::Infallible;
use embedded_hal::digital::v2::{InputPin, OutputPin};
use generic_array::typenum::{U12, U5};
use hal::gpio::{gpioa, gpiob, Alternate, Input, Output, PullUp, PushPull, AF0};
use hal::prelude::*;
use embedded_hal::spi::FullDuplex;
@ -24,20 +28,22 @@ use hal::{
spi::{EightBit, Mode, Phase, Polarity},
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::key_code::KeyCode::*;
use keyberon::key_code::KeyCode::{self, *};
use keyberon::layout::{Event, Layout};
use keyberon::layout::Layout;
use keyberon::matrix::{Matrix, PressedKeys};
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 Spi = hal::spi::Spi<
stm32::SPI1,
gpioa::PA5<Alternate<AF0>>,
@ -97,24 +103,30 @@ impl_heterogenous_array! {
[0, 1, 2, 3, 4]
}
#[rustfmt::skip]
pub static LAYERS: keyberon::layout::Layers = &[
&[
&[k(Grave), k(Kb1),k(Kb2),k(Kb3), k(Kb4),k(Kb5), k(Kb6), k(Kb7), k(Kb8), k(Kb9), k(Kb0), k(Minus), k(Space)],
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CustomActions {
LightUp,
LightDown,
&[k(Q), k(W), k(E), k(R), k(T), k(Tab), k(Y), k(U), k(I), k(O), k(P), k(LBracket)],
&[k(A), k(S), k(D), k(F), k(G), k(BSpace), k(H), k(J), k(K), k(L), k(SColon), k(Quote)],
&[k(Z), k(X), k(C), k(V), k(B), k(Enter), k(N), k(M), k(Comma), k(Dot), k(Slash), k(Bslash) ],
ModeCycle,
ColorCycle,
}
&[k(LCtrl), l(1), k(LGui), k(LShift), k(LAlt), k(Space), k(RAlt), k(RBracket), k(Equal), k(Delete),k(RShift), k(RCtrl)],
#[rustfmt::skip]
pub static LAYERS: keyberon::layout::Layers<CustomActions> = &[
&[
&[k(Kb1), k(Kb2), k(Kb3), k(Kb4), k(Kb5), k(Grave), k(Kb6), k(Kb7), k(Kb8), k(Kb9), k(Kb0), k(Minus)],
&[k(Q), k(W), k(E), k(R), k(T), k(Tab), k(Y), k(U), k(I), k(O), k(P), k(LBracket)],
&[k(A), k(S), k(D), k(F), k(G), k(BSpace), k(H), k(J), k(K), k(L), k(SColon), k(Quote)],
&[k(Z), k(X), k(C), k(V), k(B), k(Enter), k(N), k(M), k(Comma), k(Dot), k(Slash), k(Bslash) ],
&[k(LCtrl), l(1), k(LGui), k(LShift), k(LAlt), k(Space), k(RAlt), k(RBracket), k(Equal), k(Delete), k(RShift), k(RCtrl)],
], &[
&[k(F1),k(F2),k(F3),k(F4),k(F5),k(F6),k(F7),k(F8),k(F9),k(F10),k(F11),k(F12)],
&[k(SysReq), k(NumLock), Trans, Trans, Trans, k(Escape), k(Insert), k(PgUp), k(PgDown), Trans, Trans, Trans ],
&[Trans , Trans , Trans, Trans, Trans, Trans, k(Home), k(Up), k(End), Trans, Trans, Trans ],
&[k(NonUsBslash), Trans, Trans, Trans, Trans, Trans, k(Left), k(Down), k(Right), Trans, Trans, k(PgUp) ],
&[Trans, Trans, Trans, Trans, Trans, Trans, Trans, Trans, Trans, Trans, Trans, k(PgDown) ],
&[k(F1), k(F2), k(F3), k(F4), k(F5), k(F6), k(F7), k(F8), k(F9), k(F10), k(F11), k(F12)],
&[k(SysReq), k(NumLock), Trans, Trans, Trans, k(Escape), k(Insert), k(PgUp), k(PgDown), Trans, Trans, Trans ],
&[Trans , Trans , Trans, Trans, Trans, Trans, k(Home), k(Up), k(End), Trans, Trans, Trans ],
&[k(NonUsBslash), Action::Custom(CustomActions::ColorCycle), Trans, Trans, Trans, Trans, k(Left), k(Down), k(Right), Trans, Trans, k(PgUp) ],
&[Action::Custom(CustomActions::LightUp), Trans, Action::Custom(CustomActions::LightDown), Action::Custom(CustomActions::ModeCycle), Trans, Trans, Trans, Trans, Trans, Trans, Trans, Trans],
],
];
@ -155,6 +167,145 @@ where
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum BacklightMode {
Off,
Solid(RGB8),
K2000(RGB8, usize, usize, bool),
Fire,
Breath(RGB8, bool),
}
pub struct Backlight {
mode: BacklightMode,
brightness: u8,
}
trait ColorSeq {
fn next_color(&self) -> RGB8;
}
const COLORS_SEQ: [RGB8; 5] = [
colors::RED,
colors::GREEN,
colors::BLUE,
colors::VIOLET,
colors::YELLOW,
];
impl ColorSeq for RGB8 {
fn next_color(&self) -> RGB8 {
let mut next = false;
for c in &COLORS_SEQ {
if next {
return *c;
}
if *self == *c {
next = true;
}
}
COLORS_SEQ[0]
}
}
impl Backlight {
pub fn next_mode(&mut self) {
self.mode = match self.mode {
BacklightMode::Off => BacklightMode::Solid(colors::RED),
BacklightMode::Solid(_) => BacklightMode::K2000(colors::RED, 0, 0, true),
BacklightMode::K2000(_, _, _, _) => BacklightMode::Fire,
BacklightMode::Fire => BacklightMode::Breath(colors::RED, true),
BacklightMode::Breath(_, _) => BacklightMode::Off,
}
}
pub fn next_color(&mut self) {
self.mode = match self.mode {
BacklightMode::Solid(c) => BacklightMode::Solid(c.next_color()),
BacklightMode::Breath(c, dir) => BacklightMode::Breath(c.next_color(), dir),
BacklightMode::K2000(c, s, i, dir) => BacklightMode::K2000(c.next_color(), s, i, dir),
any => any,
}
}
pub fn refresh_leds(&mut self, leds: &mut Leds<Spi>) {
self.mode = match self.mode {
BacklightMode::Off => {
for l in leds.leds[4..].iter_mut() {
*l = colors::BLACK;
}
BacklightMode::Off
}
BacklightMode::Solid(c) => {
for l in leds.leds[4..].iter_mut() {
*l = c;
}
BacklightMode::Solid(c)
}
BacklightMode::Breath(c, dir) => {
for l in leds.leds[4..].iter_mut() {
*l = c;
}
let mut new_dir = dir;
if dir {
if self.brightness == 100 {
self.brightness -= 1;
new_dir = false;
}
self.brightness += 1;
} else {
if self.brightness == 0 {
self.brightness += 1;
new_dir = true;
}
self.brightness -= 1;
}
BacklightMode::Breath(c, new_dir)
}
BacklightMode::K2000(c, step, index, dir) => {
let mut new_dir = dir;
let mut new_index = index;
let mut step = step + 1;
if step == 100 {
step = 0;
if new_index == 0 && !dir {
new_index = 0;
new_dir = true;
} else if new_index == 5 && dir {
new_index = 5;
new_dir = false;
} else {
new_index = if dir { index + 1 } else { index - 1 };
}
}
for (i, l) in leds.leds[4..].iter_mut().enumerate() {
if i == new_index {
*l = c;
} else {
*l = colors::BLACK;
}
}
BacklightMode::K2000(c, step, new_index as usize, new_dir)
}
any => any,
};
leds.ws
.write(brightness(leds.leds.iter().cloned(), self.brightness));
}
}
#[app(device = crate::hal::pac, peripherals = true)]
const APP: () = {
struct Resources {
@ -162,8 +313,10 @@ const APP: () = {
usb_class: UsbClass,
matrix: Matrix<Cols, Rows>,
debouncer: Debouncer<PressedKeys<U5, U12>>,
layout: Layout,
layout: Layout<CustomActions>,
timer: timers::Timer<stm32::TIM3>,
backlight: Backlight,
}
#[init]
@ -219,7 +372,7 @@ const APP: () = {
);
// ws2812
let mut ws = ws2812::Ws2812::new(spi);
let ws = ws2812::Ws2812::new(spi);
let mut leds = Leds {
ws,
@ -270,6 +423,11 @@ const APP: () = {
debouncer: Debouncer::new(PressedKeys::default(), PressedKeys::default(), 5),
matrix: matrix.get(),
layout: Layout::new(LAYERS),
backlight: Backlight {
mode: BacklightMode::Off,
brightness: 8,
},
}
}
@ -283,9 +441,9 @@ const APP: () = {
#[task(
binds = TIM3,
priority = 2,
resources = [matrix, debouncer, timer, layout, usb_class],
resources = [matrix, debouncer, timer, layout, usb_class, backlight],
)]
fn tick(mut c: tick::Context) {
fn tick(c: tick::Context) {
c.resources.timer.wait().ok();
for event in c
@ -295,12 +453,44 @@ const APP: () = {
{
c.resources.layout.event(event);
}
let mut usb_class = c.resources.usb_class;
let backlight = c.resources.backlight;
match c.resources.layout.tick() {
keyberon::layout::CustomEvent::Release(CustomActions::LightUp) => {
let bl_val = &mut backlight.brightness;
*bl_val = if *bl_val == 100 { 100 } else { *bl_val + 1 };
usb_class.lock(|k| {
let leds = k.device_mut().leds();
leds.ws
.write(brightness(leds.leds.iter().cloned(), *bl_val));
});
}
keyberon::layout::CustomEvent::Release(CustomActions::LightDown) => {
let bl_val = &mut backlight.brightness;
*bl_val = if *bl_val == 0 { 0 } else { *bl_val - 1 };
usb_class.lock(|k| {
let leds = k.device_mut().leds();
leds.ws
.write(brightness(leds.leds.iter().cloned(), *bl_val));
});
}
keyberon::layout::CustomEvent::Release(CustomActions::ColorCycle) => {
backlight.next_color();
}
keyberon::layout::CustomEvent::Release(CustomActions::ModeCycle) => {
backlight.next_mode();
}
_ => (),
}
usb_class.lock(|k| {
backlight.refresh_leds(&mut k.device_mut().leds());
});
c.resources.layout.tick();
send_report(c.resources.layout.keycodes(), &mut c.resources.usb_class);
send_report(c.resources.layout.keycodes(), &mut usb_class);
}
extern "C" {

Loading…
Cancel
Save