feat: initial commit for corne

This commit is contained in:
uttarayan21
2025-10-12 21:43:50 +05:30
commit d483267d6b
16 changed files with 3289 additions and 0 deletions

10
.cargo/config.toml Normal file
View File

@@ -0,0 +1,10 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
runner = "probe-rs run --chip nRF52840_xxAA"
linker = "flip-link"
[build]
target = "thumbv7em-none-eabihf"
[env]
DEFMT_LOG = "info"
KEYBOARD_TOML_PATH = { value = "keyboard.toml", relative = true }

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

9
.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
target
*.bin
*.elf
*.hex
*.uf2
.DS_Store
.direnv

2611
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

97
Cargo.toml Normal file
View File

@@ -0,0 +1,97 @@
[package]
name = "corne-rs"
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 = "2021"
license = "MIT OR Apache-2.0"
[dependencies]
rmk = { version = "0.7", features = [
"nrf52840_ble",
"split",
"async_matrix",
"adafruit_bl",
] }
nrf-sdc = { version = "0.1.0", default-features = false, features = [
"defmt",
"peripheral",
"central",
"nrf52840",
] }
nrf-mpsl = { version = "0.1.0", default-features = false, features = [
"defmt",
"critical-section-impl",
"nrf52840",
] }
bt-hci = { version = "0.3", default-features = false, features = ["defmt"] }
cortex-m = "0.7.7"
cortex-m-rt = "0.7.5"
embassy-time = { version = "0.4", features = ["tick-hz-32_768", "defmt", "defmt-timestamp-uptime"] }
embassy-nrf = { version = "0.3.1", features = [
"defmt",
"nrf52840",
"time-driver-rtc1",
"gpiote",
"unstable-pac",
"nfc-pins-as-gpio",
"time",
] }
embassy-executor = { version = "0.7", features = [
"defmt",
"arch-cortex-m",
"executor-thread",
] }
defmt = "1.0"
defmt-rtt = "1.0"
panic-probe = { version = "1.0", features = ["print-defmt"] }
static_cell = "2"
rand = { version = "0.8.4", default-features = false }
rand_core = { version = "0.6" }
rand_chacha = { version = "0.3", default-features = false }
[patch.crates-io]
embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", rev = "f35aa4005a63e8d478b2b95aaa2bfb316b72dece" }
embassy-futures = { git = "https://github.com/embassy-rs/embassy.git", rev = "f35aa4005a63e8d478b2b95aaa2bfb316b72dece" }
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", rev = "f35aa4005a63e8d478b2b95aaa2bfb316b72dece" }
embassy-nrf = { git = "https://github.com/embassy-rs/embassy.git", rev = "f35aa4005a63e8d478b2b95aaa2bfb316b72dece" }
embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "f35aa4005a63e8d478b2b95aaa2bfb316b72dece" }
embassy-usb = { git = "https://github.com/embassy-rs/embassy.git", rev = "f35aa4005a63e8d478b2b95aaa2bfb316b72dece" }
embassy-embedded-hal = { git = "https://github.com/embassy-rs/embassy.git", rev = "f35aa4005a63e8d478b2b95aaa2bfb316b72dece" }
nrf-sdc = { git = "https://github.com/alexmoon/nrf-sdc.git", rev = "7be9b853e15ca0404d65c623d1ec5795fd96c204" }
nrf-mpsl = { git = "https://github.com/alexmoon/nrf-sdc.git", rev = "7be9b853e15ca0404d65c623d1ec5795fd96c204" }
trouble-host = { git = "https://github.com/embassy-rs/trouble", rev = "90c6359" }
[build-dependencies]
xz2 = "0.1.7"
json = "0.12"
const-gen = "1.6"
# Split keyboard example
[[bin]]
name = "central"
path = "src/central.rs"
[[bin]]
name = "peripheral"
path = "src/peripheral.rs"
[profile.dev]
codegen-units = 1 # better optimizations
debug = true
opt-level = 1
overflow-checks = true
lto = false
panic = 'unwind'
[profile.release]
codegen-units = 1 # better optimizations
debug = true # no overhead for bare-metal
opt-level = "z" # optimize for binary size
overflow-checks = false
lto = "fat"

83
Makefile.toml Normal file
View File

