forked from qmk/qmk_firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Keyboard] Add new keyboard: Omnikeyish - A replacement PCB for the N…
…orthgate Omnikey family (qmk#6167) * Add omnikeyish keyboard support. * remove out of date comment * PCB Rev 1.1 moved Row5's pin to E6, because the teensy++ hangs an onboard LED off D6. * Move string.h include to .c file * Add pcb kicad link. * Add info.json * Move macro programming to numlock's keyposition, the most useless key on the post model M layout. Force numlock enabled on host at init time, so you're not stuck without a numpad (hopefully) * Make the macro blink function toggle LEDs from their previous state. * Use incorrect but code style compliant opening curly bracing style. * Make PCB rev 1.1 the default Omnikeyish config, as the author has the only rev 1.0 boards that'll ever be. * Fix silly spelling error in 3 defines * First set of review changes. * Layout macro and keymap defined using it. * Layout macros for the northgate factory plates. * minor rearrangements * ALL the layouts. * Forgot ultra-t in info.json
- Loading branch information
1 parent
7f23ad7
commit 1c75385
Showing
9 changed files
with
753 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#pragma once | ||
|
||
#include "config_common.h" | ||
|
||
#define KEYBOARD_PCB_REV 11 | ||
|
||
/* USB Device descriptor parameter */ | ||
#define VENDOR_ID 0xFEED | ||
#define PRODUCT_ID 0x0666 | ||
#define DEVICE_VER 0x1337 | ||
#define MANUFACTURER Henrik O. Sørensen | ||
#define PRODUCT Omnikey(-ish) Keyboard | ||
#define DESCRIPTION Replacement PCB for Omnikey keyboards | ||
|
||
/* key matrix size */ | ||
#define MATRIX_ROWS 6 | ||
#define MATRIX_COLS 23 | ||
|
||
/* key matrix pins */ | ||
#if KEYBOARD_PCB_REV == 10 | ||
#define MATRIX_ROW_PINS { D2, D3, D4, D5, D6, D7 } | ||
#else | ||
#define MATRIX_ROW_PINS { D2, D3, D4, D5, E6, D7 } | ||
#endif | ||
#define MATRIX_COL_PINS { F0, F1, F2, F3, F4, F5, F6, F7, C7, C6, C5, C4, C3, C2, C1, C0, B0, B1, B2, B3, B4, B5, B6 } | ||
|
||
#define NUMLOCKLEDPIN E0 | ||
#define CAPSLOCKLEDPIN E1 | ||
#define SCROLLLOCKLEDPIN B7 | ||
|
||
/* COL2ROW or ROW2COL */ | ||
#define DIODE_DIRECTION ROW2COL | ||
|
||
/* number of backlight levels */ | ||
#ifdef BACKLIGHT_PIN | ||
#define BACKLIGHT_LEVELS 0 | ||
#endif | ||
|
||
/* Set 0 if debouncing isn't needed */ | ||
#define DEBOUNCE 5 | ||
|
||
/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ | ||
#define LOCKING_SUPPORT_ENABLE | ||
|
||
/* Locking resynchronize hack */ | ||
#define LOCKING_RESYNC_ENABLE | ||
|
||
/* force n-key rollover*/ | ||
#define FORCE_NKRO | ||
|
||
#ifdef RGB_DI_PIN | ||
#define RGBLIGHT_ANIMATIONS | ||
#define RGBLED_NUM 0 | ||
#define RGBLIGHT_HUE_STEP 8 | ||
#define RGBLIGHT_SAT_STEP 8 | ||
#define RGBLIGHT_VAL_STEP 8 | ||
#endif | ||
|
||
#define DYNAMIC_MACRO_COUNT 12 | ||
#define DYNAMIC_MACRO_SIZE 48 | ||
#define DYNAMIC_MACRO_EEPROM_STORAGE | ||
#define DYNAMIC_MACRO_EEPROM_MAGIC_ADDR (uint16_t*)32 | ||
#define DYNAMIC_MACRO_EEPROM_BLOCK0_ADDR (uint8_t*)34 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
#include QMK_KEYBOARD_H | ||
#include <string.h> | ||
|
||
void dynamic_macro_init(void) { | ||
/* zero out macro blocks */ | ||
memset(&dynamic_macros, 0, DYNAMIC_MACRO_COUNT * sizeof(dynamic_macro_t)); | ||
} | ||
|
||
/* Blink the LEDs to notify the user about some event. */ | ||
void dynamic_macro_led_blink(void) { | ||
#ifdef BACKLIGHT_ENABLE | ||
backlight_toggle(); | ||
wait_ms(100); | ||
backlight_toggle(); | ||
#else | ||
led_set(host_keyboard_leds() ^ 0xFF); | ||
wait_ms(100); | ||
led_set(host_keyboard_leds()); | ||
#endif | ||
} | ||
|
||
/** | ||
* Start recording of the dynamic macro. | ||
* | ||
* @param macro_id[in] The id of macro to be recorded | ||
*/ | ||
void dynamic_macro_record_start(uint8_t macro_id) { | ||
dprintf("dynamic macro recording: started for slot %d\n", macro_id); | ||
|
||
dynamic_macro_led_blink(); | ||
|
||
clear_keyboard(); | ||
layer_clear(); | ||
|
||
dynamic_macros[macro_id].length = 0; | ||
} | ||
|
||
/** | ||
* Play the dynamic macro. | ||
* | ||
* @param macro_id[in] The id of macro to be played | ||
*/ | ||
void dynamic_macro_play(uint8_t macro_id) { | ||
dprintf("dynamic macro: slot %d playback, length %d\n", macro_id, dynamic_macros[macro_id].length); | ||
|
||
uint32_t saved_layer_state = layer_state; | ||
|
||
clear_keyboard(); | ||
layer_clear(); | ||
|
||
for (uint8_t i = 0; i < dynamic_macros[macro_id].length; ++i) { | ||
process_record(&dynamic_macros[macro_id].events[i]); | ||
} | ||
|
||
clear_keyboard(); | ||
|
||
layer_state = saved_layer_state; | ||
} | ||
|
||
/** | ||
* Record a single key in a dynamic macro. | ||
* | ||
* @param macro_id[in] The start of the used macro buffer. | ||
* @param record[in] The current keypress. | ||
*/ | ||
void dynamic_macro_record_key(uint8_t macro_id, keyrecord_t* record) { | ||
dynamic_macro_t* macro = &dynamic_macros[macro_id]; | ||
uint8_t length = macro->length; | ||
|
||
/* If we've just started recording, ignore all the key releases. */ | ||
if (!record->event.pressed && length == 0) { | ||
dprintln("dynamic macro: ignoring a leading key-up event"); | ||
return; | ||
} | ||
|
||
if (length < DYNAMIC_MACRO_SIZE) { | ||
macro->events[length] = *record; | ||
macro->length = ++length; | ||
} else { | ||
dynamic_macro_led_blink(); | ||
} | ||
|
||
dprintf("dynamic macro: slot %d length: %d/%d\n", macro_id, length, DYNAMIC_MACRO_SIZE); | ||
} | ||
|
||
/** | ||
* End recording of the dynamic macro. Essentially just update the | ||
* pointer to the end of the macro. | ||
*/ | ||
void dynamic_macro_record_end(uint8_t macro_id) { | ||
dynamic_macro_led_blink(); | ||
|
||
dynamic_macro_t* macro = &dynamic_macros[macro_id]; | ||
uint8_t length = macro->length; | ||
|
||
keyrecord_t* events_begin = &(macro->events[0]); | ||
keyrecord_t* events_pointer = &(macro->events[length - 1]); | ||
|
||
dprintf("dynamic_macro: macro length before trimming: %d\n", macro->length); | ||
while (events_pointer != events_begin && (events_pointer)->event.pressed) { | ||
dprintln("dynamic macro: trimming a trailing key-down event"); | ||
--(macro->length); | ||
--events_pointer; | ||
} | ||
|
||
#ifdef DYNAMIC_MACRO_EEPROM_STORAGE | ||
macro->checksum = dynamic_macro_calc_crc(macro); | ||
dynamic_macro_save_eeprom(macro_id); | ||
#endif | ||
|
||
dprintf("dynamic macro: slot %d saved, length: %d\n", macro_id, length); | ||
} | ||
|
||
/* Handle the key events related to the dynamic macros. Should be | ||
* called from process_record_user() like this: | ||
* | ||
* bool process_record_user(uint16_t keycode, keyrecord_t *record) { | ||
* if (!process_record_dynamic_macro(keycode, record)) { | ||
* return false; | ||
* } | ||
* <...THE REST OF THE FUNCTION...> | ||
* } | ||
*/ | ||
bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t* record) { | ||
/* 0 to DYNAMIC_MACRO_COUNT -1 - macro macro_id is being recorded */ | ||
static uint8_t macro_id = 255; | ||
static uint8_t recording_state = STATE_NOT_RECORDING; | ||
|
||
if (STATE_NOT_RECORDING == recording_state) { | ||
/* Program key pressed to request programming mode */ | ||
if (keycode == DYN_MACRO_PROG && record->event.pressed) { | ||
dynamic_macro_led_blink(); | ||
|
||
recording_state = STATE_RECORD_KEY_PRESSED; | ||
dprintf("dynamic macro: programming key pressed, waiting for macro slot selection. %d\n", recording_state); | ||
|
||
return false; | ||
} | ||
/* Macro key pressed to request macro playback */ | ||
if (keycode >= DYN_MACRO_KEY1 && keycode <= DYN_MACRO_KEY12 && record->event.pressed) { | ||
dynamic_macro_play(keycode - DYN_MACRO_KEY1); | ||
|
||
return false; | ||
} | ||
|
||
/* Non-dynamic macro key, process it elsewhere. */ | ||
return true; | ||
} else if (STATE_RECORD_KEY_PRESSED == recording_state) { | ||
/* Program key pressed again before a macro selector key, cancel macro recording. | ||
Blink leds to indicate cancelation. */ | ||
if (keycode == DYN_MACRO_PROG && record->event.pressed) { | ||
dynamic_macro_led_blink(); | ||
|
||
recording_state = STATE_NOT_RECORDING; | ||
dprintf("dynamic macro: programming key pressed, programming mode canceled. %d\n", recording_state); | ||
|
||
return false; | ||
} else if (keycode >= DYN_MACRO_KEY1 && keycode <= DYN_MACRO_KEY12 && record->event.pressed) { | ||
macro_id = keycode - DYN_MACRO_KEY1; | ||
|
||
/* Macro slot selected, enter recording state. */ | ||
recording_state = STATE_CURRENTLY_RECORDING; | ||
dynamic_macro_record_start(macro_id); | ||
|
||
return false; | ||
} | ||
/* Ignore any non-macro key press while in RECORD_KEY_PRESSED state. */ | ||
return false; | ||
} else if (STATE_CURRENTLY_RECORDING == recording_state) { | ||
/* Program key pressed to request end of macro recording. */ | ||
if (keycode == DYN_MACRO_PROG && record->event.pressed) { | ||
dynamic_macro_record_end(macro_id); | ||
recording_state = STATE_NOT_RECORDING; | ||
|
||
return false; | ||
} | ||
/* Don't record other macro key presses. */ | ||
else if (keycode >= DYN_MACRO_KEY1 && keycode <= DYN_MACRO_KEY12 && record->event.pressed) { | ||
dprintln("dynamic macro: playback key ignored in programming mode."); | ||
return false; | ||
} | ||
/* Non-macro keypress that should be recorded */ | ||
else { | ||
dynamic_macro_record_key(macro_id, record); | ||
|
||
/* Don't output recorded keypress. */ | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
#ifdef __AVR__ | ||
# include <util/crc16.h> | ||
uint16_t dynamic_macro_calc_crc(dynamic_macro_t* macro) { | ||
uint16_t crc = 0; | ||
uint8_t* data = (uint8_t*)macro; | ||
|
||
for (uint16_t i = 0; i < DYNAMIC_MACRO_CRC_LENGTH; ++i) { | ||
crc = _crc16_update(crc, *(data++)); | ||
} | ||
return crc; | ||
} | ||
#endif /* __AVR__ */ | ||
|
||
inline void* dynamic_macro_eeprom_macro_addr(uint8_t macro_id) { | ||
return DYNAMIC_MACRO_EEPROM_BLOCK0_ADDR + sizeof(dynamic_macro_t) * macro_id; | ||
} | ||
|
||
bool dynamic_macro_header_correct(void) { | ||
return eeprom_read_word(DYNAMIC_MACRO_EEPROM_MAGIC_ADDR) == DYNAMIC_MACRO_EEPROM_MAGIC; | ||
} | ||
|
||
void dynamic_macro_load_eeprom_all(void) { | ||
if (!dynamic_macro_header_correct()) { | ||
dprintf("dynamic_macro: eeprom header not valid, not restoring macros.\n"); | ||
return; | ||
} | ||
|
||
for (uint8_t i = 0; i < DYNAMIC_MACRO_COUNT; ++i) { | ||
dynamic_macro_load_eeprom(i); | ||
} | ||
} | ||
|
||
void dynamic_macro_load_eeprom(uint8_t macro_id) { | ||
dynamic_macro_t* dst = &dynamic_macros[macro_id]; | ||
|
||
eeprom_read_block(dst, dynamic_macro_eeprom_macro_addr(macro_id), sizeof(dynamic_macro_t)); | ||
|
||
/* Validate checksum, ifchecksum is NOT valid for macro, set its length to 0 to prevent its use. */ | ||
if (dynamic_macro_calc_crc(dst) != dst->checksum) { | ||
dprintf("dynamic macro: slot %d not loaded, checksum mismatch\n", macro_id); | ||
dst->length = 0; | ||
|
||
return; | ||
} | ||
|
||
dprintf("dynamic macro: slot %d loaded from eeprom, checksum okay\n", macro_id); | ||
} | ||
|
||
void dynamic_macro_save_eeprom(uint8_t macro_id) { | ||
if (!dynamic_macro_header_correct()) { | ||
eeprom_write_word(DYNAMIC_MACRO_EEPROM_MAGIC_ADDR, DYNAMIC_MACRO_EEPROM_MAGIC); | ||
dprintf("dynamic macro: writing magic eeprom header\n"); | ||
} | ||
|
||
dynamic_macro_t* src = &dynamic_macros[macro_id]; | ||
|
||
eeprom_update_block(src, dynamic_macro_eeprom_macro_addr(macro_id), sizeof(dynamic_macro_t)); | ||
dprintf("dynamic macro: slot %d saved to eeprom\n", macro_id); | ||
} |
Oops, something went wrong.