diff --git a/drivers/bluetooth/iton_bt.c b/drivers/bluetooth/iton_bt.c index b18f51727ff2..eaacfa136e6b 100644 --- a/drivers/bluetooth/iton_bt.c +++ b/drivers/bluetooth/iton_bt.c @@ -1,43 +1,32 @@ -// Copyright 2022 1Conan (@1Conan) +// Copyright 2023 1Conan (@1Conan) // SPDX-License-Identifier: GPL-2.0-or-later #include -#include #include -#include "config.h" #include "gpio.h" +#include "config.h" #include "iton_bt.h" -#include "report.h" -#include "keycode_config.h" #ifndef ITON_BT_SPI_PORT -#define ITON_BT_SPI_PORT SPID1 +# define ITON_BT_SPI_PORT SPID0 #endif #ifndef ITON_BT_IRQ_LINE -#define ITON_BT_IRQ_LINE A0 +# define ITON_BT_IRQ_LINE A0 #endif #ifndef ITON_BT_INT_LINE -#define ITON_BT_INT_LINE A1 -#endif - -#ifndef ITON_BT_MAX_PROFILE -#define ITON_BT_MAX_PROFILE 3 -#endif - -#ifndef ITON_BT_TX_LEN -#define ITON_BT_TX_LEN 16 -#endif - -#ifndef ITON_BT_RX_LEN -#define ITON_BT_RX_LEN 3 +# define ITON_BT_INT_LINE A1 #endif #ifdef KEYBOARD_SHARED_EP -#define HID_REPORT_OFFSET 1 +# define HID_REPORT_OFFSET 1 #else -#define HID_REPORT_OFFSET 0 +# define HID_REPORT_OFFSET 0 +#endif + +#ifndef ITON_BT_BUFFER_LEN +# define ITON_BT_BUFFER_LEN 16 #endif /** @@ -45,62 +34,142 @@ */ #define HIGH_BITS(x) ((uint8_t)(x >> 8)) #define LOW_BITS(x) ((uint8_t)(x & 0x00FF)) -#define WAIT_FOR_FINISH() while(readPin(ITON_BT_IRQ_LINE)) /** * Function definitions */ void iton_bt_data_cb(SPIDriver *spip); -static void iton_bt_rx_end(void *arg); + +/** + * Callbacks + */ +__attribute__((weak)) void iton_bt_battery_voltage_low(void) {} +__attribute__((weak)) void iton_bt_battery_exit_low_battery_mode(void) {} +__attribute__((weak)) void iton_bt_battery_low_power_shutdown(void) {} +__attribute__((weak)) void iton_bt_battery_level(uint8_t level) {} + +__attribute__((weak)) void iton_bt_connection_successful(void) {} +__attribute__((weak)) void iton_bt_entered_pairing(void) {} +__attribute__((weak)) void iton_bt_disconnected(void) {} +__attribute__((weak)) void iton_bt_enters_connection_state(void) {} /** * Driver variables */ -uint8_t iton_bt_rx[ITON_BT_RX_LEN]; -uint8_t iton_bt_tx[ITON_BT_TX_LEN]; +bool iton_bt_is_connected = false; uint8_t iton_bt_led_state = 0x00; + +static uint8_t iton_bt_buffer[ITON_BT_BUFFER_LEN]; uint8_t iton_bt_send_kb_last_key = 0x00; -#if defined(PAL_USE_CALLBACKS) || defined(PAL_USE_WAIT) -static THD_WORKING_AREA(iton_bt_rx_thd_wa, 128); -thread_t *iton_bt_rx_thd; -#endif const SPIConfig iton_bt_spicfg = { .slave = true, .data_cb = iton_bt_data_cb, - // mcu specific - .ctrl0 = (8 << 8), // Data Length = 8 + // SN32 specific + .ctrl0 = SPI_DATA_LENGTH(8), }; /** * Callbacks */ #if defined(PAL_USE_CALLBACKS) || defined(PAL_USE_WAIT) -static THD_FUNCTION(iton_bt_rx_thd_func, arg) { - iton_bt_rx_thd = chThdGetSelfX(); - while (true) { - chEvtWaitAny((eventmask_t)1); +static inline void iton_bt_rx_battery_notif(uint8_t data) { + switch (data) { + case batt_voltage_low: + iton_bt_battery_voltage_low(); + break; + case batt_exit_low_battery_mode: + iton_bt_battery_exit_low_battery_mode(); + break; + case batt_low_power_shutdown: + iton_bt_battery_low_power_shutdown(); + break; + case batt_above_70: + case batt_between_30_70: + case batt_below_30: + iton_bt_battery_level(data); + break; + case batt_wake_mcu: + #ifdef ITON_BT_ENABLE_ACK + iton_bt_send_ack(control_bt, wake_ack); + #endif + break; + case batt_unknown: + #ifdef ITON_BT_ENABLE_ACK + iton_bt_send_ack(control_bt, unknown_ack); + #endif + break; + case query_working_mode: + break; + case query_bt_name: + break; + } +} - if (iton_bt_rx[0] == led_state) { - iton_bt_led_state = iton_bt_rx[1]; - } +static inline void iton_bt_rx_bluetooth_notif(uint8_t data) { + switch (iton_bt_buffer[2]) { + case bt_connection_success: + iton_bt_is_connected = true; + + #ifdef ITON_BT_ENABLE_ACK + iton_bt_send_ack(control_bt, connect_ack); + #endif + + iton_bt_connection_successful(); + break; + case bt_entered_pairing: + iton_bt_entered_pairing(); + break; + case bt_disconected: + iton_bt_is_connected = false; + + #ifdef ITON_BT_ENABLE_ACK + iton_bt_send_ack(control_bt, disconnect_ack); + #endif + + iton_bt_disconnected(); + break; + case bt_enters_connection: + iton_bt_enters_connection_state(); + break; } } -static void iton_bt_rx_end(void *arg) { +static void iton_bt_rx_cb(void *arg) { if (readPin(ITON_BT_INT_LINE)) { chSysLockFromISR(); - spiStartReceiveI(&ITON_BT_SPI_PORT, ITON_BT_RX_LEN, &iton_bt_rx[0]); + spiStartReceiveI(&ITON_BT_SPI_PORT, ITON_BT_BUFFER_LEN, &iton_bt_buffer[0]); chSysUnlockFromISR(); } else { chSysLockFromISR(); spiStopTransferI(&ITON_BT_SPI_PORT, NULL); - chEvtSignalI(iton_bt_rx_thd, (eventmask_t)1); chSysUnlockFromISR(); + + #ifdef ITON_BT_ENABLE_ACK + // hack to make sure irq is low since acks messes with stuff + writePinLow(ITON_BT_IRQ_LINE); + #endif + + switch (iton_bt_buffer[0]) { + case led_state: + iton_bt_led_state = iton_bt_buffer[1]; + break; + case notification: + switch (iton_bt_buffer[1]) { + case notif_battery: + iton_bt_rx_battery_notif(iton_bt_buffer[2]); + break; + case notif_bluetooth: + iton_bt_rx_bluetooth_notif(iton_bt_buffer[2]); + break; + } + break; + } } } #endif + void iton_bt_data_cb(SPIDriver *spip) { writePinLow(ITON_BT_IRQ_LINE); } @@ -111,79 +180,71 @@ void iton_bt_data_cb(SPIDriver *spip) { void iton_bt_init(void) { setPinOutput(ITON_BT_IRQ_LINE); setPinInput(ITON_BT_INT_LINE); -#if defined(PAL_USE_CALLBACKS) || defined(PAL_USE_WAIT) - palSetLineCallback(ITON_BT_INT_LINE, iton_bt_rx_end, NULL); -#endif -} -void iton_bt_start(void) { - spiStart(&ITON_BT_SPI_PORT, &iton_bt_spicfg); + writePinLow(ITON_BT_IRQ_LINE); + #if defined(PAL_USE_CALLBACKS) || defined(PAL_USE_WAIT) + palSetLineCallback(ITON_BT_INT_LINE, iton_bt_rx_cb, NULL); palEnableLineEvent(ITON_BT_INT_LINE, PAL_EVENT_MODE_BOTH_EDGES); - chThdCreateStatic( - iton_bt_rx_thd_wa, - sizeof(iton_bt_rx_thd_wa), - HIGHPRIO, - iton_bt_rx_thd_func, - NULL - ); #endif -} -void iton_bt_stop(void) { - spiStopTransfer(&ITON_BT_SPI_PORT, NULL); -#if defined(PAL_USE_CALLBACKS) || defined(PAL_USE_WAIT) - palDisableLineEvent(ITON_BT_INT_LINE); -#endif - spiStop(&ITON_BT_SPI_PORT); + spiStart(&ITON_BT_SPI_PORT, &iton_bt_spicfg); } void iton_bt_send(uint8_t cmd, uint8_t *data, uint8_t len) { - WAIT_FOR_FINISH(); + while (readPin(ITON_BT_IRQ_LINE)); + writePinHigh(ITON_BT_IRQ_LINE); - iton_bt_tx[0] = cmd; - memcpy(&iton_bt_tx[1], data, len); - spiStartSend(&ITON_BT_SPI_PORT, len + 1, &iton_bt_tx[0]); + iton_bt_buffer[0] = cmd; + memcpy(&iton_bt_buffer[1], data, len); + spiStartSend(&ITON_BT_SPI_PORT, len + 1, &iton_bt_buffer[0]); } void iton_bt_send2(uint8_t cmd, uint8_t b1, uint8_t b2) { - WAIT_FOR_FINISH(); + while (readPin(ITON_BT_IRQ_LINE)); + writePinHigh(ITON_BT_IRQ_LINE); - iton_bt_tx[0] = cmd; - iton_bt_tx[1] = b1; - iton_bt_tx[2] = b2; - spiStartSend(&ITON_BT_SPI_PORT, 3, &iton_bt_tx[0]); -} + iton_bt_buffer[0] = cmd; + iton_bt_buffer[1] = b1; + iton_bt_buffer[2] = b2; -void iton_bt_report_hid(uint8_t *raw) { - iton_bt_send(report_hid, raw, 8); + spiStartSend(&ITON_BT_SPI_PORT, 3, &iton_bt_buffer[0]); } -void iton_bt_report_nkro(uint8_t *raw) { - iton_bt_send(report_nkro, raw, 15); +inline void iton_bt_send_ack(uint8_t b1, uint8_t b2) { + writePinHigh(ITON_BT_IRQ_LINE); + iton_bt_buffer[0] = control; + iton_bt_buffer[1] = b1; + iton_bt_buffer[2] = b2; + chSysLockFromISR(); + spiStartSendI(&ITON_BT_SPI_PORT, 3, &iton_bt_buffer[0]); + chSysUnlockFromISR(); } -void iton_bt_report_media(uint16_t data) { - iton_bt_send2(report_media, HIGH_BITS(data), LOW_BITS(data)); +void iton_bt_send_fn(bool pressed) { + uint8_t data = pressed ? 0xA3 : 0x00; + + iton_bt_send(report_fn, &data, 1); } -void iton_bt_report_system(uint16_t data) { +void iton_bt_send_system(uint16_t data) { iton_bt_send(report_system, (uint8_t *)&data, 1); } -void iton_bt_send_keyboard(report_keyboard_t *report) { +void iton_bt_send_consumer(uint16_t data) { + iton_bt_send2(report_consumer, HIGH_BITS(data), LOW_BITS(data)); +} -#ifndef ITON_BT_NO_6KRO_HACK +void iton_bt_send_keyboard(report_keyboard_t *report) { // iton module only reads 5 of the keys in the hid report // so we send the last key as an nkro report. if (report->keys[5] != iton_bt_send_kb_last_key) { - uint8_t nkro_report[16] = {0}; + uint8_t nkro_report[15] = {0}; nkro_report[report->keys[5] >> 3] |= (1 << (report->keys[5] & 7)); iton_bt_send_kb_last_key = report->keys[5]; - return iton_bt_report_nkro(&nkro_report[0]); + return iton_bt_send(report_nkro, &nkro_report[0], 15); } -#endif - iton_bt_report_hid(&report->raw[HID_REPORT_OFFSET]); + iton_bt_send(report_hid, &report->raw[HID_REPORT_OFFSET], 8); } diff --git a/drivers/bluetooth/iton_bt.h b/drivers/bluetooth/iton_bt.h index c1258fa86f1c..cdbf48cb3e95 100644 --- a/drivers/bluetooth/iton_bt.h +++ b/drivers/bluetooth/iton_bt.h @@ -1,4 +1,4 @@ -// Copyright 2022 1Conan (@1Conan) +// Copyright 2023 1Conan (@1Conan) // SPDX-License-Identifier: GPL-2.0-or-later #include "report.h" @@ -12,7 +12,7 @@ enum iton_bt_cmd { // mcu to iton report_hid = 0xA1, report_nkro = 0xA2, - report_media = 0xA3, + report_consumer = 0xA3, report_system = 0xA4, report_fn = 0xA5, control = 0xA6, @@ -25,12 +25,18 @@ enum iton_bt_cmd { }; enum iton_bt_control_cmd { + control_power = 0x25, control_usb = 0x58, control_bt = 0x51, control_pins = 0x52, }; enum iton_bt_control_param { + // control_power + sleep_idle_10m = 0x01, + sleep_idle_20m = 0x02, + sleep_idle_30m = 0x03, + // control_usb mode_usb = 0x01, @@ -38,11 +44,20 @@ enum iton_bt_control_param { mode_bt = 0x62, reset_pairing = 0x70, enter_pairing = 0x89, - switch_profile = 0x81, // + 0-5 profiles + switch_profile = 0x81, // + 0-5 profiles os_mac = 0x74, os_win = 0x75, + connect_ack = 0x50, disconnect_ack = 0x51, + wake_ack = 0x60, + unknown_ack = 0x52, + + query_voltage = 0x66, + query_battery_level = 0x61, + + disable_sleep = 0x65, + enable_sleep = 0x68, }; enum iton_bt_notification_type { @@ -56,9 +71,18 @@ enum iton_bt_notification_param { batt_exit_low_battery_mode = 0x0A, batt_low_power_shutdown = 0x07, + batt_above_70 = 0x04, + batt_between_30_70 = 0x02, + batt_below_30 = 0x01, + query_working_mode = 0xA0, query_bt_name = 0xA1, + // Wake from batt_low_power_shutdown + batt_wake_mcu = 0x0B, + + batt_unknown = 0x08, + // notif_bluetooth bt_connection_success = 0x76, bt_entered_pairing = 0x77, @@ -70,33 +94,54 @@ enum iton_bt_notification_param { * Exported Variables */ uint8_t iton_bt_led_state; +bool iton_bt_is_connected; + +/** + * Driver Callbacks + */ + +/** + * Driver Callbacks + */ +void iton_bt_battery_voltage_low(void); +void iton_bt_battery_exit_low_battery_mode(void); +void iton_bt_battery_low_power_shutdown(void); +void iton_bt_battery_level(uint8_t level); + +void iton_bt_connection_successful(void); +void iton_bt_entered_pairing(void); +void iton_bt_disconnected(void); +void iton_bt_enters_connection_state(void); /** * Driver Functions */ void iton_bt_init(void); -void iton_bt_start(void); -void iton_bt_stop(void); void iton_bt_send(uint8_t cmd, uint8_t *data, uint8_t len); void iton_bt_send2(uint8_t cmd, uint8_t b1, uint8_t b2); -void iton_bt_report_hid(uint8_t *raw); -void iton_bt_report_nkro(uint8_t *raw); -void iton_bt_report_media(uint16_t data); -void iton_bt_report_system(uint16_t data); +void iton_bt_send_ack(uint8_t b1, uint8_t b2); + +void iton_bt_send_fn(bool pressed); +void iton_bt_send_system(uint16_t data); +void iton_bt_send_consumer(uint16_t data); void iton_bt_send_keyboard(report_keyboard_t *report); /** * Driver Macros */ - #define iton_bt_control(cmd, param) iton_bt_send2(control, cmd, param) #define iton_bt_control_bt(param) iton_bt_control(control_bt, param) -#define iton_bt_control_usb(param) iton_bt_control(control_bt, param) +#define iton_bt_control_usb(param) iton_bt_control(control_usb, param) #define iton_bt_mode_usb() iton_bt_control_usb(mode_usb) #define iton_bt_mode_bt() iton_bt_control_bt(mode_bt) #define iton_bt_reset_pairing() iton_bt_control_bt(reset_pairing) #define iton_bt_enter_pairing() iton_bt_control_bt(enter_pairing) #define iton_bt_switch_profile(x) iton_bt_control_bt(switch_profile + x) -#define iton_bt_os_win() iton_bt_control_bt(os_win) #define iton_bt_os_mac() iton_bt_control_bt(os_mac) +#define iton_bt_os_win() iton_bt_control_bt(os_win) +#define iton_bt_query_voltage() iton_bt_control_bt(query_voltage) + +#define iton_bt_query_battery_level() iton_bt_control_bt(query_battery_level) +#define iton_bt_disable_sleep() iton_bt_control_bt(disable_sleep) +#define iton_bt_enable_sleep() iton_bt_control_bt(enable_sleep) diff --git a/drivers/bluetooth/outputselect.c b/drivers/bluetooth/outputselect.c index 0656799dd0bc..bb88f9765a42 100644 --- a/drivers/bluetooth/outputselect.c +++ b/drivers/bluetooth/outputselect.c @@ -55,6 +55,12 @@ uint8_t auto_detect_output(void) { } #endif +#ifdef BLUETOOTH_ITON_BT + if (iton_bt_is_connected) { + return OUTPUT_BLUETOOTH; + } +#endif + #ifdef BLUETOOTH_ENABLE return OUTPUT_BLUETOOTH; // should check if BT is connected here #endif