@@ -0,0 +1,83 @@
[tasks.install-llvm-tools]
install_crate = { rustup_component_name = "llvm-tools" }
[tasks.flip-link]
install_crate = { crate_name = "flip-link", binary = "flip-link", test_arg = ["-h"] }
[tasks.build]
command = "cargo"
args = ["build", "--release"]
dependencies = ["install-llvm-tools", "flip-link"]
[tasks.objcopy-central]
install_crate = { crate_name = "cargo-binutils", binary = "cargo", test_arg = [
"objcopy",
"--help",
] }
command = "cargo"
args = [
"objcopy",
"--release",
"--bin",
"central",
"--",
"-O",
"ihex",
"corne-rs-central.hex",
]
dependencies = ["build"]
[tasks.objcopy-peripheral]
install_crate = { crate_name = "cargo-binutils", binary = "cargo", test_arg = [
"objcopy",
"--help",
] }
command = "cargo"
args = [
"objcopy",
"--release",
"--bin",
"peripheral",
"--",
"-O",
"ihex",
"corne-rs-peripheral.hex",
]
dependencies = ["build"]
[tasks.uf2-central]
install_crate = { crate_name = "cargo-hex-to-uf2", binary = "cargo", test_arg = [
"hex-to-uf2",
"--help",
] }
command = "cargo"
args = [
"hex-to-uf2",
"--input-path",
"corne-rs-central.hex",
"--output-path",
"corne-rs-central.uf2",
"--family",
"nrf52840",
]
dependencies = ["objcopy-central"]
[tasks.uf2-peripheral]
install_crate = { crate_name = "cargo-hex-to-uf2", binary = "cargo", test_arg = [
"hex-to-uf2",
"--help",
] }
command = "cargo"
args = [
"hex-to-uf2",
"--input-path",
"corne-rs-peripheral.hex",
"--output-path",
"corne-rs-peripheral.uf2",
"--family",
"nrf52840",
]
dependencies = ["objcopy-peripheral"]
[tasks.uf2]
dependencies = ["uf2-central", "uf2-peripheral"]

32
README.md Normal file
View File

