mirror of
https://github.com/qmk/qmk_firmware.git
synced 2026-10-02 06:49:16 +02:00
Asynchronous, robust serial protocol. (#39)
* bla personal ap2-c18 keymap. * Bidirectional, asynchronous message-based communication with Shine. - Requires a matching Shine version. - Protocol is resiliant to loosing bytes during communication, chips won't lock waiting for bytes that aren't coming. - Chips resynchronize in event of loosing a byte using a AA0D header. Regressions: - Key masking/locking doesn't work right now. (did it work before?) - Not all user keymaps build against it. * Clang-format + code to ease reducing speed of LED UART. - Did clang-format --style=file -i on multiple files according to coding_conventions_c.md - Added separate serial speed for IAP boot and Led communication, it's possible that reducing this to 9600 helped someone with faulty HW. With this code they can do it with simple replacing of a value. * Main chip can set/clear foreground using a mask mechanism. - Some preparations for selective colouring. * Selective mask works - tested on capslock. - Migrated personal keymaps to new status API. * Clear the foreground colors to show profile when it's modified. - Show example of achieving selective caps-lock painting + foreground painting for layers. - annepro2LedMaskSetRow is implemented, but still requires testing. * Implement the QMK side of led blinking to indicate the command was received. - This stupidly blinks the key when user presses one of the bluetooth commands to let the user know that the command was received and forwarded to the BT chip. - TODO: Row/col key positions are hardcoded and not taken from the keymap. * Reduce memory footprint. Applying code review suggestions. Moved msgId to globals - preparing for transmission without copying payload when no retries are necessary. Added empty readme.md files - required by QMK lint. Co-authored-by: Tomasz bla Fortuna <bla@thera.be>
This commit is contained in:
committed by
bwisn
co-authored by
Tomasz bla Fortuna
parent
1637c81d9c
commit
f771cb545f
@@ -4,35 +4,31 @@
|
||||
#include "annepro2_ble.h"
|
||||
#include "spi_master.h"
|
||||
#include "qmk_ap2_led.h"
|
||||
#include "protocol.h"
|
||||
|
||||
static const SerialConfig ledUartConfig = {
|
||||
.speed = 115200,
|
||||
static const SerialConfig ledUartInitConfig = {
|
||||
.speed = 115200,
|
||||
};
|
||||
|
||||
/*
|
||||
* Some people have serial issues between main chip and led chip.
|
||||
* This code allows them to easily reduce the speed to 9600 for testing
|
||||
*/
|
||||
static const SerialConfig ledUartRuntimeConfig = {
|
||||
.speed = 115200,
|
||||
};
|
||||
|
||||
static const SerialConfig bleUartConfig = {
|
||||
.speed = 115200,
|
||||
.speed = 115200,
|
||||
};
|
||||
|
||||
static uint8_t ledMcuWakeup[11] = {
|
||||
0x7b, 0x10, 0x43, 0x10, 0x03, 0x00, 0x00, 0x7d, 0x02, 0x01, 0x02
|
||||
};
|
||||
|
||||
static bool ledEnabled = false;
|
||||
static uint8_t ledMcuWakeup[11] = {0x7b, 0x10, 0x43, 0x10, 0x03, 0x00, 0x00, 0x7d, 0x02, 0x01, 0x02};
|
||||
|
||||
ble_capslock_t BLECapsLock = {._dummy = {0}, .caps_lock = false};
|
||||
|
||||
uint16_t annepro2LedMatrix[MATRIX_ROWS * MATRIX_COLS] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
};
|
||||
|
||||
void OVERRIDE bootloader_jump(void) {
|
||||
|
||||
// Send msg to shine to boot into IAP
|
||||
sdPut(&SD0, CMD_LED_IAP);
|
||||
annepro2SetIAP();
|
||||
|
||||
// wait for shine to boot into IAP
|
||||
wait_ms(15);
|
||||
@@ -42,7 +38,7 @@ void OVERRIDE bootloader_jump(void) {
|
||||
wait_ms(15);
|
||||
|
||||
// Magic key to set keyboard to IAP
|
||||
*((uint32_t*)0x20001ffc) = 0x0000fab2;
|
||||
*((uint32_t *)0x20001ffc) = 0x0000fab2;
|
||||
|
||||
// Load the main MCU into IAP
|
||||
__disable_irq();
|
||||
@@ -53,20 +49,21 @@ void OVERRIDE keyboard_pre_init_kb(void) {
|
||||
#if HAL_USE_SPI == TRUE
|
||||
spi_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OVERRIDE keyboard_post_init_kb(void) {
|
||||
// Start LED UART
|
||||
sdStart(&SD0, &ledUartConfig);
|
||||
sdStart(&SD0, &ledUartInitConfig);
|
||||
sdWrite(&SD0, ledMcuWakeup, 11);
|
||||
|
||||
// wait to receive response from wakeup
|
||||
wait_ms(15);
|
||||
|
||||
// loop to clear out receive buffer from shine wakeup
|
||||
while(!sdGetWouldBlock(&SD0))
|
||||
sdGet(&SD0);
|
||||
protoInit(&proto, ledCommandCallback);
|
||||
|
||||
// loop to clear out receive buffer from shine wakeup
|
||||
while (!sdGetWouldBlock(&SD0)) sdGet(&SD0);
|
||||
|
||||
sdStart(&SD0, &ledUartRuntimeConfig);
|
||||
}
|
||||
|
||||
void OVERRIDE keyboard_post_init_kb(void) {
|
||||
// Start BLE UART
|
||||
sdStart(&SD1, &bleUartConfig);
|
||||
annepro2_ble_startup();
|
||||
@@ -76,30 +73,34 @@ void OVERRIDE keyboard_post_init_kb(void) {
|
||||
wait_ms(15);
|
||||
|
||||
// loop to clear out receive buffer from ble wakeup
|
||||
while(!sdGetWouldBlock(&SD1))
|
||||
sdGet(&SD1);
|
||||
while (!sdGetWouldBlock(&SD1)) sdGet(&SD1);
|
||||
|
||||
annepro2LedGetStatus();
|
||||
|
||||
keyboard_post_init_user();
|
||||
}
|
||||
|
||||
void OVERRIDE matrix_init_kb(void) {
|
||||
matrix_init_user();
|
||||
}
|
||||
void OVERRIDE matrix_init_kb(void) { matrix_init_user(); }
|
||||
|
||||
void matrix_scan_kb() {
|
||||
// if there's stuff on the ble serial buffer
|
||||
// read it into the capslock struct
|
||||
while(!sdGetWouldBlock(&SD1)) {
|
||||
sdReadTimeout(&SD1, (uint8_t *) &BLECapsLock, sizeof(ble_capslock_t), 10);
|
||||
while (!sdGetWouldBlock(&SD1)) {
|
||||
sdReadTimeout(&SD1, (uint8_t *)&BLECapsLock, sizeof(ble_capslock_t), 10);
|
||||
|
||||
// if it's capslock from ble, darken led
|
||||
if (BLECapsLock.caps_lock) {
|
||||
annepro2LedClearMask(MATRIX_COLS * 2);
|
||||
// annepro2LedClearMask(MATRIX_COLS * 2);
|
||||
} else {
|
||||
annepro2LedSetMask(MATRIX_COLS * 2);
|
||||
// annepro2LedSetMask(MATRIX_COLS * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* While there's data from LED keyboard sent - read it. */
|
||||
while (!sdGetWouldBlock(&SD0)) {
|
||||
uint8_t byte = sdGet(&SD0);
|
||||
protoConsume(&proto, byte);
|
||||
}
|
||||
|
||||
matrix_scan_user();
|
||||
}
|
||||
@@ -109,25 +110,37 @@ void matrix_scan_kb() {
|
||||
*/
|
||||
bool OVERRIDE process_record_kb(uint16_t keycode, keyrecord_t *record) {
|
||||
if (record->event.pressed) {
|
||||
if (AP2_LED_ENABLED && AP2_LED_DYNAMIC_PROFILE && !AP2_FOREGROUND_COLOR_SET) {
|
||||
if (annepro2LedStatus.matrixEnabled && annepro2LedStatus.isReactive) {
|
||||
annepro2LedForwardKeypress(record->event.key.row, record->event.key.col);
|
||||
}
|
||||
|
||||
const annepro2Led_t blue = {
|
||||
.p.blue = 0xff,
|
||||
.p.red = 0x00,
|
||||
.p.green = 0x00,
|
||||
.p.alpha = 0xff,
|
||||
};
|
||||
|
||||
switch (keycode) {
|
||||
case KC_AP2_BT1:
|
||||
annepro2_ble_broadcast(0);
|
||||
/* FIXME: This hardcodes col/row position */
|
||||
annepro2LedBlink(0, 1, blue, 8, 50);
|
||||
return false;
|
||||
|
||||
case KC_AP2_BT2:
|
||||
annepro2_ble_broadcast(1);
|
||||
annepro2LedBlink(0, 2, blue, 8, 50);
|
||||
return false;
|
||||
|
||||
case KC_AP2_BT3:
|
||||
annepro2_ble_broadcast(2);
|
||||
annepro2LedBlink(0, 3, blue, 8, 50);
|
||||
return false;
|
||||
|
||||
case KC_AP2_BT4:
|
||||
annepro2_ble_broadcast(3);
|
||||
annepro2LedBlink(0, 4, blue, 8, 50);
|
||||
return false;
|
||||
|
||||
case KC_AP2_USB:
|
||||
@@ -140,31 +153,35 @@ bool OVERRIDE process_record_kb(uint16_t keycode, keyrecord_t *record) {
|
||||
|
||||
case KC_AP_LED_OFF:
|
||||
annepro2LedDisable();
|
||||
ledEnabled = false;
|
||||
break;
|
||||
|
||||
case KC_AP_LED_ON:
|
||||
if (ledEnabled) {
|
||||
if (annepro2LedStatus.matrixEnabled) {
|
||||
annepro2LedNextProfile();
|
||||
} else {
|
||||
ledEnabled = true;
|
||||
annepro2LedEnable();
|
||||
}
|
||||
annepro2LedResetForegroundColor();
|
||||
break;
|
||||
|
||||
case KC_AP_LED_NEXT_PROFILE:
|
||||
annepro2LedNextProfile();
|
||||
annepro2LedResetForegroundColor();
|
||||
break;
|
||||
|
||||
case KC_AP_LED_PREV_PROFILE:
|
||||
annepro2LedPrevProfile();
|
||||
annepro2LedResetForegroundColor();
|
||||
break;
|
||||
|
||||
case KC_AP_LED_NEXT_INTENSITY:
|
||||
annepro2LedNextIntensity();
|
||||
annepro2LedResetForegroundColor();
|
||||
return false;
|
||||
|
||||
case KC_AP_LED_SPEED:
|
||||
annepro2LedNextAnimationSpeed();
|
||||
annepro2LedResetForegroundColor();
|
||||
return false;
|
||||
|
||||
default:
|
||||
@@ -172,4 +189,4 @@ bool OVERRIDE process_record_kb(uint16_t keycode, keyrecord_t *record) {
|
||||
}
|
||||
}
|
||||
return process_record_user(keycode, record);
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,11 @@
|
||||
#pragma once
|
||||
#include "quantum.h"
|
||||
|
||||
#define OVERRIDE __attribute__ ((noinline))
|
||||
#define OVERRIDE __attribute__((noinline))
|
||||
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint8_t _dummy[10];
|
||||
bool caps_lock;
|
||||
bool caps_lock;
|
||||
} ble_capslock_t;
|
||||
|
||||
extern uint16_t annepro2LedMatrix[MATRIX_ROWS * MATRIX_COLS];
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
AnnePro2, ANSI C15 version.
|
||||
@@ -3,7 +3,8 @@ SRC = \
|
||||
matrix.c \
|
||||
hardfault_handler.c \
|
||||
annepro2_ble.c \
|
||||
qmk_ap2_led.c
|
||||
qmk_ap2_led.c \
|
||||
protocol.c
|
||||
|
||||
LAYOUTS +=
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
// #define NO_DEBUG
|
||||
|
||||
/* disable print */
|
||||
// #define NO_PRINTg
|
||||
// #define NO_PRINT
|
||||
|
||||
/* disable action features */
|
||||
//#define NO_ACTION_LAYER
|
||||
@@ -192,4 +192,3 @@
|
||||
//#define NO_ACTION_ONESHOT
|
||||
//#define NO_ACTION_MACRO
|
||||
//#define NO_ACTION_FUNCTION
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
AnnePro2, ANSI C18 version.
|
||||
@@ -3,7 +3,8 @@ SRC = \
|
||||
matrix.c \
|
||||
hardfault_handler.c \
|
||||
annepro2_ble.c \
|
||||
qmk_ap2_led.c
|
||||
qmk_ap2_led.c \
|
||||
protocol.c
|
||||
|
||||
ifeq ($(strip $(ANNEPRO2_EEPROM)), yes)
|
||||
OPT_DEFS += -DANNEPRO2_EEPROM
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
// Obins stock firmware has something similar to this already enabled, but disabled by default in QMK
|
||||
#define PERMISSIVE_HOLD
|
||||
@@ -0,0 +1,157 @@
|
||||
#include <stdint.h>
|
||||
#include "annepro2.h"
|
||||
#include "qmk_ap2_led.h"
|
||||
#include "config.h"
|
||||
|
||||
enum anne_pro_layers {
|
||||
_BASE_LAYER,
|
||||
_FN1_LY,
|
||||
_FN2_LY,
|
||||
};
|
||||
|
||||
// Key symbols are based on QMK. Use them to remap your keyboard
|
||||
/*
|
||||
* Layer _BASE_LAYER
|
||||
* ,-----------------------------------------------------------------------------------------.
|
||||
* | esc | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | Bksp |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Tab | q | w | e | r | t | y | u | i | o | p | [ | ] | \ |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Ctrl/Bks| a | s | d | f | g | h | j | k | l | ; | ' | Enter |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Shift | z | x | c | v | b | n | m | , | . | / | Shift |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
|
||||
* \-----------------------------------------------------------------------------------------/
|
||||
* Layer TAP in _BASE_LAYER
|
||||
* ,-----------------------------------------------------------------------------------------.
|
||||
* | | | | | | | | | | | | | | |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | | | | | | | | | | | | | | |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Bksp | | | | | | | | | | | | |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | | | | | | | | | | | | UP |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | | `~ | | | | LEFT | DOWN | RIGHT |
|
||||
* \-----------------------------------------------------------------------------------------/
|
||||
*/
|
||||
const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[_BASE_LAYER] = KEYMAP( /* Base */
|
||||
KC_ESC, 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_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,
|
||||
MT(MOD_LCTL, KC_ESC), 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, RSFT_T(KC_UP),
|
||||
KC_LCTL, MT(MOD_LGUI, KC_GRV), KC_LALT, KC_SPC, KC_RALT, LT(_FN1_LY,KC_LEFT), LT(_FN2_LY,KC_DOWN), RCTL_T(KC_RGHT)
|
||||
),
|
||||
/*
|
||||
* Layer _FN1_LY
|
||||
* ,-----------------------------------------------------------------------------------------.
|
||||
* | ` | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | MEDIA PLAY|
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Tab | q | UP | e | 7 | 8 | 9 | u | i | o | PS | HOME | END | \ |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | |LEFT |DOWN |RIGHT| 4 | 5 | 6 | j | k | l | PGUP|PGDN | Enter |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | LayerHold? |V-UP |V-DWN|MUTE | 1 | 2 | 3 | m | , |INSRT| DEL | Shift |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Ctrl | L1 | Alt | 0 | Alt | FN1 | FN2 | Ctrl |
|
||||
* \-----------------------------------------------------------------------------------------/
|
||||
*
|
||||
*/
|
||||
[_FN1_LY] = KEYMAP( /* Base */
|
||||
KC_GRV, 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_MEDIA_PLAY_PAUSE,
|
||||
KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_7, KC_8, KC_9, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_HOME, KC_END, KC_TRNS,
|
||||
MO(_FN2_LY), KC_LEFT, KC_DOWN, KC_RGHT, KC_4, KC_5, KC_6, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_PGDN, KC_TRNS,
|
||||
KC_TRNS, KC_VOLU, KC_VOLD, KC_MUTE, KC_1, KC_2, KC_3, KC_TRNS, KC_TRNS, KC_INS, KC_DEL, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_0, KC_TRNS, KC_TRNS, MO(_FN2_LY), KC_TRNS
|
||||
),
|
||||
/*
|
||||
* Layer _FN2_LY
|
||||
* ,-----------------------------------------------------------------------------------------.
|
||||
* | ~ | BT1 | BT2 | BT3 | BT4 | F5 | F6 | F7 |LEDOF|LEDON| F10 | F11 | F12 | MEDIA PLAY|
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Tab | q | UP | e | r | t | y | u | i | o | PS | HOME | END | \ |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Esc |LEFT |DOWN |RIGHT| f | g | h | j | k | l | PGUP|PGDN | Enter |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Shift | z | x | c | v | b | n | m | , |INSRT| DEL | Shift |
|
||||
* |-----------------------------------------------------------------------------------------+
|
||||
* | Ctrl | L1 | Alt | space | Alt | FN1 | FN2 | Ctrl |
|
||||
* \-----------------------------------------------------------------------------------------/
|
||||
*
|
||||
*/
|
||||
[_FN2_LY] = KEYMAP( /* Base */
|
||||
KC_TRNS, KC_AP2_BT1, KC_AP2_BT2, KC_AP2_BT3, KC_AP2_BT4, KC_TRNS, KC_TRNS, KC_TRNS, KC_AP_LED_OFF, KC_AP_LED_ON, KC_AP_LED_NEXT_INTENSITY, KC_AP_LED_SPEED, KC_TRNS, KC_MEDIA_PLAY_PAUSE,
|
||||
MO(_FN2_LY), KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_HOME, KC_END, KC_TRNS,
|
||||
KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_PGDN, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_INS, KC_DEL, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, MO(_FN1_LY), MO(_FN2_LY), KC_TRNS
|
||||
),
|
||||
};
|
||||
const uint16_t keymaps_size = sizeof(keymaps);
|
||||
|
||||
|
||||
void matrix_init_user(void) {
|
||||
}
|
||||
|
||||
void matrix_scan_user(void) {
|
||||
}
|
||||
|
||||
// Code to run after initializing the keyboard
|
||||
void keyboard_post_init_user(void) {
|
||||
// Here are two common functions that you can use. For more LED functions, refer to the file "qmk_ap2_led.h"
|
||||
|
||||
// annepro2-shine disables LEDs by default. Uncomment this function to enable them at startup.
|
||||
// annepro2LedEnable();
|
||||
|
||||
// Additionally, it also chooses the first LED profile by default. Refer to the "profiles" array in main.c in
|
||||
// annepro2-shine to see the order. Replace "i" with the index of your preferred profile. (i.e the RED profile is index 0)
|
||||
// annepro2LedSetProfile(i);
|
||||
debug_enable=true;
|
||||
}
|
||||
|
||||
layer_state_t layer_state_set_user(layer_state_t layer) {
|
||||
switch(get_highest_layer(layer)) {
|
||||
case _FN1_LY:
|
||||
// Set the leds to green
|
||||
annepro2LedSetForegroundColor(0x00, 0xFF, 0x00);
|
||||
break;
|
||||
case _FN2_LY:
|
||||
// Set the leds to blue
|
||||
annepro2LedSetForegroundColor(0x00, 0x00, 0xFF);
|
||||
break;
|
||||
default:
|
||||
// Reset back to the current profile
|
||||
annepro2LedResetForegroundColor();
|
||||
break;
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
|
||||
// The function to handle the caps lock logic. It's executed after caps or layer
|
||||
// changes state, after layer_state_set_user.
|
||||
bool led_update_user(led_t leds) {
|
||||
if (leds.caps_lock) {
|
||||
const annepro2Led_t color = {
|
||||
.p.red = 0xff,
|
||||
.p.green = 0x00,
|
||||
.p.blue = 0x00,
|
||||
.p.alpha = 0xff
|
||||
};
|
||||
|
||||
annepro2LedMaskSetKey(2, 0, color);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!layer_state_is(_FN1_LY) && !layer_state_is(_FN2_LY)) {
|
||||
const annepro2Led_t color = {
|
||||
.p.red = 0xff,
|
||||
.p.green = 0x00,
|
||||
.p.blue = 0x00,
|
||||
.p.alpha = 0x00
|
||||
};
|
||||
annepro2LedMaskSetKey(2, 0, color);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -130,17 +130,32 @@ layer_state_t layer_state_set_user(layer_state_t layer) {
|
||||
}
|
||||
|
||||
// The function to handle the caps lock logic
|
||||
// It's called after the capslock changes state or after entering layers 1 and 2.
|
||||
bool led_update_user(led_t leds) {
|
||||
if (leds.caps_lock) {
|
||||
// Set the leds to red
|
||||
annepro2LedSetForegroundColor(0xFF, 0x00, 0x00);
|
||||
// Set the caps-lock to red
|
||||
const annepro2Led_t color = {
|
||||
.p.red = 0xff,
|
||||
.p.green = 0x00,
|
||||
.p.blue = 0x00,
|
||||
.p.alpha = 0xff
|
||||
};
|
||||
|
||||
annepro2LedMaskSetKey(2, 0, color);
|
||||
/* NOTE: Instead of colouring the capslock only, you can change the whole
|
||||
keyboard with annepro2LedSetForegroundColor */
|
||||
} else {
|
||||
// Reset back to the current profile if there is no layer active
|
||||
// Reset the capslock if there is no layer active
|
||||
if(!layer_state_is(_FN1_LAYER) && !layer_state_is(_FN2_LAYER)) {
|
||||
annepro2LedResetForegroundColor();
|
||||
const annepro2Led_t color = {
|
||||
.p.red = 0xff,
|
||||
.p.green = 0x00,
|
||||
.p.blue = 0x00,
|
||||
.p.alpha = 0x00
|
||||
};
|
||||
annepro2LedMaskSetKey(2, 0, color);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,6 @@ typedef union {
|
||||
// define out default user_config
|
||||
user_config_t user_config = {.magic = 0xDE, .leds_on = 0, .leds_profile = 0};
|
||||
|
||||
// keep the number of profiles so we can track along with the shine proc
|
||||
uint8_t numProfiles = 0;
|
||||
|
||||
static uint8_t usb_buf[256];
|
||||
static uint8_t buf_fil = 0;
|
||||
|
||||
@@ -165,7 +162,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t* record)
|
||||
return false;
|
||||
case KC_AP_LED_NEXT_PROFILE:
|
||||
if (record->event.pressed) {
|
||||
user_config.leds_profile = (user_config.leds_profile + 1) % numProfiles;
|
||||
user_config.leds_profile = (user_config.leds_profile + 1) % annepro2LedStatus.amountOfProfiles;
|
||||
annepro2LedSetProfile(user_config.leds_profile);
|
||||
eeprom_write((void*)&user_config, 0, sizeof(user_config_t));
|
||||
}
|
||||
@@ -206,6 +203,4 @@ void keyboard_post_init_user(void)
|
||||
annepro2LedDisable();
|
||||
}
|
||||
#endif
|
||||
|
||||
numProfiles = annepro2LedGetNumProfiles();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ SRC = \
|
||||
matrix.c \
|
||||
hardfault_handler.c \
|
||||
annepro2_ble.c \
|
||||
qmk_ap2_led.c
|
||||
qmk_ap2_led.c \
|
||||
protocol.c
|
||||
|
||||
ifeq ($(strip $(ANNEPRO2_EEPROM)), yes)
|
||||
OPT_DEFS += -DANNEPRO2_EEPROM
|
||||
@@ -44,4 +45,3 @@ RAW_ENABLE = yes
|
||||
MIDI_ENABLE = no
|
||||
VIRTSER_ENABLE = no
|
||||
COMBO_ENABLE = no
|
||||
|
||||
|
||||
+11
-13
@@ -27,7 +27,7 @@
|
||||
|
||||
static matrix_row_t matrix[MATRIX_ROWS];
|
||||
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
|
||||
static uint32_t debounce_times[MATRIX_ROWS];
|
||||
static uint32_t debounce_times[MATRIX_ROWS];
|
||||
|
||||
extern ioline_t row_list[MATRIX_ROWS];
|
||||
extern ioline_t col_list[MATRIX_COLS];
|
||||
@@ -45,7 +45,10 @@ uint8_t matrix_scan(void) {
|
||||
// scan each row
|
||||
for (int row = 0; row < MATRIX_ROWS; row++) {
|
||||
palClearLine(row_list[row]);
|
||||
__NOP(); __NOP(); __NOP(); __NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
// read i/o ports
|
||||
port_cache[0] = palReadPort(IOPORTA);
|
||||
port_cache[1] = palReadPort(IOPORTB);
|
||||
@@ -67,10 +70,10 @@ uint8_t matrix_scan(void) {
|
||||
if (matrix_debouncing[row] != data) {
|
||||
// whenever row changes restart debouncing
|
||||
matrix_debouncing[row] = data;
|
||||
debounce_times[row] = timer_read32();
|
||||
} else if(debounce_times[row] && timer_elapsed32(debounce_times[row]) >= DEBOUNCE){
|
||||
debounce_times[row] = timer_read32();
|
||||
} else if (debounce_times[row] && timer_elapsed32(debounce_times[row]) >= DEBOUNCE) {
|
||||
// when debouncing complete, update matrix
|
||||
matrix[row] = matrix_debouncing[row];
|
||||
matrix[row] = matrix_debouncing[row];
|
||||
debounce_times[row] = 0;
|
||||
}
|
||||
}
|
||||
@@ -79,13 +82,8 @@ uint8_t matrix_scan(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool matrix_is_on(uint8_t row, uint8_t col) {
|
||||
return (matrix[row] & (1 << col));
|
||||
}
|
||||
bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & (1 << col)); }
|
||||
|
||||
matrix_row_t matrix_get_row(uint8_t row) {
|
||||
return matrix[row];
|
||||
}
|
||||
matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; }
|
||||
|
||||
void matrix_print(void) {
|
||||
}
|
||||
void matrix_print(void) {}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* (c) 2021 by Tomasz bla Fortuna
|
||||
* License: GPLv2
|
||||
*
|
||||
* This file is shared with the Shine firmware. Keep it in sync (and in the
|
||||
* shine's clang formatting).
|
||||
*
|
||||
* Implementation of a robust serial protocol which can handle single dropped
|
||||
* characters during transit without locking.
|
||||
*
|
||||
* At 115200, transmitting the shortest message takes 0.043ms, at 9600 - 0.52ms.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "protocol.h"
|
||||
#include "board.h"
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
/* UART communication protocol state */
|
||||
protocol_t proto;
|
||||
|
||||
void protoInit(protocol_t *proto, void (*callback)(const message_t *)) {
|
||||
proto->previousId = 0;
|
||||
proto->callback = callback;
|
||||
proto->state = STATE_SYNC_1;
|
||||
proto->errors = 0;
|
||||
}
|
||||
|
||||
static uint8_t msgId = 0;
|
||||
void protoTx(uint8_t cmd, const unsigned char *buf, int payloadSize,
|
||||
int retries) {
|
||||
chDbgCheck(payloadSize <= MAX_PAYLOAD_SIZE);
|
||||
|
||||
const uint8_t header[5] = {
|
||||
0x7A, 0x1D, cmd, ++msgId, payloadSize,
|
||||
};
|
||||
|
||||
/* We don't implement ACKs, yet some messages should not be lost. */
|
||||
for (int i = 0; i < retries; i++) {
|
||||
sdWrite(&PROTOCOL_SD, header, sizeof(header));
|
||||
if (payloadSize)
|
||||
sdWrite(&PROTOCOL_SD, buf, payloadSize);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void messageReceived(protocol_t *proto) {
|
||||
if (proto->buffer.msgId != proto->previousId) {
|
||||
/* It's not a resend / duplicate */
|
||||
proto->callback(&proto->buffer);
|
||||
proto->previousId = proto->buffer.msgId;
|
||||
}
|
||||
proto->state = STATE_SYNC_1;
|
||||
}
|
||||
|
||||
void protoConsume(protocol_t *proto, uint8_t byte) {
|
||||
switch (proto->state) {
|
||||
case STATE_SYNC_1:
|
||||
if (byte == 0x7A) {
|
||||
proto->state = STATE_SYNC_2;
|
||||
} else {
|
||||
proto->errors++;
|
||||
}
|
||||
return;
|
||||
|
||||
case STATE_SYNC_2:
|
||||
if (byte == 0x1D) {
|
||||
proto->state = STATE_CMD;
|
||||
} else {
|
||||
proto->state = STATE_SYNC_1;
|
||||
proto->errors++;
|
||||
}
|
||||
return;
|
||||
|
||||
case STATE_CMD:
|
||||
proto->buffer.command = byte;
|
||||
proto->state = STATE_ID;
|
||||
return;
|
||||
|
||||
case STATE_ID:
|
||||
proto->buffer.msgId = byte;
|
||||
proto->state = STATE_PAYLOAD_SIZE;
|
||||
return;
|
||||
|
||||
case STATE_PAYLOAD_SIZE:
|
||||
proto->buffer.payloadSize = byte;
|
||||
if (proto->buffer.payloadSize > MAX_PAYLOAD_SIZE) {
|
||||
proto->buffer.payloadSize = MAX_PAYLOAD_SIZE;
|
||||
proto->errors++;
|
||||
}
|
||||
proto->payloadPosition = 0;
|
||||
if (proto->buffer.payloadSize == 0) {
|
||||
/* No payload - whole message received */
|
||||
messageReceived(proto);
|
||||
} else {
|
||||
proto->state = STATE_PAYLOAD;
|
||||
}
|
||||
return;
|
||||
|
||||
case STATE_PAYLOAD:
|
||||
/* NOTE: This could be read with sdReadTimeout probably, but that breaks
|
||||
* abstraction */
|
||||
proto->buffer.payload[proto->payloadPosition] = byte;
|
||||
proto->payloadPosition++;
|
||||
if (proto->payloadPosition == proto->buffer.payloadSize) {
|
||||
/* Payload read - message received */
|
||||
messageReceived(proto);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void protoSilence(protocol_t *proto) {
|
||||
if (proto->state != STATE_SYNC_1) {
|
||||
proto->state = STATE_SYNC_1;
|
||||
proto->errors++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* (c) 2021 by Tomasz bla Fortuna
|
||||
* License: GPLv2
|
||||
*
|
||||
* This file is shared with the Shine firmware. Keep it in sync (and in the
|
||||
* shine's clang formatting).
|
||||
*/
|
||||
|
||||
#ifndef PROTOCOL_INCLUDED
|
||||
#define PROTOCOL_INCLUDED
|
||||
#include <inttypes.h>
|
||||
|
||||
#define PROTOCOL_SD SD0
|
||||
|
||||
enum {
|
||||
/*
|
||||
* Main -> LED
|
||||
*/
|
||||
/* Basic config */
|
||||
CMD_LED_ON = 0x01,
|
||||
CMD_LED_OFF = 0x02,
|
||||
|
||||
CMD_LED_SET_PROFILE = 0x03,
|
||||
CMD_LED_NEXT_PROFILE = 0x04,
|
||||
CMD_LED_PREV_PROFILE = 0x05,
|
||||
|
||||
CMD_LED_NEXT_INTENSITY = 0x06,
|
||||
CMD_LED_NEXT_ANIMATION_SPEED = 0x07,
|
||||
|
||||
/* Masks */
|
||||
/* Override a key color, eg. capslock */
|
||||
CMD_LED_MASK_SET_KEY = 0x10,
|
||||
/* Override all keys in a row with configurable colors */
|
||||
CMD_LED_MASK_SET_ROW = 0x11,
|
||||
|
||||
/* Override all keys with single color (eg. foreground color) */
|
||||
CMD_LED_MASK_SET_MONO = 0x12,
|
||||
|
||||
/* Reactive / status */
|
||||
CMD_LED_GET_STATUS = 0x20,
|
||||
CMD_LED_KEY_BLINK = 0x21,
|
||||
CMD_LED_KEY_DOWN = 0x22,
|
||||
CMD_LED_KEY_UP = 0x23, /* TODO */
|
||||
CMD_LED_IAP = 0x24,
|
||||
|
||||
/* LED -> Main */
|
||||
/* Payload with data to send over HID */
|
||||
CMD_LED_DEBUG = 0x40,
|
||||
|
||||
/* Number of profiles, current profile, on/off state,
|
||||
reactive flag, brightness, errors */
|
||||
CMD_LED_STATUS = 0x41,
|
||||
};
|
||||
|
||||
/* 1 ROW * 14 COLS * 4B (RGBX) = 56 + header prefix. */
|
||||
#define MAX_PAYLOAD_SIZE 64
|
||||
|
||||
/** Enum of the states used for the serial protocol finite-state automaton */
|
||||
enum protoState {
|
||||
/* 2-byte initial start-of-message sync */
|
||||
STATE_SYNC_1,
|
||||
STATE_SYNC_2,
|
||||
/* Waiting for command byte */
|
||||
STATE_CMD,
|
||||
/* Waiting for ID byte */
|
||||
STATE_ID,
|
||||
/* Waiting for payload size */
|
||||
STATE_PAYLOAD_SIZE,
|
||||
/* Reading payload until payloadPosition == payloadSize */
|
||||
STATE_PAYLOAD,
|
||||
};
|
||||
|
||||
/* Buffer holding a single message */
|
||||
typedef struct {
|
||||
uint8_t command;
|
||||
uint8_t msgId;
|
||||
uint8_t payloadSize;
|
||||
uint8_t payload[MAX_PAYLOAD_SIZE];
|
||||
} message_t;
|
||||
|
||||
/* Internal protocol state */
|
||||
typedef struct {
|
||||
/* Callback to call upon receiving a valid message */
|
||||
void (*callback)(const message_t *);
|
||||
|
||||
/* Number of read payload bytes */
|
||||
uint8_t payloadPosition;
|
||||
|
||||
/* Current finite-state-automata state */
|
||||
enum protoState state;
|
||||
|
||||
uint8_t previousId;
|
||||
uint8_t errors;
|
||||
|
||||
/* Currently received message */
|
||||
message_t buffer;
|
||||
} protocol_t;
|
||||
|
||||
/* NOTE: This didn't work when defined on stack */
|
||||
extern protocol_t proto;
|
||||
|
||||
/* Init state */
|
||||
extern void protoInit(protocol_t *proto, void (*callback)(const message_t *));
|
||||
|
||||
/* Consume one byte and push state forward - might call the callback */
|
||||
extern void protoConsume(protocol_t *proto, uint8_t byte);
|
||||
|
||||
/* Prolonged silence - reset state */
|
||||
extern void protoSilence(protocol_t *proto);
|
||||
|
||||
/* Transmit message */
|
||||
extern void protoTx(uint8_t cmd, const unsigned char *buf, int payloadSize,
|
||||
int retries);
|
||||
|
||||
#endif
|
||||
@@ -1,115 +1,106 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "hal.h"
|
||||
#include "annepro2.h"
|
||||
#include "qmk_ap2_led.h"
|
||||
#include "protocol.h"
|
||||
|
||||
bool AP2_LED_ENABLED = false;
|
||||
bool AP2_LED_DYNAMIC_PROFILE = false;
|
||||
bool AP2_FOREGROUND_COLOR_SET = false;
|
||||
annepro2Led_t ledMask[KEY_COUNT];
|
||||
annepro2LedStatus_t annepro2LedStatus;
|
||||
|
||||
void annepro2LedDisable(void)
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_OFF);
|
||||
AP2_LED_ENABLED = false;
|
||||
void ledCommandCallback(const message_t *msg) {
|
||||
switch (msg->command) {
|
||||
case CMD_LED_STATUS:
|
||||
annepro2LedStatus.amountOfProfiles = msg->payload[0];
|
||||
annepro2LedStatus.currentProfile = msg->payload[1];
|
||||
annepro2LedStatus.matrixEnabled = msg->payload[2];
|
||||
annepro2LedStatus.isReactive = msg->payload[3];
|
||||
annepro2LedStatus.ledIntensity = msg->payload[4];
|
||||
annepro2LedStatus.errors = msg->payload[5];
|
||||
break;
|
||||
|
||||
#ifdef CONSOLE_ENABLE
|
||||
case CMD_LED_DEBUG:
|
||||
/* TODO: Don't use printf. */
|
||||
printf("LED:");
|
||||
for (int i = 0; i < msg->payloadSize; i++) {
|
||||
printf("%02x ", msg->payload[i]);
|
||||
}
|
||||
for (int i = 0; i < msg->payloadSize; i++) {
|
||||
printf("%c", msg->payload[i]);
|
||||
}
|
||||
printf("\n");
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void annepro2LedEnable(void)
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_ON);
|
||||
AP2_LED_ENABLED = true;
|
||||
void annepro2SetIAP(void) { protoTx(CMD_LED_IAP, NULL, 0, 3); }
|
||||
|
||||
void annepro2LedDisable(void) { protoTx(CMD_LED_OFF, NULL, 0, 3); }
|
||||
|
||||
void annepro2LedEnable(void) { protoTx(CMD_LED_ON, NULL, 0, 3); }
|
||||
|
||||
void annepro2LedSetProfile(uint8_t prof) { protoTx(CMD_LED_SET_PROFILE, &prof, sizeof(prof), 3); }
|
||||
|
||||
void annepro2LedGetStatus() { protoTx(CMD_LED_GET_STATUS, NULL, 0, 3); }
|
||||
|
||||
void annepro2LedNextProfile() { protoTx(CMD_LED_NEXT_PROFILE, NULL, 0, 3); }
|
||||
|
||||
void annepro2LedNextIntensity() { protoTx(CMD_LED_NEXT_INTENSITY, NULL, 0, 3); }
|
||||
|
||||
void annepro2LedNextAnimationSpeed() { protoTx(CMD_LED_NEXT_ANIMATION_SPEED, NULL, 0, 3); }
|
||||
|
||||
void annepro2LedPrevProfile() { protoTx(CMD_LED_PREV_PROFILE, NULL, 0, 3); }
|
||||
|
||||
void annepro2LedMaskSetKey(uint8_t row, uint8_t col, annepro2Led_t color) {
|
||||
uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha};
|
||||
protoTx(CMD_LED_MASK_SET_KEY, payload, sizeof(payload), 1);
|
||||
}
|
||||
|
||||
void annepro2LedUpdate(uint8_t row, uint8_t col)
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_SET);
|
||||
sdPut(&SD0, row);
|
||||
sdPut(&SD0, col);
|
||||
sdWrite(&SD0, (uint8_t *)&annepro2LedMatrix[row * MATRIX_COLS + col], sizeof(uint16_t));
|
||||
/* Push a whole local row to the shine */
|
||||
void annepro2LedMaskSetRow(uint8_t row) {
|
||||
uint8_t payload[NUM_COLUMN * sizeof(annepro2Led_t) + 1];
|
||||
payload[0] = row;
|
||||
memcpy(payload + 1, &ledMask[ROWCOL2IDX(row, 0)], sizeof(*ledMask) * NUM_COLUMN);
|
||||
protoTx(CMD_LED_MASK_SET_KEY, payload, sizeof(payload), 1);
|
||||
}
|
||||
|
||||
void annepro2LedUpdateRow(uint8_t row)
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_SET_ROW);
|
||||
sdPut(&SD0, row);
|
||||
sdWrite(&SD0, (uint8_t *)&annepro2LedMatrix[row * MATRIX_COLS], sizeof(uint16_t) * MATRIX_COLS);
|
||||
/* Synchronize all rows */
|
||||
void annepro2LedMaskSetAll(void) {
|
||||
for (int row = 0; row < 5; row++) annepro2LedMaskSetRow(row);
|
||||
}
|
||||
|
||||
void annepro2LedSetProfile(uint8_t prof)
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_SET_PROFILE);
|
||||
sdPut(&SD0, prof);
|
||||
uint8_t buf = sdGet(&SD0);
|
||||
AP2_LED_DYNAMIC_PROFILE = buf;
|
||||
/* Set all keys to a given color */
|
||||
void annepro2LedMaskSetMono(const annepro2Led_t color) { protoTx(CMD_LED_MASK_SET_MONO, (uint8_t *)&color, sizeof(color), 1); }
|
||||
|
||||
void annepro2LedBlink(uint8_t row, uint8_t col, annepro2Led_t color, uint8_t count, uint8_t hundredths) {
|
||||
uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha, count, hundredths};
|
||||
protoTx(CMD_LED_KEY_BLINK, payload, sizeof(payload), 1);
|
||||
}
|
||||
|
||||
uint8_t annepro2LedGetProfile()
|
||||
{
|
||||
uint8_t buf = 0;
|
||||
sdPut(&SD0, CMD_LED_GET_PROFILE);
|
||||
buf = sdGet(&SD0);
|
||||
return buf;
|
||||
void annepro2LedSetForegroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
annepro2Led_t color = {.p.red = red, .p.green = green, .p.blue = blue, .p.alpha = 0xff};
|
||||
annepro2LedMaskSetMono(color);
|
||||
}
|
||||
|
||||
uint8_t annepro2LedGetNumProfiles()
|
||||
{
|
||||
uint8_t buf = 0;
|
||||
sdPut(&SD0, CMD_LED_GET_NUM_PROFILES);
|
||||
buf = sdGet(&SD0);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void annepro2LedNextProfile()
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_NEXT_PROFILE);
|
||||
uint8_t buf = sdGet(&SD0);
|
||||
AP2_LED_DYNAMIC_PROFILE = buf;
|
||||
}
|
||||
|
||||
void annepro2LedNextIntensity()
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_NEXT_INTENSITY);
|
||||
}
|
||||
|
||||
void annepro2LedNextAnimationSpeed()
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_NEXT_ANIMATION_SPEED);
|
||||
}
|
||||
|
||||
void annepro2LedPrevProfile()
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_PREV_PROFILE);
|
||||
uint8_t buf = sdGet(&SD0);
|
||||
AP2_LED_DYNAMIC_PROFILE = buf;
|
||||
}
|
||||
|
||||
void annepro2LedSetMask(uint8_t key)
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_SET_MASK);
|
||||
sdPut(&SD0, key);
|
||||
}
|
||||
|
||||
void annepro2LedClearMask(uint8_t key)
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_CLEAR_MASK);
|
||||
sdPut(&SD0, key);
|
||||
}
|
||||
|
||||
void annepro2LedSetForegroundColor(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_SET_FOREGROUND_COLOR);
|
||||
uint8_t colors[3]={red,green,blue};
|
||||
sdWrite(&SD0, (uint8_t *)&colors, sizeof(colors));
|
||||
AP2_FOREGROUND_COLOR_SET = true;
|
||||
}
|
||||
|
||||
void annepro2LedResetForegroundColor()
|
||||
{
|
||||
sdPut(&SD0, CMD_LED_CLEAR_FOREGROUND_COLOR);
|
||||
uint8_t buf = sdGet(&SD0);
|
||||
AP2_LED_DYNAMIC_PROFILE = buf;
|
||||
AP2_FOREGROUND_COLOR_SET = false;
|
||||
void annepro2LedResetForegroundColor() {
|
||||
annepro2Led_t color = {
|
||||
.p.red = 0,
|
||||
.p.green = 0,
|
||||
.p.blue = 0,
|
||||
.p.alpha = 0,
|
||||
};
|
||||
annepro2LedMaskSetMono(color);
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently keypresses are unified with other messages, still with single 1
|
||||
* byte payload. Transfer is normally fast enough for that to not be a problem -
|
||||
* especially with asynchronous message reading.
|
||||
*
|
||||
*
|
||||
* Previous description:
|
||||
* If enabled, this data is sent to LED MCU on every keypress.
|
||||
* In order to improve performance, both row and column values
|
||||
* are packed into a single byte.
|
||||
@@ -121,8 +112,7 @@ void annepro2LedResetForegroundColor()
|
||||
* Following it are 3 bits of row and 4 bits of col.
|
||||
* 1 + 3 + 4 = 8 bits - only a single byte is sent for every keypress.
|
||||
*/
|
||||
void annepro2LedForwardKeypress(uint8_t row, uint8_t col)
|
||||
{
|
||||
uint8_t msg = 0b10000000 | (row << 4) | col;
|
||||
sdPut(&SD0, msg);
|
||||
void annepro2LedForwardKeypress(uint8_t row, uint8_t col) {
|
||||
const uint8_t payload = row << 4 | col;
|
||||
protoTx(CMD_LED_KEY_DOWN, &payload, 1, 1);
|
||||
}
|
||||
|
||||
@@ -1,42 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#define CMD_LED_ON 0x1
|
||||
#define CMD_LED_OFF 0x2
|
||||
#define CMD_LED_SET 0x3
|
||||
#define CMD_LED_SET_ROW 0x4
|
||||
#define CMD_LED_SET_PROFILE 0x5
|
||||
#define CMD_LED_NEXT_PROFILE 0x6
|
||||
#define CMD_LED_PREV_PROFILE 0x7
|
||||
#define CMD_LED_GET_PROFILE 0x8
|
||||
#define CMD_LED_GET_NUM_PROFILES 0x9
|
||||
#define CMD_LED_SET_MASK 0xA
|
||||
#define CMD_LED_CLEAR_MASK 0xB
|
||||
#define CMD_LED_NEXT_INTENSITY 0xC
|
||||
#define CMD_LED_NEXT_ANIMATION_SPEED 0xD
|
||||
#define CMD_LED_SET_FOREGROUND_COLOR 0xE
|
||||
#define CMD_LED_CLEAR_FOREGROUND_COLOR 0xF
|
||||
#define CMD_LED_IAP 0x10
|
||||
#define CMD_LED_KEYPRESS 0x11
|
||||
#include "protocol.h"
|
||||
|
||||
// Struct defining an LED and its RGB color components
|
||||
// Compatible with Shine firmware.
|
||||
typedef union {
|
||||
struct {
|
||||
/* Little endian ordering to match uint32_t */
|
||||
uint8_t blue, green, red;
|
||||
/* Used in mask; nonzero means - use color from mask. */
|
||||
uint8_t alpha;
|
||||
} p; /* parts */
|
||||
/* Parts vector access: 0 - blue, 1 - green, 2 - red */
|
||||
uint8_t pv[4];
|
||||
/* 0xrgb in mem is b g r a */
|
||||
uint32_t rgb;
|
||||
} annepro2Led_t;
|
||||
|
||||
#define ROWCOL2IDX(row, col) (NUM_COLUMN * (row) + (col))
|
||||
#define NUM_COLUMN 14
|
||||
#define NUM_ROW 5
|
||||
#define KEY_COUNT 70
|
||||
|
||||
/* Local copy of ledMask, used to override colors on the board */
|
||||
extern annepro2Led_t ledMask[KEY_COUNT];
|
||||
|
||||
/* Handle incoming messages */
|
||||
extern void ledCommandCallback(const message_t *msg);
|
||||
|
||||
void annepro2SetIAP(void);
|
||||
void annepro2LedDisable(void);
|
||||
void annepro2LedEnable(void);
|
||||
void annepro2LedUpdate(uint8_t row, uint8_t col);
|
||||
void annepro2LedUpdateRow(uint8_t row);
|
||||
void annepro2LedSetProfile(uint8_t prof);
|
||||
uint8_t annepro2LedGetProfile(void);
|
||||
uint8_t annepro2LedGetNumProfiles(void);
|
||||
void annepro2LedGetStatus(void);
|
||||
void annepro2LedNextProfile(void);
|
||||
void annepro2LedPrevProfile(void);
|
||||
void annepro2LedSetMask(uint8_t key);
|
||||
void annepro2LedClearMask(uint8_t key);
|
||||
void annepro2LedNextIntensity(void);
|
||||
void annepro2LedNextAnimationSpeed(void);
|
||||
void annepro2LedSetForegroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void annepro2LedResetForegroundColor(void);
|
||||
void annepro2LedForwardKeypress(uint8_t row, uint8_t col);
|
||||
|
||||
/* Set single key to a given color; alpha controls which is displayed */
|
||||
void annepro2LedMaskSetKey(uint8_t row, uint8_t col, annepro2Led_t color);
|
||||
/* Push a whole local row to the shine */
|
||||
void annepro2LedMaskSetRow(uint8_t row);
|
||||
/* Synchronize all rows */
|
||||
void annepro2LedMaskSetAll(void);
|
||||
|
||||
extern bool AP2_LED_ENABLED;
|
||||
extern bool AP2_LED_DYNAMIC_PROFILE;
|
||||
extern bool AP2_FOREGROUND_COLOR_SET;
|
||||
/* Set all keys to a given color */
|
||||
void annepro2LedMaskSetMono(annepro2Led_t color);
|
||||
|
||||
/* Blink given key `count` times by masking it with a `color`. Blink takes `hundredths` of a second */
|
||||
void annepro2LedBlink(uint8_t row, uint8_t col, annepro2Led_t color, uint8_t count, uint8_t hundredths);
|
||||
|
||||
/* Kept for compatibility, but implemented using masks */
|
||||
void annepro2LedSetForegroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void annepro2LedResetForegroundColor(void);
|
||||
|
||||
typedef struct {
|
||||
uint8_t amountOfProfiles;
|
||||
uint8_t currentProfile;
|
||||
uint8_t matrixEnabled;
|
||||
uint8_t isReactive;
|
||||
uint8_t ledIntensity;
|
||||
uint8_t errors;
|
||||
} annepro2LedStatus_t;
|
||||
|
||||
extern annepro2LedStatus_t annepro2LedStatus;
|
||||
|
||||
Reference in New Issue
Block a user