From 5004e8dfdf7328219aa64163bb85d9819822452b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Hlusi=C4=8Dka?= Date: Thu, 12 Feb 2026 22:44:13 +0100 Subject: [PATCH] Support RMK device config --- firmware/acid-firmware/Cargo.toml | 2 -- firmware/acid-firmware/build.rs | 54 ++++++++++++++++++++++++++---- firmware/acid-firmware/src/main.rs | 33 ++++++++++++++++-- 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/firmware/acid-firmware/Cargo.toml b/firmware/acid-firmware/Cargo.toml index 63010f7..f32166c 100644 --- a/firmware/acid-firmware/Cargo.toml +++ b/firmware/acid-firmware/Cargo.toml @@ -3,8 +3,6 @@ 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] diff --git a/firmware/acid-firmware/build.rs b/firmware/acid-firmware/build.rs index 6eac8d0..3b1378e 100644 --- a/firmware/acid-firmware/build.rs +++ b/firmware/acid-firmware/build.rs @@ -149,16 +149,58 @@ fn generate_vial_config() { }; let vial_cfg = json::parse(&content).unwrap(); - let vial_cfg_string = json::stringify(vial_cfg.clone()); - let mut keyboard_def_compressed: Vec = Vec::new(); - XzEncoder::new(vial_cfg_string.as_bytes(), 6) - .read_to_end(&mut keyboard_def_compressed) - .unwrap(); - let keyboard_id: Vec = vec![0xB9, 0xBC, 0x09, 0xB2, 0x9D, 0x37, 0x4C, 0xEA]; + let keyboard_def_compressed: Vec = { + let vial_cfg_string = json::stringify(vial_cfg.clone()); + let mut keyboard_def_compressed = Vec::new(); + XzEncoder::new(vial_cfg_string.as_bytes(), 6) + .read_to_end(&mut keyboard_def_compressed) + .unwrap(); + keyboard_def_compressed + }; + // This is a firmware-unique randomly generated ID. + // If you fork this repo to make your own firmware, you should change this. + let keyboard_id: Vec = vec![0x9a, 0x8a, 0x08, 0xae, 0x87, 0xcd, 0xc7, 0xb9]; + let keyboard_name: &str = { + let JsonValue::Object(vial_cfg) = &vial_cfg else { + panic!("The root element in `vial.json` is not an object."); + }; + vial_cfg + .get("name") + .expect("No `name` in `vial.json`.") + .as_str() + .expect("`name` in `vial.json` is not a string.") + }; + let vendor_id: u16 = { + let JsonValue::Object(vial_cfg) = &vial_cfg else { + panic!("The root element in `vial.json` is not an object."); + }; + let vendor_id_string = vial_cfg + .get("vendorId") + .expect("No `vendorId` in `vial.json`.") + .as_str() + .expect("`vendorId` in `vial.json` is not a string."); + assert!(vendor_id_string.starts_with("0x")); + u16::from_str_radix(&vendor_id_string[2..], 16).expect("Invalid vendor ID.") + }; + let product_id: u16 = { + let JsonValue::Object(vial_cfg) = &vial_cfg else { + panic!("The root element in `vial.json` is not an object."); + }; + let product_id_string = vial_cfg + .get("productId") + .expect("No `productId` in `vial.json`.") + .as_str() + .expect("`productId` in `vial.json` is not a string."); + assert!(product_id_string.starts_with("0x")); + u16::from_str_radix(&product_id_string[2..], 16).expect("Invalid product ID.") + }; let const_declarations = [ const_declaration!(pub VIAL_KEYBOARD_DEF = keyboard_def_compressed), const_declaration!(pub VIAL_KEYBOARD_ID = keyboard_id), + const_declaration!(pub VIAL_KEYBOARD_NAME = keyboard_name), + const_declaration!(pub VIAL_VENDOR_ID = vendor_id), + const_declaration!(pub VIAL_PRODUCT_ID = product_id), ] .map(|s| "#[allow(clippy::redundant_static_lifetimes)]\n".to_owned() + s.as_str()) .join("\n"); diff --git a/firmware/acid-firmware/src/main.rs b/firmware/acid-firmware/src/main.rs index 1f26a6d..0b2da20 100644 --- a/firmware/acid-firmware/src/main.rs +++ b/firmware/acid-firmware/src/main.rs @@ -23,6 +23,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; use alloc::boxed::Box; use alloc::collections::vec_deque::VecDeque; +use alloc::format; use alloc::string::String; use alloc::sync::Arc; use alloc::vec; @@ -40,6 +41,7 @@ use esp_bootloader_esp_idf::partitions::PartitionTable; use esp_hal::Blocking; use esp_hal::clock::CpuClock; use esp_hal::dma::{BurstConfig, DmaDescriptor, DmaTxBuf, ExternalBurstConfig}; +use esp_hal::efuse::Efuse; use esp_hal::gpio::{Flex, Input, InputConfig, Level, Output, OutputConfig, Pull}; use esp_hal::i2c::master::{I2c, I2cAddress}; use esp_hal::interrupt::software::SoftwareInterruptControl; @@ -55,9 +57,12 @@ use esp_hal::timer::timg::TimerGroup; use esp_rtos::embassy::Executor; use esp_storage::FlashStorage; use indoc::writedoc; +use itertools::Itertools; use log::{error, info, warn}; use rmk::channel::{CONTROLLER_CHANNEL, ControllerSub}; -use rmk::config::{BehaviorConfig, PositionalConfig, RmkConfig, StorageConfig, VialConfig}; +use rmk::config::{ + BehaviorConfig, DeviceConfig, PositionalConfig, RmkConfig, StorageConfig, VialConfig, +}; use rmk::controller::{Controller, EventController}; use rmk::debounce::default_debouncer::DefaultDebouncer; use rmk::event::ControllerEvent; @@ -77,7 +82,10 @@ use crate::logging::LOG_LEVEL_FILTER; use crate::matrix::IoeMatrix; use crate::peripherals::st7701s::St7701s; use crate::ui::backend::{FramebufferPtr, SlintBackend}; -use crate::vial::{CustomKeycodes, VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID}; +use crate::vial::{ + CustomKeycodes, VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID, VIAL_KEYBOARD_NAME, VIAL_PRODUCT_ID, + VIAL_VENDOR_ID, +}; mutually_exclusive_features::none_or_one_of!["usb-log", "alt-log", "rtt-log"]; @@ -388,7 +396,28 @@ async fn main(_spawner: Spawner) { }, ..Default::default() }; + // Retrieve the hardware-unique MAC address. + let mac_address = Efuse::read_base_mac_address(); + static SERIAL_NUMBER: StaticCell> = StaticCell::new(); + let serial_number = SERIAL_NUMBER.init_with(|| { + /// A magic prefix string that is required for the device to be recognized by the Vial GUI. + const VIAL_SERIAL_PREFIX: &str = "vial:f64c2b3c"; + format!( + "{VIAL_SERIAL_PREFIX}:acid:{:02x}", + mac_address.iter().format("") + ) + .into_boxed_str() + }); + let device_config = DeviceConfig { + vid: VIAL_VENDOR_ID, + pid: VIAL_PRODUCT_ID, + manufacturer: "", + product_name: VIAL_KEYBOARD_NAME, + serial_number, + }; + info!("RMK Device Config: {device_config:#04x?}"); let rmk_config = RmkConfig { + device_config, vial_config, storage_config, ..Default::default()