Skip to content

Commit

Permalink
feat(combo): add vial combo support
Browse files Browse the repository at this point in the history
  • Loading branch information
pcasotti committed Nov 28, 2024
1 parent b54444d commit 27b71fa
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 74 deletions.
153 changes: 145 additions & 8 deletions rmk/src/via/process.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
use super::{protocol::*, vial::process_vial};
use super::{
protocol::*,
vial::{VialCommand, VialDynamic},
};
use crate::{
action::KeyAction,
hid::{HidError, HidReaderWriterWrapper},
keyboard_macro::{MACRO_SPACE_SIZE, NUM_MACRO},
keymap::KeyMap,
keymap::{KeyMap, COMBO_MAX_NUM},
storage::{FlashOperationMessage, FLASH_CHANNEL},
usb::descriptor::ViaReport,
via::keycode_convert::{from_via_keycode, to_via_keycode},
via::{
keycode_convert::{from_via_keycode, to_via_keycode},
vial::{VIAL_EP_SIZE, VIAL_PROTOCOL_VERSION},
},
};
use byteorder::{BigEndian, ByteOrder, LittleEndian};
use core::cell::RefCell;
use defmt::{debug, error, info, warn};
use embassy_time::Instant;
use heapless::Vec;
use num_enum::{FromPrimitive, TryFromPrimitive};
use rmk_config::VialConfig;

Expand Down Expand Up @@ -313,14 +321,143 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize>
ViaCommand::DynamicKeymapSetEncoder => {
warn!("Keymap get encoder -- not supported");
}
ViaCommand::Vial => process_vial(
report,
self.vial_config.vial_keyboard_id,
self.vial_config.vial_keyboard_def,
),
ViaCommand::Vial => self.process_vial(report).await,
ViaCommand::Unhandled => report.input_data[0] = ViaCommand::Unhandled as u8,
}
}

// Note: vial uses litte endian, while via uses big endian
async fn process_vial(&self, report: &mut ViaReport) {
// report.output_data[0] == 0xFE -> vial commands
let vial_command = VialCommand::from_primitive(report.output_data[1]);
match vial_command {
VialCommand::GetKeyboardId => {
debug!("Received Vial - GetKeyboardId");
// Returns vial protocol version + vial keyboard id
LittleEndian::write_u32(&mut report.input_data[0..4], VIAL_PROTOCOL_VERSION);
report.input_data[4..12].clone_from_slice(self.vial_config.vial_keyboard_id);
}
VialCommand::GetSize => {
debug!("Received Vial - GetSize");
LittleEndian::write_u32(
&mut report.input_data[0..4],
self.vial_config.vial_keyboard_def.len() as u32,
);
}
VialCommand::GetKeyboardDef => {
debug!("Received Vial - GetKeyboardDefinition");
let page = LittleEndian::read_u16(&report.output_data[2..4]) as usize;
let start = page * VIAL_EP_SIZE;
let mut end = start + VIAL_EP_SIZE;
if end < start || start >= self.vial_config.vial_keyboard_def.len() {
return;
}
if end > self.vial_config.vial_keyboard_def.len() {
end = self.vial_config.vial_keyboard_def.len();
}
self.vial_config.vial_keyboard_def[start..end]
.iter()
.enumerate()
.for_each(|(i, v)| {
report.input_data[i] = *v;
});
debug!(
"Vial return: page:{} start:{} end: {}, data: {:?}",
page, start, end, report.input_data
);
}
VialCommand::GetUnlockStatus => {
debug!("Received Vial - GetUnlockStatus");
// Reset all data to 0xFF(it's required!)
report.input_data.fill(0xFF);
// Unlocked
report.input_data[0] = 1;
// Unlock in progress
report.input_data[1] = 0;
}
VialCommand::QmkSettingsQuery => {
report.input_data.fill(0xFF);
}
VialCommand::DynamicEntryOp => {
let vial_dynamic = VialDynamic::from_primitive(report.output_data[2]);
match vial_dynamic {
VialDynamic::DynamicVialGetNumberOfEntries => {
debug!("DynamicEntryOp - DynamicVialGetNumberOfEntries");
// TODO: Support dynamic tap dance
report.input_data[0] = 0; // Tap dance entries
report.input_data[1] = 8; // Combo entries
// TODO: Support dynamic key override
report.input_data[2] = 0; // Key override entries
}
VialDynamic::DynamicVialTapDanceGet => {
warn!("DynamicEntryOp - DynamicVialTapDanceGet -- to be implemented");
report.input_data.fill(0x00);
}
VialDynamic::DynamicVialTapDanceSet => {
warn!("DynamicEntryOp - DynamicVialTapDanceSet -- to be implemented");
report.input_data.fill(0x00);
}
VialDynamic::DynamicVialComboGet => {
debug!("DynamicEntryOp - DynamicVialComboGet");
report.input_data[0] = 0; // Index 0 is the return code, 0 means success
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,
);
}
let keycode = to_via_keycode(combo.output);
LittleEndian::write_u16(&mut report.input_data[9..11], keycode);
} else {
report.input_data[1..11].fill(0);
}
}
VialDynamic::DynamicVialComboSet => {
debug!("DynamicEntryOp - DynamicVialComboSet");
report.input_data[0] = 0; // Index 0 is the return code, 0 means success

let combo_idx = report.output_data[3] as usize;
if combo_idx >= COMBO_MAX_NUM {
return;
}

let mut actions = Vec::new();
for i in 0..4 {
let action = from_via_keycode(LittleEndian::read_u16(
&report.output_data[4 + i * 2..6 + i * 2],
));
if action != KeyAction::No {
let _ = actions.push(action);
}
}
let output =
from_via_keycode(LittleEndian::read_u16(&report.output_data[12..14]));

let combo = &mut self.keymap.borrow_mut().combos[combo_idx];
combo.actions = actions;
combo.output = output;
}
VialDynamic::DynamicVialKeyOverrideGet => {
warn!("DynamicEntryOp - DynamicVialKeyOverrideGet -- to be implemented");
report.input_data.fill(0x00);
}
VialDynamic::DynamicVialKeyOverrideSet => {
warn!("DynamicEntryOp - DynamicVialKeyOverrideSet -- to be implemented");
report.input_data.fill(0x00);
}
VialDynamic::Unhandled => {
warn!("DynamicEntryOp - Unhandled -- subcommand not recognized");
report.input_data.fill(0x00);
}
}
}
_ => (),
}
}
}

