diff --git a/keyboards/annepro2/annepro2.c b/keyboards/annepro2/annepro2.c index 9e72dbf6fb0f..1ea663f856f9 100644 --- a/keyboards/annepro2/annepro2.c +++ b/keyboards/annepro2/annepro2.c @@ -43,6 +43,8 @@ static const SerialConfig ble_uart_config = { static uint8_t led_mcu_wakeup[11] = {0x7b, 0x10, 0x43, 0x10, 0x03, 0x00, 0x00, 0x7d, 0x02, 0x01, 0x02}; ble_capslock_t ble_capslock = {._dummy = {0}, .caps_lock = false}; +static uint8_t ble_rx_buffer[sizeof(ble_capslock)]; +static uint8_t ble_rx_offset; #ifdef RGB_MATRIX_ENABLE static uint8_t led_enabled = 1; @@ -115,10 +117,20 @@ void keyboard_post_init_kb(void) { } void matrix_scan_kb(void) { - // if there's stuff on the ble serial buffer - // read it into the capslock struct + annepro2_ble_task(); + + /* + * BLE RX framing is not decoded yet. Drain one byte at a time so a short + * UART read cannot block matrix scanning for the old 10 ms timeout. + */ while (!sdGetWouldBlock(&SD1)) { - sdReadTimeout(&SD1, (uint8_t *)&ble_capslock, sizeof(ble_capslock_t), 10); + ble_rx_buffer[ble_rx_offset++] = (uint8_t)sdGet(&SD1); + if (ble_rx_offset == sizeof(ble_capslock)) { + ble_rx_offset = 0; + for (uint8_t i = 0; i < sizeof(ble_capslock); i++) { + ((uint8_t *)&ble_capslock)[i] = ble_rx_buffer[i]; + } + } } /* While there's data from LED keyboard sent - read it. */ @@ -283,7 +295,9 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { } return true; #endif - + case KC_AP2_IAP: + bootloader_jump(); + return true; default: break; } diff --git a/keyboards/annepro2/annepro2.h b/keyboards/annepro2/annepro2.h index a33194f96424..97d8d3b01cb2 100644 --- a/keyboards/annepro2/annepro2.h +++ b/keyboards/annepro2/annepro2.h @@ -44,4 +44,5 @@ enum AP2KeyCodes { KC_AP_RGB_VAD, KC_AP_RGB_TOG, KC_AP_RGB_MOD, + KC_AP2_IAP, }; diff --git a/keyboards/annepro2/annepro2_ble.c b/keyboards/annepro2/annepro2_ble.c index a382c61638f0..2cc72829dd30 100644 --- a/keyboards/annepro2/annepro2_ble.c +++ b/keyboards/annepro2/annepro2_ble.c @@ -20,6 +20,7 @@ #include "host.h" #include "host_driver.h" #include "report.h" +#include "timer.h" /* -------------------- Static Function Prototypes -------------------------- */ static uint8_t ap2_ble_leds(void); @@ -29,36 +30,43 @@ static void ap2_ble_keyboard(report_keyboard_t *report); static void ap2_ble_swtich_ble_driver(void); +#ifndef ANNEPRO2_BLE_CONNECT_GUARD_MS +# define ANNEPRO2_BLE_CONNECT_GUARD_MS 200 +#endif + /* -------------------- Static Local Variables ------------------------------ */ static host_driver_t ap2_ble_driver = { ap2_ble_leds, ap2_ble_keyboard, NULL, ap2_ble_mouse, ap2_ble_extra }; -static uint8_t ble_mcu_wakeup[11] = {0x7b, 0x12, 0x53, 0x00, 0x03, 0x00, 0x01, 0x7d, 0x02, 0x01, 0x02}; +static const uint8_t ble_mcu_wakeup[11] = {0x7b, 0x12, 0x53, 0x00, 0x03, 0x00, 0x01, 0x7d, 0x02, 0x01, 0x02}; -static uint8_t ble_mcu_start_broadcast[10] = { +static const uint8_t ble_mcu_start_broadcast[10] = { 0x7b, 0x12, 0x53, 0x00, 0x03, 0x00, 0x00, 0x7d, 0x40, 0x01, // Broadcast ID[0-3] }; -static uint8_t ble_mcu_connect[10] = { +static const uint8_t ble_mcu_connect[10] = { 0x7b, 0x12, 0x53, 0x00, 0x03, 0x00, 0x00, 0x7d, 0x40, 0x04, // Connect ID [0-3] }; -static uint8_t ble_mcu_send_report[10] = { +static const uint8_t ble_mcu_send_report[10] = { 0x7b, 0x12, 0x53, 0x00, 0x0A, 0x00, 0x00, 0x7d, 0x10, 0x04, }; -static uint8_t ble_mcu_send_consumer_report[10] = { +static const uint8_t ble_mcu_send_consumer_report[10] = { 0x7b, 0x12, 0x53, 0x00, 0x06, 0x00, 0x00, 0x7d, 0x10, 0x08, }; -static uint8_t ble_mcu_unpair[10] = { +static const uint8_t ble_mcu_unpair[10] = { 0x7b, 0x12, 0x53, 0x00, 0x02, 0x00, 0x00, 0x7d, 0x40, 0x05, }; -static uint8_t ble_mcu_bootload[11] = {0x7b, 0x10, 0x51, 0x10, 0x03, 0x00, 0x00, 0x7d, 0x02, 0x01, 0x01}; +static const uint8_t ble_mcu_bootload[11] = {0x7b, 0x10, 0x51, 0x10, 0x03, 0x00, 0x00, 0x7d, 0x02, 0x01, 0x01}; static host_driver_t *last_host_driver = NULL; +static int8_t last_broadcast = -1; +static bool ble_connect_pending; +static uint32_t ble_connect_started_at; #ifdef NKRO_ENABLE static bool lastNkroStatus = false; #endif // NKRO_ENABLE @@ -73,28 +81,56 @@ void annepro2_ble_broadcast(uint8_t port) { if (port > 3) { port = 3; } - // sdPut(&SD1, 0x00); - sdWrite(&SD1, ble_mcu_start_broadcast, sizeof(ble_mcu_start_broadcast)); - sdPut(&SD1, port); - sdPut(&SD1, 0x00); - static int lastBroadcast = -1; - if (lastBroadcast == port) { + const bool reconnect = last_broadcast == (int8_t)port; + uint8_t frame[sizeof(ble_mcu_start_broadcast) + 2]; + + if (!reconnect) { + /* Do not keep sending HID reports to a previously selected slot. */ + annepro2_ble_disconnect(); + } + + for (uint8_t i = 0; i < sizeof(ble_mcu_start_broadcast); i++) { + frame[i] = ble_mcu_start_broadcast[i]; + } + frame[sizeof(ble_mcu_start_broadcast)] = port; + frame[sizeof(ble_mcu_start_broadcast) + 1] = 0x00; + sdWrite(&SD1, frame, sizeof(frame)); + + if (reconnect) { annepro2_ble_connect(port); } - lastBroadcast = port; + last_broadcast = port; } void annepro2_ble_connect(uint8_t port) { if (port > 3) { port = 3; } - sdWrite(&SD1, ble_mcu_connect, sizeof(ble_mcu_connect)); - sdPut(&SD1, port); - sdPut(&SD1, 0x00); - ap2_ble_swtich_ble_driver(); + uint8_t frame[sizeof(ble_mcu_connect) + 2]; + + /* A reconnect must not let stale reports enter the newly selected slot. */ + annepro2_ble_disconnect(); + + for (uint8_t i = 0; i < sizeof(ble_mcu_connect); i++) { + frame[i] = ble_mcu_connect[i]; + } + frame[sizeof(ble_mcu_connect)] = port; + frame[sizeof(ble_mcu_connect) + 1] = 0x00; + sdWrite(&SD1, frame, sizeof(frame)); + + /* + * The BLE firmware's connect-complete indication is not decoded yet. + * Keep QMK on its previous host driver briefly so the command reaches the + * module before it can receive HID reports; this is not a link-state ACK. + */ + ble_connect_started_at = timer_read32(); + ble_connect_pending = true; } void annepro2_ble_disconnect(void) { + ble_connect_pending = false; + last_broadcast = -1; + /* Skip if the driver is already enabled */ if (host_get_driver() != &ap2_ble_driver) { return; @@ -108,8 +144,17 @@ void annepro2_ble_disconnect(void) { } void annepro2_ble_unpair(void) { - // sdPut(&SD1, 0x0); sdWrite(&SD1, ble_mcu_unpair, sizeof(ble_mcu_unpair)); + annepro2_ble_disconnect(); +} + +void annepro2_ble_task(void) { + if (!ble_connect_pending || timer_elapsed32(ble_connect_started_at) < ANNEPRO2_BLE_CONNECT_GUARD_MS) { + return; + } + + ble_connect_pending = false; + ap2_ble_swtich_ble_driver(); } /* ------------------- Static Function Implementation ----------------------- */ @@ -153,11 +198,14 @@ static inline uint16_t CONSUMER2AP2(uint16_t usage) { static void ap2_ble_extra(report_extra_t *report) { if (report->report_id == REPORT_ID_CONSUMER) { - sdPut(&SD1, 0x0); - sdWrite(&SD1, ble_mcu_send_consumer_report, sizeof(ble_mcu_send_consumer_report)); - sdPut(&SD1, CONSUMER2AP2(report->usage)); - static const uint8_t dummy[3] = {0}; - sdWrite(&SD1, dummy, sizeof(dummy)); + uint8_t frame[1 + sizeof(ble_mcu_send_consumer_report) + 4] = {0}; + + frame[0] = 0x00; + for (uint8_t i = 0; i < sizeof(ble_mcu_send_consumer_report); i++) { + frame[i + 1] = ble_mcu_send_consumer_report[i]; + } + frame[sizeof(ble_mcu_send_consumer_report) + 1] = CONSUMER2AP2(report->usage); + sdWrite(&SD1, frame, sizeof(frame)); } } @@ -165,7 +213,14 @@ static void ap2_ble_extra(report_extra_t *report) { * @brief Send keyboard HID report for Bluetooth driver */ static void ap2_ble_keyboard(report_keyboard_t *report) { - sdPut(&SD1, 0x0); - sdWrite(&SD1, ble_mcu_send_report, sizeof(ble_mcu_send_report)); - sdWrite(&SD1, (uint8_t *)report, KEYBOARD_REPORT_SIZE); + uint8_t frame[1 + sizeof(ble_mcu_send_report) + KEYBOARD_REPORT_SIZE]; + + frame[0] = 0x00; + for (uint8_t i = 0; i < sizeof(ble_mcu_send_report); i++) { + frame[i + 1] = ble_mcu_send_report[i]; + } + for (uint8_t i = 0; i < KEYBOARD_REPORT_SIZE; i++) { + frame[sizeof(ble_mcu_send_report) + 1 + i] = ((const uint8_t *)report)[i]; + } + sdWrite(&SD1, frame, sizeof(frame)); } diff --git a/keyboards/annepro2/annepro2_ble.h b/keyboards/annepro2/annepro2_ble.h index 37dd6d31a1c5..a5739043593a 100644 --- a/keyboards/annepro2/annepro2_ble.h +++ b/keyboards/annepro2/annepro2_ble.h @@ -24,3 +24,6 @@ void annepro2_ble_broadcast(uint8_t port); void annepro2_ble_connect(uint8_t port); void annepro2_ble_disconnect(void); void annepro2_ble_unpair(void); + +/* Run from the keyboard scan loop to finish a requested BLE driver change. */ +void annepro2_ble_task(void);