@@ -0,0 +1,32 @@
# RMK
RMK is a feature-rich and easy-to-use keyboard firmware.
## uf2 support
If youre using the Adafruit_nRF52_Bootloader (pre-installed on the nice!nano), youre in luck! This bootloader supports the .uf2 firmware format, which eliminates the need for a debugging probe to flash your firmware. RMK uses the `cargo-make` tool to generate .uf2 firmware, with the generation process defined in the `Makefile.toml`.
Follow these steps to generate and flash the .uf2 firmware with RMK:
1. Get `cargo-make` tool:
```shell
cargo install --force cargo-make
```
2. Compile RMK and generates .uf2 firmware:
```shell
cargo make uf2 --release
```
3. Flash
- Put your board into bootloader mode. A USB drive will appear on your computer.
- Drag and drop the generated .uf2 firmware file onto the USB drive. The RMK firmware will be automatically flashed onto your microcontroller.
For additional details on entering bootloader mode and flashing firmware, refer to the [nice!nano documentation](https://nicekeyboards.com/docs/nice-nano/getting-started#flashing-firmware-and-bootloaders)
### Tips for nRF52840
Most nice!nano compatible boards have bootloader with SoftDevice pre-flashed. Since v0.7.x, RMK will remove old SoftDevice Bluetooth stack and replace it with its own. So if you want to rollback to v0.6.x, or switch to firmwares that use SoftDevice stack(for example, zmk), you will need to [re-flash the bootloader](https://nicekeyboards.com/docs/nice-nano/troubleshooting#my-nicenano-seems-to-be-acting-up-and-i-want-to-re-flash-the-bootloader).
### Additional notes
RMK defaults to USB-priority mode if a USB cable is connected. After flashing, remember to disconnect the USB cable, or [switch to BLE-priority mode](https://rmk.rs/docs/features/wireless.html#multiple-profile-support) by pressing User11(Switch Output) key.

87
build.rs Normal file
View File

@@ -0,0 +1,87 @@
//! 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.
//!
//! The build script also sets the linker flags to tell it which link script to use.
use const_gen::*;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::{env, fs};
use xz2::read::XzEncoder;
fn main() {
// Generate vial config at the root of project
println!("cargo:rerun-if-changed=vial.json");
println!("cargo:rerun-if-changed=keyboard.toml");
generate_vial_config();
// 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");
// Specify linker arguments.
// `--nmagic` is required if memory section addresses are not aligned to 0x10000,
// for example the FLASH and RAM sections in your `memory.x`.
// See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
println!("cargo:rustc-link-arg=--nmagic");
// Set the linker script to the one provided by cortex-m-rt.
println!("cargo:rustc-link-arg=-Tlink.x");
// Set the extra linker script from defmt
println!("cargo:rustc-link-arg=-Tdefmt.x");
// Use flip-link overflow check: https://github.com/knurling-rs/flip-link
println!("cargo:rustc-linker=flip-link");
}
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();
}

120
flake.lock generated Normal file
View File

@@ -0,0 +1,120 @@
{
"nodes": {
"crates-io-index": {
"flake": false,
"locked": {
"lastModified": 1760269763,
"narHash": "sha256-tQKMd4cnyRnPBcQrOTIwvgN3zP+08UToiO3e0h8ve1E=",
"owner": "rust-lang",
"repo": "crates.io-index",
"rev": "17599ab4988926ab8789bbf7d8634514c6bb65a0",
"type": "github"
},
"original": {
"owner": "rust-lang",
"repo": "crates.io-index",
"type": "github"
}
},
"crates-nix": {
"inputs": {
"crates-io-index": [
"crates-io-index"
]
},
"locked": {
"lastModified": 1759305425,
"narHash": "sha256-Za25XBr6UjZyguuXbctheUNT/6wPhbLs8YSXNTqyXaw=",
"owner": "uttarayan21",
"repo": "crates.nix",
"rev": "8879158206af5508a2c740d732bca92ae799c2b5",
"type": "github"
},
"original": {
"owner": "uttarayan21",
"repo": "crates.nix",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1760038930,
"narHash": "sha256-Oncbh0UmHjSlxO7ErQDM3KM0A5/Znfofj2BSzlHLeVw=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "0b4defa2584313f3b781240b29d61f6f9f7e0df3",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"crates-io-index": "crates-io-index",
"crates-nix": "crates-nix",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1760236527,
"narHash": "sha256-h9+WEQtUIZaZMvA1pnbZbMM+5X39OFnW92Q8hNoToD0=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "a38dd7f462825c75ce8567816ae38c2e7d826bfa",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

69
flake.nix Normal file
View File

@@ -0,0 +1,69 @@
{
description = "A very basic clang devshell flake";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
crates-nix = {
url = "github:uttarayan21/crates.nix";
inputs.crates-io-index.follows = "crates-io-index";
};
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
crates-io-index = {
url = "github:rust-lang/crates.io-index";
flake = false;
};
};
outputs = {
self,
nixpkgs,
flake-utils,
crates-nix,
rust-overlay,
...
}:
flake-utils.lib.eachDefaultSystem (system: let
overlays = [
# (final: prev: {
# })
rust-overlay.overlays.default
];
pkgs = import nixpkgs {
inherit system overlays;
};
crates = crates-nix.mkLib {inherit pkgs;};
stableToolchain = pkgs.rust-bin.stable.latest.default.override {
targets = ["thumbv7em-none-eabihf"];
extensions = ["rust-src" "llvm-tools"];
};
stableToolchainWithLLvmTools = pkgs.rust-bin.stable.latest.default.override {
targets = ["thumbv7em-none-eabihf"];
extensions = ["rust-src" "llvm-tools"];
};
stableToolchainWithRustAnalyzer = pkgs.rust-bin.stable.latest.default.override {
targets = ["thumbv7em-none-eabihf"];
extensions = ["rust-src" "llvm-tools" "rust-analyzer"];
};
in {
# packages = {
# };
devShells.default = pkgs.mkShell {
nativeBuildInputs = with pkgs; [clang pkg-config];
buildInputs = with pkgs; [libiconv];
# PKG_CONFIG_PATH = pkgs.lib.makeSearchPath "lib/pkgconfig" (with pkgs; [ncnn]);
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";
packages = with pkgs; [
(crates.buildCrate "rmkit" {})
(crates.buildCrate "cargo-hex-to-uf2" {})
flip-link
cargo-make
cargo-binutils
stableToolchainWithRustAnalyzer
];
};
});
}

65
keyboard.toml Normal file
View File

@@ -0,0 +1,65 @@
[keyboard]
name = "corne-rs"
product_name = "corne-rs"
vendor_id = 0x4c4b
product_id = 0x4643
manufacturer = "RMK"
chip = "nrf52840"
[layout]
# WARNING: Currently row2col/col2row is set in RMK's feature gate, row2col config here is valid ONLY when you're using cloud compilation.
# Checkout doc here: https://rmk.rs/docs/user_guide/faq.html#my-matrix-is-row2col-the-matrix-doesn-t-work
# row2col = true
rows = 4
cols = 12
layers = 3
keymap = [
[
["Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "Backspace"],
["LCtrl", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Semicolon", "Quote"],
["LShift", "Z", "X", "C", "V", "B", "N", "M", "Comma", "Dot", "Slash", "Enter"],
["__", "__", "__", "OSM(LGui)", "LAlt", "Space", "Enter", "MO(2)", "MO(1)", "__", "__", "__"]
],
[
["Tab", "Kc1", "Kc2", "Kc3", "Kc4", "Kc5", "Kc6", "Kc7", "Kc8", "Kc9", "Kc0", "Delete"],
["_", "AudioVolDown", "AudioVolUp", "AudioMute", "BrightnessDown", "BrightnessUp", "Left", "Down", "UP", "Right", "Semicolon", "Quote"],
["_", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F12", "_"],
["__", "__", "__", "_", "_", "_", "_", "_", "_", "__", "__", "__"]
],
[
["_", "WM(Kc1, LShift)", "WM(Kc2, LShift)", "WM(Kc3, LShift)", "WM(Kc4, LShift)", "WM(Kc5, LShift)", "WM(Kc6, LShift)", "WM(Kc7, LShift)", "WM(Kc8, LShift)", "WM(Kc9, LShift)", "WM(Kc0, LShift)", "Backspace"],
["_", "User0", "User1", "User2", "User4", "User5", "Minus", "Equal", "LeftBracket", "RightBracket", "Backslash", "Grave"],
["_", "User10", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_"],
["__", "__", "__", "_", "_", "_", "_", "_", "LAlt", "__", "__", "__"]
],
]
[ble]
enabled = true
[behavior]
tap_hold = { enable_hrm = true }
[split]
connection = "ble"
[split.central]
rows = 4
cols = 6
row_offset = 0
col_offset = 0
ble_addr = [0x18, 0xe2, 0x21, 0x80, 0xc0, 0xc7]
[split.central.matrix]
input_pins = ["P0_22", "P0_24", "P1_00", "P0_11"]
output_pins = ["P0_31", "P0_29", "P0_02", "P1_15", "P1_13", "P1_11"]
[[split.peripheral]]
rows = 4
cols = 6
row_offset = 0
col_offset = 6
ble_addr = [0x7e, 0xfe, 0x73, 0x9e, 0x66, 0xe3]
[split.peripheral.matrix]
input_pins = ["P0_22", "P0_24", "P1_00", "P0_11"]
output_pins = ["P1_11", "P1_13", "P1_15", "P0_02", "P0_29", "P0_31"]

11
memory.x Normal file
View File

@@ -0,0 +1,11 @@
MEMORY
{
/* NOTE 1 K = 1 KiB = 1024 bytes */
/* These values correspond to the nRF52840 WITH Adafruit nRF52 bootloader */
FLASH : ORIGIN = 0x00001000, LENGTH = 1020K
RAM : ORIGIN = 0x20000008, LENGTH = 255K
/* These values correspond to the nRF52840 */
/* FLASH : ORIGIN = 0x00000000, LENGTH = 1024K */
/* RAM : ORIGIN = 0x20000000, LENGTH = 256K */
}

6
rust-toolchain.toml Normal file
View File

@@ -0,0 +1,6 @@
[toolchain]
channel = "stable"
components = ["rust-src", "rustfmt", "llvm-tools"]
targets = [
"thumbv7em-none-eabihf",
]

7
src/central.rs Normal file
View File

@@ -0,0 +1,7 @@
#![no_main]
#![no_std]
use rmk::macros::rmk_central;
#[rmk_central]
mod keyboard_central {}

7
src/peripheral.rs Normal file
View File

@@ -0,0 +1,7 @@
#![no_main]
#![no_std]
use rmk::macros::rmk_peripheral;
#[rmk_peripheral(id = 0)]
mod keyboard_peripheral {}

74
vial.json Normal file
View File

@@ -0,0 +1,74 @@
{
"name": "corne-rs",
"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"
]
]
}
}