Split firmware inte left.rs and right.rs.
This commit is contained in:
60
Cargo.lock
generated
60
Cargo.lock
generated
@ -670,36 +670,6 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itsybitsy_rp2040_keyboard"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"embassy-executor",
|
||||
"embassy-futures",
|
||||
"embassy-rp",
|
||||
"embassy-sync",
|
||||
"embassy-time",
|
||||
"embassy-usb",
|
||||
"embassy-usb-driver",
|
||||
"embassy-usb-logger",
|
||||
"embedded-alloc",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-io",
|
||||
"futures",
|
||||
"log",
|
||||
"pio",
|
||||
"pio-proc",
|
||||
"postcard",
|
||||
"ron",
|
||||
"smart-leds",
|
||||
"static_cell",
|
||||
"tgnt",
|
||||
"usb-device",
|
||||
"usbd-hid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop"
|
||||
version = "0.19.8"
|
||||
@ -1225,6 +1195,36 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tangentbord1"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"embassy-executor",
|
||||
"embassy-futures",
|
||||
"embassy-rp",
|
||||
"embassy-sync",
|
||||
"embassy-time",
|
||||
"embassy-usb",
|
||||
"embassy-usb-driver",
|
||||
"embassy-usb-logger",
|
||||
"embedded-alloc",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-io",
|
||||
"futures",
|
||||
"log",
|
||||
"pio",
|
||||
"pio-proc",
|
||||
"postcard",
|
||||
"ron",
|
||||
"smart-leds",
|
||||
"static_cell",
|
||||
"tgnt",
|
||||
"usb-device",
|
||||
"usbd-hid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "0.7.0"
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
[package]
|
||||
name = "itsybitsy_rp2040_keyboard"
|
||||
name = "tangentbord1"
|
||||
version = "0.1.0"
|
||||
authors = ["Joakim Hulthe <joakim@hulthe.net>"]
|
||||
description = "Keyboard firmware"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
17
build.rs
17
build.rs
@ -17,7 +17,8 @@ use tgnt::layer::Layer;
|
||||
|
||||
fn main() {
|
||||
memory();
|
||||
serialize_layout();
|
||||
serialize_layout("./layers-left.ron", "./src/bin/layers-left.pc");
|
||||
serialize_layout("./layers-right.ron", "./src/bin/layers-right.pc");
|
||||
}
|
||||
|
||||
fn memory() {
|
||||
@ -44,16 +45,16 @@ fn memory() {
|
||||
//println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
||||
|
||||
fn serialize_layout() {
|
||||
println!("cargo:rerun-if-changed=layers.ron");
|
||||
fn serialize_layout(ron_path: &str, postcard_path: &str) {
|
||||
println!("cargo:rerun-if-changed={ron_path}");
|
||||
|
||||
let layers = fs::read_to_string("layers.ron").expect("Failed to read layers.ron");
|
||||
let layers: Vec<Layer> = ron::from_str(&layers).expect("Failed to deserialize layers.ron");
|
||||
let layers = fs::read_to_string(ron_path).expect("Failed to read .ron");
|
||||
let layers: Vec<Layer> = ron::from_str(&layers).expect("Failed to deserialize .ron");
|
||||
|
||||
let serialized = postcard::to_stdvec(&layers).expect("Failed to serialize layers");
|
||||
|
||||
File::create("./src/layers.pc")
|
||||
.expect("Failed to create layers.pc")
|
||||
File::create(postcard_path)
|
||||
.expect("Failed to create .pc")
|
||||
.write_all(&serialized)
|
||||
.expect("Failed to write layers.pc");
|
||||
.expect("Failed to write .pc");
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
[
|
||||
Layer(
|
||||
buttons: [
|
||||
/* Left */
|
||||
// Row 1
|
||||
Key(Apostrophe),
|
||||
Key(Comma),
|
||||
@ -27,33 +26,6 @@
|
||||
Mod(LShift),
|
||||
Mod(LCtrl),
|
||||
NextLayer,
|
||||
|
||||
/* Right */
|
||||
// Row 1
|
||||
Key(F),
|
||||
Key(G),
|
||||
Key(C),
|
||||
Key(R),
|
||||
Key(L),
|
||||
|
||||
// Row 2
|
||||
Key(D),
|
||||
Key(H),
|
||||
Key(T),
|
||||
Key(N),
|
||||
Key(S),
|
||||
|
||||
// Row 3
|
||||
Key(B),
|
||||
Key(M),
|
||||
Key(W),
|
||||
Key(V),
|
||||
Key(Z),
|
||||
|
||||
// Thumbpad
|
||||
PrevLayer,
|
||||
Mod(RAlt),
|
||||
Mod(RMod),
|
||||
],
|
||||
)
|
||||
]
|
||||
31
layers-right.ron
Normal file
31
layers-right.ron
Normal file
@ -0,0 +1,31 @@
|
||||
[
|
||||
Layer(
|
||||
buttons: [
|
||||
// Row 1
|
||||
Key(F),
|
||||
Key(G),
|
||||
Key(C),
|
||||
Key(R),
|
||||
Key(L),
|
||||
|
||||
// Row 2
|
||||
Key(D),
|
||||
Key(H),
|
||||
Key(T),
|
||||
Key(N),
|
||||
Key(S),
|
||||
|
||||
// Row 3
|
||||
Key(B),
|
||||
Key(M),
|
||||
Key(W),
|
||||
Key(V),
|
||||
Key(Z),
|
||||
|
||||
// Thumbpad
|
||||
PrevLayer,
|
||||
Mod(RAlt),
|
||||
Mod(RMod),
|
||||
],
|
||||
)
|
||||
]
|
||||
@ -8,7 +8,7 @@ use embedded_alloc::Heap;
|
||||
static HEAP: Heap = Heap::empty();
|
||||
|
||||
pub fn init() {
|
||||
const HEAP_SIZE: usize = 2048;
|
||||
const HEAP_SIZE: usize = 4096;
|
||||
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
|
||||
unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }
|
||||
}
|
||||
|
||||
BIN
src/bin/layers-left.pc
Normal file
BIN
src/bin/layers-left.pc
Normal file
Binary file not shown.
BIN
src/bin/layers-right.pc
Normal file
BIN
src/bin/layers-right.pc
Normal file
Binary file not shown.
88
src/bin/left.rs
Normal file
88
src/bin/left.rs
Normal file
@ -0,0 +1,88 @@
|
||||
//! Firmware for Tangentbord1, left half.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate cortex_m_rt;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::gpio::{Level, Output, Pin};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use tangentbord1::board::Board;
|
||||
use tangentbord1::keyboard::KeyboardConfig;
|
||||
use tangentbord1::util::{stall, wheel};
|
||||
use tangentbord1::ws2812::{Rgb, Ws2812};
|
||||
use tangentbord1::{allocator, usb};
|
||||
use tgnt::layer::Layer;
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
allocator::init();
|
||||
|
||||
let p = embassy_rp::init(Default::default());
|
||||
let board = Board::from(p);
|
||||
|
||||
let _led = Output::new(board.d13, Level::High);
|
||||
let _neopixel_power = Output::new(board.neopixel_power, Level::High);
|
||||
|
||||
let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel.degrade());
|
||||
let mut neopixels_d5 = Ws2812::new(board.PIO1, board.DMA_CH1, board.d5.degrade());
|
||||
|
||||
neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await;
|
||||
usb::setup_logger_and_keyboard(board.USB).await;
|
||||
neopixel.write(&[Rgb::new(0x00, 0x00, 0xFF)]).await;
|
||||
|
||||
//Timer::after(Duration::from_millis(3000)).await;
|
||||
|
||||
let layers = include_bytes!("layers-left.pc");
|
||||
let Ok(layers): Result<Vec<Layer>, _> = postcard::from_bytes(layers) else {
|
||||
log::error!("Failed to deserialize layer config");
|
||||
stall().await
|
||||
};
|
||||
|
||||
let keyboard = KeyboardConfig {
|
||||
layers,
|
||||
pins: [
|
||||
// row 1
|
||||
board.d24.degrade(),
|
||||
board.a3.degrade(),
|
||||
board.a2.degrade(),
|
||||
board.a1.degrade(),
|
||||
board.a0.degrade(),
|
||||
// row 2
|
||||
board.d25.degrade(),
|
||||
board.sck.degrade(),
|
||||
board.mosi.degrade(),
|
||||
board.miso.degrade(),
|
||||
board.d2.degrade(),
|
||||
// row 3
|
||||
board.d12.degrade(),
|
||||
board.d11.degrade(),
|
||||
board.d10.degrade(),
|
||||
board.d9.degrade(),
|
||||
board.d3.degrade(),
|
||||
// thumbpad
|
||||
board.d7.degrade(),
|
||||
board.scl.degrade(),
|
||||
board.sda.degrade(),
|
||||
],
|
||||
};
|
||||
|
||||
keyboard.create().await;
|
||||
|
||||
for w in 0usize.. {
|
||||
neopixel.write(&[wheel(w as u8)]).await;
|
||||
neopixels_d5
|
||||
.write(&[
|
||||
wheel((w + 50) as u8),
|
||||
wheel((w + 100) as u8),
|
||||
wheel((w + 150) as u8),
|
||||
wheel((w + 200) as u8),
|
||||
])
|
||||
.await;
|
||||
Timer::after(Duration::from_millis(10)).await;
|
||||
}
|
||||
}
|
||||
89
src/bin/right.rs
Normal file
89
src/bin/right.rs
Normal file
@ -0,0 +1,89 @@
|
||||
//! Firmware for Tangentbord1, right half.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate cortex_m_rt;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::gpio::{Level, Output, Pin};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use tangentbord1::board::Board;
|
||||
use tangentbord1::keyboard::KeyboardConfig;
|
||||
use tangentbord1::util::{stall, wheel};
|
||||
use tangentbord1::ws2812::{Rgb, Ws2812};
|
||||
use tangentbord1::{allocator, usb};
|
||||
use tgnt::layer::Layer;
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
allocator::init();
|
||||
|
||||
let p = embassy_rp::init(Default::default());
|
||||
let board = Board::from(p);
|
||||
|
||||
let _led = Output::new(board.d13, Level::High);
|
||||
let _neopixel_power = Output::new(board.neopixel_power, Level::High);
|
||||
|
||||
let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel.degrade());
|
||||
let mut neopixels_d5 = Ws2812::new(board.PIO1, board.DMA_CH1, board.d5.degrade());
|
||||
|
||||
neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).await;
|
||||
usb::setup_logger_and_keyboard(board.USB).await;
|
||||
neopixel.write(&[Rgb::new(0x00, 0x00, 0xFF)]).await;
|
||||
|
||||
//Timer::after(Duration::from_millis(3000)).await;
|
||||
|
||||
let layers = include_bytes!("layers-right.pc");
|
||||
let Ok(layers): Result<Vec<Layer>, _> = postcard::from_bytes(layers) else {
|
||||
log::error!("Failed to deserialize layer config");
|
||||
stall().await
|
||||
};
|
||||
|
||||
let keyboard = KeyboardConfig {
|
||||
layers,
|
||||
pins: [
|
||||
// TODO: reconfigure these for right PCB
|
||||
// row 1
|
||||
board.d24.degrade(),
|
||||
board.a3.degrade(),
|
||||
board.a2.degrade(),
|
||||
board.a1.degrade(),
|
||||
board.a0.degrade(),
|
||||
// row 2
|
||||
board.d25.degrade(),
|
||||
board.sck.degrade(),
|
||||
board.mosi.degrade(),
|
||||
board.miso.degrade(),
|
||||
board.d2.degrade(),
|
||||
// row 3
|
||||
board.d12.degrade(),
|
||||
board.d11.degrade(),
|
||||
board.d10.degrade(),
|
||||
board.d9.degrade(),
|
||||
board.d3.degrade(),
|
||||
// thumbpad
|
||||
board.d7.degrade(),
|
||||
board.scl.degrade(),
|
||||
board.sda.degrade(),
|
||||
],
|
||||
};
|
||||
|
||||
keyboard.create().await;
|
||||
|
||||
for w in 0usize.. {
|
||||
neopixel.write(&[wheel(w as u8)]).await;
|
||||
neopixels_d5
|
||||
.write(&[
|
||||
wheel((w + 50) as u8),
|
||||
wheel((w + 100) as u8),
|
||||
wheel((w + 150) as u8),
|
||||
wheel((w + 200) as u8),
|
||||
])
|
||||
.await;
|
||||
Timer::after(Duration::from_millis(10)).await;
|
||||
}
|
||||
}
|
||||
72
src/board.rs
72
src/board.rs
@ -1,8 +1,26 @@
|
||||
use embassy_rp::peripherals::*;
|
||||
use embassy_rp::{peripherals::*, Peripherals};
|
||||
|
||||
/// Pinouts for the ItsyBitsy
|
||||
#[allow(dead_code)]
|
||||
#[allow(dead_code, non_snake_case)]
|
||||
pub struct Board {
|
||||
pub USB: USB,
|
||||
pub UART0: UART0,
|
||||
pub UART1: UART1,
|
||||
pub PIO0: PIO0,
|
||||
pub PIO1: PIO1,
|
||||
pub DMA_CH0: DMA_CH0,
|
||||
pub DMA_CH1: DMA_CH1,
|
||||
pub DMA_CH2: DMA_CH2,
|
||||
pub DMA_CH3: DMA_CH3,
|
||||
pub DMA_CH4: DMA_CH4,
|
||||
pub DMA_CH5: DMA_CH5,
|
||||
pub DMA_CH6: DMA_CH6,
|
||||
pub DMA_CH7: DMA_CH7,
|
||||
pub DMA_CH8: DMA_CH8,
|
||||
pub DMA_CH9: DMA_CH9,
|
||||
pub DMA_CH10: DMA_CH10,
|
||||
|
||||
// pins
|
||||
pub a0: PIN_26,
|
||||
pub a1: PIN_27,
|
||||
pub a2: PIN_28,
|
||||
@ -29,3 +47,53 @@ pub struct Board {
|
||||
pub neopixel: PIN_17,
|
||||
pub neopixel_power: PIN_16,
|
||||
}
|
||||
|
||||
impl From<Peripherals> for Board {
|
||||
fn from(p: Peripherals) -> Self {
|
||||
Board {
|
||||
USB: p.USB,
|
||||
UART0: p.UART0,
|
||||
UART1: p.UART1,
|
||||
PIO0: p.PIO0,
|
||||
PIO1: p.PIO1,
|
||||
DMA_CH0: p.DMA_CH0,
|
||||
DMA_CH1: p.DMA_CH1,
|
||||
DMA_CH2: p.DMA_CH2,
|
||||
DMA_CH3: p.DMA_CH3,
|
||||
DMA_CH4: p.DMA_CH4,
|
||||
DMA_CH5: p.DMA_CH5,
|
||||
DMA_CH6: p.DMA_CH6,
|
||||
DMA_CH7: p.DMA_CH7,
|
||||
DMA_CH8: p.DMA_CH8,
|
||||
DMA_CH9: p.DMA_CH9,
|
||||
DMA_CH10: p.DMA_CH10,
|
||||
|
||||
// pins
|
||||
a0: p.PIN_26,
|
||||
a1: p.PIN_27,
|
||||
a2: p.PIN_28,
|
||||
a3: p.PIN_29,
|
||||
d24: p.PIN_24,
|
||||
d25: p.PIN_25,
|
||||
sck: p.PIN_18,
|
||||
mosi: p.PIN_19,
|
||||
miso: p.PIN_20,
|
||||
d2: p.PIN_12,
|
||||
d3: p.PIN_5,
|
||||
d4: p.PIN_4,
|
||||
rx: p.PIN_1,
|
||||
tx: p.PIN_0,
|
||||
sda: p.PIN_2,
|
||||
scl: p.PIN_3,
|
||||
d5: p.PIN_14,
|
||||
d7: p.PIN_6,
|
||||
d9: p.PIN_7,
|
||||
d10: p.PIN_8,
|
||||
d11: p.PIN_9,
|
||||
d12: p.PIN_10,
|
||||
d13: p.PIN_11,
|
||||
neopixel: p.PIN_17,
|
||||
neopixel_power: p.PIN_16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,9 @@ use core::sync::atomic::{AtomicU16, Ordering};
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::gpio::{AnyPin, Input, Pin, Pull};
|
||||
use log::{error, warn};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use futures::{select_biased, FutureExt};
|
||||
use log::{debug, error, info, warn};
|
||||
use tgnt::{button::Button, layer::Layer};
|
||||
|
||||
use crate::usb::keyboard::KB_REPORT;
|
||||
@ -24,6 +26,11 @@ impl KeyboardConfig {
|
||||
return;
|
||||
}
|
||||
|
||||
info!(
|
||||
"setting up keyboard layout with {} layer(s)",
|
||||
self.layers.len()
|
||||
);
|
||||
|
||||
let layers = Box::leak(self.layers.into_boxed_slice());
|
||||
for (i, layer) in layers.iter().enumerate() {
|
||||
if layer.buttons.len() != SWITCH_COUNT {
|
||||
@ -43,7 +50,10 @@ impl KeyboardConfig {
|
||||
}
|
||||
}
|
||||
|
||||
const MOD_TAP_TIME: Duration = Duration::from_millis(100);
|
||||
const SWITCH_COUNT: usize = 18;
|
||||
|
||||
/// Task for monitoring a single switch pin, and handling button presses.
|
||||
#[embassy_executor::task(pool_size = 18)]
|
||||
async fn switch_task(switch_num: usize, pin: AnyPin, layers: &'static [Layer]) -> ! {
|
||||
let _pin_nr = pin.pin();
|
||||
@ -51,27 +61,39 @@ async fn switch_task(switch_num: usize, pin: AnyPin, layers: &'static [Layer]) -
|
||||
loop {
|
||||
// pins are pull-up, so when the switch is pressed they are brought low.
|
||||
pin.wait_for_low().await;
|
||||
|
||||
// TODO: do we need debouncing?
|
||||
|
||||
// get current layer
|
||||
let mut current_layer = CURRENT_LAYER.load(Ordering::Relaxed);
|
||||
let layer_count = layers.len() as u16;
|
||||
if current_layer >= layer_count {
|
||||
error!("current layer was out of bounds for some reason ({current_layer})");
|
||||
current_layer = 0;
|
||||
}
|
||||
|
||||
let Some(Layer { buttons }) = layers.get(usize::from(current_layer)) else {
|
||||
error!("current layer was out of bounds for some reason ({current_layer})");
|
||||
CURRENT_LAYER.store(0, Ordering::Relaxed);
|
||||
continue;
|
||||
};
|
||||
|
||||
// and current button
|
||||
let Some(button) = buttons.get(switch_num) else {
|
||||
warn!("no button defined for switch {switch_num}");
|
||||
continue;
|
||||
};
|
||||
|
||||
debug!("switch {switch_num} button {button:?} pressed");
|
||||
|
||||
let wait_for_release = async {
|
||||
pin.wait_for_high().await;
|
||||
debug!("switch {switch_num} button {button:?} released");
|
||||
};
|
||||
|
||||
match button {
|
||||
&Button::Key(key) => {
|
||||
KB_REPORT.lock().await.press_key(key);
|
||||
pin.wait_for_high().await;
|
||||
wait_for_release.await;
|
||||
KB_REPORT.lock().await.release_key(key);
|
||||
continue;
|
||||
}
|
||||
@ -83,7 +105,19 @@ async fn switch_task(switch_num: usize, pin: AnyPin, layers: &'static [Layer]) -
|
||||
//continue;
|
||||
}
|
||||
Button::ModTap { keycode, modifier } => {
|
||||
// TODO
|
||||
select_biased! {
|
||||
_ = Timer::after(MOD_TAP_TIME).fuse() => {
|
||||
// TODO: Modifier
|
||||
pin.wait_for_high().await;
|
||||
continue;
|
||||
}
|
||||
_ = wait_for_release.fuse() => {
|
||||
KB_REPORT.lock().await.press_key(*keycode);
|
||||
Timer::after(Duration::from_millis(10)).await;
|
||||
KB_REPORT.lock().await.release_key(*keycode);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Button::NextLayer => {
|
||||
let next_layer = (current_layer + 1) % layer_count;
|
||||
@ -96,7 +130,7 @@ async fn switch_task(switch_num: usize, pin: AnyPin, layers: &'static [Layer]) -
|
||||
Button::None => {}
|
||||
}
|
||||
|
||||
pin.wait_for_high().await;
|
||||
wait_for_release.await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
13
src/lib.rs
Normal file
13
src/lib.rs
Normal file
@ -0,0 +1,13 @@
|
||||
#![no_std]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod allocator;
|
||||
pub mod board;
|
||||
pub mod keyboard;
|
||||
pub mod neopixel;
|
||||
pub mod panic_handler;
|
||||
pub mod usb;
|
||||
pub mod util;
|
||||
pub mod ws2812;
|
||||
166
src/main.rs
166
src/main.rs
@ -1,166 +0,0 @@
|
||||
//! # GPIO 'Blinky' Example
|
||||
//!
|
||||
//! Blinks the LED on a Adafruit itsy-bitsy RP2040 board
|
||||
//!
|
||||
//! It may need to be adapted to your particular board layout and/or pin assignment.
|
||||
//!
|
||||
//! See the `Cargo.toml` file for Copyright and license details.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate cortex_m_rt;
|
||||
|
||||
mod allocator;
|
||||
mod board;
|
||||
mod keyboard;
|
||||
mod neopixel;
|
||||
mod panic_handler;
|
||||
mod usb;
|
||||
mod util;
|
||||
mod ws2812;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use board::Board;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::gpio::{Level, Output, Pin};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use tgnt::layer::Layer;
|
||||
use ws2812::Rgb;
|
||||
|
||||
use crate::keyboard::KeyboardConfig;
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
allocator::init();
|
||||
|
||||
let p = embassy_rp::init(Default::default());
|
||||
|
||||
let board = Board {
|
||||
a0: p.PIN_26,
|
||||
a1: p.PIN_27,
|
||||
a2: p.PIN_28,
|
||||
a3: p.PIN_29,
|
||||
d24: p.PIN_24,
|
||||
d25: p.PIN_25,
|
||||
sck: p.PIN_18,
|
||||
mosi: p.PIN_19,
|
||||
miso: p.PIN_20,
|
||||
d2: p.PIN_12,
|
||||
d3: p.PIN_5,
|
||||
d4: p.PIN_4,
|
||||
rx: p.PIN_1,
|
||||
tx: p.PIN_0,
|
||||
sda: p.PIN_2,
|
||||
scl: p.PIN_3,
|
||||
d5: p.PIN_14,
|
||||
d7: p.PIN_6,
|
||||
d9: p.PIN_7,
|
||||
d10: p.PIN_8,
|
||||
d11: p.PIN_9,
|
||||
d12: p.PIN_10,
|
||||
d13: p.PIN_11,
|
||||
neopixel: p.PIN_17,
|
||||
neopixel_power: p.PIN_16,
|
||||
};
|
||||
|
||||
//let mut led = Output::new(board.d13, Level::Low);
|
||||
let _neopixel_power = Output::new(board.neopixel_power, Level::High);
|
||||
|
||||
let mut neopixel = ws2812::Ws2812::new(p.PIO0, p.DMA_CH0, board.neopixel.degrade());
|
||||
let mut neopixels_d5 = ws2812::Ws2812::new(p.PIO1, p.DMA_CH1, board.d5.degrade());
|
||||
|
||||
neopixel.write(&[Rgb::new(0xb7, 0x31, 0x2c)]).await;
|
||||
|
||||
let mut builder = usb::builder(p.USB);
|
||||
|
||||
usb::logger::setup(&mut builder).await;
|
||||
|
||||
neopixel.write(&[Rgb::new(0xf0, 0xd0, 0x20)]).await;
|
||||
|
||||
log::error!("log_level: error");
|
||||
log::warn!("log_level: warn");
|
||||
log::info!("log_level: info");
|
||||
log::debug!("log_level: debug");
|
||||
log::trace!("log_level: trace");
|
||||
|
||||
usb::keyboard::setup(&mut builder).await;
|
||||
|
||||
let usb = builder.build();
|
||||
|
||||
spawner.must_spawn(usb::run(usb));
|
||||
|
||||
Timer::after(Duration::from_millis(3000)).await;
|
||||
|
||||
let layers = include_bytes!("layers.pc");
|
||||
let Ok(layers): Result<Vec<Layer>, _> = postcard::from_bytes(layers) else {
|
||||
log::error!("Failed to deserialize layer config");
|
||||
loop_forever().await
|
||||
};
|
||||
|
||||
let keyboard = KeyboardConfig {
|
||||
layers,
|
||||
pins: [
|
||||
// row 1
|
||||
board.d24.degrade(),
|
||||
board.a3.degrade(),
|
||||
board.a2.degrade(),
|
||||
board.a1.degrade(),
|
||||
board.a0.degrade(),
|
||||
// row 2
|
||||
board.d25.degrade(),
|
||||
board.sck.degrade(),
|
||||
board.mosi.degrade(),
|
||||
board.miso.degrade(),
|
||||
board.d2.degrade(),
|
||||
// row 3
|
||||
board.d12.degrade(),
|
||||
board.d11.degrade(),
|
||||
board.d10.degrade(),
|
||||
board.d9.degrade(),
|
||||
board.d3.degrade(),
|
||||
// thumbpad
|
||||
board.d7.degrade(),
|
||||
board.scl.degrade(),
|
||||
board.sda.degrade(),
|
||||
],
|
||||
};
|
||||
|
||||
keyboard.create().await;
|
||||
|
||||
for w in 0usize.. {
|
||||
neopixel.write(&[wheel(w as u8)]).await;
|
||||
neopixels_d5
|
||||
.write(&[
|
||||
wheel((w + 50) as u8),
|
||||
wheel((w + 100) as u8),
|
||||
wheel((w + 150) as u8),
|
||||
wheel((w + 200) as u8),
|
||||
])
|
||||
.await;
|
||||
Timer::after(Duration::from_millis(10)).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn loop_forever() -> ! {
|
||||
loop {
|
||||
Timer::after(Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Input a value 0 to 255 to get a color value
|
||||
// The colours are a transition r - g - b - back to r.
|
||||
fn wheel(mut wheel_pos: u8) -> Rgb {
|
||||
wheel_pos = 255 - wheel_pos;
|
||||
if wheel_pos < 85 {
|
||||
return Rgb::new(255 - wheel_pos * 3, 0, wheel_pos * 3);
|
||||
}
|
||||
if wheel_pos < 170 {
|
||||
wheel_pos -= 85;
|
||||
return Rgb::new(0, wheel_pos * 3, 255 - wheel_pos * 3);
|
||||
}
|
||||
wheel_pos -= 170;
|
||||
Rgb::new(wheel_pos * 3, 255 - wheel_pos * 3, 0)
|
||||
}
|
||||
16
src/usb.rs
16
src/usb.rs
@ -1,3 +1,4 @@
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::{interrupt, peripherals::USB, usb::Driver};
|
||||
use embassy_usb::{Builder, Config, UsbDevice};
|
||||
use static_cell::StaticCell;
|
||||
@ -16,6 +17,21 @@ struct State {
|
||||
|
||||
static STATE: StaticCell<State> = StaticCell::new();
|
||||
|
||||
pub async fn setup_logger_and_keyboard(usb: USB) {
|
||||
let mut builder = builder(usb);
|
||||
logger::setup(&mut builder).await;
|
||||
|
||||
log::error!("log_level: error");
|
||||
log::warn!("log_level: warn");
|
||||
log::info!("log_level: info");
|
||||
log::debug!("log_level: debug");
|
||||
log::trace!("log_level: trace");
|
||||
|
||||
keyboard::setup(&mut builder).await;
|
||||
let usb = builder.build();
|
||||
Spawner::for_current_executor().await.must_spawn(run(usb));
|
||||
}
|
||||
|
||||
pub fn builder(usb: USB) -> Builder<'static, Driver<'static, USB>> {
|
||||
let state = STATE.init(State {
|
||||
device_descriptor: [0; 256],
|
||||
|
||||
@ -99,7 +99,7 @@ async fn keyboard_test(mut stream: HidStream, _handler: &'static Handler) -> Res
|
||||
|
||||
let report = KB_REPORT.lock().await.clone();
|
||||
if report.keycodes != EMPTY_KEYBOARD_REPORT.keycodes {
|
||||
log::debug!("keys: {:x?}", report.keycodes);
|
||||
log::trace!("keys: {:x?}", report.keycodes);
|
||||
}
|
||||
|
||||
#[cfg(feature = "n-key-rollover")]
|
||||
|
||||
@ -36,7 +36,6 @@ pub const EMPTY_KEYBOARD_REPORT: KeyboardReport = KeyboardReport {
|
||||
impl KeyboardReport {
|
||||
pub fn set_key(&mut self, key: Key, pressed: bool) {
|
||||
let keycode = u8::from(key);
|
||||
log::debug!("setting key: {key:?} ({keycode:x})");
|
||||
let byte = keycode >> 3;
|
||||
let bit = keycode & 0b111;
|
||||
let mask = 1 << bit;
|
||||
@ -48,7 +47,7 @@ impl KeyboardReport {
|
||||
*k &= !mask;
|
||||
}
|
||||
} else {
|
||||
log::warn!("Tried to set out-of-range keycode: {keycode:x}");
|
||||
log::warn!("Tried to set out-of-range keycode: 0x{keycode:x}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
24
src/util.rs
24
src/util.rs
@ -1,3 +1,27 @@
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_time::{Duration, Timer};
|
||||
|
||||
use crate::ws2812::Rgb;
|
||||
|
||||
pub type CS = CriticalSectionRawMutex;
|
||||
|
||||
pub async fn stall() -> ! {
|
||||
loop {
|
||||
Timer::after(Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Input a value 0 to 255 to get a color value
|
||||
// The colours are a transition r - g - b - back to r.
|
||||
pub fn wheel(mut wheel_pos: u8) -> Rgb {
|
||||
wheel_pos = 255 - wheel_pos;
|
||||
if wheel_pos < 85 {
|
||||
return Rgb::new(255 - wheel_pos * 3, 0, wheel_pos * 3);
|
||||
}
|
||||
if wheel_pos < 170 {
|
||||
wheel_pos -= 85;
|
||||
return Rgb::new(0, wheel_pos * 3, 255 - wheel_pos * 3);
|
||||
}
|
||||
wheel_pos -= 170;
|
||||
Rgb::new(wheel_pos * 3, 255 - wheel_pos * 3, 0)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user