diff --git a/keyboards/annepro2/annepro2.c b/keyboards/annepro2/annepro2.c index 60c630a2ec34..9658b7804046 100644 --- a/keyboards/annepro2/annepro2.c +++ b/keyboards/annepro2/annepro2.c @@ -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, }; -static const SerialConfig bleUartConfig = { - .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 uint8_t ledMcuWakeup[11] = { - 0x7b, 0x10, 0x43, 0x10, 0x03, 0x00, 0x00, 0x7d, 0x02, 0x01, 0x02 +static const SerialConfig bleUartConfig = { + .speed = 115200, }; -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(); @@ -54,19 +50,20 @@ void OVERRIDE keyboard_pre_init_kb(void) { spi_init(); #endif // Start LED UART - sdStart(&SD0, &ledUartConfig); + sdStart(&SD0, &ledUartInitConfig); sdWrite(&SD0, ledMcuWakeup, 11); // wait to receive response from wakeup wait_ms(15); + protoInit(&proto, ledCommandCallback); + // loop to clear out receive buffer from shine wakeup - while(!sdGetWouldBlock(&SD0)) - sdGet(&SD0); + 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: diff --git a/keyboards/annepro2/annepro2.h b/keyboards/annepro2/annepro2.h index a7383c759788..a6c984d75d4c 100644 --- a/keyboards/annepro2/annepro2.h +++ b/keyboards/annepro2/annepro2.h @@ -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]; diff --git a/keyboards/annepro2/c15/readme.md b/keyboards/annepro2/c15/readme.md new file mode 100644 index 000000000000..5fadb7390951 --- /dev/null +++ b/keyboards/annepro2/c15/readme.md @@ -0,0 +1 @@ +AnnePro2, ANSI C15 version. diff --git a/keyboards/annepro2/c15/rules.mk b/keyboards/annepro2/c15/rules.mk index cbef25300e5c..e50ee99516b7 100644 --- a/keyboards/annepro2/c15/rules.mk +++ b/keyboards/annepro2/c15/rules.mk @@ -3,7 +3,8 @@ SRC = \ matrix.c \ hardfault_handler.c \ annepro2_ble.c \ - qmk_ap2_led.c + qmk_ap2_led.c \ + protocol.c LAYOUTS += diff --git a/keyboards/annepro2/c18/config.h b/keyboards/annepro2/c18/config.h index f47d622229bf..726e4a3995e0 100644 --- a/keyboards/annepro2/c18/config.h +++ b/keyboards/annepro2/c18/config.h @@ -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 - diff --git a/keyboards/annepro2/c18/readme.md b/keyboards/annepro2/c18/readme.md new file mode 100644 index 000000000000..f2e2fc45b8f2 --- /dev/null +++ b/keyboards/annepro2/c18/readme.md @@ -0,0 +1 @@ +AnnePro2, ANSI C18 version. diff --git a/keyboards/annepro2/c18/rules.mk b/keyboards/annepro2/c18/rules.mk index 1bf42df7d4e3..c63a90ace46c 100644 --- a/keyboards/annepro2/c18/rules.mk +++ b/keyboards/annepro2/c18/rules.mk @@ -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 diff --git a/keyboards/annepro2/keymaps/bla/config.h b/keyboards/annepro2/keymaps/bla/config.h new file mode 100644 index 000000000000..1840bc748496 --- /dev/null +++ b/keyboards/annepro2/keymaps/bla/config.h @@ -0,0 +1,2 @@ +// Obins stock firmware has something similar to this already enabled, but disabled by default in QMK +#define PERMISSIVE_HOLD diff --git a/keyboards/annepro2/keymaps/bla/keymap.c b/keyboards/annepro2/keymaps/bla/keymap.c new file mode 100644 index 000000000000..c0af30ff56bc --- /dev/null +++ b/keyboards/annepro2/keymaps/bla/keymap.c @@ -0,0 +1,157 @@ +#include +#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; +} diff --git a/keyboards/annepro2/keymaps/codetector/keymap.c b/keyboards/annepro2/keymaps/codetector/keymap.c index f8cd6bf07c46..d1eed7e5c717 100644 --- a/keyboards/annepro2/keymaps/codetector/keymap.c +++ b/keyboards/annepro2/keymaps/codetector/keymap.c @@ -137,9 +137,23 @@ layer_state_t layer_state_set_user(layer_state_t layer) { bool led_update_user(led_t leds) { if (leds.caps_lock) { - annepro2LedSetMask(CAPS_LOCATION); + const annepro2Led_t color = { + .p.red = 0xff, + .p.green = 0x00, + .p.blue = 0x00, + .p.alpha = 0xff + }; + + annepro2LedMaskSetKey(2, 0, color); + } else { - annepro2LedClearMask(CAPS_LOCATION); + const annepro2Led_t color = { + .p.red = 0xff, + .p.green = 0x00, + .p.blue = 0x00, + .p.alpha = 0x00 + }; + annepro2LedMaskSetKey(2, 0, color); } return true; } diff --git a/keyboards/annepro2/keymaps/default-layer-indicators/keymap.c b/keyboards/annepro2/keymaps/default-layer-indicators/keymap.c index 4ab9fad3d93b..6cabda933006 100644 --- a/keyboards/annepro2/keymaps/default-layer-indicators/keymap.c +++ b/keyboards/annepro2/keymaps/default-layer-indicators/keymap.c @@ -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; } - diff --git a/keyboards/annepro2/keymaps/kdarkhan/keymap.c b/keyboards/annepro2/keymaps/kdarkhan/keymap.c index 50b8b8311bac..cb3a3a0a932b 100644 --- a/keyboards/annepro2/keymaps/kdarkhan/keymap.c +++ b/keyboards/annepro2/keymaps/kdarkhan/keymap.c @@ -32,9 +32,6 @@ enum tap_dance_codes { // 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; - // this means that there should not be more than 16 profiles uint16_t dyn_key_mask = 0; @@ -177,7 +174,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { case KC_AP_LED_ON: if (record->event.pressed) { if (user_config.leds_on) { - user_config.leds_profile = (user_config.leds_profile + 1) % numProfiles; + user_config.leds_profile = (user_config.leds_profile + 1) % annepro2LedStatus.amountOfProfiles; } else { user_config.leds_on = true; } @@ -187,7 +184,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)); } @@ -233,8 +230,6 @@ void keyboard_post_init_user(void) { annepro2LedDisable(); } #endif - - numProfiles = annepro2LedGetNumProfiles(); } void dance_cln_finished(qk_tap_dance_state_t *state, void *user_data) { diff --git a/keyboards/annepro2/keymaps/tech2077/keymap.c b/keyboards/annepro2/keymaps/tech2077/keymap.c index 28d76edab02f..f35555c897c7 100644 --- a/keyboards/annepro2/keymaps/tech2077/keymap.c +++ b/keyboards/annepro2/keymaps/tech2077/keymap.c @@ -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(); } diff --git a/keyboards/annepro2/keymaps/thomazmoura/rules.mk b/keyboards/annepro2/keymaps/thomazmoura/rules.mk index 32697215d61f..2b6ec483cca1 100644 --- a/keyboards/annepro2/keymaps/thomazmoura/rules.mk +++ b/keyboards/annepro2/keymaps/thomazmoura/rules.mk @@ -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 - diff --git a/keyboards/annepro2/matrix.c b/keyboards/annepro2/matrix.c index 5e9f2895fbc8..a723e523a738 100644 --- a/keyboards/annepro2/matrix.c +++ b/keyboards/annepro2/matrix.c @@ -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) {} diff --git a/keyboards/annepro2/protocol.c b/keyboards/annepro2/protocol.c new file mode 100644 index 000000000000..ff2f328e4c9f --- /dev/null +++ b/keyboards/annepro2/protocol.c @@ -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++; + } +} diff --git a/keyboards/annepro2/protocol.h b/keyboards/annepro2/protocol.h new file mode 100644 index 000000000000..9effea44d618 --- /dev/null +++ b/keyboards/annepro2/protocol.h @@ -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 + +#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 diff --git a/keyboards/annepro2/qmk_ap2_led.c b/keyboards/annepro2/qmk_ap2_led.c index 5f7e9fcf83d5..d0b34122c27a 100644 --- a/keyboards/annepro2/qmk_ap2_led.c +++ b/keyboards/annepro2/qmk_ap2_led.c @@ -1,115 +1,106 @@ +#include +#include #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; -void annepro2LedEnable(void) -{ - sdPut(&SD0, CMD_LED_ON); - AP2_LED_ENABLED = true; +#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 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)); -} +void annepro2SetIAP(void) { protoTx(CMD_LED_IAP, NULL, 0, 3); } -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); -} +void annepro2LedDisable(void) { protoTx(CMD_LED_OFF, NULL, 0, 3); } -void annepro2LedSetProfile(uint8_t prof) -{ - sdPut(&SD0, CMD_LED_SET_PROFILE); - sdPut(&SD0, prof); - uint8_t buf = sdGet(&SD0); - AP2_LED_DYNAMIC_PROFILE = buf; -} +void annepro2LedEnable(void) { protoTx(CMD_LED_ON, NULL, 0, 3); } -uint8_t annepro2LedGetProfile() -{ - uint8_t buf = 0; - sdPut(&SD0, CMD_LED_GET_PROFILE); - buf = sdGet(&SD0); - return buf; -} +void annepro2LedSetProfile(uint8_t prof) { protoTx(CMD_LED_SET_PROFILE, &prof, sizeof(prof), 3); } -uint8_t annepro2LedGetNumProfiles() -{ - uint8_t buf = 0; - sdPut(&SD0, CMD_LED_GET_NUM_PROFILES); - buf = sdGet(&SD0); - return buf; -} +void annepro2LedGetStatus() { protoTx(CMD_LED_GET_STATUS, NULL, 0, 3); } -void annepro2LedNextProfile() -{ - sdPut(&SD0, CMD_LED_NEXT_PROFILE); - uint8_t buf = sdGet(&SD0); - AP2_LED_DYNAMIC_PROFILE = buf; -} +void annepro2LedNextProfile() { protoTx(CMD_LED_NEXT_PROFILE, NULL, 0, 3); } -void annepro2LedNextIntensity() -{ - sdPut(&SD0, CMD_LED_NEXT_INTENSITY); -} +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 annepro2LedNextAnimationSpeed() -{ - sdPut(&SD0, CMD_LED_NEXT_ANIMATION_SPEED); +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 annepro2LedPrevProfile() -{ - sdPut(&SD0, CMD_LED_PREV_PROFILE); - uint8_t buf = sdGet(&SD0); - AP2_LED_DYNAMIC_PROFILE = buf; +/* 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 annepro2LedSetMask(uint8_t key) -{ - sdPut(&SD0, CMD_LED_SET_MASK); - sdPut(&SD0, key); +/* Synchronize all rows */ +void annepro2LedMaskSetAll(void) { + for (int row = 0; row < 5; row++) annepro2LedMaskSetRow(row); } -void annepro2LedClearMask(uint8_t key) -{ - sdPut(&SD0, CMD_LED_CLEAR_MASK); - sdPut(&SD0, key); +/* 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); } -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 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); } -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); } diff --git a/keyboards/annepro2/qmk_ap2_led.h b/keyboards/annepro2/qmk_ap2_led.h index d4658119afdf..0abec2dcba09 100644 --- a/keyboards/annepro2/qmk_ap2_led.h +++ b/keyboards/annepro2/qmk_ap2_led.h @@ -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 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); + +/* 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); -void annepro2LedForwardKeypress(uint8_t row, uint8_t col); +typedef struct { + uint8_t amountOfProfiles; + uint8_t currentProfile; + uint8_t matrixEnabled; + uint8_t isReactive; + uint8_t ledIntensity; + uint8_t errors; +} annepro2LedStatus_t; -extern bool AP2_LED_ENABLED; -extern bool AP2_LED_DYNAMIC_PROFILE; -extern bool AP2_FOREGROUND_COLOR_SET; +extern annepro2LedStatus_t annepro2LedStatus;