diff options
author | Snipeye <Snipeye@gmail.com> | 2018-12-05 19:31:21 -0700 |
---|---|---|
committer | Drashna Jaelre <drashna@live.com> | 2018-12-05 18:31:21 -0800 |
commit | 57678238a9f7023b3e0ba03bd9a61f6a7c309f9d (patch) | |
tree | c4f5aee61f4ca84a5f355d42c13b82bcd6fc35ea /keyboards/dichotomy | |
parent | 8ad561c8f091a4baf167ad4d7c90c02383905e38 (diff) | |
download | qmk_firmware-57678238a9f7023b3e0ba03bd9a61f6a7c309f9d.tar.gz qmk_firmware-57678238a9f7023b3e0ba03bd9a61f6a7c309f9d.zip |
Keyboard: Fixing spelling, updating code, finalizing keymap for Dichotomy (#4539)
* Fixing spelling, updating code, finalizing keymap for Dichotomy
* Fixing requested changes in PR
* Further PR-requested changes for convention
* Making macros functionable, removing unecessary defs
* Fixing keymap to properly use previously-changed macros
Diffstat (limited to 'keyboards/dichotomy')
-rwxr-xr-x | keyboards/dichotomy/config.h | 85 | ||||
-rwxr-xr-x | keyboards/dichotomy/dichotomy.c | 89 | ||||
-rwxr-xr-x | keyboards/dichotomy/dichotomy.h | 46 | ||||
-rw-r--r-- | keyboards/dichotomy/info.json | 12 | ||||
-rwxr-xr-x | keyboards/dichotomy/keymaps/default/keymap.c | 506 | ||||
-rwxr-xr-x | keyboards/dichotomy/matrix.c | 228 | ||||
-rwxr-xr-x | keyboards/dichotomy/readme.md | 33 | ||||
-rwxr-xr-x | keyboards/dichotomy/rules.mk | 77 |
8 files changed, 1076 insertions, 0 deletions
diff --git a/keyboards/dichotomy/config.h b/keyboards/dichotomy/config.h new file mode 100755 index 0000000000..f0847ec52c --- /dev/null +++ b/keyboards/dichotomy/config.h @@ -0,0 +1,85 @@ +/* +Copyright 2012 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include "config_common.h" + +/* USB Device descriptor parameter */ + +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0xACC7 +#define DEVICE_VER 0x0002 +#define MANUFACTURER Broekhuijsen +#define PRODUCT Dichotomy +#define DESCRIPTION q.m.k. keyboard firmware for Dichotomy + +/* key matrix size */ +#define MATRIX_ROWS 5 +#define MATRIX_COLS 12 + +/* define if matrix has ghost */ +//#define MATRIX_HAS_GHOST + +/* number of backlight levels */ +//#define BACKLIGHT_LEVELS 3 + +#define ONESHOT_TIMEOUT 500 + + +/* key combination for command */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ +) + +/* + * Feature disable options + * These options are also useful to firmware size reduction. + */ + +/* disable debug print */ +//#define NO_DEBUG + +/* disable print */ +//#define NO_PRINT + +/* disable action features */ +//#define NO_ACTION_LAYER +//#define NO_ACTION_TAPPING +//#define NO_ACTION_ONESHOT +//#define NO_ACTION_MACRO +//#define NO_ACTION_FUNCTION + +//UART settings for communication with the RF microcontroller +#define SERIAL_UART_BAUD 1000000 +#define SERIAL_UART_DATA UDR1 +#define SERIAL_UART_UBRR (F_CPU / (16UL * SERIAL_UART_BAUD) - 1) +#define SERIAL_UART_TXD_READY (UCSR1A & _BV(UDRE1)) +#define SERIAL_UART_RXD_PRESENT (UCSR1A & _BV(RXC1)) +#define SERIAL_UART_INIT() do { \ + /* baud rate */ \ + UBRR1L = SERIAL_UART_UBRR; \ + /* baud rate */ \ + UBRR1H = SERIAL_UART_UBRR >> 8; \ + /* enable TX and RX */ \ + UCSR1B = _BV(TXEN1) | _BV(RXEN1); \ + /* 8-bit data */ \ + UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); \ + } while(0) + +#endif diff --git a/keyboards/dichotomy/dichotomy.c b/keyboards/dichotomy/dichotomy.c new file mode 100755 index 0000000000..41e12090cb --- /dev/null +++ b/keyboards/dichotomy/dichotomy.c @@ -0,0 +1,89 @@ +#include "dichotomy.h" + +void uart_init(void) { + SERIAL_UART_INIT(); +} + +void pointing_device_task(void){ + /*report_mouse_t currentReport = {}; + SERIAL_UART_INIT(); + uint32_t timeout = 0; + + //the m character requests the RF slave to send the mouse report + SERIAL_UART_DATA = 'm'; + + //trust the external inputs completely, erase old data + uint8_t uart_data[5] = {0}; + + //there are 10 bytes corresponding to 10 columns, and an end byte + for (uint8_t i = 0; i < 5; i++) { + //wait for the serial data, timeout if it's been too long + //this only happened in testing with a loose wire, but does no + //harm to leave it in here + while(!SERIAL_UART_RXD_PRESENT){ + timeout++; + if (timeout > 10000){ + xprintf("\r\nTIMED OUT"); + break; + } + } + xprintf("\r\nGOT DATA for %d",i); + uart_data[i] = SERIAL_UART_DATA; + } + + //check for the end packet, bytes 1-4 are movement and scroll + //but byte 5 has bits 0-3 for the scroll button state + //(1000 if pressed, 0000 if not) and bits 4-7 are always 1 + //We can use this to verify the report sent properly. + if (uart_data[4] == 0x0F || uart_data[4] == 0x8F) + { + xprintf("\r\nREQUESTED MOUSE, RECEIVED %i, %i, %i, %i, %i",uart_data[0],uart_data[1],uart_data[2],uart_data[3],uart_data[4]); + currentReport = pointing_device_get_report(); + //shifting and transferring the info to the mouse report varaible + //mouseReport.x = 127 max -127 min + currentReport.x = (int8_t) uart_data[0]; + //mouseReport.y = 127 max -127 min + currentReport.y = (int8_t) uart_data[1]; + //mouseReport.v = 127 max -127 min (scroll vertical) + currentReport.v = (int8_t) uart_data[2]; + //mouseReport.h = 127 max -127 min (scroll horizontal) + currentReport.h = (int8_t) uart_data[3]; + //mouseReport.buttons = 0x31 max (bitmask for mouse buttons 1-5) 0x00 min + //mouse buttons 1 and 2 are handled by the keymap, but not 3 + if (uart_data[4] == 0x0F) { //then 3 is not pressed + currentReport.buttons &= ~MOUSE_BTN3; //MOUSE_BTN3 is def in report.h + } else { //3 must be pressed + currentReport.buttons |= MOUSE_BTN3; + } + pointing_device_set_report(currentReport); + } else { + xprintf("\r\nRequested packet, data 4 was %d",uart_data[4]); + }*/ + pointing_device_send(); +} + +void led_init(void) { + DDRD |= (1<<1); + PORTD |= (1<<1); + DDRF |= (1<<4) | (1<<5); + PORTF |= (1<<4) | (1<<5); +} + + +void matrix_init_kb(void) { + // put your keyboard start-up code here + // runs once when the firmware starts up + matrix_init_user(); + uart_init(); + led_init(); +} + +void matrix_scan_kb(void) { + // put your looping keyboard code here + // runs every cycle (a lot) + matrix_scan_user(); +} + +void led_set_kb(uint8_t usb_led) { + +} diff --git a/keyboards/dichotomy/dichotomy.h b/keyboards/dichotomy/dichotomy.h new file mode 100755 index 0000000000..030209ff01 --- /dev/null +++ b/keyboards/dichotomy/dichotomy.h @@ -0,0 +1,46 @@ +#ifndef DICHOTOMY_H +#define DICHOTOMY_H + +#include QMK_KEYBOARD_H +#include "report.h" +#include "pointing_device.h" +#include "quantum.h" +#include "matrix.h" +#include "backlight.h" +#include <stddef.h> + +#define red_led_off() PORTF |= (1<<6) +#define red_led_on() PORTF &= ~(1<<6) +#define blu_led_off() PORTF |= (1<<5) +#define blu_led_on() PORTF &= ~(1<<5) +#define grn_led_off() PORTD |= (1<<1) +#define grn_led_on() PORTD &= ~(1<<1) + +#define set_led_off() red_led_off(); grn_led_off(); blu_led_off() +#define set_led_red() red_led_on(); grn_led_off(); blu_led_off() +#define set_led_blue() red_led_off(); grn_led_off(); blu_led_on() +#define set_led_green() red_led_off(); grn_led_on(); blu_led_off() +#define set_led_yellow() red_led_on(); grn_led_on(); blu_led_off() +#define set_led_magenta() red_led_on(); grn_led_off(); blu_led_on() +#define set_led_cyan() red_led_off(); grn_led_on(); blu_led_on() +#define set_led_white() red_led_on(); grn_led_on(); blu_led_on() + +// This a shortcut to help you visually see your layout. +// The first section contains all of the arguements +// The second converts the arguments into a two-dimensional array +#define LAYOUT( \ + k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B, \ + k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B, \ + k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2A, k2B, \ + k33, k34, k35, k36, k37, k38, \ + k42, k43, k44, k45, k46, k47, k48, k49 \ +) \ +{ \ + { k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B }, \ + { k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B }, \ + { k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2A, k2B }, \ + { KC_NO, KC_NO, KC_NO, k33, k34, k35, k36, k37, k38, KC_NO, KC_NO, KC_NO }, \ + { KC_NO, KC_NO, k42, k43, k44, k45, k46, k47, k48, k49, KC_NO, KC_NO } \ +} + +#endif diff --git a/keyboards/dichotomy/info.json b/keyboards/dichotomy/info.json new file mode 100644 index 0000000000..aeb00edce7 --- /dev/null +++ b/keyboards/dichotomy/info.json @@ -0,0 +1,12 @@ +{ + "keyboard_name": "Dichotomy", + "url": "", + "maintainer": "qmk", + "width": 13, + "height": 6, + "layouts": { + "LAYOUT": { + "layout": [{"label":"k00", "x":0, "y":0.5}, {"label":"k01", "x":1, "y":0.5}, {"label":"k02", "x":2, "y":0.25}, {"label":"k03", "x":3, "y":0}, {"label":"k04", "x":4, "y":0.5}, {"label":"k05", "x":5, "y":0.5}, {"label":"k06", "x":7, "y":0.5}, {"label":"k07", "x":8, "y":0.5}, {"label":"k08", "x":9, "y":0}, {"label":"k09", "x":10, "y":0.25}, {"label":"k0A", "x":11, "y":0.5}, {"label":"k0B", "x":12, "y":0.5}, {"label":"k10", "x":0, "y":1.5}, {"label":"k11", "x":1, "y":1.5}, {"label":"k12", "x":2, "y":1.25}, {"label":"k13", "x":3, "y":1}, {"label":"k14", "x":4, "y":1.5}, {"label":"k15", "x":5, "y":1.5}, {"label":"k16", "x":7, "y":1.5}, {"label":"k17", "x":8, "y":1.5}, {"label":"k18", "x":9, "y":1}, {"label":"k19", "x":10, "y":1.25}, {"label":"k1A", "x":11, "y":1.5}, {"label":"k1B", "x":12, "y":1.5}, {"label":"k20", "x":0, "y":2.5}, {"label":"k21", "x":1, "y":2.5}, {"label":"k22", "x":2, "y":2.25}, {"label":"k23", "x":3, "y":2}, {"label":"k24", "x":4, "y":2.5}, {"label":"k25", "x":5, "y":2.5}, {"label":"k26", "x":7, "y":2.5}, {"label":"k27", "x":8, "y":2.5}, {"label":"k28", "x":9, "y":2}, {"label":"k29", "x":10, "y":2.25}, {"label":"k2A", "x":11, "y":2.5}, {"label":"k2B", "x":12, "y":2.5}, {"label":"k33", "x":3, "y":4}, {"label":"k34", "x":4, "y":4}, {"label":"k35", "x":5, "y":4}, {"label":"k36", "x":7, "y":4}, {"label":"k37", "x":8, "y":4}, {"label":"k38", "x":9, "y":4}, {"label":"k43", "x":3, "y":5}, {"label":"k44", "x":4, "y":5}, {"label":"k45", "x":5, "y":5}, {"label":"k46", "x":7, "y":5}, {"label":"k47", "x":8, "y":5}, {"label":"k48", "x":9, "y":5}] + } + } +} diff --git a/keyboards/dichotomy/keymaps/default/keymap.c b/keyboards/dichotomy/keymaps/default/keymap.c new file mode 100755 index 0000000000..e44bd21d9e --- /dev/null +++ b/keyboards/dichotomy/keymaps/default/keymap.c @@ -0,0 +1,506 @@ +// this is the style you want to emulate. +// This is the canonical layout file for the Quantum project. If you want to add another keyboard, + +#include "dichotomy.h" + +// Each layer gets a name for readability, which is then used in the keymap matrix below. +// The underscores don't mean anything - you can have a layer called STUFF or any other name. +// Layer names don't all need to be of the same length, obviously, and you can also skip them +// entirely and just use numbers. +enum dichotomy_layers { + _BS, + _SF, + _NM, + _NS, + _MS +}; + +#define LONGPRESS_COUNT 4 + +enum dichotomy_keycodes +{ + CK_1G = SAFE_RANGE, + CK_BSPE, + CK_QE, + CK_TE, //these 4 CK_XXXX keys are special "alternate long-press" keys controlled with unique timers. Make sure you understand them before you mess with them. + NS_HYPH, + NS_EQU, + NUMKEY, + SFTKEY, + MOUKEY, + MS_BTN1, + MS_BTN2, + MS_BTN3 +}; + +#define CUSTOM_LONGPRESS 150 +#define CUSTOM_TOGGLE_TIME 300 + +#define RED_BRIGHTNESS 3 +#define GREEN_BRIGHTNESS 2 +#define BLUE_BRIGHTNESS 2 + +// Fillers to make layering more clear +#define _______ KC_TRNS +#define XXXXXXX KC_NO + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { +[_BS] = LAYOUT( /* Base layout, nearly qwerty but with modifications because it's not a full keyboard. Obviously. */ + CK_TE, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC, + NUMKEY, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, CK_QE, + SFTKEY, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, MOUKEY, + KC_LCTL, KC_LALT, KC_LGUI, KC_RGUI, KC_RALT, KC_RCTL, + MS_BTN3, KC_LBRC, KC_LPRN, KC_SPC, KC_SPC, KC_RPRN, KC_RBRC, MS_BTN3 +), + +[_SF] = LAYOUT( /* Shifted layout, small changes (because angle brackets have been moved to thumb cluster buttons) */ + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, NS_HYPH, KC_UNDS, _______, _______, + _______, _______, _______, _______, _______, _______, + _______, _______, KC_LABK, _______, _______, KC_RABK, _______, _______ +), + +[_NM] = LAYOUT( /* Number layout, basically the main function layer */ + _______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, _______, + _______, CK_1G, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, CK_BSPE, + _______, KC_F11, KC_F12, KC_F13, KC_F14, KC_F15, KC_F16, KC_F17, KC_F18, KC_F19, KC_F20, _______, + _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______ +), + +[_NS] = LAYOUT( /* Shifted number/function layout, for per-key control. Only active when shift is held, and number is toggled or held */ + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PLUS, NS_EQU, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______ +), + +[_MS] = LAYOUT( /* Mouse layer, including buttons for clicking. */ + _______, _______, _______, _______, _______, _______, KC_VOLU, KC_HOME, KC_PGUP, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, MS_BTN1, MS_BTN2, _______, _______, _______, + _______, _______, _______, _______, _______, _______, KC_VOLD, KC_END, KC_PGDN, _______, _______, _______, + _______, _______, _______, _______, KC_UP, _______, + _______, _______, _______, _______, KC_LEFT, KC_DOWN, KC_RGHT, _______ +) + +}; + + +const uint16_t PROGMEM fn_actions[] = { + +}; + +static uint16_t special_timers[LONGPRESS_COUNT] = {0xFFFF,0xFFFF,0xFFFF,0xFFFF}; +static bool special_key_states[LONGPRESS_COUNT] = {0,0,0,0}; +static bool special_key_pressed[LONGPRESS_COUNT] = {0,0,0,0}; + +static uint16_t shift_timer; +static uint16_t num_timer; +static uint16_t mouse_timer; + +static uint8_t red_timer; +static uint8_t green_timer; +static uint8_t blue_timer; + +static bool shift_singular_key = false; +static bool number_singular_key = false; +static bool mouse_singular_key = false; +static bool capsLED = false; +static bool shiftLED = false; +static bool numLED = false; +static bool mouseLED = false; + +static bool shift_held = false; +static bool shift_suspended = false; +report_mouse_t currentReport = {}; + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + //uint8_t layer; + //layer = biton32(layer_state); // get the current layer //Or don't, I didn't use it. + bool returnVal = true; //this is to determine if more key processing is needed. + + //custom layer handling for tri_layer, + switch (keycode) { + case NUMKEY: + if (record->event.pressed) { + num_timer = timer_read(); + number_singular_key = true; + layer_invert(_NM); + numLED = !numLED; + } else { + if (timer_elapsed(num_timer) < CUSTOM_TOGGLE_TIME && number_singular_key) { + //do nothing, the layer has already been inverted + } else { + layer_invert(_NM); + numLED = !numLED; + } + } + update_tri_layer(_NM, _SF, _NS); + returnVal = false; + break; + //SHIFT is handled as LSHIFT in the general case - 'toggle' shoudl activate caps, while the layer is only active when shift is held. + case SFTKEY: + if (record->event.pressed) { + shift_held = true; + shiftLED = true; + shift_suspended = false; + shift_timer = timer_read(); + shift_singular_key = true; + layer_on(_SF); + register_code(KC_LSFT); + } else { + shift_held = false; + shiftLED = false; + if (timer_elapsed(shift_timer) < CUSTOM_TOGGLE_TIME && shift_singular_key) { + //this was basically a toggle, so activate/deactivate caps lock. + SEND_STRING(SS_TAP(X_CAPSLOCK)); + capsLED = !capsLED; + } + layer_off(_SF); + unregister_code(KC_LSFT); + } + update_tri_layer(_NM, _SF, _NS); + returnVal = false; + break; + //MOUSE layer needs to be handled the same way as NUMKEY, but differently from shift + case MOUKEY: + if (record->event.pressed) { + mouse_timer = timer_read(); + mouse_singular_key = true; + layer_invert(_MS); + mouseLED = !mouseLED; + } else { + if (timer_elapsed(mouse_timer) < CUSTOM_TOGGLE_TIME && mouse_singular_key){ + //do nothing, it was a toggle (and it's already been toggled) + } else { + layer_invert(_MS); + mouseLED = !mouseLED; + } + } + returnVal = false; + break; + //Custom macros for strange keys with different long-tap behavior + case CK_1G: + if (shift_held && shift_suspended){ + register_code(KC_LSFT); + shift_suspended = false; + } + if (record->event.pressed) { + special_timers[CK_1G-SAFE_RANGE] = timer_read(); + special_key_pressed[CK_1G-SAFE_RANGE] = 1; + } else { + if (special_key_states[CK_1G-SAFE_RANGE]){ + //key was activated after custom_longpress, need to close those keycodes + special_key_states[CK_1G-SAFE_RANGE] = 0; + unregister_code(KC_GRAVE); + } else { + if (special_key_pressed[CK_1G-SAFE_RANGE]){ + //key was not activated, return macro activating proper, pre-long-tap key + SEND_STRING(SS_TAP(X_1)); + special_key_pressed[CK_1G-SAFE_RANGE] = 0; + } else { + //the short key was already sent, because another key was pressed. + //Do nothing. + } + + } + } + returnVal = false; + break; + case CK_BSPE: + if (shift_held && shift_suspended){ + register_code(KC_LSFT); + shift_suspended = false; + } + if (record->event.pressed) { + special_timers[CK_BSPE-SAFE_RANGE] = timer_read(); + special_key_pressed[CK_BSPE-SAFE_RANGE] = 1; + } else { + if (special_key_states[CK_BSPE-SAFE_RANGE]){ + //key was activated after custom_longpress, need to close those keycodes + special_key_states[CK_BSPE-SAFE_RANGE] = 0; + unregister_code(KC_ENTER); + } else { + if (special_key_pressed[CK_BSPE-SAFE_RANGE]){ + //key was not activated, return macro activating proper, pre-long-tap key + SEND_STRING(SS_TAP(X_BSLASH)); + special_key_pressed[CK_BSPE-SAFE_RANGE] = 0; + } else { + //the short key was already sent, because another key was pressed. + //Do nothing. + } + } + } + returnVal = false; + break; + case CK_QE: + if (shift_held && shift_suspended){ + register_code(KC_LSFT); + shift_suspended = false; + } + if (record->event.pressed) { + special_timers[CK_QE-SAFE_RANGE] = timer_read(); + special_key_pressed[CK_QE-SAFE_RANGE] = 1; + } else { + if (special_key_states[CK_QE-SAFE_RANGE]){ + //key was activated after custom_longpress, need to close those keycodes + special_key_states[CK_QE-SAFE_RANGE] = 0; + unregister_code(KC_ENTER); + } else { + if (special_key_pressed[CK_QE-SAFE_RANGE]){ + //the long-press key was not activated, return macro activating proper, pre-long-tap key + SEND_STRING(SS_TAP(X_QUOTE)); + special_key_pressed[CK_QE-SAFE_RANGE] = 0; + } else { + //the short key was already sent, because another key was pressed. + //Do nothing. + } + } + } + returnVal = false; + break; + case CK_TE: + if (shift_held && shift_suspended){ + register_code(KC_LSFT); + shift_suspended = false; + } + if (record->event.pressed) { + special_timers[CK_TE-SAFE_RANGE] = timer_read(); + special_key_pressed[CK_TE-SAFE_RANGE] = 1; + } else { + if (special_key_states[CK_TE-SAFE_RANGE]){ + //key was activated after custom_longpress, need to close those keycodes + special_key_states[CK_TE-SAFE_RANGE] = 0; + unregister_code(KC_ESCAPE); + } else { + if (special_key_pressed[CK_TE-SAFE_RANGE]){ + //the long-press key was not activated, return macro activating proper, pre-long-tap key + SEND_STRING(SS_TAP(X_TAB)); + special_key_pressed[CK_TE-SAFE_RANGE] = 0; + } else { + //the short key was already sent, because another key was pressed. + //Do nothing. + } + } + } + returnVal = false; + break; + //No-shift keys, they unregister the KC_LSFT code so they can send + //unshifted values - but they don't change the bool. if any other + //key is pressed and the bool is set, KC_LSFT is registered again. + case NS_HYPH: + if (record->event.pressed) { + shift_suspended = true; + unregister_code(KC_LSFT); + register_code(KC_MINS); + } else { + unregister_code(KC_MINS); + if (shift_held && shift_suspended){ + register_code(KC_LSFT); + shift_suspended = false; + } + } + returnVal = false; + break; + case NS_EQU: + if (record->event.pressed) { + shift_suspended = true; + unregister_code(KC_LSFT); + register_code(KC_EQUAL); + } else { + unregister_code(KC_EQUAL); + if (shift_held && shift_suspended){ + register_code(KC_LSFT); + shift_suspended = false; + } + } + returnVal = false; + break; + + //mouse buttons, for 1-3, to update the mouse report: + case MS_BTN1: + currentReport = pointing_device_get_report(); + if (record->event.pressed) { + if (shift_held && shift_suspended){ + register_code(KC_LSFT); + shift_suspended = false; + } + //update mouse report here + currentReport.buttons |= MOUSE_BTN1; //MOUSE_BTN1 is a const defined in report.h + } else { + //update mouse report here + currentReport.buttons &= ~MOUSE_BTN1; + } + pointing_device_set_report(currentReport); + returnVal = false; + break; + case MS_BTN2: + currentReport = pointing_device_get_report(); + if (record->event.pressed) { + if (shift_held && shift_suspended){ + register_code(KC_LSFT); + shift_suspended = false; + } + //update mouse report here + currentReport.buttons |= MOUSE_BTN2; //MOUSE_BTN2 is a const defined in report.h + } else { + //update mouse report here + currentReport.buttons &= ~MOUSE_BTN2; + } + pointing_device_set_report(currentReport); + returnVal = false; + break; + case MS_BTN3: + currentReport = pointing_device_get_report(); + if (record->event.pressed) { + if (shift_held && shift_suspended){ + register_code(KC_LSFT); + shift_suspended = false; + } + //update mouse report here + currentReport.buttons |= MOUSE_BTN3; //MOUSE_BTN3 is a const defined in report.h + } else { + //update mouse report here + currentReport.buttons &= ~MOUSE_BTN3; + } + pointing_device_set_report(currentReport); + returnVal = false; + break; + //Additionally, if NS_ keys are in use, then shift may be held (but is + //disabled for the unshifted keycodes to be send. Check the bool and + //register shift as necessary. + default: + if (shift_held){ + register_code(KC_LSFT); + } + break; + } + switch (keycode){ + case KC_BSPC: + case KC_NO: + case NUMKEY: + case SFTKEY: + case MOUKEY: + //don't want to reset single key variables + break; + default: + //If any other key was pressed during the layer mod hold period, + //then the layer mod was used momentarily, and should block latching + shift_singular_key = false; + number_singular_key = false; + mouse_singular_key = false; + break; + } + switch (keycode){ + case KC_BSPC: + case KC_NO: + case NUMKEY: + case SFTKEY: + case MOUKEY: + case MOUSE_BTN1: + case MOUSE_BTN2: + case MOUSE_BTN3: + case KC_LCTL: + case KC_LALT: + case KC_LGUI: + case KC_RCTL: + case KC_RALT: + case KC_RGUI: + case CK_1G: + case CK_BSPE: + case CK_QE: + case CK_TE: + //Do nothing, don't want to trigger the timer key rollover + break; + default: + //Now we're checking to see if any of the special timer keys are pressed + //if so, we need to activate their short-press features + if (record->event.pressed) { + for (uint8_t i = 0; i<LONGPRESS_COUNT; i++){ + if ((!special_key_states[i]) && special_key_pressed[i]){ + switch (i + SAFE_RANGE){ + case CK_1G: + SEND_STRING(SS_TAP(X_1)); + break; + case CK_BSPE: + SEND_STRING(SS_TAP(X_BSLASH)); + break; + case CK_QE: + SEND_STRING(SS_TAP(X_QUOTE)); + break; + case CK_TE: + SEND_STRING(SS_TAP(X_TAB)); + break; + } + special_key_pressed[i] = 0; + } + } + } else { + //do nothing, we don't want to trigger short presses on key releases. + } + break; + } + return returnVal; +}; + +void matrix_scan_user(void) { + //uint8_t layer = biton32(layer_state); + for (uint8_t i = 0; i<LONGPRESS_COUNT; i++){ + if ((timer_elapsed(special_timers[i]) >= CUSTOM_LONGPRESS) && (!special_key_states[i]) && special_key_pressed[i]){ + switch (i + SAFE_RANGE){ + case CK_1G: + register_code(KC_GRAVE); + break; + case CK_BSPE: + register_code(KC_ENTER); + break; + case CK_QE: + register_code(KC_ENTER); + break; + case CK_TE: + register_code(KC_ESCAPE); + break; + } + special_key_pressed[i] = 0; + special_key_states[i] = 1; + } + } + if (shiftLED || capsLED){ + red_timer++; + if (red_timer < RED_BRIGHTNESS){ + red_led_on(); + } else { + red_timer = 0; + red_led_off(); + } + } else { + red_timer = 0; + red_led_off(); + } + if (numLED){ + green_timer++; + if (green_timer < GREEN_BRIGHTNESS){ + grn_led_on(); + } else { + green_timer = 0; + grn_led_off(); + } + } else { + green_timer = 0; + grn_led_off(); + } + if (mouseLED){ + blue_timer++; + if (blue_timer < BLUE_BRIGHTNESS){ + blu_led_on(); + } else { + blue_timer = 0; + blu_led_off(); + } + } else { + blue_timer = 0; + blu_led_off(); + } +}; diff --git a/keyboards/dichotomy/matrix.c b/keyboards/dichotomy/matrix.c new file mode 100755 index 0000000000..14c3f0d8e3 --- /dev/null +++ b/keyboards/dichotomy/matrix.c @@ -0,0 +1,228 @@ +/* +Copyright 2012 Jun Wako +Copyright 2014 Jack Humbert + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#include <stdint.h> +#include <stdbool.h> +#if defined(__AVR__) +#include <avr/io.h> +#endif +#include "wait.h" +#include "print.h" +#include "debug.h" +#include "util.h" +#include "matrix.h" +#include "timer.h" +#include "dichotomy.h" +#include "pointing_device.h" +#include "report.h" + +#if (MATRIX_COLS <= 8) +# define print_matrix_header() print("\nr/c 01234567\n") +# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop(matrix[i]) +# define ROW_SHIFTER ((uint8_t)1) +#elif (MATRIX_COLS <= 16) +# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n") +# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop16(matrix[i]) +# define ROW_SHIFTER ((uint16_t)1) +#elif (MATRIX_COLS <= 32) +# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n") +# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop32(matrix[i]) +# define ROW_SHIFTER ((uint32_t)1) +#endif + +#define MAIN_ROWMASK 0xFFF0; +#define LOWER_ROWMASK 0x3FC0; + +/* matrix state(1:on, 0:off) */ +static matrix_row_t matrix[MATRIX_ROWS]; + +__attribute__ ((weak)) +void matrix_init_quantum(void) { + matrix_init_kb(); +} + +__attribute__ ((weak)) +void matrix_scan_quantum(void) { + matrix_scan_kb(); +} + +__attribute__ ((weak)) +void matrix_init_kb(void) { + matrix_init_user(); +} + +__attribute__ ((weak)) +void matrix_scan_kb(void) { + matrix_scan_user(); +} + +__attribute__ ((weak)) +void matrix_init_user(void) { +} + +__attribute__ ((weak)) +void matrix_scan_user(void) { +} + +inline +uint8_t matrix_rows(void) { + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) { + return MATRIX_COLS; +} + +void matrix_init(void) { + DDRF |= (1<<6); + DDRF |= (1<<5); + DDRD |= (1<<1); + matrix_init_quantum(); +} + +uint8_t matrix_scan(void) +{ + SERIAL_UART_INIT(); + //xprintf("\r\nTRYING TO SCAN"); + + uint32_t timeout = 0; + + //the s character requests the RF slave to send the matrix + SERIAL_UART_DATA = 's'; + + //trust the external keystates entirely, erase the last data + uint8_t uart_data[11] = {0}; + + //there are 10 bytes corresponding to 10 columns, and an end byte + for (uint8_t i = 0; i < 11; i++) { + //wait for the serial data, timeout if it's been too long + //this only happened in testing with a loose wire, but does no + //harm to leave it in here + while(!SERIAL_UART_RXD_PRESENT){ + timeout++; + if (timeout > 10000){ + xprintf("\r\nTime out in keyboard."); + break; + } + } + uart_data[i] = SERIAL_UART_DATA; + } + + //check for the end packet, the key state bytes use the LSBs, so 0xE0 + //will only show up here if the correct bytes were recieved + uint8_t checksum = 0x00; + for (uint8_t z=0; z<10; z++){ + checksum = checksum^uart_data[z]; + } + checksum = checksum ^ (uart_data[10] & 0xF0); + // Smash the checksum from 1 byte into 4 bits + checksum = (checksum ^ ((checksum & 0xF0)>>4)) & 0x0F; +//xprintf("\r\nGOT RAW PACKET: \r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d",uart_data[0],uart_data[1],uart_data[2],uart_data[3],uart_data[4],uart_data[5],uart_data[6],uart_data[7],uart_data[8],uart_data[9],uart_data[10],checksum); + if ((uart_data[10] & 0x0F) == checksum) { //this is an arbitrary binary checksum (1001) (that would be 0x9.) + //xprintf("\r\nGOT PACKET: \r\n%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n%d",uart_data[0],uart_data[1],uart_data[2],uart_data[3],uart_data[4],uart_data[5]); + //shifting and transferring the keystates to the QMK matrix variable + //bits 1-12 are row 1, 13-24 are row 2, 25-36 are row 3, + //bits 37-42 are row 4 (only 6 wide, 1-3 are 0, and 10-12 are 0) + //bits 43-48 are row 5 (same as row 4) + /* ASSUMING MSB FIRST */ + matrix[0] = (((uint16_t) uart_data[0] << 8) | ((uint16_t) uart_data[1])) & MAIN_ROWMASK; + matrix[1] = ((uint16_t) uart_data[1] << 12) | ((uint16_t) uart_data[2] << 4); + matrix[2] = (((uint16_t) uart_data[3] << 8) | ((uint16_t) uart_data[4])) & MAIN_ROWMASK; + matrix[3] = (((uint16_t) uart_data[4] << 9) | ((uint16_t) uart_data[5] << 1)) & LOWER_ROWMASK; + matrix[4] = (((uint16_t) uart_data[5] << 7) | ((uart_data[10] & 1<<7) ? 1:0) << 13 | ((uart_data[10] & 1<<6) ? 1:0) << 6) & LOWER_ROWMASK; + /* OK, TURNS OUT THAT WAS A BAD ASSUMPTION */ + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + //I've unpacked these into the mirror image of what QMK expects them to be, so... + /*uint8_t halfOne = (matrix[i]>>8); + uint8_t halfTwo = (matrix[i] & 0xFF); + halfOne = ((halfOne * 0x0802LU & 0x22110LU) | (halfOne * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; + halfTwo = ((halfTwo * 0x0802LU & 0x22110LU) | (halfTwo * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; + matrix[i] = ((halfTwo<<8) & halfOne);*/ + //matrix[i] = ((matrix[i] * 0x0802LU & 0x22110LU) | (matrix[i] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; + matrix[i] = bitrev16(matrix[i]); + //bithack mirror! Doesn't make any sense, but works - and efficiently. + } + //if (uart_data[6]!=0 || uart_data[7]!=0){ + //if (maxCount<101){ + // xprintf("\r\nMouse data: x=%d, y=%d",(int8_t)uart_data[6],(int8_t)uart_data[7]); + //} + report_mouse_t currentReport = {}; + //check for the end packet, bytes 1-4 are movement and scroll + //but byte 5 has bits 0-3 for the scroll button state + //(1000 if pressed, 0000 if not) and bits 4-7 are always 1 + //We can use this to verify the report sent properly. + + currentReport = pointing_device_get_report(); + //shifting and transferring the info to the mouse report varaible + //mouseReport.x = 127 max -127 min + currentReport.x = (int8_t) uart_data[6]; + //mouseReport.y = 127 max -127 min + currentReport.y = (int8_t) uart_data[7]; + //mouseReport.v = 127 max -127 min (scroll vertical) + currentReport.v = (int8_t) uart_data[8]; + //mouseReport.h = 127 max -127 min (scroll horizontal) + currentReport.h = (int8_t) uart_data[9]; + /* + currentReport.x = 0; + currentReport.y = 0; + currentReport.v = 0; + currentReport.h = 0;*/ + pointing_device_set_report(currentReport); + } else { + //xprintf("\r\nRequested packet, data 10 was %d but checksum was %d",(uart_data[10] & 0x0F), (checksum & 0x0F)); + } + //matrix_print(); + + matrix_scan_quantum(); + return 1; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & ((matrix_row_t)1<col)); +} + +inline +matrix_row_t matrix_get_row(uint8_t row) +{ + return matrix[row]; +} + +void matrix_print(void) +{ + print_matrix_header(); + + for (uint8_t row = 0; row < MATRIX_ROWS; row++) { + phex(row); print(": "); + print_matrix_row(row); + print("\n"); + } +} + +uint8_t matrix_key_count(void) +{ + uint8_t count = 0; + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + count += matrix_bitpop(i); + } + return count; +} diff --git a/keyboards/dichotomy/readme.md b/keyboards/dichotomy/readme.md new file mode 100755 index 0000000000..9027825c3c --- /dev/null +++ b/keyboards/dichotomy/readme.md @@ -0,0 +1,33 @@ +Dichotomy Keyboard Firmware +====================== + +These configuration files were based off the Mitosis keyboard. This keyboard uses a completely different 'matrix scan' system to other keyboards, it relies on an external nRF51822 microcontroller maintaining a matrix of keystates received from the keyboard halves - it also receives mouse pointer information from the keyboard halves, which is implemented through a new feature, "Pointing Device". The matrix.c file contains the code to poll the external microcontroller for the key matrix, and the keymap.c file contains similar code to obtain the mouse report. As long as the relavant functions in these files are not changed, all other QMK features are supported. + +Build log of the keyboard can be found [here](http://google.com) + +Hardware design files can be found [here](http://google.com) + +Firmware for the nordic MCUs can be found [here](http://google.com) + +## Quantum MK Firmware + +For the full Quantum feature list, see [the parent readme](/). + +## Building + +Download or clone the whole firmware and navigate to the keyboards/atreus folder. Once your dev env is setup, you'll be able to type `make` to generate your .hex - you can then use `make dfu` to program your PCB once you hit the reset button. + +Depending on which keymap you would like to use, you will have to compile slightly differently. + +### Default +To build with the default keymap, simply run `make default`. + +### Other Keymaps +Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create file named `<name>.c` and see keymap document (you can find in top readme.md) and existent keymap files. + +To build the firmware binary hex file with a keymap just do `make` with a keymap like this: + +``` +$ make [default|jack|<name>] +``` +Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder. diff --git a/keyboards/dichotomy/rules.mk b/keyboards/dichotomy/rules.mk new file mode 100755 index 0000000000..4dbc999b74 --- /dev/null +++ b/keyboards/dichotomy/rules.mk @@ -0,0 +1,77 @@ + +OPT_DEFS += -DDICHOTOMY_PROMICRO +DICHOTOMY_UPLOAD_COMMAND = while [ ! -r $(USB) ]; do sleep 1; done; \ + avrdude -p $(MCU) -c avr109 -U flash:w:$(TARGET).hex -P $(USB) + +# # project specific files +SRC = matrix.c + + +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Bootloader + # This definition is optional, and if your keyboard supports multiple bootloaders of + # different sizes, comment this out, and the correct address will be loaded + # automatically (+60). See bootloader.mk for all options. + BOOTLOADER = caterina + +# Interrupt driven control endpoint task(+60) +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + +# Build Options +# comment out to disable the options. +# +#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +#MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +POINTING_DEVICE_ENABLE = yes # Generic Pointer, not as big as mouse keys hopefully. +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +CUSTOM_MATRIX = yes # Remote matrix from the wireless bridge +# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE +# SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA +# BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality +# MIDI_ENABLE = YES # MIDI controls +UNICODE_ENABLE = YES # Unicode +# BLUETOOTH_ENABLE = yes # Enable Bluetooth with the Adafruit EZ-Key HID + +USB = /dev/ttyACM0 + +#upload: build +# $(DICHOTOMY_UPLOAD_COMMAND) |