1use std::collections::HashMap;
2use std::path::Path;
3
4use config::{Config, File, FileFormat};
5use serde::de;
6use serde::Deserialize as SerdeDeserialize;
7use serde_derive::Deserialize;
8use serde_inline_default::serde_inline_default;
9
10pub mod chip;
11pub mod communication;
12pub mod keyboard;
13#[rustfmt::skip]
14pub mod usb_interrupt_map;
15pub mod behavior;
16pub mod board;
17pub mod keycode_alias;
18pub mod layout;
19pub mod light;
20pub mod storage;
21
22pub use board::{BoardConfig, UniBodyConfig};
23pub use chip::{ChipModel, ChipSeries};
24pub use communication::{CommunicationConfig, UsbInfo};
25pub use keyboard::Basic;
26pub use keycode_alias::KEYCODE_ALIAS;
27
28#[serde_inline_default]
30#[derive(Clone, Debug, Deserialize)]
31#[serde(deny_unknown_fields)]
32pub struct RmkConstantsConfig {
33 #[serde_inline_default(20)]
35 pub mouse_key_interval: u32,
36 #[serde_inline_default(80)]
38 pub mouse_wheel_interval: u32,
39 #[serde_inline_default(8)]
41 #[serde(deserialize_with = "check_combo_max_num")]
42 pub combo_max_num: usize,
43 #[serde_inline_default(4)]
45 pub combo_max_length: usize,
46 #[serde_inline_default(8)]
48 #[serde(deserialize_with = "check_fork_max_num")]
49 pub fork_max_num: usize,
50 #[serde_inline_default(256)]
52 pub macro_space_size: usize,
53 #[serde_inline_default(20)]
55 pub debounce_time: u16,
56 #[serde_inline_default(16)]
58 pub event_channel_size: usize,
59 #[serde_inline_default(16)]
61 pub controller_channel_size: usize,
62 #[serde_inline_default(8)]
64 pub controller_channel_pubs: usize,
65 #[serde_inline_default(8)]
67 pub controller_channel_subs: usize,
68 #[serde_inline_default(16)]
70 pub report_channel_size: usize,
71 #[serde_inline_default(4)]
73 pub vial_channel_size: usize,
74 #[serde_inline_default(4)]
76 pub flash_channel_size: usize,
77 #[serde_inline_default(1)]
79 pub split_peripherals_num: usize,
80 #[serde_inline_default(4)]
82 pub split_message_channel_size: usize,
83 #[serde_inline_default(3)]
85 pub ble_profiles_num: usize,
86}
87
88fn check_combo_max_num<'de, D>(deserializer: D) -> Result<usize, D::Error>
89where
90 D: de::Deserializer<'de>,
91{
92 let value = SerdeDeserialize::deserialize(deserializer)?;
93 if value > 256 {
94 panic!("❌ Parse `keyboard.toml` error: combo_max_num must be between 0 and 256, got {value}");
95 }
96 Ok(value)
97}
98
99fn check_fork_max_num<'de, D>(deserializer: D) -> Result<usize, D::Error>
100where
101 D: de::Deserializer<'de>,
102{
103 let value = SerdeDeserialize::deserialize(deserializer)?;
104 if value > 256 {
105 panic!("❌ Parse `keyboard.toml` error: fork_max_num must be between 0 and 256, got {value}");
106 }
107 Ok(value)
108}
109
110impl Default for RmkConstantsConfig {
112 fn default() -> Self {
113 Self {
114 mouse_key_interval: 20,
115 mouse_wheel_interval: 80,
116 combo_max_num: 8,
117 combo_max_length: 4,
118 fork_max_num: 8,
119 macro_space_size: 256,
120 debounce_time: 20,
121 event_channel_size: 16,
122 controller_channel_size: 16,
123 controller_channel_pubs: 8,
124 controller_channel_subs: 8,
125 report_channel_size: 16,
126 vial_channel_size: 4,
127 flash_channel_size: 4,
128 split_peripherals_num: 1,
129 split_message_channel_size: 4,
130 ble_profiles_num: 3,
131 }
132 }
133}
134
135#[derive(Clone, Debug, Deserialize)]
137#[allow(unused)]
138pub struct KeyboardTomlConfig {
139 keyboard: Option<KeyboardInfo>,
141 matrix: Option<MatrixConfig>,
143 aliases: Option<HashMap<String, String>>,
145 layer: Option<Vec<LayerTomlConfig>>,
147 layout: Option<LayoutTomlConfig>,
150 behavior: Option<BehaviorConfig>,
152 light: Option<LightConfig>,
154 storage: Option<StorageConfig>,
156 ble: Option<BleConfig>,
158 dependency: Option<DependencyConfig>,
160 split: Option<SplitConfig>,
162 input_device: Option<InputDeviceConfig>,
164 #[serde(default)]
166 pub rmk: RmkConstantsConfig,
167}
168
169impl KeyboardTomlConfig {
170 pub fn new_from_toml_str<P: AsRef<Path>>(config_toml_path: P) -> Self {
171 let user_config = match std::fs::read_to_string(config_toml_path.as_ref()) {
173 Ok(s) => match toml::from_str::<KeyboardTomlConfig>(&s) {
174 Ok(c) => c,
175 Err(e) => panic!("Parse {:?} error: {}", config_toml_path.as_ref(), e.message()),
176 },
177 Err(e) => panic!("Read keyboard config file {:?} error: {}", config_toml_path.as_ref(), e),
178 };
179 let default_config_str = user_config.get_chip_model().unwrap().get_default_config_str().unwrap();
180
181 Config::builder()
183 .add_source(File::from_str(default_config_str, FileFormat::Toml))
184 .add_source(File::with_name(config_toml_path.as_ref().to_str().unwrap()))
185 .build()
186 .unwrap()
187 .try_deserialize()
188 .unwrap()
189 }
190}
191
192#[derive(Clone, Debug, Deserialize)]
194#[allow(unused)]
195pub struct LayoutTomlConfig {
196 pub rows: u8,
197 pub cols: u8,
198 pub layers: u8,
199 pub keymap: Option<Vec<Vec<Vec<String>>>>, pub matrix_map: Option<String>, }
202
203#[derive(Clone, Debug, Deserialize)]
204#[allow(unused)]
205pub struct LayerTomlConfig {
206 pub name: Option<String>,
207 pub keys: String,
208}
209
210#[derive(Clone, Debug, Default, Deserialize)]
212pub struct KeyboardInfo {
213 pub name: String,
215 pub vendor_id: u16,
217 pub product_id: u16,
219 pub manufacturer: Option<String>,
221 pub product_name: Option<String>,
223 pub serial_number: Option<String>,
225 pub board: Option<String>,
227 pub chip: Option<String>,
229 pub usb_enable: Option<bool>,
231}
232
233#[derive(Clone, Debug, Default, Deserialize)]
234#[allow(non_camel_case_types)]
235pub enum MatrixType {
236 #[default]
237 normal,
238 direct_pin,
239}
240
241#[derive(Clone, Debug, Default, Deserialize)]
242pub struct MatrixConfig {
243 #[serde(default)]
244 pub matrix_type: MatrixType,
245 pub input_pins: Option<Vec<String>>,
246 pub output_pins: Option<Vec<String>>,
247 pub direct_pins: Option<Vec<Vec<String>>>,
248 #[serde(default = "default_true")]
249 pub direct_pin_low_active: bool,
250 #[serde(default = "default_false")]
251 pub row2col: bool,
252}
253
254#[derive(Clone, Copy, Debug, Default, Deserialize)]
256#[serde(deny_unknown_fields)]
257pub struct StorageConfig {
258 pub start_addr: Option<usize>,
261 pub num_sectors: Option<u8>,
263 #[serde(default = "default_true")]
264 pub enabled: bool,
265 pub clear_storage: Option<bool>,
267}
268
269#[derive(Clone, Default, Debug, Deserialize)]
270#[serde(deny_unknown_fields)]
271pub struct BleConfig {
272 pub enabled: bool,
273 pub battery_adc_pin: Option<String>,
274 pub charge_state: Option<PinConfig>,
275 pub charge_led: Option<PinConfig>,
276 pub adc_divider_measured: Option<u32>,
277 pub adc_divider_total: Option<u32>,
278}
279
280#[derive(Clone, Default, Debug, Deserialize)]
282#[serde(deny_unknown_fields)]
283pub struct LightConfig {
284 pub capslock: Option<PinConfig>,
285 pub scrolllock: Option<PinConfig>,
286 pub numslock: Option<PinConfig>,
287}
288
289#[derive(Clone, Default, Debug, Deserialize)]
291#[serde(deny_unknown_fields)]
292pub struct PinConfig {
293 pub pin: String,
294 pub low_active: bool,
295}
296
297#[derive(Clone, Debug, Deserialize)]
299#[serde(deny_unknown_fields)]
300pub struct DependencyConfig {
301 #[serde(default = "default_true")]
303 pub defmt_log: bool,
304}
305
306impl Default for DependencyConfig {
307 fn default() -> Self {
308 Self { defmt_log: true }
309 }
310}
311
312#[derive(Clone, Debug, Default, Deserialize)]
314#[serde(deny_unknown_fields)]
315pub struct LayoutConfig {
316 pub rows: u8,
317 pub cols: u8,
318 pub layers: u8,
319 pub keymap: Vec<Vec<Vec<String>>>,
320}
321
322#[derive(Clone, Debug, Default, Deserialize)]
324#[serde(deny_unknown_fields)]
325pub struct BehaviorConfig {
326 pub tri_layer: Option<TriLayerConfig>,
327 pub tap_hold: Option<TapHoldConfig>,
328 pub one_shot: Option<OneShotConfig>,
329 pub combo: Option<CombosConfig>,
330 pub fork: Option<ForksConfig>,
331}
332
333#[derive(Clone, Debug, Deserialize)]
335#[serde(deny_unknown_fields)]
336pub struct TapHoldConfig {
337 pub enable_hrm: Option<bool>,
338 pub prior_idle_time: Option<DurationMillis>,
339 pub post_wait_time: Option<DurationMillis>,
340 pub hold_timeout: Option<DurationMillis>,
341}
342
343#[derive(Clone, Debug, Deserialize)]
345#[serde(deny_unknown_fields)]
346pub struct TriLayerConfig {
347 pub upper: u8,
348 pub lower: u8,
349 pub adjust: u8,
350}
351
352#[derive(Clone, Debug, Deserialize)]
354#[serde(deny_unknown_fields)]
355pub struct OneShotConfig {
356 pub timeout: Option<DurationMillis>,
357}
358
359#[derive(Clone, Debug, Deserialize)]
361#[serde(deny_unknown_fields)]
362pub struct CombosConfig {
363 pub combos: Vec<ComboConfig>,
364 pub timeout: Option<DurationMillis>,
365}
366
367#[derive(Clone, Debug, Deserialize)]
369pub struct ComboConfig {
370 pub actions: Vec<String>,
371 pub output: String,
372 pub layer: Option<u8>,
373}
374
375#[derive(Clone, Debug, Deserialize)]
377#[serde(deny_unknown_fields)]
378pub struct ForksConfig {
379 pub forks: Vec<ForkConfig>,
380}
381
382#[derive(Clone, Debug, Deserialize)]
384pub struct ForkConfig {
385 pub trigger: String,
386 pub negative_output: String,
387 pub positive_output: String,
388 pub match_any: Option<String>,
389 pub match_none: Option<String>,
390 pub kept_modifiers: Option<String>,
391 pub bindable: Option<bool>,
392}
393
394#[derive(Clone, Debug, Default, Deserialize)]
396#[serde(deny_unknown_fields)]
397pub struct SplitConfig {
398 pub connection: String,
399 pub central: SplitBoardConfig,
400 pub peripheral: Vec<SplitBoardConfig>,
401}
402
403#[allow(unused)]
407#[derive(Clone, Debug, Default, Deserialize)]
408#[serde(deny_unknown_fields)]
409pub struct SplitBoardConfig {
410 pub rows: usize,
412 pub cols: usize,
414 pub row_offset: usize,
416 pub col_offset: usize,
418 pub ble_addr: Option<[u8; 6]>,
420 pub serial: Option<Vec<SerialConfig>>,
422 pub matrix: MatrixConfig,
424 pub input_device: Option<InputDeviceConfig>,
426}
427
428#[derive(Clone, Debug, Default, Deserialize)]
430pub struct SerialConfig {
431 pub instance: String,
432 pub tx_pin: String,
433 pub rx_pin: String,
434}
435
436#[derive(Clone, Debug, Deserialize)]
438pub struct DurationMillis(#[serde(deserialize_with = "parse_duration_millis")] pub u64);
439
440const fn default_true() -> bool {
441 true
442}
443
444const fn default_false() -> bool {
445 false
446}
447
448fn parse_duration_millis<'de, D: de::Deserializer<'de>>(deserializer: D) -> Result<u64, D::Error> {
449 let input: String = de::Deserialize::deserialize(deserializer)?;
450 let num = input.trim_end_matches(|c: char| !c.is_numeric());
451 let unit = &input[num.len()..];
452 let num: u64 = num.parse().map_err(|_| {
453 de::Error::custom(format!(
454 "Invalid number \"{num}\" in duration: number part must be a u64"
455 ))
456 })?;
457
458 match unit {
459 "s" => Ok(num * 1000),
460 "ms" => Ok(num),
461 other => Err(de::Error::custom(format!(
462 "Invalid duration unit \"{other}\": unit part must be either \"s\" or \"ms\""
463 ))),
464 }
465}
466
467#[derive(Clone, Debug, Default, Deserialize)]
470#[allow(unused)]
471#[serde(deny_unknown_fields)]
472pub struct InputDeviceConfig {
473 pub encoder: Option<Vec<EncoderConfig>>,
474 pub pointing: Option<Vec<PointingDeviceConfig>>,
475 pub joystick: Option<Vec<JoystickConfig>>,
476}
477
478#[derive(Clone, Debug, Default, Deserialize)]
479#[allow(unused)]
480#[serde(deny_unknown_fields)]
481pub struct JoystickConfig {
482 pub name: String,
484 pub pin_x: String,
486 pub pin_y: String,
488 pub pin_z: String,
490 pub transform: Vec<Vec<i16>>,
491 pub bias: Vec<i16>,
492 pub resolution: u16,
493}
494
495#[derive(Clone, Debug, Default, Deserialize)]
496#[allow(unused)]
497#[serde(deny_unknown_fields)]
498pub struct EncoderConfig {
499 pub pin_a: String,
501 pub pin_b: String,
503 pub phase: Option<String>,
509 pub resolution: Option<u8>,
511 pub reverse: Option<bool>,
513 #[serde(default = "default_false")]
515 pub internal_pullup: bool,
516}
517
518#[derive(Clone, Debug, Default, Deserialize)]
520#[allow(unused)]
521#[serde(deny_unknown_fields)]
522pub struct PointingDeviceConfig {
523 pub interface: Option<CommunicationProtocol>,
524}
525
526#[derive(Clone, Debug, Deserialize)]
527#[allow(unused)]
528pub enum CommunicationProtocol {
529 I2c(I2cConfig),
530 Spi(SpiConfig),
531}
532
533#[derive(Clone, Debug, Default, Deserialize)]
535#[allow(unused)]
536pub struct SpiConfig {
537 pub instance: String,
538 pub sck: String,
539 pub mosi: String,
540 pub miso: String,
541 pub cs: Option<String>,
542 pub cpi: Option<u32>,
543}
544
545#[derive(Clone, Debug, Default, Deserialize)]
547#[allow(unused)]
548pub struct I2cConfig {
549 pub instance: String,
550 pub sda: String,
551 pub scl: String,
552 pub address: u8,
553}