Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
- stm32h7b0vb
- esp32c3
- esp32c6
- esp32h2
steps:
- uses: cargo-bins/cargo-binstall@main
- uses: actions/checkout@v3
Expand All @@ -50,6 +51,7 @@ jobs:
- pico_w
- esp32c3
- esp32c6
- esp32h2
steps:
- uses: cargo-bins/cargo-binstall@main
- uses: actions/checkout@v3
Expand Down
14 changes: 14 additions & 0 deletions esp32h2/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[target.'cfg(all(any(target_arch = "riscv32", target_arch = "xtensa"), target_os = "none"))']
runner = "espflash flash --monitor"

[build]
target = "riscv32imac-unknown-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"
KEYBOARD_TOML_PATH = { value = "keyboard.toml", relative = true }
8 changes: 8 additions & 0 deletions esp32h2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
target

*.bin
*.elf
*.hex
*.uf2

.DS_Store
76 changes: 76 additions & 0 deletions esp32h2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
[package]
name = "{{ project_name }}"
version = "0.1.0"
authors = ["Haobo Gu <haobogu@outlook.com>"]
description = "Keyboard firmware written in Rust"
homepage = "https://github.com/haobogu/rmk"
repository = "https://github.com/haobogu/rmk"
readme = "README.md"
edition = "2024"
license = "MIT OR Apache-2.0"

[dependencies]
# TODO: switch to crates-io version when it's released.
rmk = { git = "https://github.com/HaoboGu/rmk", rev = "9a740762d80b208c2180cfd2dbde7ed889339d3e", default-features = false, features = [
"esp32h2_ble",
"log",
"storage",
"vial",
] }
embassy-executor = { version = "0.10" }
esp-backtrace = { version = "0.19", features = [
"esp32h2",
"panic-handler",
"println",
] }
esp-storage = { version = "0.9", features = ["esp32h2"] }
esp-hal = { version = "1.1", features = ["esp32h2", "unstable"] }
esp-alloc = { version = "0.10" }
esp-println = { version = "0.17", features = ["esp32h2", "log-04"] }
esp-radio = { version = "0.18", features = ["esp32h2", "unstable", "ble"] }
esp-rtos = { version = "0.3", features = ["esp32h2", "esp-radio", "embassy"] }
esp-bootloader-esp-idf = { version = "0.5", features = ["esp32h2", "log-04"] }
bt-hci = { version = "0.9" }

[build-dependencies]
xz2 = "0.1.7"
json = "0.12"
const-gen = "1.6"
embuild = "0.33"
cc = "1.2.9"

[[bin]]
name = "{{ project_name }}"
test = false
bench = false

