From 256952cd41838bfebea80b0aae64c875521cd016 Mon Sep 17 00:00:00 2001 From: Pedro Casotti Date: Tue, 26 Nov 2024 14:38:48 -0300 Subject: [PATCH] feat(combo): add combos to persistent storage --- rmk/src/keymap.rs | 15 +++++++- rmk/src/storage/mod.rs | 82 +++++++++++++++++++++++++++++++++++++++++- rmk/src/via/process.rs | 24 +++++++++---- 3 files changed, 113 insertions(+), 8 deletions(-) diff --git a/rmk/src/keymap.rs b/rmk/src/keymap.rs index 8d5bb425..90de8c1a 100644 --- a/rmk/src/keymap.rs +++ b/rmk/src/keymap.rs @@ -102,6 +102,7 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize> ) -> Self { // If the storage is initialized, read keymap from storage let mut macro_cache = [0; MACRO_SPACE_SIZE]; + let mut combos = [(); COMBO_MAX_NUM].map(|_| Combo::empty()); if let Some(storage) = storage { // Read keymap to `action_map` if storage.read_keymap(action_map).await.is_err() { @@ -124,6 +125,18 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize> .ok(); reboot_keyboard(); + } else { + if storage.read_combos(&mut combos).await.is_err() { + error!("Wrong combo cache, clearing the storage..."); + sequential_storage::erase_all( + &mut storage.flash, + storage.storage_range.clone(), + ) + .await + .ok(); + + reboot_keyboard(); + } } } } @@ -134,7 +147,7 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize> default_layer: 0, layer_cache: [[0; COL]; ROW], macro_cache, - combos: [(); COMBO_MAX_NUM].map(|_| Combo::empty()), + combos, } } diff --git a/rmk/src/storage/mod.rs b/rmk/src/storage/mod.rs index 6ba6aed4..cca64d5c 100644 --- a/rmk/src/storage/mod.rs +++ b/rmk/src/storage/mod.rs @@ -9,6 +9,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embedded_storage::nor_flash::NorFlash; use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash; +use heapless::Vec; use rmk_config::StorageConfig; use sequential_storage::{ cache::NoCache, @@ -18,11 +19,11 @@ use sequential_storage::{ #[cfg(feature = "_nrf_ble")] use {crate::ble::nrf::bonder::BondInfo, core::mem}; -use crate::keyboard_macro::MACRO_SPACE_SIZE; use crate::{ action::KeyAction, via::keycode_convert::{from_via_keycode, to_via_keycode}, }; +use crate::{keyboard_macro::MACRO_SPACE_SIZE, keymap::Combo}; use self::eeconfig::EeKeymapConfig; @@ -57,6 +58,8 @@ pub(crate) enum FlashOperationMessage { }, // Current saved connection type ConnectionType(u8), + // Write combo + WriteCombo(ComboData), } #[repr(u32)] @@ -68,6 +71,7 @@ pub(crate) enum StorageKeys { LayoutConfig, KeymapKeys, MacroData, + ComboData, ConnectionType, #[cfg(feature = "_nrf_ble")] ActiveBleProfile = 0xEE, @@ -85,6 +89,7 @@ impl StorageKeys { 4 => Some(StorageKeys::LayoutConfig), 5 => Some(StorageKeys::KeymapKeys), 6 => Some(StorageKeys::MacroData), + 7 => Some(StorageKeys::ComboData), #[cfg(feature = "_nrf_ble")] 0xEF => Some(StorageKeys::BleBondInfo), _ => None, @@ -99,6 +104,7 @@ pub(crate) enum StorageData { KeymapConfig(EeKeymapConfig), KeymapKey(KeymapKey), MacroData([u8; MACRO_SPACE_SIZE]), + ComboData(ComboData), ConnectionType(u8), #[cfg(feature = "_nrf_ble")] BondInfo(BondInfo), @@ -162,6 +168,20 @@ impl Value<'_> for StorageData { buffer[1..MACRO_SPACE_SIZE + 1].copy_from_slice(d); Ok(MACRO_SPACE_SIZE + 1) } + StorageData::ComboData(combo) => { + if buffer.len() < 11 { + return Err(SerializationError::BufferTooSmall); + } + buffer[0] = StorageKeys::ComboData as u8; + for i in 0..4 { + BigEndian::write_u16( + &mut buffer[1 + i * 2..3 + i * 2], + to_via_keycode(combo.actions[i]), + ); + } + BigEndian::write_u16(&mut buffer[9..11], to_via_keycode(combo.output)); + Ok(11) + } StorageData::ConnectionType(ty) => { buffer[0] = StorageKeys::ConnectionType as u8; buffer[1] = *ty; @@ -245,6 +265,22 @@ impl Value<'_> for StorageData { buf.copy_from_slice(&buffer[1..MACRO_SPACE_SIZE + 1]); Ok(StorageData::MacroData(buf)) } + StorageKeys::ComboData => { + if buffer.len() < 11 { + return Err(SerializationError::InvalidData); + } + let mut actions = [KeyAction::No; 4]; + for i in 0..4 { + actions[i] = + from_via_keycode(BigEndian::read_u16(&buffer[1 + i * 2..3 + i * 2])); + } + let output = from_via_keycode(BigEndian::read_u16(&buffer[9..11])); + Ok(StorageData::ComboData(ComboData { + idx: 0, + actions, + output, + })) + } StorageKeys::ConnectionType => Ok(StorageData::ConnectionType(buffer[1])), #[cfg(feature = "_nrf_ble")] StorageKeys::BleBondInfo => { @@ -274,6 +310,7 @@ impl StorageData { panic!("To get storage key for KeymapKey, use `get_keymap_key` instead"); } StorageData::MacroData(_) => StorageKeys::MacroData as u32, + StorageData::ComboData(_) => StorageKeys::ComboData as u32, StorageData::ConnectionType(_) => StorageKeys::ConnectionType as u32, #[cfg(feature = "_nrf_ble")] StorageData::BondInfo(b) => get_bond_info_key(b.slot_num), @@ -282,6 +319,7 @@ impl StorageData { } } } + #[derive(Clone, Copy, Debug, Format)] pub(crate) struct LocalStorageConfig { enable: bool, @@ -301,6 +339,13 @@ pub(crate) struct KeymapKey { action: KeyAction, } +#[derive(Clone, Copy, Debug, Format)] +pub(crate) struct ComboData { + pub(crate) idx: u8, + pub(crate) actions: [KeyAction; 4], + pub(crate) output: KeyAction, +} + pub(crate) struct Storage< F: AsyncNorFlash, const ROW: usize, @@ -488,6 +533,17 @@ impl { + store_item( + &mut self.flash, + self.storage_range.clone(), + &mut storage_cache, + &mut self.buffer, + &(0x2000 + combo.idx as u32), + &StorageData::ComboData(combo), + ) + .await + } FlashOperationMessage::ConnectionType(ty) => { store_item( &mut self.flash, @@ -616,6 +672,30 @@ impl Result<(), ()> { + for i in 0..combos.len() { + let read_data = fetch_item::( + &mut self.flash, + self.storage_range.clone(), + &mut NoCache::new(), + &mut self.buffer, + &(0x2000 + i as u32), + ) + .await + .map_err(|e| print_storage_error::(e))?; + + if let Some(StorageData::ComboData(combo)) = read_data { + let mut actions = Vec::<_, 4>::new(); + for &action in combo.actions.iter().filter(|&&a| a != KeyAction::No) { + let _ = actions.push(action); + } + combos[i] = Combo::new(actions, combo.output); + } + } + + Ok(()) + } + async fn initialize_storage_with_config( &mut self, keymap: &[[[KeyAction; COL]; ROW]; NUM_LAYER], diff --git a/rmk/src/via/process.rs b/rmk/src/via/process.rs index 67405e5c..afd66e26 100644 --- a/rmk/src/via/process.rs +++ b/rmk/src/via/process.rs @@ -7,7 +7,7 @@ use crate::{ hid::{HidError, HidReaderWriterWrapper}, keyboard_macro::{MACRO_SPACE_SIZE, NUM_MACRO}, keymap::{KeyMap, COMBO_MAX_NUM}, - storage::{FlashOperationMessage, FLASH_CHANNEL}, + storage::{ComboData, FlashOperationMessage, FLASH_CHANNEL}, usb::descriptor::ViaReport, via::{ keycode_convert::{from_via_keycode, to_via_keycode}, @@ -403,15 +403,15 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize> let combo_idx = report.output_data[3] as usize; if let Some(combo) = self.keymap.borrow().combos.get(combo_idx) { for i in 0..4 { - let keycode = - to_via_keycode(*combo.actions.get(i).unwrap_or(&KeyAction::No)); LittleEndian::write_u16( &mut report.input_data[1 + i * 2..3 + i * 2], - keycode, + to_via_keycode(*combo.actions.get(i).unwrap_or(&KeyAction::No)), ); } - let keycode = to_via_keycode(combo.output); - LittleEndian::write_u16(&mut report.input_data[9..11], keycode); + LittleEndian::write_u16( + &mut report.input_data[9..11], + to_via_keycode(combo.output), + ); } else { report.input_data[1..11].fill(0); } @@ -440,6 +440,18 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize> let combo = &mut self.keymap.borrow_mut().combos[combo_idx]; combo.actions = actions; combo.output = output; + + let mut actions = [KeyAction::No; 4]; + for (i, &action) in combo.actions.iter().enumerate() { + actions[i] = action; + } + FLASH_CHANNEL + .send(FlashOperationMessage::WriteCombo(ComboData { + idx: combo_idx as u8, + actions, + output, + })) + .await; } VialDynamic::DynamicVialKeyOverrideGet => { warn!("DynamicEntryOp - DynamicVialKeyOverrideGet -- to be implemented");