Skip to content

Commit

Permalink
[Keyboard] Add new keyboard: Omnikeyish - A replacement PCB for the N…
Browse files Browse the repository at this point in the history
…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
henrikosorensen authored and drashna committed Jun 22, 2019
1 parent 7f23ad7 commit 1c75385
Show file tree
Hide file tree
Showing 9 changed files with 753 additions and 0 deletions.
63 changes: 63 additions & 0 deletions keyboards/omnikeyish/config.h
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
252 changes: 252 additions & 0 deletions keyboards/omnikeyish/dynamic_macro.c
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);
}
Loading

0 comments on commit 1c75385

Please sign in to comment.