[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

# esp-radio (crates.io 0.18) still pins bt-hci 0.8, but rmk/trouble-host need bt-hci 0.9.
# Pin the esp-hal graph to the embassy-rs/esp-hal fork (esp-radio 0.18 + bt-hci 0.9) —
# the same rev trouble's own esp CI uses. Drop once esp-radio ships bt-hci 0.9.
[patch.crates-io]
esp-alloc = { git = "https://github.com/embassy-rs/esp-hal.git", rev = "b7eec0fe94aa62d49dfc12d3bf87ca038a8d119f" }
esp-backtrace = { git = "https://github.com/embassy-rs/esp-hal.git", rev = "b7eec0fe94aa62d49dfc12d3bf87ca038a8d119f" }
esp-bootloader-esp-idf = { git = "https://github.com/embassy-rs/esp-hal.git", rev = "b7eec0fe94aa62d49dfc12d3bf87ca038a8d119f" }
esp-hal = { git = "https://github.com/embassy-rs/esp-hal.git", rev = "b7eec0fe94aa62d49dfc12d3bf87ca038a8d119f" }
esp-println = { git = "https://github.com/embassy-rs/esp-hal.git", rev = "b7eec0fe94aa62d49dfc12d3bf87ca038a8d119f" }
esp-radio = { git = "https://github.com/embassy-rs/esp-hal.git", rev = "b7eec0fe94aa62d49dfc12d3bf87ca038a8d119f" }
esp-rtos = { git = "https://github.com/embassy-rs/esp-hal.git", rev = "b7eec0fe94aa62d49dfc12d3bf87ca038a8d119f" }
esp-storage = { git = "https://github.com/embassy-rs/esp-hal.git", rev = "b7eec0fe94aa62d49dfc12d3bf87ca038a8d119f" }
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", rev = "1d3c3dec8edbf37450d0174b312f8d3d6cc0bf12" }
12 changes: 12 additions & 0 deletions esp32h2/Makefile.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[tasks.build]
command = "cargo"
args = ["build", "--release"]

[tasks.uf2]
install_crate = { crate_name = "cargo-espflash", binary = "cargo", test_arg = [
"espflash",
"--help",
] }
command = "cargo"
args = ["espflash", "save-image", "--release", "--chip", "esp32h2", "--merge", "{{ project_name }}.bin"]
dependencies = ["build"]
68 changes: 68 additions & 0 deletions esp32h2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# RMK

RMK is a feature-rich and easy-to-use keyboard firmware.

## Use the template

To run this firmware, you should have latest Rust 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:

```
cargo 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/riscv32imac-unknown-none-elf/release/{{ project_name }}`
[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: esp32h2 (revision v0.1)
Crystal frequency: 32 MHz
Flash size: 4MB
Features: BLE 5, IEEE 802.15.4
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/riscv32imac-unknown-none-elf/release/{{ project_name }} --chip esp32h2
```
49 changes: 49 additions & 0 deletions esp32h2/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
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() {
println!("cargo:rerun-if-changed=keyboard.toml");

// 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();
}
53 changes: 53 additions & 0 deletions esp32h2/keyboard.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
[keyboard]
name = "{{ project_name }}"
product_name = "{{ project_name }}"
vendor_id = 0x4c4b
product_id = 0x4643
manufacturer = "RMK"
chip = "esp32h2"
usb_enable = false

[matrix]
# Row and col pins are mandatory
# Note: esp32h2 exposes GPIO0-15 and GPIO22-27 (GPIO16-21 don't exist)
row_pins = ["GPIO6", "GPIO7", "GPIO10", "GPIO11"]
col_pins = ["GPIO3", "GPIO4", "GPIO5"]

# RMK uses col2row as the default matrix diode direction, if you want to use a row2col matrix, add `row2col = true`
# row2col = true

[layout]
rows = 4
cols = 3
layers = 2
keymap = [
[
["A", "B", "C"],
["Kc1", "Kc2", "Kc3"],
["LCtrl", "MO(1)", "LShift"],
["OSL(1)", "LT(2, Kc9)", "LM(1, LShift | LGui)"]
],
[
["_", "TT(1)", "TG(2)"],
["_", "_", "_"],
["_", "_", "_"],
["_", "_", "_"]
],
]

[light]
# All light pins are high-active by default, uncomment if you want it to be low-active
# capslock.pin = "GPIO12"
# capslock.low_active = true
# scrolllock.pin = "GPIO13"
# scrolllock.low_active = true
# Just ignore if no light pin is used for it
# numslock.pin = "GPIO14"
# numslock.low_active = true

[storage]
# Storage feature is enabled by default
# enabled = false

[ble]
enabled = true
6 changes: 6 additions & 0 deletions esp32h2/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[toolchain]
channel = "stable"
components = ["rust-src", "rustfmt", "llvm-tools"]
targets = [
"riscv32imac-unknown-none-elf",
]
9 changes: 9 additions & 0 deletions esp32h2/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![no_std]
#![no_main]

use rmk::macros::rmk_keyboard;

// Vial config is automatically generated by `build.rs`, according to `vial.json`
// Please put `vial.json` at your project's root
#[rmk_keyboard]
mod keyboard {}
74 changes: 74 additions & 0 deletions esp32h2/vial.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"name": "{{ project_name }}",
"vendorId": "0x4C4B",
"productId": "0x4643",
"lighting": "none",
"matrix": {
"rows": 4,
"cols": 3
},
"customKeycodes": [
{
"name": "BT0",
"title": "Bluetooth Channel 0",
"shortName": "BT0"
},
{
"name": "BT1",
"title": "Bluetooth Channel 1",
"shortName": "BT1"
},
{
"name": "BT2",
"title": "Bluetooth Channel 2",
"shortName": "BT2"
},
{
"name": "NEXT_BT",
"title": "Switch to the next Bluetooth channel",
"shortName": "Next\nBT"
},
{
"name": "PREV_BT",
"title": "Switch to the previous Bluetooth channel",
"shortName": "Prev\nBT"
},
{
"name": "CLR_BT",
"title": "Clear bond info for current channel",
"shortName": "Clear\nBT"
},
{
"name": "SWITCH",
"title": "Switch default output mode between USB/BLE",
"shortName": "Switch\nOutput"
}
],
"layouts": {
"keymap": [
[
"0,0",
"0,1",
"0,2"
],
[
"1,0",
"1,1",
"1,2"
],
[
"2,0",
"2,1",
"2,2"
],
[
{
"y": -2,
"x": 4
},
"3,0",
"3,2"
]
]
}
}
Loading
Loading