1use std::collections::HashMap;
2use std::path::Path;
3
4use config::{Config, File, FileFormat};
5use serde::{Deserialize as SerdeDeserialize, de};
6use serde_derive::Deserialize;
7use serde_inline_default::serde_inline_default;
8
9pub mod chip;
10pub mod communication;
11pub mod keyboard;
12#[rustfmt::skip]
13pub mod usb_interrupt_map;
14pub mod behavior;
15pub mod board;
16pub mod host;
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#[derive(Clone, Debug, Deserialize)]
30#[allow(unused)]
31pub struct KeyboardTomlConfig {
32 keyboard: Option<KeyboardInfo>,
34 matrix: Option<MatrixConfig>,
36 aliases: Option<HashMap<String, String>>,
38 layer: Option<Vec<LayerTomlConfig>>,
40 layout: Option<LayoutTomlConfig>,
43 behavior: Option<BehaviorConfig>,
45 light: Option<LightConfig>,
47 storage: Option<StorageConfig>,
49 ble: Option<BleConfig>,
51 chip: Option<HashMap<String, ChipConfig>>,
53 dependency: Option<DependencyConfig>,
55 split: Option<SplitConfig>,
57 input_device: Option<InputDeviceConfig>,
59 output: Option<Vec<OutputConfig>>,
61 pub host: Option<HostConfig>,
63 #[serde(default)]
65 pub rmk: RmkConstantsConfig,
66}
67
68impl KeyboardTomlConfig {
69 pub fn new_from_toml_path<P: AsRef<Path>>(config_toml_path: P) -> Self {
70 let user_config = match std::fs::read_to_string(config_toml_path.as_ref()) {
72 Ok(s) => match toml::from_str::<KeyboardTomlConfig>(&s) {
73 Ok(c) => c,
74 Err(e) => panic!("Parse {:?} error: {}", config_toml_path.as_ref(), e.message()),
75 },
76 Err(e) => panic!("Read keyboard config file {:?} error: {}", config_toml_path.as_ref(), e),
77 };
78 let default_config_str = user_config.get_chip_model().unwrap().get_default_config_str().unwrap();
79
80 let mut config: KeyboardTomlConfig = Config::builder()
82 .add_source(File::from_str(default_config_str, FileFormat::Toml))
83 .add_source(File::with_name(config_toml_path.as_ref().to_str().unwrap()))
84 .build()
85 .unwrap()
86 .try_deserialize()
87 .unwrap();
88
89 config.auto_calculate_parameters();
90
91 config
92 }
93
94 pub fn auto_calculate_parameters(&mut self) {
100 if let Some(split) = &self.split
102 && split.peripheral.len() > self.rmk.split_peripherals_num
103 {
104 self.rmk.split_peripherals_num = split.peripheral.len();
110 }
111
112 if let Some(behavior) = &self.behavior {
113 if let Some(morse) = &behavior.morse
115 && let Some(morses) = &morse.morses
116 {
117 let mut max_required_patterns = self.rmk.max_patterns_per_key;
118
119 for morse in morses {
120 let tap_actions_len = morse.tap_actions.as_ref().map(|v| v.len()).unwrap_or(0);
121 let hold_actions_len = morse.hold_actions.as_ref().map(|v| v.len()).unwrap_or(0);
122
123 let n = tap_actions_len.max(hold_actions_len);
124 if n > 15 {
125 panic!("The number of taps per morse is too large, the max number of taps is 15, got {n}");
126 }
127
128 let morse_actions_len = morse.morse_actions.as_ref().map(|v| v.len()).unwrap_or(0);
129
130 max_required_patterns =
131 max_required_patterns.max(tap_actions_len + hold_actions_len + morse_actions_len);
132 }
133 self.rmk.max_patterns_per_key = max_required_patterns;
134
135 self.rmk.morse_max_num = self.rmk.morse_max_num.max(morses.len());
137 }
138 }
139 }
140}
141
142#[serde_inline_default]
144#[derive(Clone, Debug, Deserialize)]
145#[serde(deny_unknown_fields)]
146pub struct RmkConstantsConfig {
147 #[serde_inline_default(20)]
149 pub mouse_key_interval: u32,
150 #[serde_inline_default(80)]
152 pub mouse_wheel_interval: u32,
153 #[serde_inline_default(8)]
155 #[serde(deserialize_with = "check_combo_max_num")]
156 pub combo_max_num: usize,
157 #[serde_inline_default(4)]
159 pub combo_max_length: usize,
160 #[serde_inline_default(8)]
162 #[serde(deserialize_with = "check_fork_max_num")]
163 pub fork_max_num: usize,
164 #[serde_inline_default(8)]
166 #[serde(deserialize_with = "check_morse_max_num")]
167 pub morse_max_num: usize,
168 #[serde_inline_default(8)]
170 #[serde(deserialize_with = "check_max_patterns_per_key")]
171 pub max_patterns_per_key: usize,
172 #[serde_inline_default(256)]
174 pub macro_space_size: usize,
175 #[serde_inline_default(20)]
177 pub debounce_time: u16,
178 #[serde_inline_default(16)]
180 pub event_channel_size: usize,
181 #[serde_inline_default(16)]
183 pub controller_channel_size: usize,
184 #[serde_inline_default(12)]
186 pub controller_channel_pubs: usize,
187 #[serde_inline_default(8)]
189 pub controller_channel_subs: usize,
190 #[serde_inline_default(16)]
192 pub report_channel_size: usize,
193 #[serde_inline_default(4)]
195 pub vial_channel_size: usize,
196 #[serde_inline_default(4)]
198 pub flash_channel_size: usize,
199 #[serde_inline_default(1)]
201 pub split_peripherals_num: usize,
202 #[serde_inline_default(3)]
204 pub ble_profiles_num: usize,
205 #[serde_inline_default(0)]
207 pub split_central_sleep_timeout_seconds: u32,
208}
209
210fn check_combo_max_num<'de, D>(deserializer: D) -> Result<usize, D::Error>
211where
212 D: de::Deserializer<'de>,
213{
214 let value = SerdeDeserialize::deserialize(deserializer)?;
215 if value > 256 {
216 panic!("❌ Parse `keyboard.toml` error: combo_max_num must be between 0 and 256, got {value}");
217 }
218 Ok(value)
219}
220
221fn check_morse_max_num<'de, D>(deserializer: D) -> Result<usize, D::Error>
222where
223 D: de::Deserializer<'de>,
224{
225 let value = SerdeDeserialize::deserialize(deserializer)?;
226 if value > 256 {
227 panic!("❌ Parse `keyboard.toml` error: morse_max_num must be between 0 and 256, got {value}");
228 }
229 Ok(value)
230}
231
232fn check_max_patterns_per_key<'de, D>(deserializer: D) -> Result<usize, D::Error>
233where
234 D: de::Deserializer<'de>,
235{
236 let value = SerdeDeserialize::deserialize(deserializer)?;
237 if !(4..=65536).contains(&value) {
238 panic!("❌ Parse `keyboard.toml` error: max_patterns_per_key must be between 4 and 65566, got {value}");
239 }
240 Ok(value)
241}
242
243fn check_fork_max_num<'de, D>(deserializer: D) -> Result<usize, D::Error>
244where
245 D: de::Deserializer<'de>,
246{
247 let value = SerdeDeserialize::deserialize(deserializer)?;
248 if value > 256 {
249 panic!("❌ Parse `keyboard.toml` error: fork_max_num must be between 0 and 256, got {value}");
250 }
251 Ok(value)
252}
253
254impl Default for RmkConstantsConfig {
256 fn default() -> Self {
257 Self {
258 mouse_key_interval: 20,
259 mouse_wheel_interval: 80,
260 combo_max_num: 8,
261 combo_max_length: 4,
262 fork_max_num: 8,
263 morse_max_num: 8,
264 max_patterns_per_key: 8,
265 macro_space_size: 256,
266 debounce_time: 20,
267 event_channel_size: 16,
268 controller_channel_size: 16,
269 controller_channel_pubs: 12,
270 controller_channel_subs: 8,
271 report_channel_size: 16,
272 vial_channel_size: 4,
273 flash_channel_size: 4,
274 split_peripherals_num: 0,
275 ble_profiles_num: 3,
276 split_central_sleep_timeout_seconds: 0,
277 }
278 }
279}
280
281#[derive(Clone, Debug, Deserialize)]
283#[allow(unused)]
284pub struct LayoutTomlConfig {
285 pub rows: u8,
286 pub cols: u8,
287 pub layers: u8,
288 pub keymap: Option<Vec<Vec<Vec<String>>>>, pub matrix_map: Option<String>, pub encoder_map: Option<Vec<Vec<[String; 2]>>>, }
292
293#[derive(Clone, Debug, Deserialize)]
294#[allow(unused)]
295pub struct LayerTomlConfig {
296 pub name: Option<String>,
297 pub keys: String,
298 pub encoders: Option<Vec<[String; 2]>>,
299}
300
301#[derive(Clone, Debug, Default, Deserialize)]
303pub struct KeyboardInfo {
304 pub name: String,
306 pub vendor_id: u16,
308 pub product_id: u16,
310 pub manufacturer: Option<String>,
312 pub product_name: Option<String>,
314 pub serial_number: Option<String>,
316 pub board: Option<String>,
318 pub chip: Option<String>,
320 pub usb_enable: Option<bool>,
322}
323
324#[derive(Clone, Debug, Default, Deserialize)]
325#[allow(non_camel_case_types)]
326pub enum MatrixType {
327 #[default]
328 normal,
329 direct_pin,
330}
331
332#[derive(Clone, Debug, Default, Deserialize)]
333pub struct MatrixConfig {
334 #[serde(default)]
335 pub matrix_type: MatrixType,
336 pub row_pins: Option<Vec<String>>,
337 pub col_pins: Option<Vec<String>>,
338 pub direct_pins: Option<Vec<Vec<String>>>,
339 #[serde(default = "default_true")]
340 pub direct_pin_low_active: bool,
341 #[serde(default = "default_false")]
342 pub row2col: bool,
343 pub debouncer: Option<String>,
344}
345
346#[derive(Clone, Copy, Debug, Default, Deserialize)]
348#[serde(deny_unknown_fields)]
349pub struct StorageConfig {
350 pub start_addr: Option<usize>,
353 pub num_sectors: Option<u8>,
355 #[serde(default = "default_true")]
356 pub enabled: bool,
357 pub clear_storage: Option<bool>,
359 pub clear_layout: Option<bool>,
361}
362
363#[derive(Clone, Default, Debug, Deserialize)]
364#[serde(deny_unknown_fields)]
365pub struct BleConfig {
366 pub enabled: bool,
367 pub battery_adc_pin: Option<String>,
368 pub charge_state: Option<PinConfig>,
369 pub charge_led: Option<PinConfig>,
370 pub adc_divider_measured: Option<u32>,
371 pub adc_divider_total: Option<u32>,
372 pub default_tx_power: Option<i8>,
373 pub ble_use_2m_phy: Option<bool>,
374}
375
376#[derive(Clone, Default, Debug, Deserialize)]
378#[serde(deny_unknown_fields)]
379pub struct ChipConfig {
380 pub dcdc_reg0: Option<bool>,
382 pub dcdc_reg1: Option<bool>,
384 pub dcdc_reg0_voltage: Option<String>,
387}
388
389#[derive(Clone, Default, Debug, Deserialize)]
391#[serde(deny_unknown_fields)]
392pub struct LightConfig {
393 pub capslock: Option<PinConfig>,
394 pub scrolllock: Option<PinConfig>,
395 pub numslock: Option<PinConfig>,
396}
397
398#[derive(Clone, Default, Debug, Deserialize)]
400#[serde(deny_unknown_fields)]
401pub struct PinConfig {
402 pub pin: String,
403 pub low_active: bool,
404}
405
406#[derive(Clone, Debug, Deserialize)]
408#[serde(deny_unknown_fields)]
409pub struct DependencyConfig {
410 #[serde(default = "default_true")]
412 pub defmt_log: bool,
413}
414
415impl Default for DependencyConfig {
416 fn default() -> Self {
417 Self { defmt_log: true }
418 }
419}
420
421#[derive(Clone, Debug, Default, Deserialize)]
423#[serde(deny_unknown_fields)]
424pub struct LayoutConfig {
425 pub rows: u8,
426 pub cols: u8,
427 pub layers: u8,
428 pub keymap: Vec<Vec<Vec<String>>>,
429 pub encoder_map: Vec<Vec<[String; 2]>>, }
431
432#[derive(Clone, Debug, Default, Deserialize)]
433#[serde(deny_unknown_fields)]
434pub struct KeyInfo {
435 pub hand: char, }
437
438#[derive(Clone, Debug, Default, Deserialize)]
440#[serde(deny_unknown_fields)]
441pub struct BehaviorConfig {
442 pub tri_layer: Option<TriLayerConfig>,
443 pub one_shot: Option<OneShotConfig>,
444 pub combo: Option<CombosConfig>,
445 #[serde(alias = "macro")]
446 pub macros: Option<MacrosConfig>,
447 pub fork: Option<ForksConfig>,
448 pub morse: Option<MorsesConfig>,
449}
450
451#[derive(Clone, Debug, Deserialize, Default)]
454pub struct MorseProfile {
455 pub unilateral_tap: Option<bool>,
457
458 pub permissive_hold: Option<bool>,
461 pub hold_on_other_press: Option<bool>,
462 pub normal_mode: Option<bool>,
463
464 pub hold_timeout: Option<DurationMillis>,
466
467 pub gap_timeout: Option<DurationMillis>,
469}
470
471#[derive(Clone, Debug, Deserialize)]
473#[serde(deny_unknown_fields)]
474pub struct TriLayerConfig {
475 pub upper: u8,
476 pub lower: u8,
477 pub adjust: u8,
478}
479
480#[derive(Clone, Debug, Deserialize)]
482#[serde(deny_unknown_fields)]
483pub struct OneShotConfig {
484 pub timeout: Option<DurationMillis>,
485}
486
487#[derive(Clone, Debug, Deserialize)]
489#[serde(deny_unknown_fields)]
490pub struct CombosConfig {
491 pub combos: Vec<ComboConfig>,
492 pub timeout: Option<DurationMillis>,
493}
494
495#[derive(Clone, Debug, Deserialize)]
497pub struct ComboConfig {
498 pub actions: Vec<String>,
499 pub output: String,
500 pub layer: Option<u8>,
501}
502
503#[derive(Clone, Debug, Deserialize)]
505#[serde(deny_unknown_fields)]
506pub struct MacrosConfig {
507 pub macros: Vec<MacroConfig>,
508}
509
510#[derive(Clone, Debug, Deserialize)]
512pub struct MacroConfig {
513 pub operations: Vec<MacroOperation>,
514}
515
516#[derive(Clone, Debug, Deserialize)]
518#[serde(tag = "operation", rename_all = "lowercase")]
519pub enum MacroOperation {
520 Tap { keycode: String },
521 Down { keycode: String },
522 Up { keycode: String },
523 Delay { duration: DurationMillis },
524 Text { text: String },
525}
526
527#[derive(Clone, Debug, Deserialize)]
529#[serde(deny_unknown_fields)]
530pub struct ForksConfig {
531 pub forks: Vec<ForkConfig>,
532}
533
534#[derive(Clone, Debug, Deserialize)]
536#[serde(deny_unknown_fields)]
537pub struct ForkConfig {
538 pub trigger: String,
539 pub negative_output: String,
540 pub positive_output: String,
541 pub match_any: Option<String>,
542 pub match_none: Option<String>,
543 pub kept_modifiers: Option<String>,
544 pub bindable: Option<bool>,
545}
546
547#[derive(Clone, Debug, Deserialize)]
549#[serde(deny_unknown_fields)]
550pub struct MorsesConfig {
551 pub enable_flow_tap: Option<bool>, pub prior_idle_time: Option<DurationMillis>,
554
555 pub unilateral_tap: Option<bool>,
557
558 pub permissive_hold: Option<bool>,
561 pub hold_on_other_press: Option<bool>,
562 pub normal_mode: Option<bool>,
563
564 pub hold_timeout: Option<DurationMillis>,
566
567 pub gap_timeout: Option<DurationMillis>,
569
570 pub profiles: Option<HashMap<String, MorseProfile>>,
572
573 pub morses: Option<Vec<MorseConfig>>,
575}
576
577#[derive(Clone, Debug, Deserialize)]
579#[serde(deny_unknown_fields)]
580pub struct MorseConfig {
581 pub profile: Option<String>,
583
584 pub tap: Option<String>,
585 pub hold: Option<String>,
586 pub hold_after_tap: Option<String>,
587 pub double_tap: Option<String>,
588 pub tap_actions: Option<Vec<String>>,
590 pub hold_actions: Option<Vec<String>>,
592 pub morse_actions: Option<Vec<MorseActionPair>>,
594}
595
596#[derive(Clone, Debug, Deserialize)]
598#[serde(deny_unknown_fields)]
599pub struct MorseActionPair {
600 pub pattern: String, pub action: String, }
603
604#[derive(Clone, Debug, Default, Deserialize)]
606#[serde(deny_unknown_fields)]
607pub struct SplitConfig {
608 pub connection: String,
609 pub central: SplitBoardConfig,
610 pub peripheral: Vec<SplitBoardConfig>,
611}
612
613#[allow(unused)]
617#[derive(Clone, Debug, Default, Deserialize)]
618#[serde(deny_unknown_fields)]
619pub struct SplitBoardConfig {
620 pub rows: usize,
622 pub cols: usize,
624 pub row_offset: usize,
626 pub col_offset: usize,
628 pub ble_addr: Option<[u8; 6]>,
630 pub serial: Option<Vec<SerialConfig>>,
632 pub matrix: MatrixConfig,
634 pub input_device: Option<InputDeviceConfig>,
636 pub output: Option<Vec<OutputConfig>>,
638}
639
640#[derive(Clone, Debug, Default, Deserialize)]
642pub struct SerialConfig {
643 pub instance: String,
644 pub tx_pin: String,
645 pub rx_pin: String,
646}
647
648#[derive(Clone, Debug, Deserialize)]
650pub struct DurationMillis(#[serde(deserialize_with = "parse_duration_millis")] pub u64);
651
652const fn default_true() -> bool {
653 true
654}
655
656const fn default_false() -> bool {
657 false
658}
659
660fn parse_duration_millis<'de, D: de::Deserializer<'de>>(deserializer: D) -> Result<u64, D::Error> {
661 let input: String = de::Deserialize::deserialize(deserializer)?;
662 let num = input.trim_end_matches(|c: char| !c.is_numeric());
663 let unit = &input[num.len()..];
664 let num: u64 = num.parse().map_err(|_| {
665 de::Error::custom(format!(
666 "Invalid number \"{num}\" in duration: number part must be a u64"
667 ))
668 })?;
669
670 match unit {
671 "s" => Ok(num * 1000),
672 "ms" => Ok(num),
673 other => Err(de::Error::custom(format!(
674 "Invalid duration unit \"{other}\": unit part must be either \"s\" or \"ms\""
675 ))),
676 }
677}
678
679#[serde_inline_default]
681#[derive(Clone, Debug, Deserialize)]
682#[serde(deny_unknown_fields)]
683pub struct HostConfig {
684 #[serde_inline_default(true)]
686 pub vial_enabled: bool,
687 pub unlock_keys: Option<Vec<[u8; 2]>>,
689}
690
691impl Default for HostConfig {
692 fn default() -> Self {
693 Self {
694 vial_enabled: true,
695 unlock_keys: None,
696 }
697 }
698}
699
700#[derive(Clone, Debug, Default, Deserialize)]
703#[allow(unused)]
704#[serde(deny_unknown_fields)]
705pub struct InputDeviceConfig {
706 pub encoder: Option<Vec<EncoderConfig>>,
707 pub pointing: Option<Vec<PointingDeviceConfig>>,
708 pub joystick: Option<Vec<JoystickConfig>>,
709 pub pmw3610: Option<Vec<Pmw3610Config>>,
710}
711
712#[derive(Clone, Debug, Default, Deserialize)]
713#[allow(unused)]
714#[serde(deny_unknown_fields)]
715pub struct JoystickConfig {
716 pub name: String,
718 pub pin_x: String,
720 pub pin_y: String,
722 pub pin_z: String,
724 pub transform: Vec<Vec<i16>>,
725 pub bias: Vec<i16>,
726 pub resolution: u16,
727}
728
729#[derive(Clone, Debug, Default, Deserialize)]
731#[allow(unused)]
732#[serde(deny_unknown_fields)]
733pub struct Pmw3610Config {
734 pub name: String,
736 pub spi: SpiConfig,
738 pub motion: Option<String>,
740 pub cpi: Option<u16>,
742 #[serde(default)]
744 pub invert_x: bool,
745 #[serde(default)]
747 pub invert_y: bool,
748 #[serde(default)]
750 pub swap_xy: bool,
751 #[serde(default)]
753 pub force_awake: bool,
754 #[serde(default)]
756 pub smart_mode: bool,
757}
758
759#[derive(Clone, Debug, Default, Deserialize)]
760#[allow(unused)]
761#[serde(deny_unknown_fields)]
762pub struct EncoderConfig {
763 pub pin_a: String,
765 pub pin_b: String,
767 pub phase: Option<String>,
774 pub resolution: Option<EncoderResolution>,
776 pub detent: Option<u8>,
778 pub pulse: Option<u8>,
780 pub reverse: Option<bool>,
782 #[serde(default = "default_false")]
784 pub internal_pullup: bool,
785}
786
787#[derive(Clone, Debug, Deserialize)]
788#[allow(unused)]
789#[serde(deny_unknown_fields, untagged)]
790pub enum EncoderResolution {
791 Value(u8),
792 Derived { detent: u8, pulse: u8 },
793}
794
795impl Default for EncoderResolution {
796 fn default() -> Self {
797 Self::Value(4)
798 }
799}
800
801#[derive(Clone, Debug, Default, Deserialize)]
803#[allow(unused)]
804#[serde(deny_unknown_fields)]
805pub struct PointingDeviceConfig {
806 pub interface: Option<CommunicationProtocol>,
807}
808
809#[derive(Clone, Debug, Deserialize)]
810#[allow(unused)]
811pub enum CommunicationProtocol {
812 I2c(I2cConfig),
813 Spi(SpiConfig),
814}
815
816#[derive(Clone, Debug, Default, Deserialize)]
818#[allow(unused)]
819pub struct SpiConfig {
820 pub instance: String,
821 pub sck: String,
822 pub mosi: String,
823 pub miso: String,
824 pub cs: Option<String>,
825 pub cpi: Option<u32>,
826}
827
828#[derive(Clone, Debug, Default, Deserialize)]
830#[allow(unused)]
831pub struct I2cConfig {
832 pub instance: String,
833 pub sda: String,
834 pub scl: String,
835 pub address: u8,
836}
837
838#[allow(unused)]
840#[derive(Clone, Debug, Default, Deserialize)]
841#[serde(deny_unknown_fields)]
842pub struct OutputConfig {
843 pub pin: String,
844 #[serde(default)]
845 pub low_active: bool,
846 #[serde(default)]
847 pub initial_state_active: bool,
848}
849
850impl KeyboardTomlConfig {
851 pub fn get_output_config(&self) -> Result<Vec<OutputConfig>, String> {
852 let output_config = self.output.clone();
853 let split = self.split.clone();
854 match (output_config, split) {
855 (None, Some(s)) => Ok(s.central.output.unwrap_or_default()),
856 (Some(c), None) => Ok(c),
857 (None, None) => Ok(Default::default()),
858 _ => Err("Use [[split.output]] to define outputs for split in your keyboard.toml!".to_string()),
859 }
860 }
861}