Alternative RMK firmware
This commit is contained in:
parent
b3216575fd
commit
4a3a6db684
19
firmware2/.cargo/config.toml
Normal file
19
firmware2/.cargo/config.toml
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
[target.'cfg(all(any(target_arch = "riscv32", target_arch = "xtensa"), target_os = "none"))']
|
||||||
|
runner = "espflash flash --monitor"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
target = "xtensa-esp32s3-none-elf"
|
||||||
|
rustflags = [
|
||||||
|
# Required to obtain backtraces (e.g. when using the "esp-backtrace" crate.)
|
||||||
|
# NOTE: May negatively impact performance of produced code
|
||||||
|
"-C", "force-frame-pointers",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[env]
|
||||||
|
ESP_LOG = "info"
|
||||||
|
|
||||||
|
# Xtensa only:
|
||||||
|
# Needed for nightly, until llvm upstream has support for Rust Xtensa.
|
||||||
|
[unstable]
|
||||||
|
build-std = ["alloc", "core"]
|
||||||
3199
firmware2/Cargo.lock
generated
Normal file
3199
firmware2/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
73
firmware2/Cargo.toml
Normal file
73
firmware2/Cargo.toml
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
[package]
|
||||||
|
name = "acid-firmware"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ['Jakub "Limeth" Hlusička']
|
||||||
|
description = "Firmware for the ACID keyboard"
|
||||||
|
homepage = "https://github.com/haobogu/rmk"
|
||||||
|
repository = "https://github.com/haobogu/rmk"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
no_usb = ["rmk/_no_usb"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rmk = { version = "0.8.2", default-features = false, features = [
|
||||||
|
"esp32s3_ble",
|
||||||
|
"log",
|
||||||
|
"storage",
|
||||||
|
"vial",
|
||||||
|
] }
|
||||||
|
embassy-executor = { version = "0.9" }
|
||||||
|
esp-backtrace = { version = "0.18", features = [
|
||||||
|
"esp32s3",
|
||||||
|
"panic-handler",
|
||||||
|
"println",
|
||||||
|
] }
|
||||||
|
esp-hal = { version = "1.0", features = ["esp32s3", "unstable", "psram"] }
|
||||||
|
esp-storage = { version = "0.8.0", features = ["esp32s3"] }
|
||||||
|
esp-alloc = { version = "0.9.0" }
|
||||||
|
esp-println = { version = "0.16.0", features = ["esp32s3", "log-04"] }
|
||||||
|
esp-radio = { version = "0.17", features = ["esp32s3", "unstable", "ble"] }
|
||||||
|
esp-rtos = { version = "0.2", features = ["esp32s3", "esp-radio", "embassy"] }
|
||||||
|
esp-bootloader-esp-idf = { version = "0.4", features = ["esp32s3", "log-04"] }
|
||||||
|
bt-hci = { version = "0.6" }
|
||||||
|
rand_core = { version = "0.6", default-features = false }
|
||||||
|
static_cell = "2"
|
||||||
|
lazy_static = { version = "1.5.0", features = ["spin_no_std"], default-features = false }
|
||||||
|
log = "0.4.29"
|
||||||
|
bitflags = "2.10.0"
|
||||||
|
paste = "1.0.15"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
xz2 = "0.1.7"
|
||||||
|
json = "0.12"
|
||||||
|
const-gen = "1.6"
|
||||||
|
embuild = "0.33"
|
||||||
|
cc = "1.2.9"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "acid-firmware"
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
|
|
||||||
|
[profile.release-with-debug]
|
||||||
|
inherits = "release"
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
[profile.dev.package.esp-storage]
|
||||||
|
opt-level = 3
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
# Rust debug is too slow.
|
||||||
|
# For debug builds always builds with some optimization
|
||||||
|
opt-level = "s"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
codegen-units = 1 # LLVM can perform better optimizations using a single thread
|
||||||
|
debug = 2
|
||||||
|
debug-assertions = false
|
||||||
|
incremental = false
|
||||||
|
lto = 'thin'
|
||||||
|
opt-level = 3
|
||||||
|
overflow-checks = false
|
||||||
|
|
||||||
65
firmware2/README.md
Normal file
65
firmware2/README.md
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# esp32s3 BLE example
|
||||||
|
|
||||||
|
To run this example, you should have latest Rust in **esp** channel installed. The full instruction of installing esp Rust toolchain can be found [here](https://docs.esp-rs.org/book/installation/index.html).
|
||||||
|
|
||||||
|
[`espflash`](https://github.com/esp-rs/espflash) should also be installed:
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo install cargo-espflash espflash
|
||||||
|
```
|
||||||
|
|
||||||
|
After having everything installed, use the following command to run the example:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd examples/use_rust/esp32s3_ble
|
||||||
|
cargo +esp run --release
|
||||||
|
```
|
||||||
|
|
||||||
|
If everything is good, you'll see the log as the following:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo run --release
|
||||||
|
Compiling ...
|
||||||
|
...
|
||||||
|
...
|
||||||
|
Finished `release` profile [optimized + debuginfo] target(s) in 11.70s
|
||||||
|
Running `espflash flash --monitor --port /dev/cu.usbmodem211401 target/xtensa-esp32s3-none-elf/release/rmk-esp32s3`
|
||||||
|
[2025-04-10T10:01:23Z INFO ] Serial port: '/dev/cu.usbmodem211401'
|
||||||
|
[2025-04-10T10:01:23Z INFO ] Connecting...
|
||||||
|
[2025-04-10T10:01:23Z INFO ] Using flash stub
|
||||||
|
Chip type: esp32s3 (revision v0.1)
|
||||||
|
Crystal frequency: 40 MHz
|
||||||
|
Flash size: 4MB
|
||||||
|
Features: WiFi 6, BT 5
|
||||||
|
MAC address: 40:4c:ca:5b:c7:dc
|
||||||
|
App/part. size: 768,944/4,128,768 bytes, 18.62%
|
||||||
|
[2025-04-10T10:01:23Z INFO ] Segment at address '0x0' has not changed, skipping write
|
||||||
|
[2025-04-10T10:01:23Z INFO ] Segment at address '0x8000' has not changed, skipping write
|
||||||
|
[00:00:06] [========================================] 411/411 0x10000 [2025-04-10T10:01:31Z INFO ] Flashing has completed!
|
||||||
|
```
|
||||||
|
|
||||||
|
If espflash reports the following error:
|
||||||
|
|
||||||
|
```
|
||||||
|
Error: espflash::connection_failed
|
||||||
|
|
||||||
|
× Error while connecting to device
|
||||||
|
╰─▶ Serial port not found
|
||||||
|
```
|
||||||
|
|
||||||
|
You should to identify which serial port are connected to your esp board, and use `--port` to specify the used serial port:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Suppose that the esp board are connected to /dev/cu.usbmodem211401
|
||||||
|
cargo run --release -- --port /dev/cu.usbmodem211401
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to get some insight of segments of your binary, [`espsegs`](https://github.com/bjoernQ/espsegs) would help:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Install it first
|
||||||
|
cargo install --git https://github.com/bjoernQ/espsegs
|
||||||
|
|
||||||
|
# Check all segments
|
||||||
|
espsegs target/xtensa-esp32s3-none-elf/release/rmk-esp32s3 --chip esp32s3
|
||||||
|
```
|
||||||
47
firmware2/build.rs
Normal file
47
firmware2/build.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
|
use const_gen::*;
|
||||||
|
use xz2::read::XzEncoder;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Generate vial config at the root of project
|
||||||
|
println!("cargo:rerun-if-changed=vial.json");
|
||||||
|
generate_vial_config();
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-arg-bins=-Tlinkall.x");
|
||||||
|
|
||||||
|
// Set the extra linker script from defmt
|
||||||
|
// println!("cargo:rustc-link-arg=-Tdefmt.x");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_vial_config() {
|
||||||
|
// Generated vial config file
|
||||||
|
let out_file = Path::new(&env::var_os("OUT_DIR").unwrap()).join("config_generated.rs");
|
||||||
|
|
||||||
|
let p = Path::new("vial.json");
|
||||||
|
let mut content = String::new();
|
||||||
|
match File::open(p) {
|
||||||
|
Ok(mut file) => {
|
||||||
|
file.read_to_string(&mut content).expect("Cannot read vial.json");
|
||||||
|
}
|
||||||
|
Err(e) => println!("Cannot find vial.json {p:?}: {e}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let vial_cfg = json::stringify(json::parse(&content).unwrap());
|
||||||
|
let mut keyboard_def_compressed: Vec<u8> = Vec::new();
|
||||||
|
XzEncoder::new(vial_cfg.as_bytes(), 6)
|
||||||
|
.read_to_end(&mut keyboard_def_compressed)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let keyboard_id: Vec<u8> = vec![0xB9, 0xBC, 0x09, 0xB2, 0x9D, 0x37, 0x4C, 0xEA];
|
||||||
|
let const_declarations = [
|
||||||
|
const_declaration!(pub VIAL_KEYBOARD_DEF = keyboard_def_compressed),
|
||||||
|
const_declaration!(pub VIAL_KEYBOARD_ID = keyboard_id),
|
||||||
|
]
|
||||||
|
.map(|s| "#[allow(clippy::redundant_static_lifetimes)]\n".to_owned() + s.as_str())
|
||||||
|
.join("\n");
|
||||||
|
fs::write(out_file, const_declarations).unwrap();
|
||||||
|
}
|
||||||
2
firmware2/rust-toolchain.toml
Normal file
2
firmware2/rust-toolchain.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "esp"
|
||||||
19
firmware2/src/keymap.rs
Normal file
19
firmware2/src/keymap.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
use rmk::types::action::KeyAction;
|
||||||
|
use rmk::{a, k, layer, mo};
|
||||||
|
|
||||||
|
use crate::matrix::{MATRIX_COLS, MATRIX_ROWS};
|
||||||
|
|
||||||
|
pub const NUM_LAYER: usize = 1;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub const fn get_default_keymap() -> [[[KeyAction; MATRIX_COLS]; MATRIX_ROWS]; NUM_LAYER] {
|
||||||
|
[
|
||||||
|
layer!([
|
||||||
|
[k!(Escape), k!(Kc1), k!(Kc2), k!(Kc3), k!(Kc4), k!(Kc5), k!(Kc6), k!(Kc7), k!(Kc8), k!(Kc9), k!(Kc0), k!(Backspace)],
|
||||||
|
[k!(Tab), k!(Q), k!(W), k!(E), k!(R), k!(T), k!(Z), k!(U), k!(I), k!(O), k!(P), k!(Delete)],
|
||||||
|
[k!(LCtrl), k!(A), k!(S), k!(D), k!(F), k!(G), k!(H), k!(J), k!(K), k!(L), k!(Comma), k!(Enter)],
|
||||||
|
[k!(LShift), k!(Y), k!(X), k!(C), k!(V), k!(B), k!(N), k!(M), a!(No), a!(No), k!(Up), k!(RShift)],
|
||||||
|
[a!(No), a!(No), k!(LGui), k!(LAlt), k!(TriLayerLower), k!(Space), k!(Space), k!(TriLayerLower), k!(RAlt), k!(Left), k!(Down), k!(Right)]
|
||||||
|
])
|
||||||
|
]
|
||||||
|
}
|
||||||
472
firmware2/src/lcd.rs
Normal file
472
firmware2/src/lcd.rs
Normal file
|
|
@ -0,0 +1,472 @@
|
||||||
|
use alloc::{boxed::Box, vec, vec::Vec};
|
||||||
|
use core::iter::once;
|
||||||
|
use esp_hal::{
|
||||||
|
delay::Delay,
|
||||||
|
gpio::{Flex, Level, Output},
|
||||||
|
};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use crate::st7701s::Command;
|
||||||
|
|
||||||
|
fn spi_delay() {
|
||||||
|
Delay::new().delay_micros(1); // TODO: Async?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spi_dummy_bit(sck: &mut Output) {
|
||||||
|
sck.set_low();
|
||||||
|
spi_delay();
|
||||||
|
sck.set_high();
|
||||||
|
spi_delay();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spi_write_bit(bit: bool, mosi: &mut Flex, sck: &mut Output) {
|
||||||
|
mosi.set_level(if bit { Level::High } else { Level::Low });
|
||||||
|
sck.set_low();
|
||||||
|
spi_delay();
|
||||||
|
sck.set_high();
|
||||||
|
spi_delay();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spi_read_bit(mosi: &mut Flex, sck: &mut Output) -> bool {
|
||||||
|
sck.set_low();
|
||||||
|
spi_delay();
|
||||||
|
sck.set_high();
|
||||||
|
spi_delay();
|
||||||
|
mosi.is_high()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spi_write_bits(bits: impl Iterator<Item = bool>, mosi: &mut Flex, sck: &mut Output) {
|
||||||
|
for bit in bits {
|
||||||
|
spi_write_bit(bit, mosi, sck);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spi_write_word(is_param: bool, data: u8, mosi: &mut Flex, sck: &mut Output) {
|
||||||
|
assert!(sck.is_set_high());
|
||||||
|
spi_write_bits(
|
||||||
|
once(is_param).chain((0..8).map(|i| (data >> i) & 1 != 0).rev()),
|
||||||
|
mosi,
|
||||||
|
sck,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spi_write(
|
||||||
|
command: u8,
|
||||||
|
args: impl IntoIterator<Item = u8>,
|
||||||
|
mosi: &mut Flex,
|
||||||
|
sck: &mut Output,
|
||||||
|
cs: &mut Output,
|
||||||
|
) {
|
||||||
|
cs.set_low();
|
||||||
|
spi_write_word(false, command, mosi, sck);
|
||||||
|
|
||||||
|
for arg in args {
|
||||||
|
spi_write_word(true, arg, mosi, sck);
|
||||||
|
}
|
||||||
|
|
||||||
|
cs.set_high();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spi_read(
|
||||||
|
command: u8,
|
||||||
|
dummy_cycle: bool,
|
||||||
|
mosi: &mut Flex,
|
||||||
|
sck: &mut Output,
|
||||||
|
cs: &mut Output,
|
||||||
|
output_buffer: &mut [u8],
|
||||||
|
) {
|
||||||
|
output_buffer.fill(0);
|
||||||
|
|
||||||
|
cs.set_low();
|
||||||
|
spi_write_word(false, command, mosi, sck);
|
||||||
|
|
||||||
|
mosi.set_output_enable(false);
|
||||||
|
mosi.set_input_enable(true);
|
||||||
|
|
||||||
|
if dummy_cycle {
|
||||||
|
spi_dummy_bit(sck);
|
||||||
|
}
|
||||||
|
|
||||||
|
for output_byte in output_buffer {
|
||||||
|
for i in (0..8).rev() {
|
||||||
|
if spi_read_bit(mosi, sck) {
|
||||||
|
*output_byte |= 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mosi.set_input_enable(false);
|
||||||
|
mosi.set_output_enable(true);
|
||||||
|
|
||||||
|
cs.set_high();
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::st7701s::*;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref INIT_SEQUENCE_COMMANDS: Vec<(Vec<Box<dyn Command + Send + Sync>>, u64)> = vec![
|
||||||
|
(vec![
|
||||||
|
Box::new(CmdCn2bkxsel(
|
||||||
|
CmdCn2bkxselArg0::new(),
|
||||||
|
CmdCn2bkxselArg1::new(),
|
||||||
|
CmdCn2bkxselArg2::new(),
|
||||||
|
CmdCn2bkxselArg3::new(),
|
||||||
|
CmdCn2bkxselArg4::new().with_bksel(0x3).with_cn2(true),
|
||||||
|
)),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xEF,
|
||||||
|
args: &[0x08],
|
||||||
|
}),
|
||||||
|
Box::new(CmdCn2bkxsel(
|
||||||
|
CmdCn2bkxselArg0::new(),
|
||||||
|
CmdCn2bkxselArg1::new(),
|
||||||
|
CmdCn2bkxselArg2::new(),
|
||||||
|
CmdCn2bkxselArg3::new(),
|
||||||
|
CmdCn2bkxselArg4::new().with_bksel(0x0).with_cn2(true),
|
||||||
|
)),
|
||||||
|
Box::new(CmdLneset(
|
||||||
|
CmdLnesetArg0::new().with_bar(119).with_lde_en(false),
|
||||||
|
CmdLnesetArg1::new().with_line_delta(0),
|
||||||
|
)),
|
||||||
|
Box::new(CmdPorctrl(
|
||||||
|
CmdPorctrlArg0::new().with_vbp(17),
|
||||||
|
CmdPorctrlArg1::new().with_vfp(12),
|
||||||
|
)),
|
||||||
|
Box::new(CmdInvsel(
|
||||||
|
CmdInvselArg0::new().with_nlinv(0b111),
|
||||||
|
CmdInvselArg1::new().with_rtni(2),
|
||||||
|
)),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xCC,
|
||||||
|
args: &[0x30],
|
||||||
|
}),
|
||||||
|
Box::new(CmdPvgamctrl(
|
||||||
|
CmdPvgamctrlArg0::new().with_vc0p(6).with_aj0p(0),
|
||||||
|
CmdPvgamctrlArg1::new().with_vc4p(15).with_aj1p(3),
|
||||||
|
CmdPvgamctrlArg2::new().with_vc8p(14).with_aj2p(0),
|
||||||
|
CmdPvgamctrlArg3::new().with_vc16p(12),
|
||||||
|
CmdPvgamctrlArg4::new().with_vc24p(15).with_aj3p(0),
|
||||||
|
CmdPvgamctrlArg5::new().with_vc52p(3),
|
||||||
|
CmdPvgamctrlArg6::new().with_vc80p(0),
|
||||||
|
CmdPvgamctrlArg7::new().with_vc108p(10),
|
||||||
|
CmdPvgamctrlArg8::new().with_vc147p(7),
|
||||||
|
CmdPvgamctrlArg9::new().with_vc175p(27),
|
||||||
|
CmdPvgamctrlArg10::new().with_vc203p(3),
|
||||||
|
CmdPvgamctrlArg11::new().with_vc231p(18).with_aj4p(0),
|
||||||
|
CmdPvgamctrlArg12::new().with_vc239p(16),
|
||||||
|
CmdPvgamctrlArg13::new().with_vc247p(37).with_aj5p(0),
|
||||||
|
CmdPvgamctrlArg14::new().with_vc251p(54).with_aj6p(0),
|
||||||
|
CmdPvgamctrlArg15::new().with_vc255p(30).with_aj7p(0),
|
||||||
|
)),
|
||||||
|
Box::new(CmdNvgamctrl(
|
||||||
|
CmdNvgamctrlArg0::new().with_vc0n(12).with_aj0n(0),
|
||||||
|
CmdNvgamctrlArg1::new().with_vc4n(14).with_aj1n(3),
|
||||||
|
CmdNvgamctrlArg2::new().with_vc8n(18).with_aj2n(0),
|
||||||
|
CmdNvgamctrlArg3::new().with_vc16n(12),
|
||||||
|
CmdNvgamctrlArg4::new().with_vc24n(14).with_aj3n(0),
|
||||||
|
CmdNvgamctrlArg5::new().with_vc52n(6),
|
||||||
|
CmdNvgamctrlArg6::new().with_vc80n(3),
|
||||||
|
CmdNvgamctrlArg7::new().with_vc108n(6),
|
||||||
|
CmdNvgamctrlArg8::new().with_vc147n(8),
|
||||||
|
CmdNvgamctrlArg9::new().with_vc175n(35),
|
||||||
|
CmdNvgamctrlArg10::new().with_vc203n(6),
|
||||||
|
CmdNvgamctrlArg11::new().with_vc231n(18).with_aj4n(0),
|
||||||
|
CmdNvgamctrlArg12::new().with_vc239n(16),
|
||||||
|
CmdNvgamctrlArg13::new().with_vc247n(48).with_aj5n(0),
|
||||||
|
CmdNvgamctrlArg14::new().with_vc251n(47).with_aj6n(0),
|
||||||
|
CmdNvgamctrlArg15::new().with_vc255n(31).with_aj7n(0),
|
||||||
|
)),
|
||||||
|
Box::new(CmdCn2bkxsel(
|
||||||
|
CmdCn2bkxselArg0::new(),
|
||||||
|
CmdCn2bkxselArg1::new(),
|
||||||
|
CmdCn2bkxselArg2::new(),
|
||||||
|
CmdCn2bkxselArg3::new(),
|
||||||
|
CmdCn2bkxselArg4::new().with_bksel(0x1).with_cn2(true),
|
||||||
|
)),
|
||||||
|
Box::new(CmdVrhs(
|
||||||
|
CmdVrhsArg0::new().with_vrha(115),
|
||||||
|
)),
|
||||||
|
Box::new(CmdVcoms(
|
||||||
|
CmdVcomsArg0::new().with_vcom(124),
|
||||||
|
)),
|
||||||
|
Box::new(CmdVghss(
|
||||||
|
// The first bit is set to 1 in the original init code, but not here.
|
||||||
|
CmdVghssArg0::new().with_vghss(0x3), // 13 V
|
||||||
|
)),
|
||||||
|
Box::new(CmdTescmd(
|
||||||
|
CmdTescmdArg0::new(),
|
||||||
|
)),
|
||||||
|
Box::new(CmdVgls(
|
||||||
|
CmdVglsArg0::new().with_vgls(0x9) // -10.17 V
|
||||||
|
)),
|
||||||
|
Box::new(CmdPwctrl1(
|
||||||
|
CmdPwctrl1Arg0::new()
|
||||||
|
.with_apos(0x3) // Max
|
||||||
|
.with_apis(0x1) // Min
|
||||||
|
.with_ap(0x2) // Middle
|
||||||
|
)),
|
||||||
|
Box::new(CmdPwctrl2(
|
||||||
|
CmdPwctrl2Arg0::new()
|
||||||
|
.with_avcl(0x3) // -5 V
|
||||||
|
.with_avdd(0x3) // 6.8 V
|
||||||
|
)),
|
||||||
|
Box::new(CmdPwctrl3(
|
||||||
|
CmdPwctrl3Arg0::new()
|
||||||
|
.with_svno_pum(0) // Cell setting 4
|
||||||
|
.with_svpo_pum(0x1) // Cell setting 5
|
||||||
|
)),
|
||||||
|
Box::new(CmdPclks2(
|
||||||
|
CmdPclks2Arg0::new().with_sbstcks(0x3)
|
||||||
|
)),
|
||||||
|
Box::new(CmdPdr1(
|
||||||
|
CmdPdr1Arg0::new().with_t2d(8) // 1.6 us
|
||||||
|
)),
|
||||||
|
Box::new(CmdPdr2(
|
||||||
|
CmdPdr2Arg0::new().with_t3d(8) // 6.4 us
|
||||||
|
)),
|
||||||
|
Box::new(CmdMipiset1(
|
||||||
|
CmdMipiset1Arg0::new().with_err_sel(0).with_eotp_en(true),
|
||||||
|
)),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE0,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x0C,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE1,
|
||||||
|
args: &[
|
||||||
|
0x05,
|
||||||
|
0x96,
|
||||||
|
0x07,
|
||||||
|
0x96,
|
||||||
|
0x06,
|
||||||
|
0x96,
|
||||||
|
0x08,
|
||||||
|
0x96,
|
||||||
|
0x00,
|
||||||
|
0x44,
|
||||||
|
0x44,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE2,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE3,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x33,
|
||||||
|
0x33,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE4,
|
||||||
|
args: &[
|
||||||
|
0x44,
|
||||||
|
0x44,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE5,
|
||||||
|
args: &[
|
||||||
|
0x0D,
|
||||||
|
0xD4,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x0F,
|
||||||
|
0xD6,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x09,
|
||||||
|
0xD0,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x0B,
|
||||||
|
0xD2,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE6,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x33,
|
||||||
|
0x33,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE7,
|
||||||
|
args: &[
|
||||||
|
0x44,
|
||||||
|
0x44,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE8,
|
||||||
|
args: &[
|
||||||
|
0x0E,
|
||||||
|
0xD5,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x10,
|
||||||
|
0xD7,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x0A,
|
||||||
|
0xD1,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
0x0C,
|
||||||
|
0xD3,
|
||||||
|
0x28,
|
||||||
|
0x8C,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xEB,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x01,
|
||||||
|
0xE4,
|
||||||
|
0xE4,
|
||||||
|
0x44,
|
||||||
|
0x00,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xED,
|
||||||
|
args: &[
|
||||||
|
0xF3,
|
||||||
|
0xC1,
|
||||||
|
0xBA,
|
||||||
|
0x0F,
|
||||||
|
0x66,
|
||||||
|
0x77,
|
||||||
|
0x44,
|
||||||
|
0x55,
|
||||||
|
0x55,
|
||||||
|
0x44,
|
||||||
|
0x77,
|
||||||
|
0x66,
|
||||||
|
0xF0,
|
||||||
|
0xAB,
|
||||||
|
0x1C,
|
||||||
|
0x3F,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xEF,
|
||||||
|
args: &[
|
||||||
|
0x10,
|
||||||
|
0x0D,
|
||||||
|
0x04,
|
||||||
|
0x08,
|
||||||
|
0x3F,
|
||||||
|
0x1F,
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Box::new(CmdCn2bkxsel(
|
||||||
|
CmdCn2bkxselArg0::new(),
|
||||||
|
CmdCn2bkxselArg1::new(),
|
||||||
|
CmdCn2bkxselArg2::new(),
|
||||||
|
CmdCn2bkxselArg3::new(),
|
||||||
|
CmdCn2bkxselArg4::new().with_bksel(0x3).with_cn2(true),
|
||||||
|
)),
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE8,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x0E,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Box::new(CmdSlpout()),
|
||||||
|
], 120),
|
||||||
|
(vec![
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE8,
|
||||||
|
args: &[
|
||||||
|
0x00,
|
||||||
|
0x0C,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
], 10),
|
||||||
|
(vec![
|
||||||
|
Box::new(CustomCommand {
|
||||||
|
address: 0xE8,
|
||||||
|
args: &[
|
||||||
|
0x40,
|
||||||
|
0x00,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Box::new(CmdCn2bkxsel(
|
||||||
|
CmdCn2bkxselArg0::new(),
|
||||||
|
CmdCn2bkxselArg1::new(),
|
||||||
|
CmdCn2bkxselArg2::new(),
|
||||||
|
CmdCn2bkxselArg3::new(),
|
||||||
|
CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(false),
|
||||||
|
)),
|
||||||
|
Box::new(CmdMadctl(
|
||||||
|
CmdMadctlArg0::new().with_bgr(false).with_ml(false),
|
||||||
|
)),
|
||||||
|
Box::new(CmdColmod(
|
||||||
|
CmdColmodArg0::new().with_vipf(6) // 18-bit pixel
|
||||||
|
)),
|
||||||
|
Box::new(CmdDispon()),
|
||||||
|
], 20),
|
||||||
|
// (vec![
|
||||||
|
// Box::new(CmdCn2bkxsel(
|
||||||
|
// CmdCn2bkxselArg0::new(),
|
||||||
|
// CmdCn2bkxselArg1::new(),
|
||||||
|
// CmdCn2bkxselArg2::new(),
|
||||||
|
// CmdCn2bkxselArg3::new(),
|
||||||
|
// CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(true),
|
||||||
|
// )),
|
||||||
|
// Box::new(CmdPorctrl(
|
||||||
|
// CmdPorctrlArg0::new().with_vbp(0xFF),
|
||||||
|
// CmdPorctrlArg1::new().with_vfp(0x0),
|
||||||
|
// )),
|
||||||
|
// // Box::new(CmdRgbctrl(
|
||||||
|
// // CmdRgbctrlArg0::new()
|
||||||
|
// // .with_ep(false)
|
||||||
|
// // .with_dp(false)
|
||||||
|
// // .with_hsp(false)
|
||||||
|
// // .with_vsp(false)
|
||||||
|
// // .with_de_hv(true),
|
||||||
|
// // CmdRgbctrlArg1::new()
|
||||||
|
// // .with_hbp_hvrgb(16),
|
||||||
|
// // CmdRgbctrlArg2::new()
|
||||||
|
// // .with_vbp_hvrgb(8),
|
||||||
|
// // )),
|
||||||
|
// Box::new(CmdCn2bkxsel(
|
||||||
|
// CmdCn2bkxselArg0::new(),
|
||||||
|
// CmdCn2bkxselArg1::new(),
|
||||||
|
// CmdCn2bkxselArg2::new(),
|
||||||
|
// CmdCn2bkxselArg3::new(),
|
||||||
|
// CmdCn2bkxselArg4::new().with_bksel(0).with_cn2(false),
|
||||||
|
// )),
|
||||||
|
// ], 20),
|
||||||
|
];
|
||||||
|
}
|
||||||
12
firmware2/src/macros.rs
Normal file
12
firmware2/src/macros.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
macro_rules! config_matrix_pins_esp {
|
||||||
|
(peripherals: $p:ident, input: [$($in_pin:ident), *], output: [$($out_pin:ident), +]) => {
|
||||||
|
{
|
||||||
|
let mut output_pins = [$(Output::new($p.$out_pin, Level::Low, OutputConfig::default())), +];
|
||||||
|
let input_pins = [$(Input::new($p.$in_pin, InputConfig::default().with_pull(Pull::Down))), +];
|
||||||
|
output_pins.iter_mut().for_each(|p| {
|
||||||
|
let _ = p.set_low();
|
||||||
|
});
|
||||||
|
(input_pins, output_pins)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
463
firmware2/src/main.rs
Normal file
463
firmware2/src/main.rs
Normal file
|
|
@ -0,0 +1,463 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(macro_metavar_expr)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
mod keymap;
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
mod lcd;
|
||||||
|
mod matrix;
|
||||||
|
mod st7701s;
|
||||||
|
mod vial;
|
||||||
|
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
|
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use alloc::vec;
|
||||||
|
use bt_hci::controller::ExternalController;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use esp_alloc::{HeapRegion, MemoryCapability};
|
||||||
|
use esp_hal::clock::{CpuClock, RtcClock};
|
||||||
|
use esp_hal::delay::Delay;
|
||||||
|
use esp_hal::dma::{BurstConfig, DmaDescriptor, DmaTxBuf, ExternalBurstConfig};
|
||||||
|
use esp_hal::gpio::{Flex, Input, InputConfig, Level, Output, OutputConfig, Pull};
|
||||||
|
use esp_hal::i2c::master::{I2c, I2cAddress};
|
||||||
|
use esp_hal::lcd_cam::LcdCam;
|
||||||
|
use esp_hal::lcd_cam::lcd::dpi::{Dpi, Format, FrameTiming};
|
||||||
|
use esp_hal::lcd_cam::lcd::{ClockMode, Phase, Polarity};
|
||||||
|
use esp_hal::mcpwm::{McPwm, PeripheralClockConfig};
|
||||||
|
use esp_hal::otg_fs::Usb;
|
||||||
|
use esp_hal::otg_fs::asynch::{Config, Driver};
|
||||||
|
// use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock};
|
||||||
|
use esp_hal::rng::TrngSource;
|
||||||
|
use esp_hal::rtc_cntl::sleep::RtcSleepConfig;
|
||||||
|
use esp_hal::rtc_cntl::{Rtc, sleep};
|
||||||
|
use esp_hal::time::Rate;
|
||||||
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
|
use esp_hal::timer::timg::TimerGroup;
|
||||||
|
use esp_radio::Controller;
|
||||||
|
use esp_radio::ble::controller::BleConnector;
|
||||||
|
use esp_storage::FlashStorage;
|
||||||
|
use log::{LevelFilter, info};
|
||||||
|
use rmk::ble::build_ble_stack;
|
||||||
|
use rmk::channel::EVENT_CHANNEL;
|
||||||
|
use rmk::config::{BehaviorConfig, PositionalConfig, RmkConfig, StorageConfig, VialConfig};
|
||||||
|
use rmk::debounce::default_debouncer::DefaultDebouncer;
|
||||||
|
use rmk::futures::future::join3;
|
||||||
|
use rmk::input_device::Runnable;
|
||||||
|
use rmk::keyboard::Keyboard;
|
||||||
|
use rmk::matrix::Matrix;
|
||||||
|
use rmk::storage::async_flash_wrapper;
|
||||||
|
use rmk::{HostResources, initialize_keymap_and_storage, run_devices, run_rmk};
|
||||||
|
use static_cell::StaticCell;
|
||||||
|
use {esp_alloc as _, esp_backtrace as _};
|
||||||
|
|
||||||
|
use crate::keymap::*;
|
||||||
|
use crate::lcd::spi_write;
|
||||||
|
use crate::matrix::IoeMatrix;
|
||||||
|
use crate::vial::{VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID};
|
||||||
|
|
||||||
|
// This creates a default app-descriptor required by the esp-idf bootloader.
|
||||||
|
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
|
||||||
|
esp_bootloader_esp_idf::esp_app_desc!();
|
||||||
|
|
||||||
|
static PSRAM_ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
|
||||||
|
|
||||||
|
#[esp_rtos::main]
|
||||||
|
async fn main(spawner: Spawner) {
|
||||||
|
esp_println::logger::init_logger_from_env();
|
||||||
|
info!("Logger initialized!");
|
||||||
|
|
||||||
|
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
|
||||||
|
// .with_psram(PsramConfig {
|
||||||
|
// size: PsramSize::AutoDetect,
|
||||||
|
// core_clock: Some(SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m),
|
||||||
|
// flash_frequency: FlashFreq::default(),
|
||||||
|
// ram_frequency: SpiRamFreq::Freq80m,
|
||||||
|
// });
|
||||||
|
let peripherals: esp_hal::peripherals::Peripherals = esp_hal::init(config);
|
||||||
|
info!("System initialized!");
|
||||||
|
|
||||||
|
// Use the internal DRAM as the heap.
|
||||||
|
esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 64 * 1024);
|
||||||
|
info!("Heap initialized! {:#?}", esp_alloc::HEAP.stats());
|
||||||
|
|
||||||
|
// let timer0 = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
|
// esp_hal_embassy::init(timer0.alarm0);
|
||||||
|
// info!("Embassy initialized!");
|
||||||
|
|
||||||
|
// // Initialize the PSRAM allocator.
|
||||||
|
// {
|
||||||
|
// let (psram_offset, psram_size) = esp_hal::psram::psram_raw_parts(&peripherals.PSRAM);
|
||||||
|
// unsafe {
|
||||||
|
// PSRAM_ALLOCATOR.add_region(HeapRegion::new(
|
||||||
|
// psram_offset,
|
||||||
|
// psram_size,
|
||||||
|
// MemoryCapability::External.into(),
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// const BUFFER_LEN: usize = core::mem::size_of::<u16>()
|
||||||
|
// * (360 + /* TODO: Figure out why more bytes are needed: */ 8)
|
||||||
|
// * 960;
|
||||||
|
// // Note: We just leak this buffer.
|
||||||
|
// let buffer_ptr = unsafe {
|
||||||
|
// // ⚠️ Note: For chips that support DMA to/from PSRAM (ESP32-S3) DMA transfers to/from PSRAM
|
||||||
|
// // have extra alignment requirements. The address and size of the buffer pointed to by each
|
||||||
|
// // descriptor must be a multiple of the cache line (block) size. This is 32 bytes on
|
||||||
|
// // ESP32-S3.
|
||||||
|
// PSRAM_ALLOCATOR.alloc_caps(
|
||||||
|
// MemoryCapability::External.into(),
|
||||||
|
// Layout::from_size_align(BUFFER_LEN, 32).unwrap(),
|
||||||
|
// )
|
||||||
|
// };
|
||||||
|
// let buffer = unsafe { core::slice::from_raw_parts_mut(buffer_ptr, BUFFER_LEN) };
|
||||||
|
// let burst_config: BurstConfig = ExternalBurstConfig::Size16.into();
|
||||||
|
|
||||||
|
// info!(
|
||||||
|
// "PSRAM SPI burst config: max_compatible_chunk_size={}",
|
||||||
|
// burst_config.max_compatible_chunk_size()
|
||||||
|
// );
|
||||||
|
|
||||||
|
// let dma_buf_descs_len =
|
||||||
|
// esp_hal::dma::descriptor_count(BUFFER_LEN, burst_config.max_compatible_chunk_size(), false);
|
||||||
|
// // Descriptors are initialized by `DmaTxBuf::new`.
|
||||||
|
// let dma_buf_descs = Box::leak(vec![DmaDescriptor::EMPTY; dma_buf_descs_len].into_boxed_slice());
|
||||||
|
// let mut dma_buf = DmaTxBuf::new(dma_buf_descs, buffer).unwrap();
|
||||||
|
// // let mut dma_buf = dma_tx_buffer!(BUFFER_LEN).unwrap();
|
||||||
|
|
||||||
|
// TODO: Spawn some tasks
|
||||||
|
let _ = spawner;
|
||||||
|
|
||||||
|
// Enable pull-up on GPIO0 to prevent booting into download mode.
|
||||||
|
let gpio0 = Output::new(
|
||||||
|
peripherals.GPIO0,
|
||||||
|
Level::High,
|
||||||
|
OutputConfig::default().with_pull(Pull::Up),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Enable LDO2
|
||||||
|
let _ = Output::new(peripherals.GPIO17, Level::High, OutputConfig::default());
|
||||||
|
|
||||||
|
// Enable antenna
|
||||||
|
let _ = Output::new(peripherals.GPIO11, Level::Low, OutputConfig::default());
|
||||||
|
|
||||||
|
// TODO: Use PWM to control the pwm_pin.
|
||||||
|
let mut _pwm = McPwm::new(peripherals.MCPWM0, PeripheralClockConfig::with_prescaler(1));
|
||||||
|
let mut _pwm_pin = Output::new(peripherals.GPIO21, Level::High, OutputConfig::default());
|
||||||
|
|
||||||
|
let mut matrix_interrupt = Input::new(
|
||||||
|
peripherals.GPIO7,
|
||||||
|
InputConfig::default().with_pull(Pull::Up),
|
||||||
|
);
|
||||||
|
|
||||||
|
// esp_alloc::heap_allocator!(size: 72 * 1024);
|
||||||
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
let software_interrupt = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
|
||||||
|
esp_rtos::start(
|
||||||
|
timg0.timer0,
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
software_interrupt.software_interrupt0,
|
||||||
|
);
|
||||||
|
let _trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1);
|
||||||
|
let mut rng = esp_hal::rng::Trng::try_new().unwrap();
|
||||||
|
static RADIO: StaticCell<Controller<'static>> = StaticCell::new();
|
||||||
|
let radio = RADIO.init(esp_radio::init().unwrap());
|
||||||
|
let bluetooth = peripherals.BT;
|
||||||
|
let connector = BleConnector::new(radio, bluetooth, Default::default()).unwrap();
|
||||||
|
let controller: ExternalController<_, 20> = ExternalController::new(connector);
|
||||||
|
let central_addr = [0x18, 0xe2, 0x21, 0x80, 0xc0, 0xc7];
|
||||||
|
let mut host_resources = HostResources::new();
|
||||||
|
let stack = build_ble_stack(controller, central_addr, &mut rng, &mut host_resources).await;
|
||||||
|
|
||||||
|
// // Initialize USB
|
||||||
|
#[cfg(not(feature = "no_usb"))]
|
||||||
|
let usb_driver = {
|
||||||
|
static mut EP_MEMORY: [u8; 1024] = [0; 1024];
|
||||||
|
let usb = Usb::new(peripherals.USB0, peripherals.GPIO20, peripherals.GPIO19);
|
||||||
|
// Create the driver, from the HAL.
|
||||||
|
let config = Config::default();
|
||||||
|
Driver::new(usb, unsafe { &mut *addr_of_mut!(EP_MEMORY) }, config)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize the flash
|
||||||
|
let flash = FlashStorage::new(peripherals.FLASH);
|
||||||
|
let flash = async_flash_wrapper(flash);
|
||||||
|
|
||||||
|
let mut sck = Output::new(peripherals.GPIO36, Level::High, OutputConfig::default());
|
||||||
|
let mut mosi = Flex::new(peripherals.GPIO35);
|
||||||
|
let mut cs = Output::new(peripherals.GPIO6, Level::High, OutputConfig::default());
|
||||||
|
|
||||||
|
mosi.set_input_enable(false);
|
||||||
|
mosi.set_output_enable(true);
|
||||||
|
|
||||||
|
// info!("init sequence writing");
|
||||||
|
|
||||||
|
for (subsequence, delay_ms) in &*lcd::INIT_SEQUENCE_COMMANDS {
|
||||||
|
for command in subsequence {
|
||||||
|
spi_write(
|
||||||
|
command.address(),
|
||||||
|
command.args_iter().copied(),
|
||||||
|
&mut mosi,
|
||||||
|
&mut sck,
|
||||||
|
&mut cs,
|
||||||
|
);
|
||||||
|
// info!("COMM 0x{:02X}", command.address());
|
||||||
|
// for arg in command.args_iter() {
|
||||||
|
// info!("DATA 0x{arg:02X}");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
Delay::new().delay_millis(*delay_ms as u32); // TODO: async?
|
||||||
|
// Timer::after_millis(*delay_ms).await
|
||||||
|
}
|
||||||
|
|
||||||
|
// info!("init sequence written");
|
||||||
|
|
||||||
|
let mut lcd = LcdCam::new(peripherals.LCD_CAM).into_async().lcd;
|
||||||
|
let lcd_config = esp_hal::lcd_cam::lcd::dpi::Config::default()
|
||||||
|
// Internal memory can use the full 16 MHz, but when external PSRAM is used, it cannot keep up with the display.
|
||||||
|
// For that reason, we choose the highest value for which it doesn't glitch by showing black
|
||||||
|
// stripes on the screen.
|
||||||
|
//
|
||||||
|
// There are three knobs you can turn to improve the bandwidth situation.
|
||||||
|
// - increase psram frequency
|
||||||
|
// - decrease the peripheral's frequency
|
||||||
|
// - prevent flash from being used whilst your program is running. (There's a PR to make
|
||||||
|
// this easy to do)
|
||||||
|
// https://github.com/esp-rs/esp-hal/pull/3024
|
||||||
|
.with_frequency(Rate::from_mhz(11)) // From Adafruit
|
||||||
|
.with_clock_mode(ClockMode {
|
||||||
|
polarity: Polarity::IdleLow, // From Adafruit
|
||||||
|
phase: Phase::ShiftHigh, // From Adafruit
|
||||||
|
})
|
||||||
|
.with_format(Format {
|
||||||
|
enable_2byte_mode: true,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.with_timing({
|
||||||
|
// Adafruit's config for this LCD:
|
||||||
|
// https://github.com/adafruit/Adafruit_CircuitPython_Qualia/blob/742d336e05e6a4d8bdaa46e15bbf60c9f30d2eba/adafruit_qualia/displays/bar240x960.py#L81-L97
|
||||||
|
// https://github.com/adafruit/Adafruit_CircuitPython_Qualia/blob/742d336e05e6a4d8bdaa46e15bbf60c9f30d2eba/adafruit_qualia/displays/__init__.py#L59-L62
|
||||||
|
// CircuitPython code handling Adafruit's config
|
||||||
|
// https://github.com/adafruit/circuitpython/blob/97c6617817e95b1f6aa2ce458778aaa8371de39b/ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c#L63
|
||||||
|
// ESP-IDF peripheral configuration code:
|
||||||
|
// https://github.com/espressif/esp-idf/blob/800f141f94c0f880c162de476512e183df671307/components/esp_lcd/rgb/esp_lcd_panel_rgb.c#L556
|
||||||
|
// Espressif's docs:
|
||||||
|
// https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32s3/api-reference/peripherals/lcd/rgb_lcd.html#structures
|
||||||
|
|
||||||
|
// TODO: Investigate PORCTRL instruction in datasheet of ST7701
|
||||||
|
let horizontal_resolution: usize = 240;
|
||||||
|
let vertical_resolution = 960;
|
||||||
|
let overscan_left = 120;
|
||||||
|
let vsync_width = 8;
|
||||||
|
let hsync_width = 8;
|
||||||
|
let horizontal_blank_front_porch = 20;
|
||||||
|
let horizontal_blank_back_porch = 20;
|
||||||
|
let vertical_blank_front_porch = 20;
|
||||||
|
let vertical_blank_back_porch = 20;
|
||||||
|
let hsync_position = 0;
|
||||||
|
let horizontal_active_width = (horizontal_resolution + overscan_left).div_ceil(16) * 16; // Round up to a multiple of 16.
|
||||||
|
let vertical_active_height = vertical_resolution;
|
||||||
|
FrameTiming {
|
||||||
|
horizontal_total_width: hsync_width
|
||||||
|
+ horizontal_blank_back_porch
|
||||||
|
+ horizontal_active_width
|
||||||
|
+ horizontal_blank_front_porch,
|
||||||
|
vertical_total_height: vsync_width
|
||||||
|
+ vertical_blank_back_porch
|
||||||
|
+ vertical_active_height
|
||||||
|
+ vertical_blank_front_porch,
|
||||||
|
horizontal_blank_front_porch: horizontal_blank_front_porch + hsync_width,
|
||||||
|
vertical_blank_front_porch: vertical_blank_front_porch + vsync_width,
|
||||||
|
horizontal_active_width,
|
||||||
|
vertical_active_height,
|
||||||
|
vsync_width,
|
||||||
|
hsync_width,
|
||||||
|
hsync_position,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.with_hsync_idle_level(Level::High)
|
||||||
|
.with_vsync_idle_level(Level::High)
|
||||||
|
.with_de_idle_level(Level::Low);
|
||||||
|
let mut dpi = Dpi::new(lcd, peripherals.DMA_CH2, lcd_config)
|
||||||
|
.unwrap()
|
||||||
|
.with_de(peripherals.GPIO37)
|
||||||
|
.with_pclk(peripherals.GPIO34)
|
||||||
|
.with_hsync(peripherals.GPIO44)
|
||||||
|
.with_vsync(peripherals.GPIO43)
|
||||||
|
// Blue
|
||||||
|
.with_data0(peripherals.GPIO38)
|
||||||
|
.with_data1(peripherals.GPIO39)
|
||||||
|
.with_data2(peripherals.GPIO40)
|
||||||
|
.with_data3(peripherals.GPIO41)
|
||||||
|
.with_data4(peripherals.GPIO42)
|
||||||
|
// Green
|
||||||
|
.with_data5(peripherals.GPIO5)
|
||||||
|
.with_data6(peripherals.GPIO12)
|
||||||
|
.with_data7(peripherals.GPIO13)
|
||||||
|
.with_data8(peripherals.GPIO14)
|
||||||
|
.with_data9(peripherals.GPIO15)
|
||||||
|
.with_data10(peripherals.GPIO16)
|
||||||
|
// Red
|
||||||
|
.with_data11(gpio0)
|
||||||
|
.with_data12(peripherals.GPIO1)
|
||||||
|
.with_data13(peripherals.GPIO2)
|
||||||
|
.with_data14(peripherals.GPIO3)
|
||||||
|
.with_data15(peripherals.GPIO4);
|
||||||
|
|
||||||
|
// RMK config
|
||||||
|
let vial_config = VialConfig::new(VIAL_KEYBOARD_ID, VIAL_KEYBOARD_DEF, &[(0, 0), (1, 1)]);
|
||||||
|
let storage_config = StorageConfig {
|
||||||
|
start_addr: 0x3f0000,
|
||||||
|
num_sectors: 16,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let rmk_config = RmkConfig {
|
||||||
|
vial_config,
|
||||||
|
storage_config,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialze keyboard stuffs
|
||||||
|
// Initialize the storage and keymap
|
||||||
|
let mut default_keymap = keymap::get_default_keymap();
|
||||||
|
let mut behavior_config = BehaviorConfig::default();
|
||||||
|
let mut per_key_config = PositionalConfig::default();
|
||||||
|
let (keymap, mut storage) = initialize_keymap_and_storage(
|
||||||
|
&mut default_keymap,
|
||||||
|
flash,
|
||||||
|
&storage_config,
|
||||||
|
&mut behavior_config,
|
||||||
|
&mut per_key_config,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// Initialize the matrix and keyboard
|
||||||
|
const I2C_ADDR_MATRIX_LEFT: I2cAddress = I2cAddress::SevenBit(0b0100000);
|
||||||
|
const I2C_ADDR_MATRIX_RIGHT: I2cAddress = I2cAddress::SevenBit(0b0100001);
|
||||||
|
|
||||||
|
let i2c = I2c::new(peripherals.I2C0, Default::default())
|
||||||
|
.unwrap()
|
||||||
|
.with_sda(peripherals.GPIO8)
|
||||||
|
.with_scl(peripherals.GPIO9);
|
||||||
|
|
||||||
|
let mut matrix = IoeMatrix::new(
|
||||||
|
i2c.into_async(),
|
||||||
|
DefaultDebouncer::new(),
|
||||||
|
[I2C_ADDR_MATRIX_LEFT, I2C_ADDR_MATRIX_RIGHT],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let mut keyboard = Keyboard::new(&keymap); // Initialize the light controller
|
||||||
|
|
||||||
|
join3(
|
||||||
|
run_devices! (
|
||||||
|
(matrix) => EVENT_CHANNEL,
|
||||||
|
),
|
||||||
|
keyboard.run(), // Keyboard is special
|
||||||
|
run_rmk(
|
||||||
|
&keymap,
|
||||||
|
#[cfg(not(feature = "no_usb"))]
|
||||||
|
usb_driver,
|
||||||
|
&stack,
|
||||||
|
&mut storage,
|
||||||
|
rmk_config,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[esp_rtos::main]
|
||||||
|
// async fn main(_s: Spawner) {
|
||||||
|
// // Initialize the peripherals and bluetooth controller
|
||||||
|
// esp_println::logger::init_logger(LevelFilter::max());
|
||||||
|
// let peripherals = esp_hal::init(esp_hal::Config::default().with_cpu_clock(CpuClock::max()));
|
||||||
|
// esp_alloc::heap_allocator!(size: 72 * 1024);
|
||||||
|
// let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||||
|
// #[cfg(target_arch = "riscv32")]
|
||||||
|
// let software_interrupt = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
|
||||||
|
// esp_rtos::start(
|
||||||
|
// timg0.timer0,
|
||||||
|
// #[cfg(target_arch = "riscv32")]
|
||||||
|
// software_interrupt.software_interrupt0,
|
||||||
|
// );
|
||||||
|
// let _trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1);
|
||||||
|
// let mut rng = esp_hal::rng::Trng::try_new().unwrap();
|
||||||
|
// static RADIO: StaticCell<Controller<'static>> = StaticCell::new();
|
||||||
|
// let radio = RADIO.init(esp_radio::init().unwrap());
|
||||||
|
// let bluetooth = peripherals.BT;
|
||||||
|
// let connector = BleConnector::new(radio, bluetooth, Default::default()).unwrap();
|
||||||
|
// let controller: ExternalController<_, 20> = ExternalController::new(connector);
|
||||||
|
// let central_addr = [0x18, 0xe2, 0x21, 0x80, 0xc0, 0xc7];
|
||||||
|
// let mut host_resources = HostResources::new();
|
||||||
|
// let stack = build_ble_stack(controller, central_addr, &mut rng, &mut host_resources).await;
|
||||||
|
|
||||||
|
// // Initialize the flash
|
||||||
|
// let flash = FlashStorage::new(peripherals.FLASH);
|
||||||
|
// let flash = async_flash_wrapper(flash);
|
||||||
|
|
||||||
|
// // Initialize the IO pins
|
||||||
|
// let (row_pins, col_pins) = config_matrix_pins_esp!(peripherals: peripherals, input: [GPIO6, GPIO7, GPIO21, GPIO35], output: [GPIO3, GPIO4, GPIO5]);
|
||||||
|
|
||||||
|
// // RMK config
|
||||||
|
// let vial_config = VialConfig::new(VIAL_KEYBOARD_ID, VIAL_KEYBOARD_DEF, &[(0, 0), (1, 1)]);
|
||||||
|
// let storage_config = StorageConfig {
|
||||||
|
// start_addr: 0x3f0000,
|
||||||
|
// num_sectors: 16,
|
||||||
|
// ..Default::default()
|
||||||
|
// };
|
||||||
|
// let rmk_config = RmkConfig {
|
||||||
|
// vial_config,
|
||||||
|
// storage_config,
|
||||||
|
// ..Default::default()
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Initialze keyboard stuffs
|
||||||
|
// // Initialize the storage and keymap
|
||||||
|
// let mut default_keymap = keymap::get_default_keymap();
|
||||||
|
// let mut behavior_config = BehaviorConfig::default();
|
||||||
|
// let mut per_key_config = PositionalConfig::default();
|
||||||
|
// let (keymap, mut storage) = initialize_keymap_and_storage(
|
||||||
|
// &mut default_keymap,
|
||||||
|
// flash,
|
||||||
|
// &storage_config,
|
||||||
|
// &mut behavior_config,
|
||||||
|
// &mut per_key_config,
|
||||||
|
// )
|
||||||
|
// .await;
|
||||||
|
|
||||||
|
// // Initialize the matrix and keyboard
|
||||||
|
// let debouncer = DefaultDebouncer::new();
|
||||||
|
// let mut i2c = I2c::new(
|
||||||
|
// peripherals.I2C0,
|
||||||
|
// esp_hal::i2c::master::Config::default().with_frequency(Rate::from_khz(400)),
|
||||||
|
// )
|
||||||
|
// .unwrap()
|
||||||
|
// .with_sda(peripherals.GPIO8)
|
||||||
|
// .with_scl(peripherals.GPIO9);
|
||||||
|
|
||||||
|
// const I2C_ADDR_MATRIX_LEFT: I2cAddress = I2cAddress::SevenBit(0b0100000);
|
||||||
|
// const I2C_ADDR_MATRIX_RIGHT: I2cAddress = I2cAddress::SevenBit(0b0100001);
|
||||||
|
|
||||||
|
// let mut matrix = IoeMatrix::new(
|
||||||
|
// i2c.into_async(),
|
||||||
|
// debouncer,
|
||||||
|
// [I2C_ADDR_MATRIX_LEFT, I2C_ADDR_MATRIX_RIGHT],
|
||||||
|
// )
|
||||||
|
// .await;
|
||||||
|
// // let mut matrix = Matrix::<_, _, _, ROW, COL, true>::new(row_pins, col_pins, debouncer);
|
||||||
|
// // let mut matrix = rmk::matrix::TestMatrix::<ROW, COL>::new();
|
||||||
|
// let mut keyboard = Keyboard::new(&keymap); // Initialize the light controller
|
||||||
|
|
||||||
|
// join3(
|
||||||
|
// run_devices! (
|
||||||
|
// (matrix) => EVENT_CHANNEL,
|
||||||
|
// ),
|
||||||
|
// keyboard.run(), // Keyboard is special
|
||||||
|
// run_rmk(&keymap, &stack, &mut storage, rmk_config),
|
||||||
|
// )
|
||||||
|
// .await;
|
||||||
|
// }
|
||||||
215
firmware2/src/matrix.rs
Normal file
215
firmware2/src/matrix.rs
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
use esp_hal::{
|
||||||
|
Async,
|
||||||
|
i2c::master::{BusTimeout, I2c, I2cAddress, SoftwareTimeout},
|
||||||
|
time::Rate,
|
||||||
|
};
|
||||||
|
use log::info;
|
||||||
|
use rmk::{
|
||||||
|
debounce::{DebounceState, DebouncerTrait},
|
||||||
|
event::{Event, KeyboardEvent},
|
||||||
|
input_device::InputDevice,
|
||||||
|
matrix::{KeyState, MatrixTrait},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct RaiiGuard<F: FnOnce()> {
|
||||||
|
on_drop: Option<F>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: FnOnce()> RaiiGuard<F> {
|
||||||
|
pub fn new(on_drop: F) -> Self {
|
||||||
|
Self {
|
||||||
|
on_drop: Some(on_drop),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: FnOnce()> Drop for RaiiGuard<F> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(on_drop) = self.on_drop.take() {
|
||||||
|
(on_drop)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MATRIX_ROWS: usize = 5;
|
||||||
|
pub const MATRIX_COLS: usize = 12;
|
||||||
|
pub const MATRIX_AREA: usize = MATRIX_ROWS * MATRIX_COLS;
|
||||||
|
|
||||||
|
/// IO Expander Matrix
|
||||||
|
pub struct IoeMatrix<D>
|
||||||
|
where
|
||||||
|
D: DebouncerTrait<MATRIX_ROWS, MATRIX_COLS>,
|
||||||
|
{
|
||||||
|
i2c: I2c<'static, Async>,
|
||||||
|
/// IO expander addresses.
|
||||||
|
ioe_addresses: [I2cAddress; 2],
|
||||||
|
debouncer: D,
|
||||||
|
/// States of key switches as detected by IO expanders.
|
||||||
|
input_states: [[bool; MATRIX_ROWS]; MATRIX_COLS],
|
||||||
|
/// Debounced key states.
|
||||||
|
key_states: [[KeyState; MATRIX_ROWS]; MATRIX_COLS],
|
||||||
|
/// Index of the current key switch being processed: row * columns + column
|
||||||
|
scan_pos: usize,
|
||||||
|
/// Re-scan needed flag
|
||||||
|
#[cfg(feature = "async_matrix")]
|
||||||
|
rescan_needed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> IoeMatrix<D>
|
||||||
|
where
|
||||||
|
D: DebouncerTrait<MATRIX_ROWS, MATRIX_COLS>,
|
||||||
|
{
|
||||||
|
pub async fn new(
|
||||||
|
mut i2c: I2c<'static, Async>,
|
||||||
|
debouncer: D,
|
||||||
|
ioe_addresses: [I2cAddress; 2],
|
||||||
|
) -> Self {
|
||||||
|
i2c.apply_config(
|
||||||
|
&esp_hal::i2c::master::Config::default()
|
||||||
|
.with_frequency(Rate::from_khz(400))
|
||||||
|
.with_timeout(BusTimeout::Disabled)
|
||||||
|
.with_software_timeout(SoftwareTimeout::None),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for addr in ioe_addresses {
|
||||||
|
i2c.write_async(addr, &[0b10010000, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
i2c,
|
||||||
|
ioe_addresses,
|
||||||
|
debouncer,
|
||||||
|
input_states: Default::default(),
|
||||||
|
key_states: Default::default(),
|
||||||
|
scan_pos: 0,
|
||||||
|
#[cfg(feature = "async_matrix")]
|
||||||
|
rescan_needed: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> InputDevice for IoeMatrix<D>
|
||||||
|
where
|
||||||
|
D: DebouncerTrait<MATRIX_ROWS, MATRIX_COLS>,
|
||||||
|
{
|
||||||
|
async fn read_event(&mut self) -> Event {
|
||||||
|
loop {
|
||||||
|
if self.scan_pos == 0 {
|
||||||
|
// Load data from IO expanders.
|
||||||
|
let mut input_register_banks = [0_u8; 10];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let Err(esp_hal::i2c::master::Error::Timeout) = self
|
||||||
|
.i2c
|
||||||
|
.write_read_async(
|
||||||
|
self.ioe_addresses[0],
|
||||||
|
&[0x80],
|
||||||
|
&mut input_register_banks[..5],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
info!("I2C timed out when reading the left IO expander.");
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let Err(esp_hal::i2c::master::Error::Timeout) = self
|
||||||
|
.i2c
|
||||||
|
.write_read_async(
|
||||||
|
self.ioe_addresses[1],
|
||||||
|
&[0x80],
|
||||||
|
&mut input_register_banks[5..],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
info!("I2C timed out when reading the right IO expander.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (row_idx, (left, right)) in (0..).zip(core::iter::zip(
|
||||||
|
&input_register_banks[..5],
|
||||||
|
&input_register_banks[5..],
|
||||||
|
)) {
|
||||||
|
for col_idx_half in 0..(MATRIX_COLS / 2) {
|
||||||
|
self.input_states[col_idx_half][row_idx] = left & (1 << col_idx_half) != 0;
|
||||||
|
self.input_states[col_idx_half + MATRIX_COLS / 2][row_idx] =
|
||||||
|
right & (1 << col_idx_half) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// info!("rows: {rows:x?}")
|
||||||
|
}
|
||||||
|
|
||||||
|
let (row_idx, col_idx) = (self.scan_pos / MATRIX_COLS, self.scan_pos % MATRIX_COLS);
|
||||||
|
let on_iteration_end = RaiiGuard::new(|| {
|
||||||
|
// Process the next key switch.
|
||||||
|
self.scan_pos = (self.scan_pos + 1) % MATRIX_AREA;
|
||||||
|
});
|
||||||
|
let debounce_state = self.debouncer.detect_change_with_debounce(
|
||||||
|
row_idx,
|
||||||
|
col_idx,
|
||||||
|
self.input_states[col_idx][row_idx],
|
||||||
|
&self.key_states[col_idx][row_idx],
|
||||||
|
);
|
||||||
|
|
||||||
|
if let DebounceState::Debounced = debounce_state {
|
||||||
|
self.key_states[col_idx][row_idx].toggle_pressed();
|
||||||
|
#[cfg(feature = "async_matrix")]
|
||||||
|
{
|
||||||
|
self.rescan_needed = true;
|
||||||
|
}
|
||||||
|
return Event::Key(KeyboardEvent::key(
|
||||||
|
row_idx as u8,
|
||||||
|
col_idx as u8,
|
||||||
|
self.key_states[col_idx][row_idx].pressed,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Process the next key switch.
|
||||||
|
// self.scan_pos = (self.scan_pos + 1) % MATRIX_AREA;
|
||||||
|
|
||||||
|
// If there's key still pressed, always refresh the self.scan_start
|
||||||
|
#[cfg(feature = "async_matrix")]
|
||||||
|
if self.key_states[col_idx][row_idx].pressed {
|
||||||
|
self.rescan_needed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async_matrix")]
|
||||||
|
{
|
||||||
|
if !self.rescan_needed {
|
||||||
|
self.wait_for_key().await;
|
||||||
|
}
|
||||||
|
self.rescan_needed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(on_iteration_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> MatrixTrait<MATRIX_ROWS, MATRIX_COLS> for IoeMatrix<D>
|
||||||
|
where
|
||||||
|
D: DebouncerTrait<MATRIX_ROWS, MATRIX_COLS>,
|
||||||
|
{
|
||||||
|
#[cfg(feature = "async_matrix")]
|
||||||
|
async fn wait_for_key(&mut self) {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// First, set all output pins to high
|
||||||
|
for out in self.get_output_pins_mut().iter_mut() {
|
||||||
|
out.set_high().ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for any key press
|
||||||
|
self.wait_input_pins().await;
|
||||||
|
|
||||||
|
// Set all output pins back to low
|
||||||
|
for out in self.get_output_pins_mut().iter_mut() {
|
||||||
|
out.set_low().ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1212
firmware2/src/st7701s.rs
Normal file
1212
firmware2/src/st7701s.rs
Normal file
File diff suppressed because it is too large
Load diff
3
firmware2/src/vial.rs
Normal file
3
firmware2/src/vial.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
// Vial config is automatically generated by `build.rs`, according to `vial.json`
|
||||||
|
// Please put `vial.json` at your project's root
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/config_generated.rs"));
|
||||||
84
firmware2/vial.json
Normal file
84
firmware2/vial.json
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
{
|
||||||
|
"name": "ACID Keyboard",
|
||||||
|
"vendorId": "0x1209",
|
||||||
|
"productId": "0x9400",
|
||||||
|
"lighting": "none",
|
||||||
|
"matrix": {
|
||||||
|
"rows": 5,
|
||||||
|
"cols": 12
|
||||||
|
},
|
||||||
|
"layouts": {
|
||||||
|
"keymap": [
|
||||||
|
[
|
||||||
|
"0,0",
|
||||||
|
"0,1",
|
||||||
|
"0,2",
|
||||||
|
"0,3",
|
||||||
|
"0,4",
|
||||||
|
"0,5",
|
||||||
|
"0,6",
|
||||||
|
"0,7",
|
||||||
|
"0,8",
|
||||||
|
"0,9",
|
||||||
|
"0,10",
|
||||||
|
"0,11"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"1,0",
|
||||||
|
"1,1",
|
||||||
|
"1,2",
|
||||||
|
"1,3",
|
||||||
|
"1,4",
|
||||||
|
"1,5",
|
||||||
|
"1,6",
|
||||||
|
"1,7",
|
||||||
|
"1,8",
|
||||||
|
"1,9",
|
||||||
|
"1,10",
|
||||||
|
"1,11"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2,0",
|
||||||
|
"2,1",
|
||||||
|
"2,2",
|
||||||
|
"2,3",
|
||||||
|
"2,4",
|
||||||
|
"2,5",
|
||||||
|
"2,6",
|
||||||
|
"2,7",
|
||||||
|
"2,8",
|
||||||
|
"2,9",
|
||||||
|
"2,10",
|
||||||
|
"2,11"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"3,0",
|
||||||
|
"3,1",
|
||||||
|
"3,2",
|
||||||
|
"3,3",
|
||||||
|
"3,4",
|
||||||
|
"3,5",
|
||||||
|
"3,6",
|
||||||
|
"3,7",
|
||||||
|
"3,8",
|
||||||
|
"3,9",
|
||||||
|
"3,10",
|
||||||
|
"3,11"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"4,0",
|
||||||
|
"4,1",
|
||||||
|
"4,2",
|
||||||
|
"4,3",
|
||||||
|
"4,4",
|
||||||
|
"4,5",
|
||||||
|
"4,6",
|
||||||
|
"4,7",
|
||||||
|
"4,8",
|
||||||
|
"4,9",
|
||||||
|
"4,10",
|
||||||
|
"4,11"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue