Coder Social home page Coder Social logo

haobogu / rmk Goto Github PK

View Code? Open in Web Editor NEW
310.0 5.0 23.0 4.39 MB

Rust keyboard firmware library with layers, macros, real-time keymap editing, and wireless(BLE) support

Home Page: https://haobogu.github.io/rmk/

License: Apache License 2.0

Rust 98.60% Shell 0.40% Python 0.99%
cortex-m firmware keyboard rust stm32 rp2040 embedded keyboard-firmware usb usb-hid

rmk's Introduction

RMK

Crates.io Docs Build Discord

中文

A feature-rich Rust keyboard firmware.

Features

  • Support a wide range of microcontrollers: Powered by embassy, RMK supports a wide range of microcontrollers, such as stm32/nRF/rp2040/esp32
  • Real-time keymap editing: RMK has built-in vial support, the keymap can be changed on-the-fly
  • Advanced keyboard features: Many advanced keyboard features are available by default in RMK, such as layer switch, media control, system control, mouse control, etc
  • Wireless: BLE wireless support with auto-reconnection/multiple devices feature for nRF52 and esp32 microcontrollers, tested on nRF52840, esp32c3 and esp32s3
  • Easy configuration: RMK provides a simple way to build your keyboard: a keyboard.toml is all you need! For experienced Rust user, you can still customize your firmware easily using RMK
  • Low latency and low-power ready: RMK has a typical 2 ms latency in wired mode and 10 ms latency in wireless mode. By enabling async_matrix feature, RMK has very low power consumption, with a 2000mah battery, RMK can provide several months battery life

Real World Examples

Usage

Option 1: Initialize from template

You can use rmk-template to initialize your project.

cargo install cargo-generate
cargo generate --git https://github.com/HaoboGu/rmk-template

Then follow the steps in generated README.md. Check RMK's User Guide for details.

Option 2: Try built-in examples

Example can be found at examples. The following is a simple step-to-step instruction for rp2040. For other microcontrollers, the steps should be identical with a debug probe.

rp2040

  1. Install probe-rs

    cargo install probe-rs --features cli
  2. Build the firmware

    cd examples/use_rust/rp2040
    cargo build
  3. Flash using debug probe

    If you have a debug probe connected to your rp2040 board, flashing is quite simple: run the following command to automatically compile and flash RMK firmware to the board:

    cd examples/use_rust/rp2040
    cargo run
  4. (Optional) Flash using USB

    If you don't have a debug probe, you can use elf2uf2-rs to flash your firmware via USB. There are several additional steps you have to do:

    1. Install elf2uf2-rs: cargo install elf2uf2-rs
    2. Update examples/use_rust/rp2040/.cargo/config.toml, use elf2uf2 as the flashing tool
      - runner = "probe-rs run --chip RP2040"
      + runner = "elf2uf2-rs -d"
    3. Connect your rp2040 board holding the BOOTSEL key, ensure that rp's USB drive appears
    4. Flash
      cd examples/use_rust/rp2040
      cargo run
      Then, you will see logs like if everything goes right:
      Finished release [optimized + debuginfo] target(s) in 0.21s
      Running `elf2uf2-rs -d 'target\thumbv6m-none-eabi\release\rmk-rp2040'`
      Found pico uf2 disk G:\
      Transfering program to pico
      173.00 KB / 173.00 KB [=======================] 100.00 % 193.64 KB/s  

Current roadmap of RMK can be found here.

Minimum Supported Rust Version (MSRV)

This crate uses latest stable. Other versions should work, but they're not tested.

License

RMK is licensed under either of

at your option.

rmk's People

Contributors

haobogu avatar lonesometraveler avatar szabgab avatar tuxiqae avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

rmk's Issues

The rp2040 example doesn't work on my rpi-pico board.

linux mint 21.2
Offical raspberrypi pico core board.

I tried

cargo build
warning: unused import: `Blocking`
  --> src/main.rs:16:20
   |
16 |     flash::{Async, Blocking, Flash},
   |                    ^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

warning: `rmk-rp2040` (bin "rmk-rp2040") generated 1 warning (run `cargo fix --bin "rmk-rp2040"` to apply 1 suggestion)
    Finished dev [optimized + debuginfo] target(s) in 12.49s

and

cargo run
warning: unused import: `Blocking`
  --> src/main.rs:16:20
   |
16 |     flash::{Async, Blocking, Flash},
   |                    ^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

warning: `rmk-rp2040` (bin "rmk-rp2040") generated 1 warning (run `cargo fix --bin "rmk-rp2040"` to apply 1 suggestion)
    Finished dev [optimized + debuginfo] target(s) in 0.04s
     Running `probe-rs run --chip RP2040 target/thumbv6m-none-eabi/debug/rmk-rp2040`
      Erasing ✔ [00:00:01] [####] 116.00 KiB/116.00 KiB @ 79.42 KiB/s (eta 0s )
  Programming ✔ [00:00:02] [####] 116.00 KiB/116.00 KiB @ 46.39 KiB/s (eta 0s )    Finished in 3.991s

But the Pico board doesn't seem to have any response, I mean after connecting the USB cable to the computer.

Did I miss any steps? Thanks.

Create a template for creating Rmk firmware

A template could helps users easily use the library, but there are some stuffs to figure out in the template:

  • the list of required user input
  • stm32 support
  • nrf support
  • esp support
  • rp2040 support
  • microcontroller's default target

Purpose of `hold_start` in `KeyState`

A question about KeyState's hold_start.

pub(crate) struct KeyState {
    pub(crate) pressed: bool,
    pub(crate) changed: bool,
    hold_start: Option<Instant>,
}

Matrix has this function:

pub(crate) fn key_pressed(&mut self, row: usize, col: usize) {
    // COL2ROW
    #[cfg(feature = "col2row")]
    self.key_states[col][row].start_timer();

    // ROW2COL
    #[cfg(not(feature = "col2row"))]
    self.key_states[row][col].start_timer();
}

And Keyboard calls it to start a timer at this line:

self.matrix.key_pressed(row, col);

However, it seems that the timer is not cleared or referenced in the current implementation. So, the hold_start field is effectively unused. What is the purpose of hold_start?

nRF52832 Runtime error with version 0.1.9

Since the nrf-softdevice flash module's capacity function returns an incorrect value for nRF52832, a nRF52832 BLE program always fails at runtime here:

impl<F: AsyncNorFlash> Storage<F> {
    pub async fn new<const ROW: usize, const COL: usize, const NUM_LAYER: usize>(
        flash: F,
        keymap: &[[[KeyAction; COL]; ROW]; NUM_LAYER],
    ) -> Self {
        let storage_range = (flash.capacity() - 2 * F::ERASE_SIZE) as u32..flash.capacity() as u32;
        let mut storage = Self {
            flash,
            storage_range,
        };

        // Check whether keymap and configs have been storaged in flash
        if !storage.check_enable::<ROW, COL, NUM_LAYER>().await {
            // Initialize storage from keymap and config
            if let Err(e) = storage.initialize_storage_with_config(keymap).await {
                error!("Initialize storage error: {}", e)
            }
        }

        storage
    }

add touchpad support

there's a rust driver for the azoteq tps-65 available here. it would be nice for this to get ported to rmk. i will be trying to get this working on my current keyboard build with n!n and a tps43, but i'm making slow progress on my project so i'd like to put this out there for others to try if they'd like.

Key Mapping doesn't seem to update while building

So glad I came across this project and I even hope to start contributing to it too!

I've tried taking an rp2040 example and updated the size of the matrix and the keymapping.

The changes were made in keymap.rs, keyboard.toml, and vial.json. I see additional defmt log statements I added being printed but the key is still responding with the original keymap from the example.

I'm loading via cargo run using an RPi Pico Probe to a RPi Pico. Am I missing some step in getting the new config to be recognized and built?

Thanks!

Support embassy

Current implementation of RMK requires only rtic-monotonics. It's possible to support embassy, or both by removing rtic-monotonics.

Modifier Keys not working in combination with normal keys on MacOS

Hey,

I have tried to create a key combination like LSpace(KC_A).
However, this gets registered as "a" not as "A".

Same for LGui(KC_Space) which gets registered as space and not as LGui Space (which would open the spotlight search on macos).

I checked the keyboard.rs, however, I was not yet able to find why this happens. I tried on two different RP2040's.

I set the macros / keymap via vial.rocks

Maybe anyone has an idea why this happens.

Configuration system

RMK now uses RMKConfig as a collection of configurable settings. Users have to create and pass a config struct to RMK in main.rs. Matrix pins, light pins are also defined separately in main.rs.

Ideally, there should be a config file where users can add all keyboard specific configs and RMK reads the config file at compile-time, sets all the pin configs, keyboard configs automatically.

I've investigated some solutions, like toml-cfg, but haven't decided how to implement it. If you have any idea about it, please just comment below!

Update: For the proof-of-concept impl, I'd go for proc macro approach

Switch between usb/ble

Switch between usb/ble

  • use same storage for usb & ble
  • add usb task for ble
  • auto switch when usb cable connects

Generate vial config automatically

Just moved default vial configs to outer level, making it configurable.

The next step is automatically generate them from keymap using build.rs

No connected probes were found

After I have placed rmk clone locally, and entered the nrf52840_ble directory, I run the cargo run --release command and get the following error:

cargo run --release Finished release [optimized + debuginfo] target(s) in 0.14s Runningprobe-rs run --chip nRF52840_xxAA target/thumbv7em-none-eabi/release/rmk-nrf52840 Error: No connected probes were found.

Use jlink to connect to my pad, connect four interfaces swd, swc, gnd, vcc, my pad uses e73 module, e73 module uses 52840.
My pad used to run zmk firmware.

rust version :1.76.0
system:macos12.7.4

BLE support for nRF52832

Thank you for developing and maintaining this incredible project.

I've noticed that the BLE support is currently limited to nRF52840. Are there any plans to include support for nRF52832? If not, I'm willing to take on the task of adding support for nRF52832. I believe this will broaden the project's accessibility.

uC Power Consumption and sleep mode

Hey! First of all thank you very much for releasing this awesome firmware! I have a question regarding power consumption.

I am planning on building a wearable BLE keyboard for outdoor scenaria, where a low power consumption is important for battery life. This would mean in my project I would like to rely on embassys interrupt-triggered pin level change notifications to allow the uC to go to sleep when no key is pressed and whenever the BLE stack permits this. Getting this right could enable a half-year battery-life (or so) on a button cell or so.

From afar rmk looks like perfect fit for the software for this project. However, as far as I understand the project, rmk will currently regularly poll the keyboard GPIO pins for their level instead of relying on embassy's interrupt-triggered async GPIO pin implementation to be notified on changes of the pin levels:

rmk/rmk/src/matrix.rs

Lines 84 to 107 in 243ba43

pub(crate) async fn scan(&mut self) -> Result<(), Infallible> {
for (out_idx, out_pin) in self.output_pins.iter_mut().enumerate() {
// Pull up output pin, wait 1us ensuring the change comes into effect
out_pin.set_high()?;
Timer::after_micros(1).await;
for (in_idx, in_pin) in self.input_pins.iter_mut().enumerate() {
// Check input pins and debounce
let changed = self.debouncer.detect_change_with_debounce(
in_idx,
out_idx,
in_pin.is_high()?,
&self.key_states[out_idx][in_idx],
);
if changed {
self.key_states[out_idx][in_idx].toggle_pressed();
}
self.key_states[out_idx][in_idx].changed = changed;
}
out_pin.set_low()?;
}
Ok(())
}

This would imply the uC cannot/does not go to a lower power level in between key presses, and would cause a "high" (in terms of what is possible for mobile scenaria) power consumption. Is that correct? Is this something you would like to improve?

I'm not sure I know enough about DIY keyboards to be able to drive a new, fully async implementation here (I think an async implementation would need quite some work on the debouncing/post-processing side), but would you be open to PRs on this topic?

Thank you in advance and best regards!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.