fn get_position_from_offset(
Expand Down
84 changes: 18 additions & 66 deletions rmk/src/via/vial.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use byteorder::{ByteOrder, LittleEndian};
use defmt::debug;
use num_enum::FromPrimitive;

use crate::usb::descriptor::ViaReport;

/// Vial communication commands. Check [vial-qmk/quantum/vial.h`](https://github.com/vial-kb/vial-qmk/blob/20d61fcb373354dc17d6ecad8f8176be469743da/quantum/vial.h#L36)
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)]
#[repr(u8)]
enum VialCommand {
pub(crate) enum VialCommand {
GetKeyboardId = 0x00,
GetSize = 0x01,
GetKeyboardDef = 0x02,
Expand All @@ -25,65 +22,20 @@ enum VialCommand {
Unhandled = 0xFF,
}

const VIAL_PROTOCOL_VERSION: u32 = 6;
const VIAL_EP_SIZE: usize = 32;
///
/// Note: vial uses litte endian, while via uses big endian
pub(crate) fn process_vial(
report: &mut ViaReport,
vial_keyboard_Id: &[u8],
vial_keyboard_def: &[u8],
) {
// report.output_data[0] == 0xFE -> vial commands
let vial_command = VialCommand::from_primitive(report.output_data[1]);
match vial_command {
VialCommand::GetKeyboardId => {
debug!("Received Vial - GetKeyboardId");
// Returns vial protocol version + vial keyboard id
LittleEndian::write_u32(&mut report.input_data[0..4], VIAL_PROTOCOL_VERSION);
report.input_data[4..12].clone_from_slice(vial_keyboard_Id);
}
VialCommand::GetSize => {
debug!("Received Vial - GetSize");
LittleEndian::write_u32(&mut report.input_data[0..4], vial_keyboard_def.len() as u32);
}
VialCommand::GetKeyboardDef => {
debug!("Received Vial - GetKeyboardDefinition");
let page = LittleEndian::read_u16(&report.output_data[2..4]) as usize;
let start = page * VIAL_EP_SIZE;
let mut end = start + VIAL_EP_SIZE;
if end < start || start >= vial_keyboard_def.len() {
return;
}
if end > vial_keyboard_def.len() {
end = vial_keyboard_def.len();
}
vial_keyboard_def[start..end]
.iter()
.enumerate()
.for_each(|(i, v)| {
report.input_data[i] = *v;
});
debug!(
"Vial return: page:{} start:{} end: {}, data: {:?}",
page, start, end, report.input_data
);
}
VialCommand::GetUnlockStatus => {
debug!("Received Vial - GetUnlockStatus");
// Reset all data to 0xFF(it's required!)
report.input_data.fill(0xFF);
// Unlocked
report.input_data[0] = 1;
// Unlock in progress
report.input_data[1] = 0;
}
VialCommand::QmkSettingsQuery => {
report.input_data.fill(0xFF);
}
VialCommand::DynamicEntryOp => {
report.input_data.fill(0x00);
}
_ => (),
}
/// Vial dynamic commands. Check [vial-qmk/quantum/vial.h`](https://github.com/vial-kb/vial-qmk/blob/20d61fcb373354dc17d6ecad8f8176be469743da/quantum/vial.h#L53)
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)]
#[repr(u8)]
pub(crate) enum VialDynamic {
DynamicVialGetNumberOfEntries = 0x00,
DynamicVialTapDanceGet = 0x01,
DynamicVialTapDanceSet = 0x02,
DynamicVialComboGet = 0x03,
DynamicVialComboSet = 0x04,
DynamicVialKeyOverrideGet = 0x05,
DynamicVialKeyOverrideSet = 0x06,
#[num_enum(default)]
Unhandled = 0xFF,
}

pub(crate) const VIAL_PROTOCOL_VERSION: u32 = 6;
pub(crate) const VIAL_EP_SIZE: usize = 32;

0 comments on commit 27b71fa

Please sign in to comment.