Skip to content

Commit

Permalink
feat(combo): add combos to persistent storage
Browse files Browse the repository at this point in the history
  • Loading branch information
pcasotti committed Nov 28, 2024
1 parent 27b71fa commit 256952c
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 8 deletions.
15 changes: 14 additions & 1 deletion rmk/src/keymap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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();
}
}
}
}
Expand All @@ -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,
}
}

Expand Down
82 changes: 81 additions & 1 deletion rmk/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;

Expand Down Expand Up @@ -57,6 +58,8 @@ pub(crate) enum FlashOperationMessage {
},
// Current saved connection type
ConnectionType(u8),
// Write combo
WriteCombo(ComboData),
}

#[repr(u32)]
Expand All @@ -68,6 +71,7 @@ pub(crate) enum StorageKeys {
LayoutConfig,
KeymapKeys,
MacroData,
ComboData,
ConnectionType,
#[cfg(feature = "_nrf_ble")]
ActiveBleProfile = 0xEE,
Expand All @@ -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,
Expand All @@ -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),
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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),
Expand All @@ -282,6 +319,7 @@ impl StorageData {
}
}
}

#[derive(Clone, Copy, Debug, Format)]
pub(crate) struct LocalStorageConfig {
enable: bool,
Expand All @@ -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,
Expand Down Expand Up @@ -488,6 +533,17 @@ impl<F: AsyncNorFlash, const ROW: usize, const COL: usize, const NUM_LAYER: usiz
)
.await
}
FlashOperationMessage::WriteCombo(combo) => {
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,
Expand Down Expand Up @@ -616,6 +672,30 @@ impl<F: AsyncNorFlash, const ROW: usize, const COL: usize, const NUM_LAYER: usiz
Ok(())
}

pub(crate) async fn read_combos(&mut self, combos: &mut [Combo]) -> Result<(), ()> {
for i in 0..combos.len() {
let read_data = fetch_item::<u32, StorageData, _>(
&mut self.flash,
self.storage_range.clone(),
&mut NoCache::new(),
&mut self.buffer,
&(0x2000 + i as u32),
)
.await
.map_err(|e| print_storage_error::<F>(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],
Expand Down
24 changes: 18 additions & 6 deletions rmk/src/via/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit 256952c

Please sign in to comment.