Split firmware inte left.rs and right.rs.

This commit is contained in:
2023-03-18 00:58:42 +01:00
parent 5c154141d0
commit 4d02d0825a
19 changed files with 416 additions and 245 deletions

View File

@ -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

Binary file not shown.

BIN
src/bin/layers-right.pc Normal file

Binary file not shown.

88
src/bin/left.rs Normal file
View 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
View 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;
}
}

View File

@ -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,
}
}
}

View File

@ -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
View 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;

View File

@ -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)
}

View File

@ -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],

View File

@ -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")]

View File

@ -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}");
}
}

View File

@ -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)
}