This commit is contained in:
2023-06-12 17:39:07 +02:00
parent 59f91e2f6b
commit 9854e0c0a8
45 changed files with 4708 additions and 400 deletions

1798
left/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

29
left/Cargo.toml Normal file
View File

@ -0,0 +1,29 @@
[package]
name = "tangentbord1-left"
version = "0.1.0"
authors = ["Joakim Hulthe <joakim@hulthe.net>"]
description = "Keyboard firmware"
edition = "2021"
[dependencies.tangentbord1]
path = "../lib"
package = "tangentbord1-lib"
[dependencies]
tgnt = { git = "https://git.nubo.sh/hulthe/tgnt.git", default-features = false }
cortex-m-rt = "0.7"
embassy-rp = { git = "https://github.com/embassy-rs/embassy.git", features = ["log", "nightly", "unstable-traits", "unstable-pac", "time-driver", "critical-section-impl"] }
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", features = ["arch-cortex-m", "log", "executor-thread", "nightly", "integrated-timers" ] }
embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", features = ["log", "nightly"] }
embassy-time = { git = "https://github.com/embassy-rs/embassy.git", features = ["log"] }
embassy-futures = { git = "https://github.com/embassy-rs/embassy.git", features = ["log"] }
log = "0.4.17"
postcard = { version = "1.0.4", features = ["alloc"] }
[patch."https://git.nubo.sh/hulthe/tgnt.git"]
tgnt = { path = "../../tgnt" }
[build-dependencies]
tgnt = { git = "https://git.nubo.sh/hulthe/tgnt.git", default-features = false }
ron = "0.8.0"
postcard = { version = "1", features = ["use-std"] }

59
left/build.rs Normal file
View File

@ -0,0 +1,59 @@
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory -- wherever `Cargo.toml` is. However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! updating `memory.x` ensures a rebuild of the application with the
//! new memory settings.
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::{env, fs};
use tgnt::layer::Layer;
fn main() {
memory();
serialize_layout("./layers.ron", "./src/layers.pc");
}
fn memory() {
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("../memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=../memory.x");
// --nmagic turns off page alignment of sections (which saves flash space)
println!("cargo:rustc-link-arg-bins=--nmagic");
println!("cargo:rustc-link-arg-bins=-Tlink.x");
println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
//println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
}
fn serialize_layout(ron_path: &str, postcard_path: &str) {
println!("cargo:rerun-if-changed={ron_path}");
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(postcard_path)
.expect("Failed to create .pc")
.write_all(&serialized)
.expect("Failed to write .pc");
}

89
left/layers.ron Normal file
View File

@ -0,0 +1,89 @@
[
Layer(
buttons: [
// Row 1
Key(Escape),
Key(Comma),
Key(Period),
Key(P),
Key(Y),
// Row 2
ModTap(A, LMod),
ModTap(O, LAlt),
ModTap(E, LShift),
ModTap(U, LCtrl),
Key(I),
// Row 3
Key(Colon),
Key(Q),
Key(J),
Key(K),
Key(X),
// Thumbpad
Key(Backspace),
Key(Space),
HoldLayer(1),
],
),
Layer(
buttons: [
// Row 1
Key(Escape),
Key(Slash),
Key(Equal),
Key(Accent),
Key(Period),
// Row 2
ModTap(BackslashPipe, LMod),
ModTap(Dash, LAlt),
ModTap(LBracket, LShift),
ModTap(RBracket, LCtrl),
Key(Tab),
// Row 3
None,
None,
None,
Key(Apostrophe),
None,
// Thumbpad
Key(Backspace),
Key(Space),
HoldLayer(1),
],
),
Layer(
buttons: [
// Row 1
Key(Escape),
Key(Mute),
Key(VolumeDown),
Key(VolumeUp),
None,
// Row 2
Mod(LMod),
Mod(LAlt),
Mod(LShift),
Mod(LCtrl),
None,
// Row 3
None,
None,
None,
None,
None,
// Thumbpad
Key(Backspace),
Key(Space),
HoldLayer(1),
],
),
]

BIN
left/src/layers.pc Normal file

Binary file not shown.

111
left/src/main.rs Normal file
View File

@ -0,0 +1,111 @@
//! Firmware for Tangentbord1, left half.
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
#![cfg(target_arch = "arm")]
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 log::error;
use tangentbord1::{
board::Board,
event::Half,
keyboard::KeyboardConfig,
logger::Logger,
rgb::Rgb,
util::{stall, wheel},
ws2812::Ws2812,
{allocator, rtt, uart, usb},
};
use tgnt::layer::Layer;
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let half = Half::Left;
let rtt_write = rtt::init_rtt_logger();
let logger = Logger {
outputs: [rtt_write],
};
logger.init();
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");
allocator::init();
let p = embassy_rp::init(Default::default());
let board = Board::from(p);
let _neopixel_power = Output::new(board.neopixel_power, Level::High);
let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel);
let neopixels_d5 = Ws2812::new(board.PIO1, board.DMA_CH1, board.d5);
neopixel.write(&[Rgb::new(0xFF, 0x00, 0x00)]).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");
stall().await
};
let keyboard = KeyboardConfig {
half,
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(),
],
// the index of the LEDs is different than the switch index.
// each number is the index of the LED for the switch of that index.
led_map: [4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 14, 13, 12, 11, 10, 15, 16, 17],
led_driver: neopixels_d5,
layers,
};
let Some([events1, events2]) = keyboard.create().await else {
error!("failed to create keyboard");
return;
};
uart::start(board.tx, board.rx, board.UART0, half, events2).await;
neopixel.write(&[Rgb::new(0x00, 0x99, 0x99)]).await;
usb::setup_logger_and_keyboard(board.USB, events1).await;
neopixel.write(&[Rgb::new(0x00, 0x00, 0xFF)]).await;
for w in 0usize.. {
neopixel.write(&[wheel(w as u8)]).await;
Timer::after(Duration::from_millis(10)).await;
}
}