Reimplements Oryx's live training over raw hid (#345)

* feat: initial commit, random pairing sequence generation, host - board pairing handshakes

* feat: reimplements ory's live training over raw hid

* feat: adds planck / ergodox support

* chore: some code styling fixes

* fix: build smoke tests

* fix: code lint

* fix: disable console / command on moonlander, fixes build ci test

* fix: code lint

* fix: remove unused define(MATRIX_SIZE)
This commit is contained in:
Florian Didron
2022-05-31 19:03:21 +09:00
committed by GitHub
parent 1fbd91aa10
commit fc773ff0cf
14 changed files with 306 additions and 390 deletions

View File

@@ -3,9 +3,6 @@
#include "eeprom.h"
#include "eeconfig.h"
#include "action_layer.h"
#ifdef ORYX_ENABLE
# include "oryx.h"
#endif
#if defined(EEPROM_DRIVER)
# include "eeprom_driver.h"
@@ -60,10 +57,6 @@ void eeconfig_init_quantum(void) {
eeprom_update_dword(EECONFIG_RGB_MATRIX, 0);
eeprom_update_word(EECONFIG_RGB_MATRIX_EXTENDED, 0);
#ifdef ORYX_ENABLE
eeconfig_init_oryx();
#endif
// TODO: Remove once ARM has a way to configure EECONFIG_HANDEDNESS
// within the emulated eeprom via dfu-util or another tool
#if defined INIT_EE_HANDS_LEFT

View File

@@ -1,253 +1,180 @@
#include "oryx.h"
#include "eeprom.h"
#include <string.h>
bool oryx_state_live_training_enabled;
rawhid_state_t rawhid_state = {.pairing = false, .paired = false};
bool webusb_receive_oryx(uint8_t *data, uint8_t length) {
uint8_t command = data[0];
uint8_t *param = &(data[1]);
keypos_t keyboard_pairing_sequence[PAIRING_SEQUENCE_SIZE];
keypos_t host_pairing_sequence[PAIRING_SEQUENCE_SIZE];
uint8_t pairing_input_index = 0;
void raw_hid_receive(uint8_t *data, uint8_t length) {
uint8_t command = data[0];
uint8_t *param = &data[1];
uint8_t cmd_index = 0;
switch (command) {
case ORYX_GET_LAYER:
oryx_layer_event();
return true;
case ORYX_CMD_LIVE_TRAINING: {
uint8_t event[4];
switch (param[0]) { // 0 for querying, 1 for off, 2 for on
case 0:
break;
case 1:
oryx_state_live_training_enabled = false;
break;
case 2:
oryx_state_live_training_enabled = true;
break;
default:
webusb_error(WEBUSB_STATUS_UNKNOWN_COMMAND);
return true;
case ORYX_CMD_GET_FW_VERSION: {
uint8_t event[RAW_EPSIZE];
uint8_t fw_version_size = sizeof(FIRMWARE_VERSION);
uint8_t stop[1];
event[0] = ORYX_EVT_GET_FW_VERSION;
stop[0] = ORYX_STOP_BIT;
memcpy(event + 1, FIRMWARE_VERSION, fw_version_size);
memcpy(event + fw_version_size, stop, 1);
raw_hid_send(event, RAW_EPSIZE);
break;
}
case ORYX_CMD_PAIRING_INIT:
pairing_init_handler();
store_pairing_sequence(&keyboard_pairing_sequence[0]);
break;
case ORYX_CMD_PAIRING_VALIDATE:
for (uint8_t i = 0; i < PAIRING_SEQUENCE_SIZE; i++) {
keypos_t pos;
pos.col = param[cmd_index++];
pos.row = param[cmd_index++];
host_pairing_sequence[i] = pos;
}
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_TRAINING;
event[2] = oryx_state_live_training_enabled;
event[3] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
#ifdef DYNAMIC_KEYMAP_ENABLE
case ORYX_CMD_LIVE_UPDATE_GET_KEYCODE: {
uint8_t event[5];
// layer, row, col
uint16_t keycode = dynamic_keymap_get_keycode(param[0], param[1], param[2]);
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_GET_KEYCODE;
event[2] = keycode >> 8;
event[3] = keycode & 0xFF;
event[4] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_SET_KEYCODE: {
uint8_t event[5];
dynamic_keymap_set_keycode(param[0], param[1], param[2], (param[3] << 8) | param[4]);
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_SET_KEYCODE;
event[2] = param[3];
event[3] = param[4];
event[4] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_KEYMAP_RESET: {
uint8_t event[3];
dynamic_keymap_reset();
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_KEYMAP_RESET;
event[2] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_GET_BUFFER: {
uint16_t offset = (param[0] << 8) | param[1];
uint16_t size = param[2]; // size <= 28
uint8_t event[size+3];
uint8_t i;
dynamic_keymap_get_buffer(offset, size, &param[3]);
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_GET_BUFFER;
for (i = 0; i < size; i++) {
event[i+2] = param[i];
}
event[i+2] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_SET_BUFFER: {
uint16_t offset = (param[0] << 8) | param[1];
uint16_t size = param[2]; // size <= 28
uint8_t event[3];
dynamic_keymap_set_buffer(offset, size, &param[3]);
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_SET_BUFFER;
event[2] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_GET_LAYER_COUNT: {
uint8_t event[4];
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_GET_LAYER_COUNT;
event[2] = dynamic_keymap_get_layer_count();
event[3] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_GET_MACRO_COUNT: {
uint8_t event[4];
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_GET_MACRO_COUNT;
event[2] = dynamic_keymap_macro_get_count();
event[3] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_GET_MACRO_BUFFER_SIZE: {
uint16_t size = dynamic_keymap_macro_get_buffer_size();
uint8_t event[5];
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_GET_MACRO_BUFFER_SIZE;
event[2] = size >> 8;
event[3] = size & 0xFF;
event[4] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_GET_MACRO_BUFFER: {
uint16_t offset = (param[0] << 8) | param[1];
uint16_t size = param[2]; // size <= 28
uint8_t event[size+3];
uint8_t i;
dynamic_keymap_macro_get_buffer(offset, size, &param[3]);
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_GET_MACRO_BUFFER;
for (i = 0; i < size; i++) {
event[i+2] = param[i];
}
event[i+2] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_SET_MACRO_BUFFER: {
uint16_t offset = (param[0] << 8) | param[1];
uint16_t size = param[2]; // size <= 28
dynamic_keymap_macro_set_buffer(offset, size, &param[3]);
uint8_t event[3];
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_SET_MACRO_BUFFER;
event[2] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_MACRO_RESET: {
uint8_t event[3];
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_MACRO_RESET;
event[2] = WEBUSB_STOP_BIT;
dynamic_keymap_macro_reset();
webusb_send(event, sizeof(event));
return true;
}
case ORYX_CMD_LIVE_UPDATE_EEPROM_RESET: {
uint8_t event[3];
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_EEPROM_RESET;
event[2] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
eeconfig_init();
return true;
}
case ORYX_CMD_LIVE_UPDATE_KEYBOARD_RESET: {
uint8_t event[3];
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LIVE_UPDATE_KEYBOARD_RESET;
event[2] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
reset_keyboard();
return true;
}
#endif
default:
return webusb_receive_kb(data, length);
pairing_validate_handler();
break;
}
}
bool store_pairing_sequence(keypos_t *pairing_sequence) {
uint8_t stored_sequences[sizeof(uint16_t) * PAIRING_SEQUENCE_SIZE * PAIRING_SEQUENCE_NUM_STORED];
eeprom_read_block(&stored_sequences, (uint8_t *)EECONFIG_SIZE, PAIRING_STORAGE_SIZE);
uint8_t shiftLen = sizeof(&pairing_sequence);
for (int8_t i = PAIRING_STORAGE_SIZE; i >= 0; i--) {
if (i > shiftLen) {
stored_sequences[i] = stored_sequences[i - 1];
} else {
stored_sequences[i] = 0;
}
}
eeprom_update_block(stored_sequences, (uint8_t *)EECONFIG_SIZE, PAIRING_STORAGE_SIZE);
return true;
}
void pairing_init_handler(void) {
create_pairing_code();
uint8_t event[RAW_EPSIZE];
uint8_t event_index = 0;
event[event_index++] = ORYX_EVT_PAIRING_INPUT;
for (uint8_t i = 0; i < PAIRING_SEQUENCE_SIZE; i++) {
event[event_index++] = keyboard_pairing_sequence[i].col;
event[event_index++] = keyboard_pairing_sequence[i].row;
}
event[event_index++] = ORYX_STOP_BIT;
rawhid_state.pairing = true;
raw_hid_send(event, RAW_EPSIZE);
}
void pairing_validate_handler() {
bool valid = true;
uint8_t event[RAW_EPSIZE];
for (uint8_t i = 0; i < PAIRING_SEQUENCE_SIZE; i++) {
if (keyboard_pairing_sequence[i].row != host_pairing_sequence[i].row) {
valid = false;
break;
}
if (keyboard_pairing_sequence[i].col != host_pairing_sequence[i].col) {
valid = false;
break;
}
}
if (valid == true) {
event[0] = ORYX_EVT_PAIRING_SUCCESS;
rawhid_state.paired = true;
} else {
event[0] = ORYX_EVT_PAIRING_FAILED;
rawhid_state.paired = false;
}
event[1] = ORYX_STOP_BIT;
rawhid_state.pairing = false;
raw_hid_send(event, sizeof(event));
}
keypos_t get_random_keypos(void) {
uint8_t col = rand() % MATRIX_COLS;
uint8_t row = rand() % MATRIX_ROWS;
keypos_t pos = {.col = col, .row = row};
if (keymap_key_to_keycode(0, pos) != KC_NO) {
return pos;
} else {
return get_random_keypos();
}
}
void create_pairing_code(void) {
for (uint8_t i = 0; i < PAIRING_SEQUENCE_SIZE; i++) {
keypos_t pos = get_random_keypos();
keyboard_pairing_sequence[i] = pos;
}
}
void pairing_key_input_event(void) {
uint8_t event[RAW_EPSIZE];
event[0] = ORYX_EVT_PAIRING_KEY_INPUT;
raw_hid_send(event, sizeof(event));
}
void oryx_layer_event(void) {
uint8_t layer;
uint8_t event[4];
layer = get_highest_layer(layer_state);
#ifdef WEBUSB_ENABLE
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LAYER;
event[2] = layer;
event[3] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
#endif
uint8_t event[RAW_EPSIZE];
layer = get_highest_layer(layer_state);
event[0] = ORYX_EVT_LAYER;
event[1] = layer;
event[2] = ORYX_STOP_BIT;
raw_hid_send(event, sizeof(event));
}
bool is_oryx_live_training_enabled(void) { return (oryx_state_live_training_enabled && webusb_state.paired); }
bool process_record_oryx(uint16_t keycode, keyrecord_t *record) {
if(is_oryx_live_training_enabled()) {
uint8_t event[5];
event[0] = WEBUSB_STATUS_OK;
event[1] = record->event.pressed ? ORYX_EVT_KEYDOWN : ORYX_EVT_KEYUP;
event[2] = record->event.key.col;
event[3] = record->event.key.row;
event[4] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
}
if (keycode == WEBUSB_PAIR && record->event.pressed) {
webusb_state.pairing ^= true;
return true;
}
#ifdef DYNAMIC_KEYMAP_ENABLE
switch (keycode) {
case MACRO00 ... MACRO15:
if (record->event.pressed) {
dynamic_keymap_macro_send(keycode - MACRO00);
// In pairing mode, key events are absorbed, and the host pairing sequence is filled.
// Once filled, the keyboard and host sequence are compaired, pairing state set to false
// and the proper pairing validation event is sent to the host
if (rawhid_state.pairing == true) {
// The host pairing sequence is filled on key up only
if (!record->event.pressed) {
if (pairing_input_index < PAIRING_SEQUENCE_SIZE) {
host_pairing_sequence[pairing_input_index++] = record->event.key;
pairing_key_input_event();
}
return false;
if (pairing_input_index == PAIRING_SEQUENCE_SIZE) {
rawhid_state.pairing = false;
pairing_input_index = 0;
pairing_validate_handler();
}
}
return false;
}
// While paired, the keyboard sends keystrokes positions to the host
if (rawhid_state.paired == true) {
uint8_t event[RAW_EPSIZE];
event[0] = record->event.pressed ? ORYX_EVT_KEYDOWN : ORYX_EVT_KEYUP;
event[1] = record->event.key.col;
event[2] = record->event.key.row;
event[3] = ORYX_STOP_BIT;
raw_hid_send(event, sizeof(event));
}
#endif
return true;
}
void layer_state_set_oryx(layer_state_t state) {
if(is_oryx_live_training_enabled()) {
uint8_t event[4];
event[0] = WEBUSB_STATUS_OK;
event[1] = ORYX_EVT_LAYER;
event[2] = get_highest_layer(state);
event[3] = WEBUSB_STOP_BIT;
webusb_send(event, sizeof(event));
if (rawhid_state.paired) {
uint8_t event[RAW_EPSIZE];
event[0] = ORYX_EVT_LAYER;
event[1] = get_highest_layer(state);
event[2] = ORYX_STOP_BIT;
raw_hid_send(event, sizeof(event));
}
}
void eeconfig_init_oryx(void) {
#ifdef DYNAMIC_KEYMAP_ENABLE
// reread settings from flash into eeprom
dynamic_keymap_reset();
dynamic_keymap_macro_reset();
eeprom_update_block(FIRMWARE_VERSION, (uint8_t *)EECONFIG_SIZE, sizeof(uint8_t)*FIRMWARE_VERSION_SIZE);
}
void matrix_init_oryx(void) {
uint8_t temp[FIRMWARE_VERSION_SIZE];
uint8_t firmware[FIRMWARE_VERSION_SIZE] = FIRMWARE_VERSION;
eeprom_read_block(&temp, (uint8_t *)EECONFIG_SIZE, sizeof(uint8_t)*FIRMWARE_VERSION_SIZE);
if (!memcmp(&temp, &firmware, sizeof(uint8_t)*FIRMWARE_VERSION_SIZE)) {
eeconfig_init_oryx();
}
#endif
}

View File

@@ -1,82 +1,61 @@
#pragma once
#include "quantum.h"
#include "webusb.h"
#include "raw_hid.h"
#ifndef WEBUSB_ENABLE
# error "WebUSB needs to be enabled, please enable it!"
#ifndef RAW_ENABLE
# error "Raw hid needs to be enabled, please enable it!"
#endif
#ifndef RAW_EPSIZE
# define RAW_EPSIZE 32
#endif
// enum Oryx_Status_code {
// PLACEHOLDER = WEBUSB_STATUS_SAFE_RANGE,
// }
#define ORYX_STOP_BIT -2
#define PAIRING_BLINK_STEPS 512
#define PAIRING_BLINK_END PAIRING_BLINK_STEPS * 60
#define PAIRING_SEQUENCE_SIZE 3
#define PAIRING_SEQUENCE_NUM_STORED 5
#define PAIRING_STORAGE_SIZE PAIRING_SEQUENCE_SIZE* PAIRING_SEQUENCE_NUM_STORED * sizeof(uint16_t)
enum Oryx_Command_Code {
ORYX_GET_LAYER = WEBUSB_CMD_SAFE_RANGE,
ORYX_CMD_LIVE_TRAINING,
ORYX_CMD_LIVE_UPDATE_GET_KEYCODE,
ORYX_CMD_LIVE_UPDATE_SET_KEYCODE,
ORYX_CMD_LIVE_UPDATE_KEYMAP_RESET,
ORYX_CMD_LIVE_UPDATE_GET_BUFFER,
ORYX_CMD_LIVE_UPDATE_SET_BUFFER,
ORYX_CMD_LIVE_UPDATE_GET_LAYER_COUNT,
ORYX_CMD_LIVE_UPDATE_GET_MACRO_COUNT,
ORYX_CMD_LIVE_UPDATE_GET_MACRO_BUFFER_SIZE,
ORYX_CMD_LIVE_UPDATE_GET_MACRO_BUFFER,
ORYX_CMD_LIVE_UPDATE_SET_MACRO_BUFFER,
ORYX_CMD_LIVE_UPDATE_MACRO_RESET,
ORYX_CMD_LIVE_UPDATE_EEPROM_RESET,
ORYX_CMD_LIVE_UPDATE_KEYBOARD_RESET,
ORYX_CMD_GET_FW_VERSION,
ORYX_CMD_PAIRING_INIT,
ORYX_CMD_PAIRING_VALIDATE,
ORYX_CMD_DISCONNECT,
ORYX_GET_LAYER,
};
enum Oryx_Event_Code {
ORYX_EVT_LAYER = WEBUSB_EVT_SAFE_RANGE,
ORYX_EVT_LIVE_TRAINING,
ORYX_EVT_LIVE_UPDATE_GET_KEYCODE,
ORYX_EVT_LIVE_UPDATE_SET_KEYCODE,
ORYX_EVT_LIVE_UPDATE_KEYMAP_RESET,
ORYX_EVT_LIVE_UPDATE_GET_BUFFER,
ORYX_EVT_LIVE_UPDATE_SET_BUFFER,
ORYX_EVT_LIVE_UPDATE_GET_LAYER_COUNT,
ORYX_EVT_LIVE_UPDATE_GET_MACRO_COUNT,
ORYX_EVT_LIVE_UPDATE_GET_MACRO_BUFFER_SIZE,
ORYX_EVT_LIVE_UPDATE_GET_MACRO_BUFFER,
ORYX_EVT_LIVE_UPDATE_SET_MACRO_BUFFER,
ORYX_EVT_LIVE_UPDATE_MACRO_RESET,
ORYX_EVT_LIVE_UPDATE_EEPROM_RESET,
ORYX_EVT_LIVE_UPDATE_KEYBOARD_RESET,
ORYX_EVT_GET_FW_VERSION,
ORYX_EVT_PAIRING_INPUT,
ORYX_EVT_PAIRING_KEY_INPUT,
ORYX_EVT_PAIRING_FAILED,
ORYX_EVT_PAIRING_SUCCESS,
ORYX_EVT_LAYER,
ORYX_EVT_KEYDOWN,
ORYX_EVT_KEYUP,
};
#ifdef DYNAMIC_KEYMAP_ENABLE
enum dynamic_macros_keycodes {
MACRO00 = 0x5F12,
MACRO01,
MACRO02,
MACRO03,
MACRO04,
MACRO05,
MACRO06,
MACRO07,
MACRO08,
MACRO09,
MACRO10,
MACRO11,
MACRO12,
MACRO13,
MACRO14,
MACRO15,
};
#endif
extern bool oryx_state_live_training_enabled;
bool webusb_receive_oryx(uint8_t *data, uint8_t length);
typedef struct {
bool pairing;
bool paired;
} rawhid_state_t;
extern rawhid_state_t rawhid_state;
void create_pairing_code(void);
bool store_pairing_sequence(keypos_t* pairing_sequence);
keypos_t get_random_keypos(void);
void pairing_init_handler(void);
void pairing_validate_handler(void);
void pairing_init_event(void);
void pairing_key_input_event(void);
void pairing_failed_event(void);
void pairing_succesful_event(void);
void oryx_layer_event(void);
bool is_oryx_live_training_enabled(void);
bool process_record_oryx(uint16_t keycode, keyrecord_t *record);
bool process_record_oryx(uint16_t keycode, keyrecord_t* record);
void layer_state_set_oryx(layer_state_t state);
void eeconfig_init_oryx(void);
void matrix_init_oryx(void);

View File

@@ -258,7 +258,7 @@ bool process_record_quantum(keyrecord_t *record) {
#endif
#ifdef HAPTIC_ENABLE
process_haptic(keycode, record) &&
#endif // HAPTIC_ENABLE
#endif // HAPTIC_ENABLE
#ifdef ORYX_ENABLE
process_record_oryx(keycode, record) &&
#endif
@@ -412,7 +412,6 @@ bool process_record_quantum(keyrecord_t *record) {
}
}
return process_action_kb(record);
}
@@ -442,21 +441,19 @@ void matrix_scan_quantum() {
matrix_scan_kb();
}
#ifdef WEBUSB_ENABLE
__attribute__((weak)) bool webusb_receive_user(uint8_t *data, uint8_t length) { return false; }
__attribute__((weak)) bool webusb_receive_kb(uint8_t *data, uint8_t length) { return webusb_receive_user(data, length); }
__attribute__((weak)) bool webusb_receive_user(uint8_t *data, uint8_t length) {
return false;
}
__attribute__((weak)) bool webusb_receive_kb(uint8_t *data, uint8_t length) {
return webusb_receive_user(data, length);
}
bool webusb_receive_quantum(uint8_t *data, uint8_t length) {
# ifdef ORYX_ENABLE
return webusb_receive_oryx(data, length);
# else
return webusb_receive_kb(data, length);
# endif
}
#endif
//------------------------------------------------------------------------------
// Override these functions in your keymap file to play different tunes on
// different events such as startup and bootloader jump
@@ -465,7 +462,6 @@ __attribute__((weak)) void startup_user() {}
__attribute__((weak)) void shutdown_user() {}
void suspend_power_down_quantum(void) {
suspend_power_down_kb();
#ifndef NO_SUSPEND_POWER_DOWN