Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd819a7f7e | ||
|
|
94ba2e5a9f | ||
|
|
77399bfe51 | ||
|
|
d53432393b | ||
|
|
28929ad017 |
No files matched your search
+27
-13
@@ -254,20 +254,34 @@ QUANTUM_SRC:= \
|
|||||||
$(QUANTUM_DIR)/keymap_common.c \
|
$(QUANTUM_DIR)/keymap_common.c \
|
||||||
$(QUANTUM_DIR)/keycode_config.c
|
$(QUANTUM_DIR)/keycode_config.c
|
||||||
|
|
||||||
ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
|
# Include the standard or split matrix code if needed
|
||||||
ifneq ($(strip $(CUSTOM_MATRIX)), yes)
|
ifneq ($(strip $(CUSTOM_MATRIX)), yes)
|
||||||
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/matrix.c
|
ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
|
||||||
# Do not use $(QUANTUM_DIR)/matrix.c.
|
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/matrix.c
|
||||||
CUSTOM_MATRIX=yes
|
else
|
||||||
|
QUANTUM_SRC += $(QUANTUM_DIR)/matrix.c
|
||||||
endif
|
endif
|
||||||
OPT_DEFS += -DSPLIT_KEYBOARD
|
|
||||||
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_flags.c \
|
|
||||||
$(QUANTUM_DIR)/split_common/split_util.c
|
|
||||||
QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/i2c.c
|
|
||||||
QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/serial.c
|
|
||||||
COMMON_VPATH += $(QUANTUM_PATH)/split_common
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(strip $(CUSTOM_MATRIX)), yes)
|
# Include the standard debounce code if needed
|
||||||
QUANTUM_SRC += $(QUANTUM_DIR)/matrix.c
|
ifneq ($(strip $(CUSTOM_DEBOUNCE)), yes)
|
||||||
|
QUANTUM_SRC += $(QUANTUM_DIR)/debounce.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
|
||||||
|
OPT_DEFS += -DSPLIT_KEYBOARD
|
||||||
|
|
||||||
|
# Include files used by all split keyboards
|
||||||
|
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_flags.c \
|
||||||
|
$(QUANTUM_DIR)/split_common/split_util.c
|
||||||
|
|
||||||
|
# Determine which (if any) transport files are required
|
||||||
|
ifneq ($(strip $(SPLIT_TRANSPORT)), custom)
|
||||||
|
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/transport.c
|
||||||
|
# Functions added via QUANTUM_LIB_SRC are only included in the final binary if they're called.
|
||||||
|
# Unused functions are pruned away, which is why we can add both drivers here without bloat.
|
||||||
|
QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/i2c.c \
|
||||||
|
$(QUANTUM_DIR)/split_common/serial.c
|
||||||
|
endif
|
||||||
|
COMMON_VPATH += $(QUANTUM_PATH)/split_common
|
||||||
endif
|
endif
|
||||||
@@ -143,7 +143,7 @@ If you define these options you will enable the associated feature, which may in
|
|||||||
* Breaks any Tap Toggle functionality (`TT` or the One Shot Tap Toggle)
|
* Breaks any Tap Toggle functionality (`TT` or the One Shot Tap Toggle)
|
||||||
* `#define LEADER_TIMEOUT 300`
|
* `#define LEADER_TIMEOUT 300`
|
||||||
* how long before the leader key times out
|
* how long before the leader key times out
|
||||||
* If you're having issues finishing the sequence before it times out, you may need to increase the timeout setting. Or you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped.
|
* If you're having issues finishing the sequence before it times out, you may need to increase the timeout setting. Or you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped.
|
||||||
* `#define LEADER_PER_KEY_TIMING`
|
* `#define LEADER_PER_KEY_TIMING`
|
||||||
* sets the timer for leader key chords to run on each key press rather than overall
|
* sets the timer for leader key chords to run on each key press rather than overall
|
||||||
* `#define LEADER_KEY_STRICT_KEY_PROCESSING`
|
* `#define LEADER_KEY_STRICT_KEY_PROCESSING`
|
||||||
@@ -197,6 +197,9 @@ If you define these options you will enable the associated feature, which may in
|
|||||||
|
|
||||||
Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in your rules.mk
|
Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in your rules.mk
|
||||||
|
|
||||||
|
* `SPLIT_TRANSPORT = custom`
|
||||||
|
* Allows replacing the standard split communication routines with a custom one. ARM based split keyboards must use this at present.
|
||||||
|
|
||||||
### Setting Handedness
|
### Setting Handedness
|
||||||
|
|
||||||
One thing to remember, the side that the USB port is plugged into is always the master half. The side not plugged into USB is the slave.
|
One thing to remember, the side that the USB port is plugged into is always the master half. The side not plugged into USB is the slave.
|
||||||
@@ -208,7 +211,7 @@ There are a few different ways to set handedness for split keyboards (listed in
|
|||||||
3. Set `MASTER_RIGHT`: Half that is plugged into the USB port is determined to be the master and right half (inverse of the default)
|
3. Set `MASTER_RIGHT`: Half that is plugged into the USB port is determined to be the master and right half (inverse of the default)
|
||||||
4. Default: The side that is plugged into the USB port is the master half and is assumed to be the left half. The slave side is the right half
|
4. Default: The side that is plugged into the USB port is the master half and is assumed to be the left half. The slave side is the right half
|
||||||
|
|
||||||
* `#define SPLIT_HAND_PIN B7`
|
* `#define SPLIT_HAND_PIN B7`
|
||||||
* For using high/low pin to determine handedness, low = right hand, high = left hand. Replace `B7` with the pin you are using. This is optional, and if you leave `SPLIT_HAND_PIN` undefined, then you can still use the EE_HANDS method or MASTER_LEFT / MASTER_RIGHT defines like the stock Let's Split uses.
|
* For using high/low pin to determine handedness, low = right hand, high = left hand. Replace `B7` with the pin you are using. This is optional, and if you leave `SPLIT_HAND_PIN` undefined, then you can still use the EE_HANDS method or MASTER_LEFT / MASTER_RIGHT defines like the stock Let's Split uses.
|
||||||
|
|
||||||
* `#define EE_HANDS` (only works if `SPLIT_HAND_PIN` is not defined)
|
* `#define EE_HANDS` (only works if `SPLIT_HAND_PIN` is not defined)
|
||||||
@@ -302,6 +305,10 @@ Use these to enable or disable building certain features. The more you have enab
|
|||||||
* Current options are AdafruitEzKey, AdafruitBLE, RN42
|
* Current options are AdafruitEzKey, AdafruitBLE, RN42
|
||||||
* `SPLIT_KEYBOARD`
|
* `SPLIT_KEYBOARD`
|
||||||
* Enables split keyboard support (dual MCU like the let's split and bakingpy's boards) and includes all necessary files located at quantum/split_common
|
* Enables split keyboard support (dual MCU like the let's split and bakingpy's boards) and includes all necessary files located at quantum/split_common
|
||||||
|
* `CUSTOM_MATRIX`
|
||||||
|
* Allows replacing the standard matrix scanning routine with a custom one.
|
||||||
|
* `CUSTOM_DEBOUNCE`
|
||||||
|
* Allows replacing the standard key debouncing routine with a custom one.
|
||||||
* `WAIT_FOR_USB`
|
* `WAIT_FOR_USB`
|
||||||
* Forces the keyboard to wait for a USB connection to be established before it starts up
|
* Forces the keyboard to wait for a USB connection to be established before it starts up
|
||||||
* `NO_USB_STARTUP_CHECK`
|
* `NO_USB_STARTUP_CHECK`
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ keyrecord_t record {
|
|||||||
|
|
||||||
# LED Control
|
# LED Control
|
||||||
|
|
||||||
This allows you to control the 5 LED's defined as part of the USB Keyboard spec. It will be called when the state of one of those 5 LEDs changes.
|
QMK provides methods to read the 5 LEDs defined as part of the HID spec:
|
||||||
|
|
||||||
* `USB_LED_NUM_LOCK`
|
* `USB_LED_NUM_LOCK`
|
||||||
* `USB_LED_CAPS_LOCK`
|
* `USB_LED_CAPS_LOCK`
|
||||||
@@ -98,31 +98,46 @@ This allows you to control the 5 LED's defined as part of the USB Keyboard spec.
|
|||||||
* `USB_LED_COMPOSE`
|
* `USB_LED_COMPOSE`
|
||||||
* `USB_LED_KANA`
|
* `USB_LED_KANA`
|
||||||
|
|
||||||
|
These five constants correspond to the positional bits of the host LED state.
|
||||||
|
There are two ways to get the host LED state:
|
||||||
|
|
||||||
|
* by implementing `led_set_user()`
|
||||||
|
* by calling `host_keyboard_leds()`
|
||||||
|
|
||||||
|
## `led_set_user()`
|
||||||
|
|
||||||
|
This function will be called when the state of one of those 5 LEDs changes.
|
||||||
|
It receives the LED state as parameter.
|
||||||
|
Use the `IS_LED_ON(USB_LED, LED_NAME)` and `IS_LED_OFF(USB_LED, LED_NAME)`
|
||||||
|
macros to check the LED status.
|
||||||
|
|
||||||
|
!> `host_keyboard_leds()` may already reflect a new value before `led_set_user()` is called.
|
||||||
|
|
||||||
### Example `led_set_user()` Implementation
|
### Example `led_set_user()` Implementation
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void led_set_user(uint8_t usb_led) {
|
void led_set_user(uint8_t usb_led) {
|
||||||
if (usb_led & (1<<USB_LED_NUM_LOCK)) {
|
if (IS_LED_ON(usb_led, USB_LED_NUM_LOCK)) {
|
||||||
PORTB |= (1<<0);
|
PORTB |= (1<<0);
|
||||||
} else {
|
} else {
|
||||||
PORTB &= ~(1<<0);
|
PORTB &= ~(1<<0);
|
||||||
}
|
}
|
||||||
if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
|
if (IS_LED_ON(usb_led, USB_LED_CAPS_LOCK)) {
|
||||||
PORTB |= (1<<1);
|
PORTB |= (1<<1);
|
||||||
} else {
|
} else {
|
||||||
PORTB &= ~(1<<1);
|
PORTB &= ~(1<<1);
|
||||||
}
|
}
|
||||||
if (usb_led & (1<<USB_LED_SCROLL_LOCK)) {
|
if (IS_LED_ON(usb_led, USB_LED_SCROLL_LOCK)) {
|
||||||
PORTB |= (1<<2);
|
PORTB |= (1<<2);
|
||||||
} else {
|
} else {
|
||||||
PORTB &= ~(1<<2);
|
PORTB &= ~(1<<2);
|
||||||
}
|
}
|
||||||
if (usb_led & (1<<USB_LED_COMPOSE)) {
|
if (IS_LED_ON(usb_led, USB_LED_COMPOSE)) {
|
||||||
PORTB |= (1<<3);
|
PORTB |= (1<<3);
|
||||||
} else {
|
} else {
|
||||||
PORTB &= ~(1<<3);
|
PORTB &= ~(1<<3);
|
||||||
}
|
}
|
||||||
if (usb_led & (1<<USB_LED_KANA)) {
|
if (IS_LED_ON(usb_led, USB_LED_KANA)) {
|
||||||
PORTB |= (1<<4);
|
PORTB |= (1<<4);
|
||||||
} else {
|
} else {
|
||||||
PORTB &= ~(1<<4);
|
PORTB &= ~(1<<4);
|
||||||
@@ -135,10 +150,33 @@ void led_set_user(uint8_t usb_led) {
|
|||||||
* Keyboard/Revision: `void led_set_kb(uint8_t usb_led)`
|
* Keyboard/Revision: `void led_set_kb(uint8_t usb_led)`
|
||||||
* Keymap: `void led_set_user(uint8_t usb_led)`
|
* Keymap: `void led_set_user(uint8_t usb_led)`
|
||||||
|
|
||||||
|
## `host_keyboard_leds()`
|
||||||
|
|
||||||
|
Call this function to get the last received LED state.
|
||||||
|
This is useful for reading the LED state outside `led_set_*`, e.g. in [`matrix_scan_user()`](#matrix-scanning-code).
|
||||||
|
|
||||||
|
For convenience, you can use the `IS_HOST_LED_ON(LED_NAME)` and `IS_HOST_LED_OFF(LED_NAME)` macros instead of calling `host_keyboard_leds()` directly.
|
||||||
|
|
||||||
|
## Setting physical LED state
|
||||||
|
|
||||||
|
Some keyboard implementations provide convenience methods for setting the state of the physical LEDs.
|
||||||
|
|
||||||
|
### Ergodox and Ergodox EZ
|
||||||
|
|
||||||
|
The Ergodox EZ implementation provides `ergodox_right_led_``1`/`2`/`3_on`/`off()`
|
||||||
|
to turn individual LEDs on and off, as well as
|
||||||
|
`ergodox_right_led_on`/`off(uint8_t led)`
|
||||||
|
to turn them on and off by their number.
|
||||||
|
|
||||||
|
In addition, it is possible to specify the brightness level with `ergodox_led_all_set(uint8_t n)`,
|
||||||
|
for individual LEDs with `ergodox_right_led_1`/`2`/`3_set(uint8_t n)`
|
||||||
|
or by their number using `ergodox_right_led_set(uint8_t led, uint8_t n)`.
|
||||||
|
|
||||||
|
It defines `LED_BRIGHTNESS_LO` for the lowest brightness and `LED_BRIGHTNESS_HI` for the highest brightness, which is also the default.
|
||||||
|
|
||||||
# Matrix Initialization Code
|
# Matrix Initialization Code
|
||||||
|
|
||||||
Before a keyboard can be used the hardware must be initialized. QMK handles initialization of the keyboard matrix itself, but if you have other hardware like LED's or i²c controllers you will need to set up that hardware before it can be used.
|
Before a keyboard can be used the hardware must be initialized. QMK handles initialization of the keyboard matrix itself, but if you have other hardware like LEDs or i²c controllers you will need to set up that hardware before it can be used.
|
||||||
|
|
||||||
|
|
||||||
### Example `matrix_init_user()` Implementation
|
### Example `matrix_init_user()` Implementation
|
||||||
@@ -176,7 +214,7 @@ This example has been deliberately omitted. You should understand enough about Q
|
|||||||
|
|
||||||
This function gets called at every matrix scan, which is basically as often as the MCU can handle. Be careful what you put here, as it will get run a lot.
|
This function gets called at every matrix scan, which is basically as often as the MCU can handle. Be careful what you put here, as it will get run a lot.
|
||||||
|
|
||||||
You should use this function if you need custom matrix scanning code. It can also be used for custom status output (such as LED's or a display) or other functionality that you want to trigger regularly even when the user isn't typing.
|
You should use this function if you need custom matrix scanning code. It can also be used for custom status output (such as LEDs or a display) or other functionality that you want to trigger regularly even when the user isn't typing.
|
||||||
|
|
||||||
|
|
||||||
# Keyboard Idling/Wake Code
|
# Keyboard Idling/Wake Code
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ This allows you to send Unicode characters using `UC(<code point>)` in your keym
|
|||||||
|
|
||||||
`UNICODEMAP_ENABLE`
|
`UNICODEMAP_ENABLE`
|
||||||
|
|
||||||
This allows you to send Unicode characters using `X(<map index>)` in your keymap. You will need to maintain a mapping table in your keymap file. All possible code points (up to `0x10FFFF`) are supported.
|
This allows you to send Unicode characters using `X(<map index>)` in your keymap. You will need to maintain a mapping table in your keymap file. All possible code points (up to `0x10FFFF`) are supported.
|
||||||
|
|
||||||
`UCIS_ENABLE`
|
`UCIS_ENABLE`
|
||||||
|
|
||||||
@@ -135,6 +135,18 @@ This enables [key lock](feature_key_lock.md). This consumes an additional 260 by
|
|||||||
|
|
||||||
This enables split keyboard support (dual MCU like the let's split and bakingpy's boards) and includes all necessary files located at quantum/split_common
|
This enables split keyboard support (dual MCU like the let's split and bakingpy's boards) and includes all necessary files located at quantum/split_common
|
||||||
|
|
||||||
|
`SPLIT_TRANSPORT`
|
||||||
|
|
||||||
|
As there is no standard split communication driver for ARM-based split keyboards yet, `SPLIT_TRANSPORT = custom` must be used for these. It will prevent the standard split keyboard communication code (which is AVR-specific) from being included, allowing a custom implementation to be used.
|
||||||
|
|
||||||
|
`CUSTOM_MATRIX`
|
||||||
|
|
||||||
|
Lets you replace the default matrix scanning routine with your own code. You will need to provide your own implementations of matrix_init() and matrix_scan().
|
||||||
|
|
||||||
|
`CUSTOM_DEBOUNCE`
|
||||||
|
|
||||||
|
Lets you replace the default key debouncing routine with your own code. You will need to provide your own implementation of debounce().
|
||||||
|
|
||||||
## Customizing Makefile Options on a Per-Keymap Basis
|
## Customizing Makefile Options on a Per-Keymap Basis
|
||||||
|
|
||||||
If your keymap directory has a file called `rules.mk` any options you set in that file will take precedence over other `rules.mk` options for your particular keyboard.
|
If your keymap directory has a file called `rules.mk` any options you set in that file will take precedence over other `rules.mk` options for your particular keyboard.
|
||||||
|
|||||||
+4
-4
@@ -77,8 +77,8 @@ This is a reference only. Each group of keys links to the page documenting their
|
|||||||
|`KC_F11` | |F11 |
|
|`KC_F11` | |F11 |
|
||||||
|`KC_F12` | |F12 |
|
|`KC_F12` | |F12 |
|
||||||
|`KC_PSCREEN` |`KC_PSCR` |Print Screen |
|
|`KC_PSCREEN` |`KC_PSCR` |Print Screen |
|
||||||
|`KC_SCROLLLOCK` |`KC_SLCK` |Scroll Lock |
|
|`KC_SCROLLLOCK` |`KC_SLCK`, `KC_BRMD`|Scroll Lock, Brightness Down (macOS) |
|
||||||
|`KC_PAUSE` |`KC_PAUS`, `KC_BRK` |Pause |
|
|`KC_PAUSE` |`KC_PAUS`, `KC_BRK`, `KC_BRMU`|Pause, Brightness Up (macOS) |
|
||||||
|`KC_INSERT` |`KC_INS` |Insert |
|
|`KC_INSERT` |`KC_INS` |Insert |
|
||||||
|`KC_HOME` | |Home |
|
|`KC_HOME` | |Home |
|
||||||
|`KC_PGUP` | |Page Up |
|
|`KC_PGUP` | |Page Up |
|
||||||
@@ -203,8 +203,8 @@ This is a reference only. Each group of keys links to the page documenting their
|
|||||||
|`KC_WWW_FAVORITES` |`KC_WFAV` |Browser Favorites (Windows) |
|
|`KC_WWW_FAVORITES` |`KC_WFAV` |Browser Favorites (Windows) |
|
||||||
|`KC_MEDIA_FAST_FORWARD`|`KC_MFFD` |Next Track (macOS) |
|
|`KC_MEDIA_FAST_FORWARD`|`KC_MFFD` |Next Track (macOS) |
|
||||||
|`KC_MEDIA_REWIND` |`KC_MRWD` |Previous Track (macOS) |
|
|`KC_MEDIA_REWIND` |`KC_MRWD` |Previous Track (macOS) |
|
||||||
|`KC_BRIGHTNESS_UP` |`KC_BRIU` |Brightness Up |
|
|`KC_BRIGHTNESS_UP` |`KC_BRIU` |Brightness Up (macOS: use `KC_BRMU`) |
|
||||||
|`KC_BRIGHTNESS_DOWN` |`KC_BRID` |Brightness Down |
|
|`KC_BRIGHTNESS_DOWN` |`KC_BRID` |Brightness Down (macOS: use `KC_BRMD`) |
|
||||||
|
|
||||||
## [Quantum Keycodes](quantum_keycodes.md#qmk-keycodes)
|
## [Quantum Keycodes](quantum_keycodes.md#qmk-keycodes)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "quantum.h"
|
||||||
|
|
||||||
|
#ifndef DEBOUNCING_DELAY
|
||||||
|
# define DEBOUNCING_DELAY 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Debouncing counters
|
||||||
|
typedef uint8_t debounce_counter_t;
|
||||||
|
#define DEBOUNCE_COUNTER_MODULO 250
|
||||||
|
#define DEBOUNCE_COUNTER_INACTIVE 251
|
||||||
|
|
||||||
|
static debounce_counter_t *debounce_counters;
|
||||||
|
|
||||||
|
void debounce_init(uint8_t num_rows)
|
||||||
|
{
|
||||||
|
debounce_counters = malloc(num_rows*MATRIX_COLS);
|
||||||
|
memset(debounce_counters, DEBOUNCE_COUNTER_INACTIVE, num_rows*MATRIX_COLS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_debounce_counters(uint8_t num_rows, uint8_t current_time)
|
||||||
|
{
|
||||||
|
for (uint8_t row = 0; row < num_rows; row++)
|
||||||
|
{
|
||||||
|
for (uint8_t col = 0; col < MATRIX_COLS; col++)
|
||||||
|
{
|
||||||
|
if (debounce_counters[row*MATRIX_COLS + col] != DEBOUNCE_COUNTER_INACTIVE)
|
||||||
|
{
|
||||||
|
if (TIMER_DIFF(current_time, debounce_counters[row*MATRIX_COLS + col], DEBOUNCE_COUNTER_MODULO) >= DEBOUNCING_DELAY) {
|
||||||
|
debounce_counters[row*MATRIX_COLS + col] = DEBOUNCE_COUNTER_INACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time)
|
||||||
|
{
|
||||||
|
for (uint8_t row = 0; row < num_rows; row++)
|
||||||
|
{
|
||||||
|
matrix_row_t delta = raw[row] ^ cooked[row];
|
||||||
|
|
||||||
|
for (uint8_t col = 0; col < MATRIX_COLS; col++)
|
||||||
|
{
|
||||||
|
if (debounce_counters[row*MATRIX_COLS + col] == DEBOUNCE_COUNTER_INACTIVE && (delta & (1<<col)))
|
||||||
|
{
|
||||||
|
debounce_counters[row*MATRIX_COLS + col] = current_time;
|
||||||
|
cooked[row] ^= (1 << col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed)
|
||||||
|
{
|
||||||
|
uint8_t current_time = timer_read() % DEBOUNCE_COUNTER_MODULO;
|
||||||
|
|
||||||
|
update_debounce_counters(num_rows, current_time);
|
||||||
|
transfer_matrix_values(raw, cooked, num_rows, current_time);
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
SRC += matrix_scanrate.c matrix.c
|
#SRC += matrix_scanrate.c matrix.c
|
||||||
|
SRC += debounce.c
|
||||||
|
|
||||||
# MCU name
|
# MCU name
|
||||||
MCU = atmega32u4
|
MCU = atmega32u4
|
||||||
@@ -37,7 +38,7 @@ F_USB = $(F_CPU)
|
|||||||
|
|
||||||
# Bootloader
|
# Bootloader
|
||||||
# This definition is optional, and if your keyboard supports multiple bootloaders of
|
# This definition is optional, and if your keyboard supports multiple bootloaders of
|
||||||
# different sizes, comment this out, and the correct address will be loaded
|
# different sizes, comment this out, and the correct address will be loaded
|
||||||
# automatically (+60). See bootloader.mk for all options.
|
# automatically (+60). See bootloader.mk for all options.
|
||||||
BOOTLOADER = caterina
|
BOOTLOADER = caterina
|
||||||
|
|
||||||
@@ -59,14 +60,15 @@ MIDI_ENABLE = no # MIDI controls
|
|||||||
AUDIO_ENABLE = yes # Audio output on port C6
|
AUDIO_ENABLE = yes # Audio output on port C6
|
||||||
UNICODE_ENABLE = no # Unicode
|
UNICODE_ENABLE = no # Unicode
|
||||||
BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID
|
BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID
|
||||||
RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight.
|
RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight.
|
||||||
SPLIT_KEYBOARD = yes # Use shared split_common code
|
SPLIT_KEYBOARD = yes # Use shared split_common code
|
||||||
SUBPROJECT_rev1 = yes
|
SUBPROJECT_rev1 = yes
|
||||||
|
|
||||||
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
|
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
|
||||||
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
|
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
|
||||||
|
|
||||||
CUSTOM_MATRIX = yes
|
CUSTOM_MATRIX = no
|
||||||
|
CUSTOM_DEBOUNCE = yes
|
||||||
|
|
||||||
LAYOUTS = split60
|
LAYOUTS = split60
|
||||||
|
|
||||||
|
|||||||
@@ -85,3 +85,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
//#define NO_ACTION_ONESHOT
|
//#define NO_ACTION_ONESHOT
|
||||||
//#define NO_ACTION_MACRO
|
//#define NO_ACTION_MACRO
|
||||||
//#define NO_ACTION_FUNCTION
|
//#define NO_ACTION_FUNCTION
|
||||||
|
|
||||||
|
#ifdef USE_Link_Time_Optimization
|
||||||
|
// LTO has issues with macros (action_get_macro) and "functions" (fn_actions),
|
||||||
|
// so just disable them
|
||||||
|
#define NO_ACTION_MACRO
|
||||||
|
#define NO_ACTION_FUNCTION
|
||||||
|
|
||||||
|
#define DISABLE_LEADER
|
||||||
|
#endif // USE_Link_Time_Optimization
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
BACKLIGHT_ENABLE = no
|
BACKLIGHT_ENABLE = no
|
||||||
AUDIO_ENABLE = yes
|
AUDIO_ENABLE = yes
|
||||||
RGBLIGHT_ENABLE = yes #Don't enable this along with I2C
|
RGBLIGHT_ENABLE = yes #Don't enable this along with I2C
|
||||||
|
|
||||||
|
EXTRAFLAGS += -flto -DUSE_Link_Time_Optimization
|
||||||
@@ -0,0 +1,939 @@
|
|||||||
|
#include QMK_KEYBOARD_H
|
||||||
|
|
||||||
|
// uint8_t keyboard_leds(void)
|
||||||
|
#include <tmk_core/protocol/arm_atsam/main_arm_atsam.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if ISSI3733_LED_COUNT == 119
|
||||||
|
# define KEY_LED_COUNT 87
|
||||||
|
#elif ISSI3733_LED_COUNT == 105
|
||||||
|
# define KEY_LED_COUNT 67
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define min(x, y) (x < y ? x : y)
|
||||||
|
|
||||||
|
|
||||||
|
extern issi3733_led_t *lede;
|
||||||
|
extern issi3733_led_t led_map[];
|
||||||
|
extern led_disp_t disp;
|
||||||
|
|
||||||
|
enum ctrl_keycodes {
|
||||||
|
L_BRI = SAFE_RANGE, //LED Brightness Increase
|
||||||
|
L_BRD, //LED Brightness Decrease
|
||||||
|
L_PTN, //LED Pattern Select Next
|
||||||
|
L_PTP, //LED Pattern Select Previous
|
||||||
|
L_PSI, //LED Pattern Speed Increase
|
||||||
|
L_PSD, //LED Pattern Speed Decrease
|
||||||
|
L_T_MD, //LED Toggle Mode
|
||||||
|
L_T_ONF, //LED Toggle On / Off
|
||||||
|
L_ON, //LED On
|
||||||
|
L_OFF, //LED Off
|
||||||
|
L_T_BR, //LED Toggle Breath Effect
|
||||||
|
L_T_PTD, //LED Toggle Scrolling Pattern Direction
|
||||||
|
U_T_AUTO, //USB Extra Port Toggle Auto Detect / Always Active
|
||||||
|
U_T_AGCR, //USB Toggle Automatic GCR control
|
||||||
|
DBG_TOG, //DEBUG Toggle On / Off
|
||||||
|
DBG_MTRX, //DEBUG Toggle Matrix Prints
|
||||||
|
DBG_KBD, //DEBUG Toggle Keyboard Prints
|
||||||
|
DBG_MOU, //DEBUG Toggle Mouse Prints
|
||||||
|
MD_BOOT, //Restart into bootloader after hold timeout
|
||||||
|
|
||||||
|
L_SP_PR, //LED Splash Pattern Select Previous
|
||||||
|
L_SP_NE, //LED Splash Pattern Select Next
|
||||||
|
|
||||||
|
L_SP_WD, //LED Splash Widen Wavefront width
|
||||||
|
L_SP_NW, //LED Splash Narrow Wavefront width
|
||||||
|
|
||||||
|
L_SP_FA, //LED Splash wave travel speed faster (shorter period)
|
||||||
|
L_SP_SL, //LED Splash wave travel speed slower (longer period)
|
||||||
|
|
||||||
|
L_CP_PR, //LED Color Pattern Select Previous
|
||||||
|
L_CP_NX, //LEB Color Pattern Select Next
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TG_NKRO MAGIC_TOGGLE_NKRO //Toggle 6KRO / NKRO mode
|
||||||
|
#define ______ KC_TRNS
|
||||||
|
|
||||||
|
keymap_config_t keymap_config;
|
||||||
|
|
||||||
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
[0] = LAYOUT(
|
||||||
|
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_PSCR, KC_SLCK, KC_PAUS, \
|
||||||
|
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_INS, KC_HOME, KC_PGUP, \
|
||||||
|
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, KC_END, KC_PGDN, \
|
||||||
|
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, \
|
||||||
|
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, \
|
||||||
|
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(1), KC_APP, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT \
|
||||||
|
),
|
||||||
|
[1] = LAYOUT(
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_MUTE, _______, _______, \
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_MPLY, KC_MSTP, KC_VOLU, \
|
||||||
|
L_T_BR, L_PSD, L_BRI, L_PSI, _______, _______, _______, U_T_AUTO,U_T_AGCR,_______, MO(2), _______, _______, _______, KC_MPRV, KC_MNXT, KC_VOLD, \
|
||||||
|
L_T_PTD, L_PTP, L_BRD, L_PTN, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
|
_______, L_T_MD, L_T_ONF, _______, _______, MD_BOOT, TG_NKRO, _______, _______, _______, _______, _______, _______, \
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \
|
||||||
|
),
|
||||||
|
[2] = LAYOUT(
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
|
L_CP_NX, L_SP_SL, L_SP_WD, L_SP_FA, _______, _______, L_CP_NX, L_SP_SL, L_SP_WD, L_SP_FA, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
|
L_CP_PR, L_SP_PR, L_SP_NW, L_SP_NE, _______, _______, L_CP_PR, L_SP_PR, L_SP_NW, L_SP_NE, _______, _______, _______, \
|
||||||
|
_______, _______, _______, _______, _______, _______, TG_NKRO, _______, _______, _______, _______, _______, _______, \
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \
|
||||||
|
),
|
||||||
|
/*
|
||||||
|
[X] = LAYOUT(
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
|
_______, _______, _______, _______, _______, _______, TG_NKRO, _______, _______, _______, _______, _______, _______, \
|
||||||
|
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \
|
||||||
|
),
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
// see: /tmk_core/common/keycode.h
|
||||||
|
uint8_t KEYCODE_TO_LED_ID[256];
|
||||||
|
uint8_t DISTANCE_MAP[KEY_LED_COUNT+1][KEY_LED_COUNT+1];
|
||||||
|
struct user_led_t {
|
||||||
|
uint8_t state;
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
} USER_LED[KEY_LED_COUNT] = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t PATTERN_INDEX;
|
||||||
|
uint8_t WAVE_FRONT_WIDTH;
|
||||||
|
uint16_t WAVE_PERIOD;
|
||||||
|
uint8_t COLOR_PATTERN_INDEX;
|
||||||
|
uint8_t TRAVEL_DISTANCE;
|
||||||
|
} USER_CONFIG = {
|
||||||
|
.PATTERN_INDEX = 1,
|
||||||
|
.WAVE_FRONT_WIDTH = 3,
|
||||||
|
.WAVE_PERIOD = 50,
|
||||||
|
.COLOR_PATTERN_INDEX = 0,
|
||||||
|
.TRAVEL_DISTANCE = 25,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t ktli(uint16_t keycode){
|
||||||
|
if(keycode < 256){
|
||||||
|
// the array is initialized in `matrix_init_user()`
|
||||||
|
return KEYCODE_TO_LED_ID[keycode];
|
||||||
|
}
|
||||||
|
switch(keycode){
|
||||||
|
// definition of MO(layer): quantum/quantum_keycodes.h: line 614
|
||||||
|
case MO(1): return 82;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Runs just one time when the keyboard initializes.
|
||||||
|
static void init_keycode_to_led_map(void){
|
||||||
|
uint16_t LED_MAP[MATRIX_ROWS][MATRIX_COLS] = LAYOUT(
|
||||||
|
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
|
||||||
|
20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,
|
||||||
|
36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
|
||||||
|
52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,
|
||||||
|
#if KEY_LED_COUNT >= 87
|
||||||
|
68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
uint16_t key = 0;
|
||||||
|
for(uint8_t y = 0; y < MATRIX_ROWS; ++y){
|
||||||
|
for(uint8_t x = 0; x < MATRIX_COLS; ++x){
|
||||||
|
key = keymaps[0][y][x];
|
||||||
|
if(key < 256){
|
||||||
|
KEYCODE_TO_LED_ID[key] = LED_MAP[y][x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// https://docs.qmk.fm/#/feature_terminal
|
||||||
|
#define KEY_POSITION_MAP_ROWS 6
|
||||||
|
#define KEY_POSITION_MAP_COLUMNS 20
|
||||||
|
static void init_distance_map(void){
|
||||||
|
uint16_t KEY_POSITION_MAP[KEY_POSITION_MAP_ROWS][KEY_POSITION_MAP_COLUMNS] = {
|
||||||
|
{ KC_NO, KC_ESC, KC_NO, KC_F1, KC_F2, KC_F3, KC_F4, KC_NO, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_NO, KC_PSCR, KC_SLCK, KC_PAUS, },
|
||||||
|
// { KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, },
|
||||||
|
{ KC_NO, KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_BSPC, KC_NO, KC_INS, KC_HOME, KC_PGUP, },
|
||||||
|
{ KC_NO, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_BSLS, KC_NO, KC_DEL, KC_END, KC_PGDN, },
|
||||||
|
{ KC_NO, KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_ENT, KC_ENT, KC_NO, KC_NO, KC_NO, KC_NO, },
|
||||||
|
{ KC_NO, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_RSFT, KC_RSFT, KC_RSFT, KC_NO, KC_NO, KC_UP, KC_NO, },
|
||||||
|
{ KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_SPC, KC_SPC, KC_SPC, KC_SPC, KC_SPC, KC_RALT, KC_NO, MO(1), KC_APP, KC_RCTL, KC_RCTL, KC_RCTL, KC_NO, KC_LEFT, KC_DOWN, KC_RIGHT, },
|
||||||
|
};
|
||||||
|
uint8_t columns = KEY_POSITION_MAP_COLUMNS;
|
||||||
|
uint8_t rows = KEY_POSITION_MAP_ROWS;
|
||||||
|
|
||||||
|
for(uint8_t y = 0; y < rows; ++y){
|
||||||
|
for(uint8_t x = 0; x < columns; ++x){
|
||||||
|
uint8_t id1 = ktli(KEY_POSITION_MAP[y][x]);
|
||||||
|
|
||||||
|
for(uint8_t j = y; j < rows; ++j){
|
||||||
|
for(uint8_t i = 0; i < columns; ++i){
|
||||||
|
uint8_t id2 = ktli(KEY_POSITION_MAP[j][i]);
|
||||||
|
|
||||||
|
if(id1 == id2) continue;
|
||||||
|
|
||||||
|
uint8_t dx = abs(i - x);
|
||||||
|
uint8_t dy = abs(j - y);
|
||||||
|
uint8_t dis = dx + dy;
|
||||||
|
if(i < x && j > y){
|
||||||
|
dis -= min(dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t _dis = DISTANCE_MAP[id1][id2];
|
||||||
|
if(_dis && _dis <= dis) continue;
|
||||||
|
DISTANCE_MAP[id1][id2] = dis;
|
||||||
|
DISTANCE_MAP[id2][id1] = dis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void matrix_init_user(void) {
|
||||||
|
init_keycode_to_led_map();
|
||||||
|
init_distance_map();
|
||||||
|
};
|
||||||
|
|
||||||
|
// /tmk_core/protocol/arm_atsam/led_matrix.c: line 244
|
||||||
|
uint8_t led_enabled;
|
||||||
|
float led_animation_speed;
|
||||||
|
uint8_t led_animation_direction;
|
||||||
|
uint8_t led_animation_orientation;
|
||||||
|
uint8_t led_animation_breathing;
|
||||||
|
uint8_t led_animation_breathe_cur;
|
||||||
|
uint8_t breathe_step;
|
||||||
|
uint8_t breathe_dir;
|
||||||
|
uint64_t led_next_run;
|
||||||
|
|
||||||
|
uint8_t led_animation_id;
|
||||||
|
uint8_t led_lighting_mode;
|
||||||
|
|
||||||
|
issi3733_led_t *led_cur;
|
||||||
|
uint8_t led_per_run;
|
||||||
|
float breathe_mult;
|
||||||
|
|
||||||
|
// overrided /tmk_core/protocol/arm_atsam/led_matrix.c: line 484
|
||||||
|
void rgb_matrix_init_user(void){
|
||||||
|
led_animation_speed = ANIMATION_SPEED_STEP * 15;
|
||||||
|
led_per_run = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
// overrided /tmk_core/protocol/arm_atsam/led_matrix.c: line 262
|
||||||
|
void led_matrix_run(void)
|
||||||
|
{
|
||||||
|
float ro;
|
||||||
|
float go;
|
||||||
|
float bo;
|
||||||
|
float po;
|
||||||
|
uint8_t led_this_run = 0;
|
||||||
|
led_setup_t *f = (led_setup_t*)led_setups[led_animation_id];
|
||||||
|
|
||||||
|
if (led_cur == 0) //Denotes start of new processing cycle in the case of chunked processing
|
||||||
|
{
|
||||||
|
led_cur = led_map;
|
||||||
|
|
||||||
|
disp.frame += 1;
|
||||||
|
|
||||||
|
breathe_mult = 1;
|
||||||
|
|
||||||
|
if (led_animation_breathing)
|
||||||
|
{
|
||||||
|
led_animation_breathe_cur += breathe_step * breathe_dir;
|
||||||
|
|
||||||
|
if (led_animation_breathe_cur >= BREATHE_MAX_STEP)
|
||||||
|
breathe_dir = -1;
|
||||||
|
else if (led_animation_breathe_cur <= BREATHE_MIN_STEP)
|
||||||
|
breathe_dir = 1;
|
||||||
|
|
||||||
|
//Brightness curve created for 256 steps, 0 - ~98%
|
||||||
|
breathe_mult = 0.000015 * led_animation_breathe_cur * led_animation_breathe_cur;
|
||||||
|
if (breathe_mult > 1) breathe_mult = 1;
|
||||||
|
else if (breathe_mult < 0) breathe_mult = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t fcur = 0;
|
||||||
|
uint8_t fmax = 0;
|
||||||
|
|
||||||
|
//Frames setup
|
||||||
|
while (f[fcur].end != 1)
|
||||||
|
{
|
||||||
|
fcur++; //Count frames
|
||||||
|
}
|
||||||
|
|
||||||
|
fmax = fcur; //Store total frames count
|
||||||
|
|
||||||
|
struct user_led_t user_led_cur;
|
||||||
|
while (led_cur < lede && led_this_run < led_per_run)
|
||||||
|
{
|
||||||
|
ro = 0;
|
||||||
|
go = 0;
|
||||||
|
bo = 0;
|
||||||
|
|
||||||
|
uint8_t led_index = led_cur - led_map; // only this part differs from the original function.
|
||||||
|
if(led_index < KEY_LED_COUNT){ //
|
||||||
|
user_led_cur = USER_LED[led_index]; // `struct user_led_t USER_LED[]` is stored globally.
|
||||||
|
} //
|
||||||
|
//
|
||||||
|
if(led_index < KEY_LED_COUNT && user_led_cur.state){ // `user_led_cur` is just for convenience
|
||||||
|
ro = user_led_cur.r; //
|
||||||
|
go = user_led_cur.g; //
|
||||||
|
bo = user_led_cur.b; //
|
||||||
|
} //
|
||||||
|
else if (led_lighting_mode == LED_MODE_KEYS_ONLY && led_cur->scan == 255)
|
||||||
|
{
|
||||||
|
//Do not act on this LED
|
||||||
|
}
|
||||||
|
else if (led_lighting_mode == LED_MODE_NON_KEYS_ONLY && led_cur->scan != 255)
|
||||||
|
{
|
||||||
|
//Do not act on this LED
|
||||||
|
}
|
||||||
|
else if (led_lighting_mode == LED_MODE_INDICATORS_ONLY)
|
||||||
|
{
|
||||||
|
//Do not act on this LED (Only show indicators)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Act on LED
|
||||||
|
for (fcur = 0; fcur < fmax; fcur++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (led_animation_orientation)
|
||||||
|
{
|
||||||
|
po = led_cur->py;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
po = led_cur->px;
|
||||||
|
}
|
||||||
|
|
||||||
|
float pomod;
|
||||||
|
pomod = (float)(disp.frame % (uint32_t)(1000.0f / led_animation_speed)) / 10.0f * led_animation_speed;
|
||||||
|
|
||||||
|
//Add in any moving effects
|
||||||
|
if ((!led_animation_direction && f[fcur].ef & EF_SCR_R) || (led_animation_direction && (f[fcur].ef & EF_SCR_L)))
|
||||||
|
{
|
||||||
|
pomod *= 100.0f;
|
||||||
|
pomod = (uint32_t)pomod % 10000;
|
||||||
|
pomod /= 100.0f;
|
||||||
|
|
||||||
|
po -= pomod;
|
||||||
|
|
||||||
|
if (po > 100) po -= 100;
|
||||||
|
else if (po < 0) po += 100;
|
||||||
|
}
|
||||||
|
else if ((!led_animation_direction && f[fcur].ef & EF_SCR_L) || (led_animation_direction && (f[fcur].ef & EF_SCR_R)))
|
||||||
|
{
|
||||||
|
pomod *= 100.0f;
|
||||||
|
pomod = (uint32_t)pomod % 10000;
|
||||||
|
pomod /= 100.0f;
|
||||||
|
po += pomod;
|
||||||
|
|
||||||
|
if (po > 100) po -= 100;
|
||||||
|
else if (po < 0) po += 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if LED's po is in current frame
|
||||||
|
if (po < f[fcur].hs) continue;
|
||||||
|
if (po > f[fcur].he) continue;
|
||||||
|
//note: < 0 or > 100 continue
|
||||||
|
|
||||||
|
//Calculate the po within the start-stop percentage for color blending
|
||||||
|
po = (po - f[fcur].hs) / (f[fcur].he - f[fcur].hs);
|
||||||
|
|
||||||
|
//Add in any color effects
|
||||||
|
if (f[fcur].ef & EF_OVER)
|
||||||
|
{
|
||||||
|
ro = (po * (f[fcur].re - f[fcur].rs)) + f[fcur].rs;// + 0.5;
|
||||||
|
go = (po * (f[fcur].ge - f[fcur].gs)) + f[fcur].gs;// + 0.5;
|
||||||
|
bo = (po * (f[fcur].be - f[fcur].bs)) + f[fcur].bs;// + 0.5;
|
||||||
|
}
|
||||||
|
else if (f[fcur].ef & EF_SUBTRACT)
|
||||||
|
{
|
||||||
|
ro -= (po * (f[fcur].re - f[fcur].rs)) + f[fcur].rs;// + 0.5;
|
||||||
|
go -= (po * (f[fcur].ge - f[fcur].gs)) + f[fcur].gs;// + 0.5;
|
||||||
|
bo -= (po * (f[fcur].be - f[fcur].bs)) + f[fcur].bs;// + 0.5;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ro += (po * (f[fcur].re - f[fcur].rs)) + f[fcur].rs;// + 0.5;
|
||||||
|
go += (po * (f[fcur].ge - f[fcur].gs)) + f[fcur].gs;// + 0.5;
|
||||||
|
bo += (po * (f[fcur].be - f[fcur].bs)) + f[fcur].bs;// + 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Clamp values 0-255
|
||||||
|
if (ro > 255) ro = 255; else if (ro < 0) ro = 0;
|
||||||
|
if (go > 255) go = 255; else if (go < 0) go = 0;
|
||||||
|
if (bo > 255) bo = 255; else if (bo < 0) bo = 0;
|
||||||
|
|
||||||
|
if (led_animation_breathing)
|
||||||
|
{
|
||||||
|
ro *= breathe_mult;
|
||||||
|
go *= breathe_mult;
|
||||||
|
bo *= breathe_mult;
|
||||||
|
}
|
||||||
|
|
||||||
|
*led_cur->rgb.r = (uint8_t)ro;
|
||||||
|
*led_cur->rgb.g = (uint8_t)go;
|
||||||
|
*led_cur->rgb.b = (uint8_t)bo;
|
||||||
|
|
||||||
|
#ifdef USB_LED_INDICATOR_ENABLE
|
||||||
|
if (keyboard_leds())
|
||||||
|
{
|
||||||
|
uint8_t kbled = keyboard_leds();
|
||||||
|
if (
|
||||||
|
#if USB_LED_NUM_LOCK_SCANCODE != 255
|
||||||
|
(led_cur->scan == USB_LED_NUM_LOCK_SCANCODE && kbled & (1<<USB_LED_NUM_LOCK)) ||
|
||||||
|
#endif //NUM LOCK
|
||||||
|
#if USB_LED_CAPS_LOCK_SCANCODE != 255
|
||||||
|
(led_cur->scan == USB_LED_CAPS_LOCK_SCANCODE && kbled & (1<<USB_LED_CAPS_LOCK)) ||
|
||||||
|
#endif //CAPS LOCK
|
||||||
|
#if USB_LED_SCROLL_LOCK_SCANCODE != 255
|
||||||
|
(led_cur->scan == USB_LED_SCROLL_LOCK_SCANCODE && kbled & (1<<USB_LED_SCROLL_LOCK)) ||
|
||||||
|
#endif //SCROLL LOCK
|
||||||
|
#if USB_LED_COMPOSE_SCANCODE != 255
|
||||||
|
(led_cur->scan == USB_LED_COMPOSE_SCANCODE && kbled & (1<<USB_LED_COMPOSE)) ||
|
||||||
|
#endif //COMPOSE
|
||||||
|
#if USB_LED_KANA_SCANCODE != 255
|
||||||
|
(led_cur->scan == USB_LED_KANA_SCANCODE && kbled & (1<<USB_LED_KANA)) ||
|
||||||
|
#endif //KANA
|
||||||
|
(0))
|
||||||
|
{
|
||||||
|
if (*led_cur->rgb.r > 127) *led_cur->rgb.r = 0;
|
||||||
|
else *led_cur->rgb.r = 255;
|
||||||
|
if (*led_cur->rgb.g > 127) *led_cur->rgb.g = 0;
|
||||||
|
else *led_cur->rgb.g = 255;
|
||||||
|
if (*led_cur->rgb.b > 127) *led_cur->rgb.b = 0;
|
||||||
|
else *led_cur->rgb.b = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //USB_LED_INDICATOR_ENABLE
|
||||||
|
|
||||||
|
led_cur++;
|
||||||
|
led_this_run++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define KEY_STROKES_LENGTH 20
|
||||||
|
struct {
|
||||||
|
bool alive;
|
||||||
|
uint8_t led_id;
|
||||||
|
uint32_t time;
|
||||||
|
} KEY_STROKES[KEY_STROKES_LENGTH] = {{}};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void set_led_rgb(uint8_t led_id, uint8_t r, uint8_t g, uint8_t b){
|
||||||
|
issi3733_led_t *target_led = (led_map + led_id);
|
||||||
|
*target_led->rgb.r = r;
|
||||||
|
*target_led->rgb.g = g;
|
||||||
|
*target_led->rgb.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t DISTANCE_FROM_LAST_KEYSTROKE[KEY_LED_COUNT+1];
|
||||||
|
void calculate_keystroke_distance(void){
|
||||||
|
bool alive;
|
||||||
|
uint8_t led_id, period_passed;
|
||||||
|
uint32_t t;
|
||||||
|
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i <= KEY_LED_COUNT; ++i){
|
||||||
|
DISTANCE_FROM_LAST_KEYSTROKE[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < KEY_STROKES_LENGTH; ++i){
|
||||||
|
if(KEY_STROKES[i].alive){
|
||||||
|
t = timer_elapsed32(KEY_STROKES[i].time);
|
||||||
|
alive = 0;
|
||||||
|
led_id = KEY_STROKES[i].led_id;
|
||||||
|
period_passed = t / USER_CONFIG.WAVE_PERIOD;
|
||||||
|
|
||||||
|
uint8_t delta_period;
|
||||||
|
for(uint8_t j = 1; j <= KEY_LED_COUNT; ++j){
|
||||||
|
delta_period = period_passed - DISTANCE_MAP[led_id][j];
|
||||||
|
if(( delta_period < USER_CONFIG.WAVE_FRONT_WIDTH) && (
|
||||||
|
DISTANCE_MAP[led_id][j] <= USER_CONFIG.TRAVEL_DISTANCE
|
||||||
|
)){
|
||||||
|
switch(USER_CONFIG.PATTERN_INDEX){
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
DISTANCE_FROM_LAST_KEYSTROKE[j] += delta_period;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DISTANCE_FROM_LAST_KEYSTROKE[j] = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
alive = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KEY_STROKES[i].alive = alive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COLOR_PATTERN_RGB_COUNT 18
|
||||||
|
static uint8_t COLOR_PATTERNS[][COLOR_PATTERN_RGB_COUNT][3] = {
|
||||||
|
{ // default rainbow color
|
||||||
|
{255, 0, 0}, {255, 0, 0}, {255, 127, 0},
|
||||||
|
{255, 127, 0}, {255, 255, 0}, {255, 255, 0},
|
||||||
|
{120, 255, 0}, {120, 255, 0}, { 0, 255, 0},
|
||||||
|
{ 0, 255, 0}, { 0, 255, 120}, { 0, 255, 120},
|
||||||
|
{ 0, 0, 255}, { 0, 0, 255}, { 75, 0, 130},
|
||||||
|
{ 75, 0, 130}, { 43, 0, 130}, { 43, 0, 130},
|
||||||
|
}, { // light rainbow color
|
||||||
|
{248, 12, 18}, {238, 17, 0}, {255, 51, 17},
|
||||||
|
{255, 68, 32}, {255, 102, 68}, {255, 153, 51},
|
||||||
|
{254, 174, 45}, {204, 187, 51}, {208, 195, 16},
|
||||||
|
{170, 204, 34}, {105, 208, 37}, { 34, 204, 170},
|
||||||
|
{ 18, 189, 185}, { 17, 170, 187}, { 68, 68, 221},
|
||||||
|
{ 51, 17, 187}, { 59, 12, 189}, { 68, 34, 153},
|
||||||
|
}, { // white flat
|
||||||
|
{255, 255, 255}, {255, 255, 255}, {255, 255, 255},
|
||||||
|
{255, 255, 255}, {255, 255, 255}, {255, 255, 255},
|
||||||
|
{255, 255, 255}, {255, 255, 255}, {255, 255, 255},
|
||||||
|
{255, 255, 255}, {255, 255, 255}, {255, 255, 255},
|
||||||
|
{255, 255, 255}, {255, 255, 255}, {255, 255, 255},
|
||||||
|
{255, 255, 255}, {255, 255, 255}, {255, 255, 255},
|
||||||
|
}, { // white fade, cos curve
|
||||||
|
{255, 255, 255}, {255, 255, 255}, {252, 252, 252},
|
||||||
|
{247, 247, 247}, {240, 240, 240}, {232, 232, 232},
|
||||||
|
{221, 221, 221}, {209, 209, 209}, {196, 196, 196},
|
||||||
|
{181, 181, 181}, {164, 164, 164}, {147, 147, 147},
|
||||||
|
{128, 128, 128}, {108, 108, 108}, { 88, 88, 88},
|
||||||
|
{ 66, 66, 66}, { 45, 45, 45}, { 23, 23, 23},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
static const uint8_t COLOR_PATTERNS_COUNT = (
|
||||||
|
sizeof(COLOR_PATTERNS) / sizeof(COLOR_PATTERNS[0]));
|
||||||
|
|
||||||
|
void set_user_led_rgb(uint8_t i, uint8_t r, uint8_t g, uint8_t b){
|
||||||
|
USER_LED[i-1].state = 1;
|
||||||
|
USER_LED[i-1].r = r;
|
||||||
|
USER_LED[i-1].g = g;
|
||||||
|
USER_LED[i-1].b = b;
|
||||||
|
}
|
||||||
|
void unset_user_led_rgb(uint8_t i){
|
||||||
|
USER_LED[i-1].state = 0;
|
||||||
|
}
|
||||||
|
void set_indicator_led_rgb(uint8_t i,
|
||||||
|
uint8_t layer, uint8_t r, uint8_t g, uint8_t b){
|
||||||
|
USER_LED[i-1].state |= 1 << layer;
|
||||||
|
USER_LED[i-1].r = r;
|
||||||
|
USER_LED[i-1].g = g;
|
||||||
|
USER_LED[i-1].b = b;
|
||||||
|
}
|
||||||
|
void unset_indicator_led_rgb(uint8_t i, uint8_t layer){
|
||||||
|
USER_LED[i-1].state &= ~(1 << layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh_pattern_indicators(void){
|
||||||
|
static uint8_t GRV_123456[] = {
|
||||||
|
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6,
|
||||||
|
};
|
||||||
|
|
||||||
|
if(layer_state >= 0x04){
|
||||||
|
for(uint8_t i = 0; i < 7; ++i){
|
||||||
|
if(i == USER_CONFIG.PATTERN_INDEX){
|
||||||
|
set_indicator_led_rgb(ktli(GRV_123456[i]), 2, 0, 0, 255);
|
||||||
|
} else{
|
||||||
|
set_indicator_led_rgb(ktli(GRV_123456[i]), 2, 0, 255, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
for(uint8_t i = 0; i < 7; ++i){
|
||||||
|
unset_indicator_led_rgb(ktli(GRV_123456[i]), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void refresh_color_pattern_indicators(void){
|
||||||
|
static uint8_t ZXCVBNM_COMM_DOT[] = {
|
||||||
|
KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT,
|
||||||
|
};
|
||||||
|
|
||||||
|
if(layer_state >= 0x04){
|
||||||
|
uint8_t (*c)[3] = &COLOR_PATTERNS[USER_CONFIG.COLOR_PATTERN_INDEX][0];
|
||||||
|
for(uint8_t i = 0; i < 9; ++i){
|
||||||
|
set_indicator_led_rgb(ktli(ZXCVBNM_COMM_DOT[i]),
|
||||||
|
2, c[i][0], c[i][1], c[i][2]);
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
for(uint8_t i = 0; i < 9; ++i){
|
||||||
|
unset_indicator_led_rgb(ktli(ZXCVBNM_COMM_DOT[i]), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs constantly in the background, in a loop.
|
||||||
|
void matrix_scan_user(void) {
|
||||||
|
static uint32_t scan_timer = 0;
|
||||||
|
static uint8_t last_layer = 0;
|
||||||
|
|
||||||
|
uint8_t layer = 0;
|
||||||
|
if(layer_state >= 0x04){
|
||||||
|
layer = 2;
|
||||||
|
} else if(layer_state >= 0x02){
|
||||||
|
layer = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
calculate_keystroke_distance();
|
||||||
|
|
||||||
|
|
||||||
|
#define USE_PATTERN 0
|
||||||
|
#define BLACK_RGB 1
|
||||||
|
#define COLOR_RGB 2
|
||||||
|
uint8_t ci; // color index
|
||||||
|
uint8_t *rgb;
|
||||||
|
uint8_t handle_type;
|
||||||
|
uint8_t distance;
|
||||||
|
for(uint8_t i = 1; i <= KEY_LED_COUNT; ++i){
|
||||||
|
if(USER_LED[i-1].state >= 2) continue;
|
||||||
|
|
||||||
|
handle_type = USE_PATTERN;
|
||||||
|
distance = DISTANCE_FROM_LAST_KEYSTROKE[i];
|
||||||
|
|
||||||
|
switch(USER_CONFIG.PATTERN_INDEX){
|
||||||
|
case 0: handle_type = USE_PATTERN; break;
|
||||||
|
case 1: handle_type = distance ? USE_PATTERN : BLACK_RGB; break;
|
||||||
|
case 2: handle_type = distance ? BLACK_RGB : USE_PATTERN; break;
|
||||||
|
case 3: handle_type = distance ? COLOR_RGB : BLACK_RGB; break;
|
||||||
|
case 4: handle_type = distance ? COLOR_RGB : USE_PATTERN; break;
|
||||||
|
case 5:
|
||||||
|
case 6: handle_type = distance ? COLOR_RGB : USE_PATTERN; break;
|
||||||
|
}
|
||||||
|
switch(handle_type){
|
||||||
|
case USE_PATTERN: unset_user_led_rgb(i); break;
|
||||||
|
case BLACK_RGB: set_user_led_rgb(i, 0, 0, 0); break;
|
||||||
|
case COLOR_RGB:
|
||||||
|
ci = (DISTANCE_FROM_LAST_KEYSTROKE[i] * COLOR_PATTERN_RGB_COUNT /
|
||||||
|
USER_CONFIG.WAVE_FRONT_WIDTH) % COLOR_PATTERN_RGB_COUNT;
|
||||||
|
rgb = &COLOR_PATTERNS[USER_CONFIG.COLOR_PATTERN_INDEX][ci][0];
|
||||||
|
|
||||||
|
set_user_led_rgb(i, rgb[0], rgb[1], rgb[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// could be moved to process_record_user()
|
||||||
|
if(layer != last_layer){
|
||||||
|
|
||||||
|
static uint8_t QWEASDP[] = {
|
||||||
|
KC_Q, KC_W, KC_E, KC_A, KC_S, KC_D, KC_P,
|
||||||
|
};
|
||||||
|
static uint8_t YUIOHJKL[] = {
|
||||||
|
KC_Y, KC_U, KC_I, KC_O, KC_H, KC_J, KC_K, KC_L,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch(last_layer){
|
||||||
|
case 1:
|
||||||
|
for(uint8_t i = 0; i < 7; ++i){
|
||||||
|
unset_indicator_led_rgb(ktli(QWEASDP[i]), 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for(uint8_t i = 0; i < 6; ++i){
|
||||||
|
unset_indicator_led_rgb(ktli(QWEASDP[i]), 2);
|
||||||
|
}
|
||||||
|
for(uint8_t i = 0; i < 8; ++i){
|
||||||
|
unset_indicator_led_rgb(ktli(YUIOHJKL[i]), 2);
|
||||||
|
}
|
||||||
|
unset_indicator_led_rgb(ktli(KC_TAB), 2);
|
||||||
|
unset_indicator_led_rgb(ktli(KC_CAPS), 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch(layer){
|
||||||
|
case 1:
|
||||||
|
for(uint8_t i = 0; i < 7; ++i){
|
||||||
|
set_indicator_led_rgb(ktli(QWEASDP[i]), 1, 255, 0, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for(uint8_t i = 0; i < 6; ++i){
|
||||||
|
set_indicator_led_rgb(ktli(QWEASDP[i]), 2, 0, 255, 0);
|
||||||
|
}
|
||||||
|
for(uint8_t i = 0; i < 8; ++i){
|
||||||
|
set_indicator_led_rgb(ktli(YUIOHJKL[i]), 2, 0, 255, 0);
|
||||||
|
}
|
||||||
|
set_indicator_led_rgb(ktli(KC_TAB), 2, 0, 255, 0);
|
||||||
|
set_indicator_led_rgb(ktli(KC_CAPS), 2, 0, 255, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh_pattern_indicators();
|
||||||
|
refresh_color_pattern_indicators();
|
||||||
|
last_layer = layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch(layer){
|
||||||
|
case 0:
|
||||||
|
if(timer_elapsed32(scan_timer) > 2000){
|
||||||
|
scan_timer = timer_read32();
|
||||||
|
} else if(timer_elapsed32(scan_timer) > 1000){
|
||||||
|
// set_user_led_rgb(ktli(KC_F5), 255, 255, 255);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MODS_SHIFT (keyboard_report->mods & MOD_BIT(KC_LSHIFT) || keyboard_report->mods & MOD_BIT(KC_RSHIFT))
|
||||||
|
#define MODS_CTRL (keyboard_report->mods & MOD_BIT(KC_LCTL) || keyboard_report->mods & MOD_BIT(KC_RCTRL))
|
||||||
|
#define MODS_ALT (keyboard_report->mods & MOD_BIT(KC_LALT) || keyboard_report->mods & MOD_BIT(KC_RALT))
|
||||||
|
|
||||||
|
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
static uint32_t key_timer;
|
||||||
|
|
||||||
|
|
||||||
|
switch (keycode) {
|
||||||
|
case L_BRI:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
if (LED_GCR_STEP > LED_GCR_MAX - gcr_desired) gcr_desired = LED_GCR_MAX;
|
||||||
|
else gcr_desired += LED_GCR_STEP;
|
||||||
|
if (led_animation_breathing) gcr_breathe = gcr_desired;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_BRD:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
if (LED_GCR_STEP > gcr_desired) gcr_desired = 0;
|
||||||
|
else gcr_desired -= LED_GCR_STEP;
|
||||||
|
if (led_animation_breathing) gcr_breathe = gcr_desired;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_PTN:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
if (led_animation_id == led_setups_count - 1) led_animation_id = 0;
|
||||||
|
else led_animation_id++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_PTP:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
if (led_animation_id == 0) led_animation_id = led_setups_count - 1;
|
||||||
|
else led_animation_id--;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_PSI:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
led_animation_speed += ANIMATION_SPEED_STEP;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_PSD:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
led_animation_speed -= ANIMATION_SPEED_STEP;
|
||||||
|
if (led_animation_speed < 0) led_animation_speed = 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_T_MD:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
led_lighting_mode++;
|
||||||
|
if (led_lighting_mode > LED_MODE_MAX_INDEX) led_lighting_mode = LED_MODE_NORMAL;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_T_ONF:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
led_enabled = !led_enabled;
|
||||||
|
I2C3733_Control_Set(led_enabled);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_ON:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
led_enabled = 1;
|
||||||
|
I2C3733_Control_Set(led_enabled);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_OFF:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
led_enabled = 0;
|
||||||
|
I2C3733_Control_Set(led_enabled);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_T_BR:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
led_animation_breathing = !led_animation_breathing;
|
||||||
|
if (led_animation_breathing) {
|
||||||
|
gcr_breathe = gcr_desired;
|
||||||
|
led_animation_breathe_cur = BREATHE_MIN_STEP;
|
||||||
|
breathe_dir = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_T_PTD:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
led_animation_direction = !led_animation_direction;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case U_T_AUTO:
|
||||||
|
if (record->event.pressed && MODS_SHIFT && MODS_CTRL) {
|
||||||
|
TOGGLE_FLAG_AND_PRINT(usb_extra_manual, "USB extra port manual mode");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case U_T_AGCR:
|
||||||
|
if (record->event.pressed && MODS_SHIFT && MODS_CTRL) {
|
||||||
|
TOGGLE_FLAG_AND_PRINT(usb_gcr_auto, "USB GCR auto mode");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case DBG_TOG:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
TOGGLE_FLAG_AND_PRINT(debug_enable, "Debug mode");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case DBG_MTRX:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
TOGGLE_FLAG_AND_PRINT(debug_matrix, "Debug matrix");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case DBG_KBD:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
TOGGLE_FLAG_AND_PRINT(debug_keyboard, "Debug keyboard");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case DBG_MOU:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
TOGGLE_FLAG_AND_PRINT(debug_mouse, "Debug mouse");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case MD_BOOT:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
key_timer = timer_read32();
|
||||||
|
} else {
|
||||||
|
if (timer_elapsed32(key_timer) >= 500) {
|
||||||
|
reset_keyboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case L_SP_PR: // previous dripple pattern
|
||||||
|
case L_SP_NE: // next dripple pattern
|
||||||
|
if (record->event.pressed) {
|
||||||
|
#define PATTERN_COUNT 7
|
||||||
|
uint8_t incre = keycode == L_SP_PR ? PATTERN_COUNT-1 : 1;
|
||||||
|
USER_CONFIG.PATTERN_INDEX += incre;
|
||||||
|
USER_CONFIG.PATTERN_INDEX %= PATTERN_COUNT;
|
||||||
|
|
||||||
|
if(USER_CONFIG.PATTERN_INDEX <= 4){
|
||||||
|
USER_CONFIG.TRAVEL_DISTANCE = 25;
|
||||||
|
USER_CONFIG.COLOR_PATTERN_INDEX = 0;
|
||||||
|
USER_CONFIG.WAVE_PERIOD = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(USER_CONFIG.PATTERN_INDEX){
|
||||||
|
case 0: // None
|
||||||
|
break;
|
||||||
|
case 1: // background off, wave on
|
||||||
|
USER_CONFIG.WAVE_FRONT_WIDTH = 2;
|
||||||
|
break;
|
||||||
|
case 2: // background on, wave off
|
||||||
|
USER_CONFIG.WAVE_FRONT_WIDTH = 5;
|
||||||
|
break;
|
||||||
|
case 3: // background off, rainbow wave
|
||||||
|
USER_CONFIG.WAVE_FRONT_WIDTH = 10;
|
||||||
|
break;
|
||||||
|
case 4: // background on, rainbow wave
|
||||||
|
USER_CONFIG.WAVE_FRONT_WIDTH = 10;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
USER_CONFIG.WAVE_FRONT_WIDTH = 10;
|
||||||
|
|
||||||
|
USER_CONFIG.COLOR_PATTERN_INDEX = 2;
|
||||||
|
USER_CONFIG.TRAVEL_DISTANCE = 0;
|
||||||
|
USER_CONFIG.WAVE_PERIOD = 100;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
USER_CONFIG.WAVE_FRONT_WIDTH = 25;
|
||||||
|
|
||||||
|
USER_CONFIG.COLOR_PATTERN_INDEX = 3;
|
||||||
|
USER_CONFIG.TRAVEL_DISTANCE = 2;
|
||||||
|
USER_CONFIG.WAVE_PERIOD = 10;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove effect after changing pattern
|
||||||
|
for(int i = 0; i < KEY_STROKES_LENGTH; ++i){
|
||||||
|
KEY_STROKES[i].alive = 0;
|
||||||
|
}
|
||||||
|
refresh_pattern_indicators();
|
||||||
|
refresh_color_pattern_indicators();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_SP_WD:
|
||||||
|
case L_SP_NW:
|
||||||
|
if(record->event.pressed){
|
||||||
|
short incre = keycode == L_SP_WD ? 1 : -1;
|
||||||
|
USER_CONFIG.WAVE_FRONT_WIDTH += incre;
|
||||||
|
if(USER_CONFIG.WAVE_FRONT_WIDTH < 1){
|
||||||
|
USER_CONFIG.WAVE_FRONT_WIDTH = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case L_SP_FA:
|
||||||
|
case L_SP_SL:
|
||||||
|
if(record->event.pressed){
|
||||||
|
short incre = keycode == L_SP_FA ? -1 : 1;
|
||||||
|
|
||||||
|
USER_CONFIG.WAVE_PERIOD += 10 * incre;
|
||||||
|
if(USER_CONFIG.WAVE_PERIOD < 10){
|
||||||
|
USER_CONFIG.WAVE_PERIOD = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
// these are the keys not in range 0x04 - 0x52
|
||||||
|
case L_CP_PR:
|
||||||
|
case L_CP_NX:
|
||||||
|
if(record->event.pressed){
|
||||||
|
uint8_t incre = keycode == L_CP_PR ? COLOR_PATTERNS_COUNT - 1 : 1;
|
||||||
|
USER_CONFIG.COLOR_PATTERN_INDEX += incre;
|
||||||
|
USER_CONFIG.COLOR_PATTERN_INDEX %= COLOR_PATTERNS_COUNT;
|
||||||
|
refresh_color_pattern_indicators();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
if (record->event.pressed){
|
||||||
|
uint8_t led_id = ktli(keycode);
|
||||||
|
if(led_id){
|
||||||
|
for(int i = 0; i < KEY_STROKES_LENGTH; ++i){
|
||||||
|
if(!KEY_STROKES[i].alive){
|
||||||
|
KEY_STROKES[i].alive = 1;
|
||||||
|
KEY_STROKES[i].led_id = led_id;
|
||||||
|
KEY_STROKES[i].time = timer_read32();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true; //Process all other keycodes normally
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,8 +44,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
*/
|
*/
|
||||||
// #define MATRIX_ROW_PINS { D0, D5 }
|
// #define MATRIX_ROW_PINS { D0, D5 }
|
||||||
// #define MATRIX_COL_PINS { F1, F0, B0 }
|
// #define MATRIX_COL_PINS { F1, F0, B0 }
|
||||||
#define NO_PIN 0xFF
|
#define DIRECT_PINS { \
|
||||||
#define MATRIX_ROW_COL_PINS { \
|
|
||||||
{ F1, E6, B0, B2, B3 }, \
|
{ F1, E6, B0, B2, B3 }, \
|
||||||
{ F5, F0, B1, B7, D2 }, \
|
{ F5, F0, B1, B7, D2 }, \
|
||||||
{ F6, F7, C7, D5, D3 }, \
|
{ F6, F7, C7, D5, D3 }, \
|
||||||
@@ -54,7 +53,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define UNUSED_PINS
|
#define UNUSED_PINS
|
||||||
|
|
||||||
/* COL2ROW, ROW2COL, or CUSTOM_MATRIX */
|
/* COL2ROW, ROW2COL, or CUSTOM_MATRIX */
|
||||||
#define DIODE_DIRECTION CUSTOM_MATRIX
|
//#define DIODE_DIRECTION CUSTOM_MATRIX
|
||||||
|
|
||||||
// #define BACKLIGHT_PIN B7
|
// #define BACKLIGHT_PIN B7
|
||||||
// #define BACKLIGHT_BREATHING
|
// #define BACKLIGHT_BREATHING
|
||||||
|
|||||||
@@ -1,641 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* scan matrix
|
|
||||||
*/
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include "wait.h"
|
|
||||||
#include "print.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "matrix.h"
|
|
||||||
#include "split_util.h"
|
|
||||||
#include "pro_micro.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include "split_flags.h"
|
|
||||||
|
|
||||||
#ifdef BACKLIGHT_ENABLE
|
|
||||||
# include "backlight.h"
|
|
||||||
extern backlight_config_t backlight_config;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
# include "i2c.h"
|
|
||||||
#else // USE_SERIAL
|
|
||||||
# include "serial.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBOUNCING_DELAY
|
|
||||||
# define DEBOUNCING_DELAY 5
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (DEBOUNCING_DELAY > 0)
|
|
||||||
static uint16_t debouncing_time;
|
|
||||||
static bool debouncing = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
|
|
||||||
#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)
|
|
||||||
#else
|
|
||||||
# error "Currently only supports 8 COLS"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else // USE_SERIAL
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
#endif
|
|
||||||
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
|
|
||||||
|
|
||||||
#define ERROR_DISCONNECT_COUNT 5
|
|
||||||
|
|
||||||
#define ROWS_PER_HAND (MATRIX_ROWS/2)
|
|
||||||
|
|
||||||
static uint8_t error_count = 0;
|
|
||||||
|
|
||||||
#if ((DIODE_DIRECTION == COL2ROW) || (DIODE_DIRECTION == ROW2COL))
|
|
||||||
static uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
|
|
||||||
static uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
|
|
||||||
#elif (DIODE_DIRECTION == CUSTOM_MATRIX)
|
|
||||||
static uint8_t row_col_pins[MATRIX_ROWS][MATRIX_COLS] = MATRIX_ROW_COL_PINS;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* matrix state(1:on, 0:off) */
|
|
||||||
static matrix_row_t matrix[MATRIX_ROWS];
|
|
||||||
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
|
|
||||||
|
|
||||||
#if (DIODE_DIRECTION == COL2ROW)
|
|
||||||
static void init_cols(void);
|
|
||||||
static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
|
|
||||||
static void unselect_rows(void);
|
|
||||||
static void select_row(uint8_t row);
|
|
||||||
static void unselect_row(uint8_t row);
|
|
||||||
#elif (DIODE_DIRECTION == ROW2COL)
|
|
||||||
static void init_rows(void);
|
|
||||||
static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
|
|
||||||
static void unselect_cols(void);
|
|
||||||
static void unselect_col(uint8_t col);
|
|
||||||
static void select_col(uint8_t col);
|
|
||||||
#elif (DIODE_DIRECTION == CUSTOM_MATRIX)
|
|
||||||
static void init_cols_rows(void);
|
|
||||||
static bool read_cols(matrix_row_t current_matrix[], uint8_t current_row);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__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) {
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((weak))
|
|
||||||
void matrix_slave_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)
|
|
||||||
{
|
|
||||||
#ifdef DISABLE_JTAG
|
|
||||||
// JTAG disable for PORT F. write JTD bit twice within four cycles.
|
|
||||||
MCUCR |= (1<<JTD);
|
|
||||||
MCUCR |= (1<<JTD);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
debug_enable = true;
|
|
||||||
debug_matrix = true;
|
|
||||||
debug_mouse = true;
|
|
||||||
|
|
||||||
// Set pinout for right half if pinout for that half is defined
|
|
||||||
if (!isLeftHand) {
|
|
||||||
#ifdef MATRIX_ROW_PINS_RIGHT
|
|
||||||
const uint8_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
|
|
||||||
for (uint8_t i = 0; i < MATRIX_ROWS; i++)
|
|
||||||
row_pins[i] = row_pins_right[i];
|
|
||||||
#endif
|
|
||||||
#ifdef MATRIX_COL_PINS_RIGHT
|
|
||||||
const uint8_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
|
|
||||||
for (uint8_t i = 0; i < MATRIX_COLS; i++)
|
|
||||||
col_pins[i] = col_pins_right[i];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize row and col
|
|
||||||
#if (DIODE_DIRECTION == COL2ROW)
|
|
||||||
unselect_rows();
|
|
||||||
init_cols();
|
|
||||||
#elif (DIODE_DIRECTION == ROW2COL)
|
|
||||||
unselect_cols();
|
|
||||||
init_rows();
|
|
||||||
#elif (DIODE_DIRECTION == CUSTOM_MATRIX)
|
|
||||||
init_cols_rows();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// initialize matrix state: all keys off
|
|
||||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
|
|
||||||
matrix[i] = 0;
|
|
||||||
matrix_debouncing[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
matrix_init_quantum();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t _matrix_scan(void)
|
|
||||||
{
|
|
||||||
int offset = isLeftHand ? 0 : (ROWS_PER_HAND);
|
|
||||||
#if (DIODE_DIRECTION == COL2ROW)
|
|
||||||
// Set row, read cols
|
|
||||||
for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
|
|
||||||
# if (DEBOUNCING_DELAY > 0)
|
|
||||||
bool matrix_changed = read_cols_on_row(matrix_debouncing+offset, current_row);
|
|
||||||
|
|
||||||
if (matrix_changed) {
|
|
||||||
debouncing = true;
|
|
||||||
debouncing_time = timer_read();
|
|
||||||
}
|
|
||||||
|
|
||||||
# else
|
|
||||||
read_cols_on_row(matrix+offset, current_row);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif (DIODE_DIRECTION == ROW2COL)
|
|
||||||
// Set col, read rows
|
|
||||||
for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
|
|
||||||
# if (DEBOUNCING_DELAY > 0)
|
|
||||||
bool matrix_changed = read_rows_on_col(matrix_debouncing+offset, current_col);
|
|
||||||
if (matrix_changed) {
|
|
||||||
debouncing = true;
|
|
||||||
debouncing_time = timer_read();
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
read_rows_on_col(matrix+offset, current_col);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif (DIODE_DIRECTION == CUSTOM_MATRIX)
|
|
||||||
// Set row, read cols
|
|
||||||
for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
|
|
||||||
# if (DEBOUNCING_DELAY > 0)
|
|
||||||
bool matrix_changed = read_cols(matrix_debouncing+offset, current_row);
|
|
||||||
if (matrix_changed) {
|
|
||||||
debouncing = true;
|
|
||||||
debouncing_time = timer_read();
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
read_cols(matrix+offset, current_row);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
# if (DEBOUNCING_DELAY > 0)
|
|
||||||
if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
|
|
||||||
for (uint8_t i = 0; i < ROWS_PER_HAND; i++) {
|
|
||||||
matrix[i+offset] = matrix_debouncing[i+offset];
|
|
||||||
}
|
|
||||||
debouncing = false;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
|
|
||||||
// Get rows from other half over i2c
|
|
||||||
int i2c_transaction(void) {
|
|
||||||
int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
// write backlight info
|
|
||||||
#ifdef BACKLIGHT_ENABLE
|
|
||||||
if (BACKLIT_DIRTY) {
|
|
||||||
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
// Backlight location
|
|
||||||
err = i2c_master_write(I2C_BACKLIT_START);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
// Write backlight
|
|
||||||
i2c_master_write(get_backlight_level());
|
|
||||||
|
|
||||||
BACKLIT_DIRTY = false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
// start of matrix stored at I2C_KEYMAP_START
|
|
||||||
err = i2c_master_write(I2C_KEYMAP_START);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
// Start read
|
|
||||||
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
if (!err) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < ROWS_PER_HAND-1; ++i) {
|
|
||||||
matrix[slaveOffset+i] = i2c_master_read(I2C_ACK);
|
|
||||||
}
|
|
||||||
matrix[slaveOffset+i] = i2c_master_read(I2C_NACK);
|
|
||||||
i2c_master_stop();
|
|
||||||
} else {
|
|
||||||
i2c_error: // the cable is disconnceted, or something else went wrong
|
|
||||||
i2c_reset_state();
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef RGBLIGHT_ENABLE
|
|
||||||
if (RGB_DIRTY) {
|
|
||||||
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
// RGB Location
|
|
||||||
err = i2c_master_write(I2C_RGB_START);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
uint32_t dword = eeconfig_read_rgblight();
|
|
||||||
|
|
||||||
// Write RGB
|
|
||||||
err = i2c_master_write_data(&dword, 4);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
RGB_DIRTY = false;
|
|
||||||
i2c_master_stop();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // USE_SERIAL
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _Serial_s2m_buffer_t {
|
|
||||||
// TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack
|
|
||||||
matrix_row_t smatrix[ROWS_PER_HAND];
|
|
||||||
} Serial_s2m_buffer_t;
|
|
||||||
|
|
||||||
volatile Serial_s2m_buffer_t serial_s2m_buffer = {};
|
|
||||||
volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
|
|
||||||
uint8_t volatile status0 = 0;
|
|
||||||
|
|
||||||
SSTD_t transactions[] = {
|
|
||||||
{ (uint8_t *)&status0,
|
|
||||||
sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer,
|
|
||||||
sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void serial_master_init(void)
|
|
||||||
{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); }
|
|
||||||
|
|
||||||
void serial_slave_init(void)
|
|
||||||
{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); }
|
|
||||||
|
|
||||||
int serial_transaction(void) {
|
|
||||||
int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
|
|
||||||
|
|
||||||
if (soft_serial_transaction()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: if MATRIX_COLS > 8 change to unpack()
|
|
||||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
|
||||||
matrix[slaveOffset+i] = serial_s2m_buffer.smatrix[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef RGBLIGHT_ENABLE
|
|
||||||
// Code to send RGB over serial goes here (not implemented yet)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BACKLIGHT_ENABLE
|
|
||||||
// Write backlight level for slave to read
|
|
||||||
serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t matrix_scan(void)
|
|
||||||
{
|
|
||||||
uint8_t ret = _matrix_scan();
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
if( i2c_transaction() ) {
|
|
||||||
#else // USE_SERIAL
|
|
||||||
if( serial_transaction() ) {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
error_count++;
|
|
||||||
|
|
||||||
if (error_count > ERROR_DISCONNECT_COUNT) {
|
|
||||||
// reset other half if disconnected
|
|
||||||
int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
|
|
||||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
|
||||||
matrix[slaveOffset+i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error_count = 0;
|
|
||||||
}
|
|
||||||
matrix_scan_quantum();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void matrix_slave_scan(void) {
|
|
||||||
_matrix_scan();
|
|
||||||
|
|
||||||
int offset = (isLeftHand) ? 0 : ROWS_PER_HAND;
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
|
||||||
i2c_slave_buffer[I2C_KEYMAP_START+i] = matrix[offset+i];
|
|
||||||
}
|
|
||||||
#else // USE_SERIAL
|
|
||||||
// TODO: if MATRIX_COLS > 8 change to pack()
|
|
||||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
|
||||||
serial_s2m_buffer.smatrix[i] = matrix[offset+i];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
matrix_slave_scan_user();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool matrix_is_modified(void)
|
|
||||||
{
|
|
||||||
if (debouncing) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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("\nr/c 0123456789ABCDEF\n");
|
|
||||||
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
|
|
||||||
phex(row); print(": ");
|
|
||||||
pbin_reverse16(matrix_get_row(row));
|
|
||||||
print("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t matrix_key_count(void)
|
|
||||||
{
|
|
||||||
uint8_t count = 0;
|
|
||||||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
|
||||||
count += bitpop16(matrix[i]);
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (DIODE_DIRECTION == COL2ROW)
|
|
||||||
|
|
||||||
static void init_cols(void)
|
|
||||||
{
|
|
||||||
for(uint8_t x = 0; x < MATRIX_COLS; x++) {
|
|
||||||
uint8_t pin = col_pins[x];
|
|
||||||
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
|
|
||||||
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
|
|
||||||
{
|
|
||||||
// Store last value of row prior to reading
|
|
||||||
matrix_row_t last_row_value = current_matrix[current_row];
|
|
||||||
|
|
||||||
// Clear data in matrix row
|
|
||||||
current_matrix[current_row] = 0;
|
|
||||||
|
|
||||||
// Select row and wait for row selecton to stabilize
|
|
||||||
select_row(current_row);
|
|
||||||
wait_us(30);
|
|
||||||
|
|
||||||
// For each col...
|
|
||||||
for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
|
|
||||||
|
|
||||||
// Select the col pin to read (active low)
|
|
||||||
uint8_t pin = col_pins[col_index];
|
|
||||||
uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
|
|
||||||
|
|
||||||
// Populate the matrix row with the state of the col pin
|
|
||||||
current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unselect row
|
|
||||||
unselect_row(current_row);
|
|
||||||
|
|
||||||
return (last_row_value != current_matrix[current_row]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void select_row(uint8_t row)
|
|
||||||
{
|
|
||||||
uint8_t pin = row_pins[row];
|
|
||||||
_SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
|
|
||||||
_SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unselect_row(uint8_t row)
|
|
||||||
{
|
|
||||||
uint8_t pin = row_pins[row];
|
|
||||||
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
|
|
||||||
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unselect_rows(void)
|
|
||||||
{
|
|
||||||
for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
|
|
||||||
uint8_t pin = row_pins[x];
|
|
||||||
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
|
|
||||||
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif (DIODE_DIRECTION == ROW2COL)
|
|
||||||
|
|
||||||
static void init_rows(void)
|
|
||||||
{
|
|
||||||
for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
|
|
||||||
uint8_t pin = row_pins[x];
|
|
||||||
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
|
|
||||||
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
|
|
||||||
{
|
|
||||||
bool matrix_changed = false;
|
|
||||||
|
|
||||||
// Select col and wait for col selecton to stabilize
|
|
||||||
select_col(current_col);
|
|
||||||
wait_us(30);
|
|
||||||
|
|
||||||
// For each row...
|
|
||||||
for(uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Store last value of row prior to reading
|
|
||||||
matrix_row_t last_row_value = current_matrix[row_index];
|
|
||||||
|
|
||||||
// Check row pin state
|
|
||||||
if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)) == 0)
|
|
||||||
{
|
|
||||||
// Pin LO, set col bit
|
|
||||||
current_matrix[row_index] |= (ROW_SHIFTER << current_col);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Pin HI, clear col bit
|
|
||||||
current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if the matrix changed state
|
|
||||||
if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
|
|
||||||
{
|
|
||||||
matrix_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unselect col
|
|
||||||
unselect_col(current_col);
|
|
||||||
|
|
||||||
return matrix_changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void select_col(uint8_t col)
|
|
||||||
{
|
|
||||||
uint8_t pin = col_pins[col];
|
|
||||||
_SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
|
|
||||||
_SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unselect_col(uint8_t col)
|
|
||||||
{
|
|
||||||
uint8_t pin = col_pins[col];
|
|
||||||
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
|
|
||||||
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unselect_cols(void)
|
|
||||||
{
|
|
||||||
for(uint8_t x = 0; x < MATRIX_COLS; x++) {
|
|
||||||
uint8_t pin = col_pins[x];
|
|
||||||
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
|
|
||||||
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif (DIODE_DIRECTION == CUSTOM_MATRIX)
|
|
||||||
|
|
||||||
static void init_cols_rows(void)
|
|
||||||
{
|
|
||||||
for(int row = 0; row < MATRIX_ROWS; row++) {
|
|
||||||
for(int col = 0; col < MATRIX_COLS; col++) {
|
|
||||||
uint8_t pin = row_col_pins[row][col];
|
|
||||||
if(pin == NO_PIN) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// DDxn set 0 for input
|
|
||||||
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF);
|
|
||||||
// PORTxn set 1 for input/pullup
|
|
||||||
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool read_cols(matrix_row_t current_matrix[], uint8_t current_row)
|
|
||||||
{
|
|
||||||
matrix_row_t last_row_value = current_matrix[current_row];
|
|
||||||
current_matrix[current_row] = 0;
|
|
||||||
|
|
||||||
for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
|
|
||||||
uint8_t pin = row_col_pins[current_row][col_index];
|
|
||||||
if(pin == NO_PIN) {
|
|
||||||
current_matrix[current_row] |= 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
|
|
||||||
current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (last_row_value != current_matrix[current_row]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
SRC += matrix.c
|
|
||||||
|
|
||||||
# MCU name
|
# MCU name
|
||||||
#MCU = at90usb1286
|
#MCU = at90usb1286
|
||||||
@@ -83,6 +82,6 @@ FAUXCLICKY_ENABLE = no # Use buzzer to emulate clicky switches
|
|||||||
HD44780_ENABLE = no # Enable support for HD44780 based LCDs (+400)
|
HD44780_ENABLE = no # Enable support for HD44780 based LCDs (+400)
|
||||||
|
|
||||||
DEBUG_ENABLE = no
|
DEBUG_ENABLE = no
|
||||||
CUSTOM_MATRIX = yes # Use custom matrix code
|
CUSTOM_MATRIX = no # Use custom matrix code
|
||||||
SPLIT_KEYBOARD = yes # Use shared split_common code
|
SPLIT_KEYBOARD = yes # Use shared split_common code
|
||||||
|
|
||||||
@@ -21,6 +21,9 @@
|
|||||||
#define ROW2COL 1
|
#define ROW2COL 1
|
||||||
#define CUSTOM_MATRIX 2 /* Disables built-in matrix scanning code */
|
#define CUSTOM_MATRIX 2 /* Disables built-in matrix scanning code */
|
||||||
|
|
||||||
|
// useful for direct pin mapping
|
||||||
|
#define NO_PIN (~0)
|
||||||
|
|
||||||
#ifdef __AVR__
|
#ifdef __AVR__
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
#include "matrix.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "quantum.h"
|
||||||
|
|
||||||
|
#ifndef DEBOUNCING_DELAY
|
||||||
|
# define DEBOUNCING_DELAY 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void debounce_init(uint8_t num_rows) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBOUNCING_DELAY > 0
|
||||||
|
|
||||||
|
static bool debouncing = false;
|
||||||
|
|
||||||
|
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
||||||
|
static uint16_t debouncing_time;
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
debouncing = true;
|
||||||
|
debouncing_time = timer_read();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
|
||||||
|
for (uint8_t i = 0; i < num_rows; i++) {
|
||||||
|
cooked[i] = raw[i];
|
||||||
|
}
|
||||||
|
debouncing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool debounce_active(void) {
|
||||||
|
return debouncing;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// no debounce
|
||||||
|
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < num_rows; i++) {
|
||||||
|
cooked[i] = raw[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool debounce_active(void) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// raw is the current key state
|
||||||
|
// on entry cooked is the previous debounced state
|
||||||
|
// on exit cooked is the current debounced state
|
||||||
|
// changed is true if raw has changed since the last call
|
||||||
|
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
|
||||||
|
|
||||||
|
bool debounce_active(void);
|
||||||
|
|
||||||
|
void debounce_init(uint8_t num_rows);
|
||||||
+18
-61
@@ -21,21 +21,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
#include "timer.h"
|
#include "debounce.h"
|
||||||
#include "quantum.h"
|
#include "quantum.h"
|
||||||
|
|
||||||
|
|
||||||
/* Set 0 if debouncing isn't needed */
|
|
||||||
|
|
||||||
#ifndef DEBOUNCING_DELAY
|
|
||||||
# define DEBOUNCING_DELAY 5
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (DEBOUNCING_DELAY > 0)
|
|
||||||
static uint16_t debouncing_time;
|
|
||||||
static bool debouncing = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (MATRIX_COLS <= 8)
|
#if (MATRIX_COLS <= 8)
|
||||||
# define print_matrix_header() print("\nr/c 01234567\n")
|
# define print_matrix_header() print("\nr/c 01234567\n")
|
||||||
# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
|
# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
|
||||||
@@ -63,9 +51,9 @@ static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* matrix state(1:on, 0:off) */
|
/* matrix state(1:on, 0:off) */
|
||||||
static matrix_row_t matrix[MATRIX_ROWS];
|
static matrix_row_t raw_matrix[MATRIX_ROWS];
|
||||||
|
|
||||||
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
|
static matrix_row_t matrix[MATRIX_ROWS];
|
||||||
|
|
||||||
|
|
||||||
#if (DIODE_DIRECTION == COL2ROW)
|
#if (DIODE_DIRECTION == COL2ROW)
|
||||||
@@ -157,70 +145,39 @@ void matrix_init(void) {
|
|||||||
|
|
||||||
// initialize matrix state: all keys off
|
// initialize matrix state: all keys off
|
||||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
|
||||||
|
raw_matrix[i] = 0;
|
||||||
matrix[i] = 0;
|
matrix[i] = 0;
|
||||||
matrix_debouncing[i] = 0;
|
|
||||||
}
|
}
|
||||||
|
debounce_init(MATRIX_ROWS);
|
||||||
|
|
||||||
matrix_init_quantum();
|
matrix_init_quantum();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t matrix_scan(void)
|
uint8_t matrix_scan(void)
|
||||||
{
|
{
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
#if (DIODE_DIRECTION == COL2ROW)
|
#if (DIODE_DIRECTION == COL2ROW)
|
||||||
|
// Set row, read cols
|
||||||
// Set row, read cols
|
for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
|
||||||
for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
|
changed |= read_cols_on_row(raw_matrix, current_row);
|
||||||
# if (DEBOUNCING_DELAY > 0)
|
}
|
||||||
bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row);
|
|
||||||
|
|
||||||
if (matrix_changed) {
|
|
||||||
debouncing = true;
|
|
||||||
debouncing_time = timer_read();
|
|
||||||
}
|
|
||||||
|
|
||||||
# else
|
|
||||||
read_cols_on_row(matrix, current_row);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif (DIODE_DIRECTION == ROW2COL)
|
#elif (DIODE_DIRECTION == ROW2COL)
|
||||||
|
// Set col, read rows
|
||||||
// Set col, read rows
|
for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
|
||||||
for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
|
changed |= read_rows_on_col(raw_matrix, current_col);
|
||||||
# if (DEBOUNCING_DELAY > 0)
|
}
|
||||||
bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
|
|
||||||
if (matrix_changed) {
|
|
||||||
debouncing = true;
|
|
||||||
debouncing_time = timer_read();
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
read_rows_on_col(matrix, current_col);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
# if (DEBOUNCING_DELAY > 0)
|
debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
|
||||||
if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
|
|
||||||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
|
||||||
matrix[i] = matrix_debouncing[i];
|
|
||||||
}
|
|
||||||
debouncing = false;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
matrix_scan_quantum();
|
matrix_scan_quantum();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matrix_is_modified(void)
|
bool matrix_is_modified(void)
|
||||||
{
|
{
|
||||||
#if (DEBOUNCING_DELAY > 0)
|
if (debounce_active()) return false;
|
||||||
if (debouncing) return false;
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -273,11 +273,17 @@ bool process_terminal(uint16_t keycode, keyrecord_t *record) {
|
|||||||
disable_terminal();
|
disable_terminal();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) {
|
||||||
|
keycode = keycode & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
if (keycode < 256) {
|
if (keycode < 256) {
|
||||||
uint8_t str_len;
|
uint8_t str_len;
|
||||||
char char_to_add;
|
char char_to_add;
|
||||||
switch (keycode) {
|
switch (keycode) {
|
||||||
case KC_ENTER:
|
case KC_ENTER:
|
||||||
|
case KC_KP_ENTER:
|
||||||
push_to_cmd_buffer();
|
push_to_cmd_buffer();
|
||||||
current_cmd_buffer_pos = 0;
|
current_cmd_buffer_pos = 0;
|
||||||
process_terminal_command();
|
process_terminal_command();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef I2C_H
|
#pragma once
|
||||||
#define I2C_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@@ -58,5 +57,3 @@ extern unsigned char i2c_readNak(void);
|
|||||||
extern unsigned char i2c_read(unsigned char ack);
|
extern unsigned char i2c_read(unsigned char ack);
|
||||||
|
|
||||||
#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
|
#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
|
||||||
|
|
||||||
#endif
|
|
||||||
+264
-489
@@ -25,529 +25,304 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
#include "split_util.h"
|
#include "split_util.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "timer.h"
|
|
||||||
#include "split_flags.h"
|
#include "split_flags.h"
|
||||||
#include "quantum.h"
|
#include "quantum.h"
|
||||||
|
#include "debounce.h"
|
||||||
#ifdef BACKLIGHT_ENABLE
|
#include "transport.h"
|
||||||
# include "backlight.h"
|
|
||||||
extern backlight_config_t backlight_config;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
# include "i2c.h"
|
|
||||||
#else // USE_SERIAL
|
|
||||||
# include "serial.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBOUNCING_DELAY
|
|
||||||
# define DEBOUNCING_DELAY 5
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (DEBOUNCING_DELAY > 0)
|
|
||||||
static uint16_t debouncing_time;
|
|
||||||
static bool debouncing = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
|
|
||||||
#if (MATRIX_COLS <= 8)
|
#if (MATRIX_COLS <= 8)
|
||||||
# define print_matrix_header() print("\nr/c 01234567\n")
|
# define print_matrix_header() print("\nr/c 01234567\n")
|
||||||
# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
|
# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
|
||||||
# define matrix_bitpop(i) bitpop(matrix[i])
|
# define matrix_bitpop(i) bitpop(matrix[i])
|
||||||
# define ROW_SHIFTER ((uint8_t)1)
|
# define ROW_SHIFTER ((uint8_t)1)
|
||||||
#else
|
|
||||||
# error "Currently only supports 8 COLS"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else // USE_SERIAL
|
|
||||||
|
|
||||||
#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)
|
#elif (MATRIX_COLS <= 16)
|
||||||
# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n")
|
# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n")
|
||||||
# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row))
|
# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row))
|
||||||
# define matrix_bitpop(i) bitpop16(matrix[i])
|
# define matrix_bitpop(i) bitpop16(matrix[i])
|
||||||
# define ROW_SHIFTER ((uint16_t)1)
|
# define ROW_SHIFTER ((uint16_t)1)
|
||||||
#elif (MATRIX_COLS <= 32)
|
#elif (MATRIX_COLS <= 32)
|
||||||
# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
|
# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
|
||||||
# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row))
|
# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row))
|
||||||
# define matrix_bitpop(i) bitpop32(matrix[i])
|
# define matrix_bitpop(i) bitpop32(matrix[i])
|
||||||
# define ROW_SHIFTER ((uint32_t)1)
|
# define ROW_SHIFTER ((uint32_t)1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
|
|
||||||
|
|
||||||
#define ERROR_DISCONNECT_COUNT 5
|
#define ERROR_DISCONNECT_COUNT 5
|
||||||
|
|
||||||
#define ROWS_PER_HAND (MATRIX_ROWS/2)
|
#define ROWS_PER_HAND (MATRIX_ROWS / 2)
|
||||||
|
|
||||||
static uint8_t error_count = 0;
|
|
||||||
|
|
||||||
|
#ifdef DIRECT_PINS
|
||||||
|
static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS;
|
||||||
|
#else
|
||||||
static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
|
static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
|
||||||
static pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
|
static pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* matrix state(1:on, 0:off) */
|
/* matrix state(1:on, 0:off) */
|
||||||
static matrix_row_t matrix[MATRIX_ROWS];
|
static matrix_row_t matrix[MATRIX_ROWS];
|
||||||
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
|
static matrix_row_t raw_matrix[ROWS_PER_HAND];
|
||||||
|
|
||||||
|
// row offsets for each hand
|
||||||
|
uint8_t thisHand, thatHand;
|
||||||
|
|
||||||
|
// user-defined overridable functions
|
||||||
|
|
||||||
|
__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) {}
|
||||||
|
|
||||||
|
__attribute__((weak)) void matrix_slave_scan_user(void) {}
|
||||||
|
|
||||||
|
// helper functions
|
||||||
|
|
||||||
|
inline uint8_t matrix_rows(void) { return MATRIX_ROWS; }
|
||||||
|
|
||||||
|
inline uint8_t matrix_cols(void) { return MATRIX_COLS; }
|
||||||
|
|
||||||
|
bool matrix_is_modified(void) {
|
||||||
|
if (debounce_active()) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// matrix code
|
||||||
|
|
||||||
|
#ifdef DIRECT_PINS
|
||||||
|
|
||||||
|
static void init_pins(void) {
|
||||||
|
for (int row = 0; row < MATRIX_ROWS; row++) {
|
||||||
|
for (int col = 0; col < MATRIX_COLS; col++) {
|
||||||
|
pin_t pin = direct_pins[row][col];
|
||||||
|
if (pin != NO_PIN) {
|
||||||
|
setPinInputHigh(pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
|
||||||
|
matrix_row_t last_row_value = current_matrix[current_row];
|
||||||
|
current_matrix[current_row] = 0;
|
||||||
|
|
||||||
|
for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
|
||||||
|
pin_t pin = direct_pins[current_row][col_index];
|
||||||
|
if (pin != NO_PIN) {
|
||||||
|
current_matrix[current_row] |= readPin(pin) ? 0 : (ROW_SHIFTER << col_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (last_row_value != current_matrix[current_row]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif (DIODE_DIRECTION == COL2ROW)
|
||||||
|
|
||||||
|
static void select_row(uint8_t row) {
|
||||||
|
writePinLow(row_pins[row]);
|
||||||
|
setPinOutput(row_pins[row]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unselect_row(uint8_t row) { setPinInputHigh(row_pins[row]); }
|
||||||
|
|
||||||
|
static void unselect_rows(void) {
|
||||||
|
for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
|
||||||
|
setPinInputHigh(row_pins[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_pins(void) {
|
||||||
|
unselect_rows();
|
||||||
|
for (uint8_t x = 0; x < MATRIX_COLS; x++) {
|
||||||
|
setPinInputHigh(col_pins[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
|
||||||
|
// Store last value of row prior to reading
|
||||||
|
matrix_row_t last_row_value = current_matrix[current_row];
|
||||||
|
|
||||||
|
// Clear data in matrix row
|
||||||
|
current_matrix[current_row] = 0;
|
||||||
|
|
||||||
|
// Select row and wait for row selecton to stabilize
|
||||||
|
select_row(current_row);
|
||||||
|
wait_us(30);
|
||||||
|
|
||||||
|
// For each col...
|
||||||
|
for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
|
||||||
|
// Populate the matrix row with the state of the col pin
|
||||||
|
current_matrix[current_row] |= readPin(col_pins[col_index]) ? 0 : (ROW_SHIFTER << col_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unselect row
|
||||||
|
unselect_row(current_row);
|
||||||
|
|
||||||
|
return (last_row_value != current_matrix[current_row]);
|
||||||
|
}
|
||||||
|
|
||||||
#if (DIODE_DIRECTION == COL2ROW)
|
|
||||||
static void init_cols(void);
|
|
||||||
static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
|
|
||||||
static void unselect_rows(void);
|
|
||||||
static void select_row(uint8_t row);
|
|
||||||
static void unselect_row(uint8_t row);
|
|
||||||
#elif (DIODE_DIRECTION == ROW2COL)
|
#elif (DIODE_DIRECTION == ROW2COL)
|
||||||
static void init_rows(void);
|
|
||||||
static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
|
static void select_col(uint8_t col) {
|
||||||
static void unselect_cols(void);
|
writePinLow(col_pins[col]);
|
||||||
static void unselect_col(uint8_t col);
|
setPinOutput(col_pins[col]);
|
||||||
static void select_col(uint8_t col);
|
}
|
||||||
|
|
||||||
|
static void unselect_col(uint8_t col) { setPinInputHigh(col_pins[col]); }
|
||||||
|
|
||||||
|
static void unselect_cols(void) {
|
||||||
|
for (uint8_t x = 0; x < MATRIX_COLS; x++) {
|
||||||
|
setPinInputHigh(col_pins[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_pins(void) {
|
||||||
|
unselect_cols();
|
||||||
|
for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
|
||||||
|
setPinInputHigh(row_pins[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
|
||||||
|
bool matrix_changed = false;
|
||||||
|
|
||||||
|
// Select col and wait for col selecton to stabilize
|
||||||
|
select_col(current_col);
|
||||||
|
wait_us(30);
|
||||||
|
|
||||||
|
// For each row...
|
||||||
|
for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) {
|
||||||
|
// Store last value of row prior to reading
|
||||||
|
matrix_row_t last_row_value = current_matrix[row_index];
|
||||||
|
|
||||||
|
// Check row pin state
|
||||||
|
if (readPin(row_pins[row_index])) {
|
||||||
|
// Pin HI, clear col bit
|
||||||
|
current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
|
||||||
|
} else {
|
||||||
|
// Pin LO, set col bit
|
||||||
|
current_matrix[row_index] |= (ROW_SHIFTER << current_col);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if the matrix changed state
|
||||||
|
if ((last_row_value != current_matrix[row_index]) && !(matrix_changed)) {
|
||||||
|
matrix_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unselect col
|
||||||
|
unselect_col(current_col);
|
||||||
|
|
||||||
|
return matrix_changed;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__attribute__ ((weak))
|
void matrix_init(void) {
|
||||||
void matrix_init_kb(void) {
|
debug_enable = true;
|
||||||
matrix_init_user();
|
debug_matrix = true;
|
||||||
}
|
debug_mouse = true;
|
||||||
|
|
||||||
__attribute__ ((weak))
|
// Set pinout for right half if pinout for that half is defined
|
||||||
void matrix_scan_kb(void) {
|
if (!isLeftHand) {
|
||||||
matrix_scan_user();
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((weak))
|
|
||||||
void matrix_init_user(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((weak))
|
|
||||||
void matrix_scan_user(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((weak))
|
|
||||||
void matrix_slave_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)
|
|
||||||
{
|
|
||||||
debug_enable = true;
|
|
||||||
debug_matrix = true;
|
|
||||||
debug_mouse = true;
|
|
||||||
|
|
||||||
// Set pinout for right half if pinout for that half is defined
|
|
||||||
if (!isLeftHand) {
|
|
||||||
#ifdef MATRIX_ROW_PINS_RIGHT
|
#ifdef MATRIX_ROW_PINS_RIGHT
|
||||||
const uint8_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
|
const uint8_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
|
||||||
for (uint8_t i = 0; i < MATRIX_ROWS; i++)
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
row_pins[i] = row_pins_right[i];
|
row_pins[i] = row_pins_right[i];
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef MATRIX_COL_PINS_RIGHT
|
#ifdef MATRIX_COL_PINS_RIGHT
|
||||||
const uint8_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
|
const uint8_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
|
||||||
for (uint8_t i = 0; i < MATRIX_COLS; i++)
|
for (uint8_t i = 0; i < MATRIX_COLS; i++) {
|
||||||
col_pins[i] = col_pins_right[i];
|
col_pins[i] = col_pins_right[i];
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize row and col
|
|
||||||
#if (DIODE_DIRECTION == COL2ROW)
|
|
||||||
unselect_rows();
|
|
||||||
init_cols();
|
|
||||||
#elif (DIODE_DIRECTION == ROW2COL)
|
|
||||||
unselect_cols();
|
|
||||||
init_rows();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// initialize matrix state: all keys off
|
|
||||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
|
|
||||||
matrix[i] = 0;
|
|
||||||
matrix_debouncing[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
matrix_init_quantum();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t _matrix_scan(void)
|
|
||||||
{
|
|
||||||
int offset = isLeftHand ? 0 : (ROWS_PER_HAND);
|
|
||||||
#if (DIODE_DIRECTION == COL2ROW)
|
|
||||||
// Set row, read cols
|
|
||||||
for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
|
|
||||||
# if (DEBOUNCING_DELAY > 0)
|
|
||||||
bool matrix_changed = read_cols_on_row(matrix_debouncing+offset, current_row);
|
|
||||||
|
|
||||||
if (matrix_changed) {
|
|
||||||
debouncing = true;
|
|
||||||
debouncing_time = timer_read();
|
|
||||||
}
|
|
||||||
|
|
||||||
# else
|
|
||||||
read_cols_on_row(matrix+offset, current_row);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif (DIODE_DIRECTION == ROW2COL)
|
|
||||||
// Set col, read rows
|
|
||||||
for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
|
|
||||||
# if (DEBOUNCING_DELAY > 0)
|
|
||||||
bool matrix_changed = read_rows_on_col(matrix_debouncing+offset, current_col);
|
|
||||||
if (matrix_changed) {
|
|
||||||
debouncing = true;
|
|
||||||
debouncing_time = timer_read();
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
read_rows_on_col(matrix+offset, current_col);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
# if (DEBOUNCING_DELAY > 0)
|
|
||||||
if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
|
|
||||||
for (uint8_t i = 0; i < ROWS_PER_HAND; i++) {
|
|
||||||
matrix[i+offset] = matrix_debouncing[i+offset];
|
|
||||||
}
|
|
||||||
debouncing = false;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
|
|
||||||
// Get rows from other half over i2c
|
|
||||||
int i2c_transaction(void) {
|
|
||||||
int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
// write backlight info
|
|
||||||
#ifdef BACKLIGHT_ENABLE
|
|
||||||
if (BACKLIT_DIRTY) {
|
|
||||||
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
// Backlight location
|
|
||||||
err = i2c_master_write(I2C_BACKLIT_START);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
// Write backlight
|
|
||||||
i2c_master_write(get_backlight_level());
|
|
||||||
|
|
||||||
BACKLIT_DIRTY = false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
// start of matrix stored at I2C_KEYMAP_START
|
|
||||||
err = i2c_master_write(I2C_KEYMAP_START);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
// Start read
|
|
||||||
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
if (!err) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < ROWS_PER_HAND-1; ++i) {
|
|
||||||
matrix[slaveOffset+i] = i2c_master_read(I2C_ACK);
|
|
||||||
}
|
|
||||||
matrix[slaveOffset+i] = i2c_master_read(I2C_NACK);
|
|
||||||
i2c_master_stop();
|
|
||||||
} else {
|
|
||||||
i2c_error: // the cable is disconnceted, or something else went wrong
|
|
||||||
i2c_reset_state();
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef RGBLIGHT_ENABLE
|
|
||||||
if (RGB_DIRTY) {
|
|
||||||
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
// RGB Location
|
|
||||||
err = i2c_master_write(I2C_RGB_START);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
uint32_t dword = eeconfig_read_rgblight();
|
|
||||||
|
|
||||||
// Write RGB
|
|
||||||
err = i2c_master_write_data(&dword, 4);
|
|
||||||
if (err) goto i2c_error;
|
|
||||||
|
|
||||||
RGB_DIRTY = false;
|
|
||||||
i2c_master_stop();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // USE_SERIAL
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _Serial_s2m_buffer_t {
|
|
||||||
// TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack
|
|
||||||
matrix_row_t smatrix[ROWS_PER_HAND];
|
|
||||||
} Serial_s2m_buffer_t;
|
|
||||||
|
|
||||||
volatile Serial_s2m_buffer_t serial_s2m_buffer = {};
|
|
||||||
volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
|
|
||||||
uint8_t volatile status0 = 0;
|
|
||||||
|
|
||||||
SSTD_t transactions[] = {
|
|
||||||
{ (uint8_t *)&status0,
|
|
||||||
sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer,
|
|
||||||
sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
void serial_master_init(void)
|
thisHand = isLeftHand ? 0 : (ROWS_PER_HAND);
|
||||||
{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); }
|
thatHand = ROWS_PER_HAND - thisHand;
|
||||||
|
|
||||||
void serial_slave_init(void)
|
// initialize key pins
|
||||||
{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); }
|
init_pins();
|
||||||
|
|
||||||
int serial_transaction(void) {
|
// initialize matrix state: all keys off
|
||||||
int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
|
matrix[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (soft_serial_transaction()) {
|
debounce_init(ROWS_PER_HAND);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: if MATRIX_COLS > 8 change to unpack()
|
matrix_init_quantum();
|
||||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
|
||||||
matrix[slaveOffset+i] = serial_s2m_buffer.smatrix[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
|
|
||||||
// Code to send RGB over serial goes here (not implemented yet)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BACKLIGHT_ENABLE
|
|
||||||
// Write backlight level for slave to read
|
|
||||||
serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t matrix_scan(void)
|
|
||||||
{
|
|
||||||
uint8_t ret = _matrix_scan();
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
if( i2c_transaction() ) {
|
|
||||||
#else // USE_SERIAL
|
|
||||||
if( serial_transaction() ) {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
error_count++;
|
|
||||||
|
|
||||||
if (error_count > ERROR_DISCONNECT_COUNT) {
|
|
||||||
// reset other half if disconnected
|
|
||||||
int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
|
|
||||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
|
||||||
matrix[slaveOffset+i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error_count = 0;
|
|
||||||
}
|
|
||||||
matrix_scan_quantum();
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void matrix_slave_scan(void) {
|
uint8_t _matrix_scan(void) {
|
||||||
_matrix_scan();
|
bool changed = false;
|
||||||
|
|
||||||
int offset = (isLeftHand) ? 0 : ROWS_PER_HAND;
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
|
||||||
i2c_slave_buffer[I2C_KEYMAP_START+i] = matrix[offset+i];
|
|
||||||
}
|
|
||||||
#else // USE_SERIAL
|
|
||||||
// TODO: if MATRIX_COLS > 8 change to pack()
|
|
||||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
|
||||||
serial_s2m_buffer.smatrix[i] = matrix[offset+i];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
matrix_slave_scan_user();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool matrix_is_modified(void)
|
|
||||||
{
|
|
||||||
if (debouncing) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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("\nr/c 0123456789ABCDEF\n");
|
|
||||||
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
|
|
||||||
phex(row); print(": ");
|
|
||||||
pbin_reverse16(matrix_get_row(row));
|
|
||||||
print("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t matrix_key_count(void)
|
|
||||||
{
|
|
||||||
uint8_t count = 0;
|
|
||||||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
|
||||||
count += bitpop16(matrix[i]);
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (DIODE_DIRECTION == COL2ROW)
|
|
||||||
|
|
||||||
static void init_cols(void)
|
|
||||||
{
|
|
||||||
for(uint8_t x = 0; x < MATRIX_COLS; x++) {
|
|
||||||
setPinInputHigh(col_pins[x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
|
|
||||||
{
|
|
||||||
// Store last value of row prior to reading
|
|
||||||
matrix_row_t last_row_value = current_matrix[current_row];
|
|
||||||
|
|
||||||
// Clear data in matrix row
|
|
||||||
current_matrix[current_row] = 0;
|
|
||||||
|
|
||||||
// Select row and wait for row selecton to stabilize
|
|
||||||
select_row(current_row);
|
|
||||||
wait_us(30);
|
|
||||||
|
|
||||||
// For each col...
|
|
||||||
for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
|
|
||||||
// Populate the matrix row with the state of the col pin
|
|
||||||
current_matrix[current_row] |= readPin(col_pins[col_index]) ? 0 : (ROW_SHIFTER << col_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unselect row
|
|
||||||
unselect_row(current_row);
|
|
||||||
|
|
||||||
return (last_row_value != current_matrix[current_row]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void select_row(uint8_t row)
|
|
||||||
{
|
|
||||||
writePinLow(row_pins[row]);
|
|
||||||
setPinOutput(row_pins[row]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unselect_row(uint8_t row)
|
|
||||||
{
|
|
||||||
setPinInputHigh(row_pins[row]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unselect_rows(void)
|
|
||||||
{
|
|
||||||
for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
|
|
||||||
setPinInputHigh(row_pins[x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
|
||||||
|
// Set row, read cols
|
||||||
|
for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
|
||||||
|
changed |= read_cols_on_row(raw_matrix, current_row);
|
||||||
|
}
|
||||||
#elif (DIODE_DIRECTION == ROW2COL)
|
#elif (DIODE_DIRECTION == ROW2COL)
|
||||||
|
// Set col, read rows
|
||||||
static void init_rows(void)
|
for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
|
||||||
{
|
changed |= read_rows_on_col(raw_matrix, current_col);
|
||||||
for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
|
}
|
||||||
setPinInputHigh(row_pins[x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
|
|
||||||
{
|
|
||||||
bool matrix_changed = false;
|
|
||||||
|
|
||||||
// Select col and wait for col selecton to stabilize
|
|
||||||
select_col(current_col);
|
|
||||||
wait_us(30);
|
|
||||||
|
|
||||||
// For each row...
|
|
||||||
for(uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Store last value of row prior to reading
|
|
||||||
matrix_row_t last_row_value = current_matrix[row_index];
|
|
||||||
|
|
||||||
// Check row pin state
|
|
||||||
if (readPin(row_pins[row_index]))
|
|
||||||
{
|
|
||||||
// Pin HI, clear col bit
|
|
||||||
current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Pin LO, set col bit
|
|
||||||
current_matrix[row_index] |= (ROW_SHIFTER << current_col);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if the matrix changed state
|
|
||||||
if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
|
|
||||||
{
|
|
||||||
matrix_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unselect col
|
|
||||||
unselect_col(current_col);
|
|
||||||
|
|
||||||
return matrix_changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void select_col(uint8_t col)
|
|
||||||
{
|
|
||||||
writePinLow(col_pins[col]);
|
|
||||||
setPinOutput(col_pins[col]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unselect_col(uint8_t col)
|
|
||||||
{
|
|
||||||
setPinInputHigh(col_pins[col]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unselect_cols(void)
|
|
||||||
{
|
|
||||||
for(uint8_t x = 0; x < MATRIX_COLS; x++) {
|
|
||||||
setPinInputHigh(col_pins[x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t matrix_scan(void) {
|
||||||
|
uint8_t ret = _matrix_scan();
|
||||||
|
|
||||||
|
if (is_keyboard_master()) {
|
||||||
|
static uint8_t error_count;
|
||||||
|
|
||||||
|
if (!transport_master(matrix + thatHand)) {
|
||||||
|
error_count++;
|
||||||
|
|
||||||
|
if (error_count > ERROR_DISCONNECT_COUNT) {
|
||||||
|
// reset other half if disconnected
|
||||||
|
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
||||||
|
matrix[thatHand + i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix_scan_quantum();
|
||||||
|
} else {
|
||||||
|
transport_slave(matrix + thisHand);
|
||||||
|
matrix_slave_scan_user();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,31 +1,3 @@
|
|||||||
#ifndef SPLIT_COMMON_MATRIX_H
|
#pragma once
|
||||||
#define SPLIT_COMMON_MATRIX_H
|
|
||||||
|
|
||||||
#include <common/matrix.h>
|
#include <common/matrix.h>
|
||||||
|
|
||||||
#ifdef RGBLIGHT_ENABLE
|
|
||||||
# include "rgblight.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct _Serial_m2s_buffer_t {
|
|
||||||
#ifdef BACKLIGHT_ENABLE
|
|
||||||
uint8_t backlight_level;
|
|
||||||
#endif
|
|
||||||
#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
|
|
||||||
rgblight_config_t rgblight_config; //not yet use
|
|
||||||
//
|
|
||||||
// When MCUs on both sides drive their respective RGB LED chains,
|
|
||||||
// it is necessary to synchronize, so it is necessary to communicate RGB information.
|
|
||||||
// In that case, define the RGBLIGHT_SPLIT macro.
|
|
||||||
//
|
|
||||||
// Otherwise, if the master side MCU drives both sides RGB LED chains,
|
|
||||||
// there is no need to communicate.
|
|
||||||
#endif
|
|
||||||
} Serial_m2s_buffer_t;
|
|
||||||
|
|
||||||
extern volatile Serial_m2s_buffer_t serial_m2s_buffer;
|
|
||||||
|
|
||||||
void serial_master_init(void);
|
|
||||||
void serial_slave_init(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef SOFT_SERIAL_H
|
#pragma once
|
||||||
#define SOFT_SERIAL_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@@ -61,5 +60,3 @@ int soft_serial_transaction(int sstd_index);
|
|||||||
#ifdef SERIAL_USE_MULTI_TRANSACTION
|
#ifdef SERIAL_USE_MULTI_TRANSACTION
|
||||||
int soft_serial_get_and_clean_status(int sstd_index);
|
int soft_serial_get_and_clean_status(int sstd_index);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* SOFT_SERIAL_H */
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
#ifndef SPLIT_FLAGS_H
|
#pragma once
|
||||||
#define SPLIT_FLAGS_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global Flags
|
* Global Flags
|
||||||
**/
|
**/
|
||||||
|
|
||||||
@@ -14,7 +13,3 @@ extern volatile bool RGB_DIRTY;
|
|||||||
|
|
||||||
//Backlight Stuff
|
//Backlight Stuff
|
||||||
extern volatile bool BACKLIT_DIRTY;
|
extern volatile bool BACKLIT_DIRTY;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -4,142 +4,84 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "split_flags.h"
|
#include "split_flags.h"
|
||||||
|
#include "transport.h"
|
||||||
#include "quantum.h"
|
#include "quantum.h"
|
||||||
|
|
||||||
#ifdef EE_HANDS
|
#ifdef EE_HANDS
|
||||||
# include "tmk_core/common/eeprom.h"
|
# include "tmk_core/common/eeprom.h"
|
||||||
#endif
|
# include "eeconfig.h"
|
||||||
|
|
||||||
#ifdef BACKLIGHT_ENABLE
|
|
||||||
# include "backlight.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(USE_I2C) || defined(EH)
|
|
||||||
# include "i2c.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
volatile bool isLeftHand = true;
|
volatile bool isLeftHand = true;
|
||||||
|
|
||||||
volatile uint8_t setTries = 0;
|
__attribute__((weak))
|
||||||
|
bool is_keyboard_left(void) {
|
||||||
static void setup_handedness(void) {
|
|
||||||
#ifdef SPLIT_HAND_PIN
|
#ifdef SPLIT_HAND_PIN
|
||||||
// Test pin SPLIT_HAND_PIN for High/Low, if low it's right hand
|
// Test pin SPLIT_HAND_PIN for High/Low, if low it's right hand
|
||||||
setPinInput(SPLIT_HAND_PIN);
|
setPinInput(SPLIT_HAND_PIN);
|
||||||
isLeftHand = readPin(SPLIT_HAND_PIN);
|
return readPin(SPLIT_HAND_PIN);
|
||||||
#else
|
#else
|
||||||
#ifdef EE_HANDS
|
#ifdef EE_HANDS
|
||||||
isLeftHand = eeprom_read_byte(EECONFIG_HANDEDNESS);
|
return eeprom_read_byte(EECONFIG_HANDEDNESS);
|
||||||
#else
|
#else
|
||||||
#ifdef MASTER_RIGHT
|
#ifdef MASTER_RIGHT
|
||||||
isLeftHand = !has_usb();
|
return !is_keyboard_master();
|
||||||
#else
|
#else
|
||||||
isLeftHand = has_usb();
|
return is_keyboard_master();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_keyboard_master(void)
|
||||||
|
{
|
||||||
|
#ifdef __AVR__
|
||||||
|
static enum { UNKNOWN, MASTER, SLAVE } usbstate = UNKNOWN;
|
||||||
|
|
||||||
|
// only check once, as this is called often
|
||||||
|
if (usbstate == UNKNOWN)
|
||||||
|
{
|
||||||
|
USBCON |= (1 << OTGPADE); // enables VBUS pad
|
||||||
|
wait_us(5);
|
||||||
|
|
||||||
|
usbstate = (USBSTA & (1 << VBUS)) ? MASTER : SLAVE; // checks state of VBUS
|
||||||
|
}
|
||||||
|
|
||||||
|
return (usbstate == MASTER);
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void keyboard_master_setup(void) {
|
static void keyboard_master_setup(void) {
|
||||||
#if defined(USE_I2C) || defined(EH)
|
#if defined(USE_I2C) || defined(EH)
|
||||||
i2c_master_init();
|
|
||||||
#ifdef SSD1306OLED
|
#ifdef SSD1306OLED
|
||||||
matrix_master_OLED_init ();
|
matrix_master_OLED_init ();
|
||||||
#endif
|
#endif
|
||||||
#else
|
|
||||||
serial_master_init();
|
|
||||||
#endif
|
#endif
|
||||||
|
transport_master_init();
|
||||||
|
|
||||||
// For master the Backlight info needs to be sent on startup
|
// For master the Backlight info needs to be sent on startup
|
||||||
// Otherwise the salve won't start with the proper info until an update
|
// Otherwise the salve won't start with the proper info until an update
|
||||||
BACKLIT_DIRTY = true;
|
BACKLIT_DIRTY = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboard_slave_setup(void) {
|
static void keyboard_slave_setup(void)
|
||||||
timer_init();
|
{
|
||||||
#if defined(USE_I2C) || defined(EH)
|
transport_slave_init();
|
||||||
i2c_slave_init(SLAVE_I2C_ADDRESS);
|
|
||||||
#else
|
|
||||||
serial_slave_init();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_usb(void) {
|
|
||||||
USBCON |= (1 << OTGPADE); //enables VBUS pad
|
|
||||||
_delay_us(5);
|
|
||||||
return (USBSTA & (1<<VBUS)); //checks state of VBUS
|
|
||||||
}
|
|
||||||
|
|
||||||
void split_keyboard_setup(void) {
|
|
||||||
setup_handedness();
|
|
||||||
|
|
||||||
if (has_usb()) {
|
|
||||||
keyboard_master_setup();
|
|
||||||
} else {
|
|
||||||
keyboard_slave_setup();
|
|
||||||
}
|
|
||||||
sei();
|
|
||||||
}
|
|
||||||
|
|
||||||
void keyboard_slave_loop(void) {
|
|
||||||
matrix_init();
|
|
||||||
|
|
||||||
//Init RGB
|
|
||||||
#ifdef RGBLIGHT_ENABLE
|
|
||||||
rgblight_init();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
// Matrix Slave Scan
|
|
||||||
matrix_slave_scan();
|
|
||||||
|
|
||||||
// Read Backlight Info
|
|
||||||
#ifdef BACKLIGHT_ENABLE
|
|
||||||
#ifdef USE_I2C
|
|
||||||
if (BACKLIT_DIRTY) {
|
|
||||||
backlight_set(i2c_slave_buffer[I2C_BACKLIT_START]);
|
|
||||||
BACKLIT_DIRTY = false;
|
|
||||||
}
|
|
||||||
#else // USE_SERIAL
|
|
||||||
backlight_set(serial_m2s_buffer.backlight_level);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
// Read RGB Info
|
|
||||||
#ifdef RGBLIGHT_ENABLE
|
|
||||||
#ifdef USE_I2C
|
|
||||||
if (RGB_DIRTY) {
|
|
||||||
// Disable interupts (RGB data is big)
|
|
||||||
cli();
|
|
||||||
// Create new DWORD for RGB data
|
|
||||||
uint32_t dword;
|
|
||||||
|
|
||||||
// Fill the new DWORD with the data that was sent over
|
|
||||||
uint8_t *dword_dat = (uint8_t *)(&dword);
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
dword_dat[i] = i2c_slave_buffer[I2C_RGB_START+i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the RGB now with the new data and set RGB_DIRTY to false
|
|
||||||
rgblight_update_dword(dword);
|
|
||||||
RGB_DIRTY = false;
|
|
||||||
// Re-enable interupts now that RGB is set
|
|
||||||
sei();
|
|
||||||
}
|
|
||||||
#else // USE_SERIAL
|
|
||||||
#ifdef RGBLIGHT_SPLIT
|
|
||||||
// Add serial implementation for RGB here
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this code runs before the usb and keyboard is initialized
|
// this code runs before the usb and keyboard is initialized
|
||||||
void matrix_setup(void) {
|
void matrix_setup(void)
|
||||||
split_keyboard_setup();
|
{
|
||||||
|
isLeftHand = is_keyboard_left();
|
||||||
|
|
||||||
if (!has_usb()) {
|
if (is_keyboard_master())
|
||||||
//rgblight_init();
|
{
|
||||||
keyboard_slave_loop();
|
keyboard_master_setup();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keyboard_slave_setup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,10 @@
|
|||||||
#ifndef SPLIT_KEYBOARD_UTIL_H
|
#pragma once
|
||||||
#define SPLIT_KEYBOARD_UTIL_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "eeconfig.h"
|
|
||||||
|
|
||||||
#define SLAVE_I2C_ADDRESS 0x32
|
|
||||||
|
|
||||||
extern volatile bool isLeftHand;
|
extern volatile bool isLeftHand;
|
||||||
|
|
||||||
// slave version of matix scan, defined in matrix.c
|
|
||||||
void matrix_slave_scan(void);
|
|
||||||
|
|
||||||
void split_keyboard_setup(void);
|
|
||||||
bool has_usb(void);
|
|
||||||
void keyboard_slave_loop(void);
|
|
||||||
|
|
||||||
void matrix_master_OLED_init (void);
|
void matrix_master_OLED_init (void);
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
#include "quantum.h"
|
||||||
|
|
||||||
|
#define ROWS_PER_HAND (MATRIX_ROWS/2)
|
||||||
|
|
||||||
|
#ifdef RGBLIGHT_ENABLE
|
||||||
|
# include "rgblight.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BACKLIGHT_ENABLE
|
||||||
|
# include "backlight.h"
|
||||||
|
extern backlight_config_t backlight_config;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_I2C) || defined(EH)
|
||||||
|
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
|
#ifndef SLAVE_I2C_ADDRESS
|
||||||
|
# define SLAVE_I2C_ADDRESS 0x32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (MATRIX_COLS > 8)
|
||||||
|
# error "Currently only supports 8 COLS"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Get rows from other half over i2c
|
||||||
|
bool transport_master(matrix_row_t matrix[]) {
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
// write backlight info
|
||||||
|
#ifdef BACKLIGHT_ENABLE
|
||||||
|
if (BACKLIT_DIRTY) {
|
||||||
|
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
|
||||||
|
if (err) { goto i2c_error; }
|
||||||
|
|
||||||
|
// Backlight location
|
||||||
|
err = i2c_master_write(I2C_BACKLIT_START);
|
||||||
|
if (err) { goto i2c_error; }
|
||||||
|
|
||||||
|
// Write backlight
|
||||||
|
i2c_master_write(get_backlight_level());
|
||||||
|
|
||||||
|
BACKLIT_DIRTY = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
|
||||||
|
if (err) { goto i2c_error; }
|
||||||
|
|
||||||
|
// start of matrix stored at I2C_KEYMAP_START
|
||||||
|
err = i2c_master_write(I2C_KEYMAP_START);
|
||||||
|
if (err) { goto i2c_error; }
|
||||||
|
|
||||||
|
// Start read
|
||||||
|
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ);
|
||||||
|
if (err) { goto i2c_error; }
|
||||||
|
|
||||||
|
if (!err) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ROWS_PER_HAND-1; ++i) {
|
||||||
|
matrix[i] = i2c_master_read(I2C_ACK);
|
||||||
|
}
|
||||||
|
matrix[i] = i2c_master_read(I2C_NACK);
|
||||||
|
i2c_master_stop();
|
||||||
|
} else {
|
||||||
|
i2c_error: // the cable is disconnceted, or something else went wrong
|
||||||
|
i2c_reset_state();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RGBLIGHT_ENABLE
|
||||||
|
if (RGB_DIRTY) {
|
||||||
|
err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
|
||||||
|
if (err) { goto i2c_error; }
|
||||||
|
|
||||||
|
// RGB Location
|
||||||
|
err = i2c_master_write(I2C_RGB_START);
|
||||||
|
if (err) { goto i2c_error; }
|
||||||
|
|
||||||
|
uint32_t dword = eeconfig_read_rgblight();
|
||||||
|
|
||||||
|
// Write RGB
|
||||||
|
err = i2c_master_write_data(&dword, 4);
|
||||||
|
if (err) { goto i2c_error; }
|
||||||
|
|
||||||
|
RGB_DIRTY = false;
|
||||||
|
i2c_master_stop();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transport_slave(matrix_row_t matrix[]) {
|
||||||
|
|
||||||
|
for (int i = 0; i < ROWS_PER_HAND; ++i)
|
||||||
|
{
|
||||||
|
i2c_slave_buffer[I2C_KEYMAP_START + i] = matrix[i];
|
||||||
|
}
|
||||||
|
// Read Backlight Info
|
||||||
|
#ifdef BACKLIGHT_ENABLE
|
||||||
|
if (BACKLIT_DIRTY)
|
||||||
|
{
|
||||||
|
backlight_set(i2c_slave_buffer[I2C_BACKLIT_START]);
|
||||||
|
BACKLIT_DIRTY = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef RGBLIGHT_ENABLE
|
||||||
|
if (RGB_DIRTY)
|
||||||
|
{
|
||||||
|
// Disable interupts (RGB data is big)
|
||||||
|
cli();
|
||||||
|
// Create new DWORD for RGB data
|
||||||
|
uint32_t dword;
|
||||||
|
|
||||||
|
// Fill the new DWORD with the data that was sent over
|
||||||
|
uint8_t * dword_dat = (uint8_t *)(&dword);
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
dword_dat[i] = i2c_slave_buffer[I2C_RGB_START + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the RGB now with the new data and set RGB_DIRTY to false
|
||||||
|
rgblight_update_dword(dword);
|
||||||
|
RGB_DIRTY = false;
|
||||||
|
// Re-enable interupts now that RGB is set
|
||||||
|
sei();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void transport_master_init(void) {
|
||||||
|
i2c_master_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void transport_slave_init(void) {
|
||||||
|
i2c_slave_init(SLAVE_I2C_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // USE_SERIAL
|
||||||
|
|
||||||
|
#include "serial.h"
|
||||||
|
|
||||||
|
typedef struct _Serial_s2m_buffer_t {
|
||||||
|
// TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack
|
||||||
|
matrix_row_t smatrix[ROWS_PER_HAND];
|
||||||
|
} Serial_s2m_buffer_t;
|
||||||
|
|
||||||
|
typedef struct _Serial_m2s_buffer_t {
|
||||||
|
#ifdef BACKLIGHT_ENABLE
|
||||||
|
uint8_t backlight_level;
|
||||||
|
#endif
|
||||||
|
#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
|
||||||
|
rgblight_config_t rgblight_config; //not yet use
|
||||||
|
//
|
||||||
|
// When MCUs on both sides drive their respective RGB LED chains,
|
||||||
|
// it is necessary to synchronize, so it is necessary to communicate RGB information.
|
||||||
|
// In that case, define the RGBLIGHT_SPLIT macro.
|
||||||
|
//
|
||||||
|
// Otherwise, if the master side MCU drives both sides RGB LED chains,
|
||||||
|
// there is no need to communicate.
|
||||||
|
#endif
|
||||||
|
} Serial_m2s_buffer_t;
|
||||||
|
|
||||||
|
volatile Serial_s2m_buffer_t serial_s2m_buffer = {};
|
||||||
|
volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
|
||||||
|
uint8_t volatile status0 = 0;
|
||||||
|
|
||||||
|
SSTD_t transactions[] = {
|
||||||
|
{ (uint8_t *)&status0,
|
||||||
|
sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer,
|
||||||
|
sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void transport_master_init(void)
|
||||||
|
{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); }
|
||||||
|
|
||||||
|
void transport_slave_init(void)
|
||||||
|
{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); }
|
||||||
|
|
||||||
|
bool transport_master(matrix_row_t matrix[]) {
|
||||||
|
|
||||||
|
if (soft_serial_transaction()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: if MATRIX_COLS > 8 change to unpack()
|
||||||
|
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
||||||
|
matrix[i] = serial_s2m_buffer.smatrix[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
|
||||||
|
// Code to send RGB over serial goes here (not implemented yet)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BACKLIGHT_ENABLE
|
||||||
|
// Write backlight level for slave to read
|
||||||
|
serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transport_slave(matrix_row_t matrix[]) {
|
||||||
|
|
||||||
|
// TODO: if MATRIX_COLS > 8 change to pack()
|
||||||
|
for (int i = 0; i < ROWS_PER_HAND; ++i)
|
||||||
|
{
|
||||||
|
serial_s2m_buffer.smatrix[i] = matrix[i];
|
||||||
|
}
|
||||||
|
#ifdef BACKLIGHT_ENABLE
|
||||||
|
backlight_set(serial_m2s_buffer.backlight_level);
|
||||||
|
#endif
|
||||||
|
#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
|
||||||
|
// Add serial implementation for RGB here
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common/matrix.h>
|
||||||
|
|
||||||
|
void transport_master_init(void);
|
||||||
|
void transport_slave_init(void);
|
||||||
|
|
||||||
|
// returns false if valid data not received from slave
|
||||||
|
bool transport_master(matrix_row_t matrix[]);
|
||||||
|
void transport_slave(matrix_row_t matrix[]);
|
||||||
@@ -46,6 +46,12 @@ void host_consumer_send(uint16_t data);
|
|||||||
uint16_t host_last_system_report(void);
|
uint16_t host_last_system_report(void);
|
||||||
uint16_t host_last_consumer_report(void);
|
uint16_t host_last_consumer_report(void);
|
||||||
|
|
||||||
|
#define IS_LED_ON(USB_LED, LED_NAME) ((USB_LED) & (1 << (LED_NAME)))
|
||||||
|
#define IS_LED_OFF(USB_LED, LED_NAME) (~(USB_LED) & (1 << (LED_NAME)))
|
||||||
|
|
||||||
|
#define IS_HOST_LED_ON(LED_NAME) IS_LED_ON(host_keyboard_leds(), (LED_NAME))
|
||||||
|
#define IS_HOST_LED_OFF(LED_NAME) IS_LED_OFF(host_keyboard_leds(), (LED_NAME))
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ void keyboard_init(void);
|
|||||||
void keyboard_task(void);
|
void keyboard_task(void);
|
||||||
/* it runs when host LED status is updated */
|
/* it runs when host LED status is updated */
|
||||||
void keyboard_set_leds(uint8_t leds);
|
void keyboard_set_leds(uint8_t leds);
|
||||||
|
/* it runs whenever code has to behave differently on a slave */
|
||||||
|
bool is_keyboard_master(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,6 +174,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define KC_BRIU KC_BRIGHTNESS_UP
|
#define KC_BRIU KC_BRIGHTNESS_UP
|
||||||
#define KC_BRID KC_BRIGHTNESS_DOWN
|
#define KC_BRID KC_BRIGHTNESS_DOWN
|
||||||
|
|
||||||
|
/* System Specific */
|
||||||
|
#define KC_BRMU KC_SCROLLLOCK
|
||||||
|
#define KC_BRMD KC_PAUSE
|
||||||
|
|
||||||
/* Mouse Keys */
|
/* Mouse Keys */
|
||||||
#define KC_MS_U KC_MS_UP
|
#define KC_MS_U KC_MS_UP
|
||||||
#define KC_MS_D KC_MS_DOWN
|
#define KC_MS_D KC_MS_DOWN
|
||||||
|
|||||||
Reference in new issue
Block a user