From 228e330322d5a57289f0f8678b2763884d5551c1 Mon Sep 17 00:00:00 2001 From: gxcreator Date: Tue, 5 Nov 2024 00:58:00 +0100 Subject: [PATCH] WIP: iton_bt placeholder commit --- builddefs/common_features.mk | 7 +- data/schemas/keyboard.jsonschema | 2 +- drivers/bluetooth/bluetooth.c | 8 + drivers/bluetooth/iton_bt.c | 245 +++++++++++++++++++++++++++++++ drivers/bluetooth/iton_bt.h | 147 +++++++++++++++++++ drivers/bluetooth/outputselect.c | 10 ++ quantum/keyboard.c | 2 +- 7 files changed, 418 insertions(+), 3 deletions(-) create mode 100644 drivers/bluetooth/iton_bt.c create mode 100644 drivers/bluetooth/iton_bt.h diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 0734f70f47ca..00c8b4a4a291 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -879,7 +879,7 @@ ifeq ($(strip $(USBPD_ENABLE)), yes) endif BLUETOOTH_ENABLE ?= no -VALID_BLUETOOTH_DRIVER_TYPES := bluefruit_le custom rn42 +VALID_BLUETOOTH_DRIVER_TYPES := bluefruit_le custom rn42 iton_bt ifeq ($(strip $(BLUETOOTH_ENABLE)), yes) ifeq ($(filter $(strip $(BLUETOOTH_DRIVER)),$(VALID_BLUETOOTH_DRIVER_TYPES)),) $(call CATASTROPHIC_ERROR,Invalid BLUETOOTH_DRIVER,BLUETOOTH_DRIVER="$(BLUETOOTH_DRIVER)" is not a valid Bluetooth driver type) @@ -902,6 +902,11 @@ ifeq ($(strip $(BLUETOOTH_ENABLE)), yes) SRC += $(DRIVER_PATH)/bluetooth/bluetooth.c SRC += $(DRIVER_PATH)/bluetooth/rn42.c endif + + ifeq ($(strip $(BLUETOOTH_DRIVER)), iton_bt) + SRC += $(DRIVER_PATH)/bluetooth/bluetooth.c + SRC += $(DRIVER_PATH)/bluetooth/iton_bt.c + endif endif ENCODER_ENABLE ?= no diff --git a/data/schemas/keyboard.jsonschema b/data/schemas/keyboard.jsonschema index 769786f2b5aa..9990330e9112 100644 --- a/data/schemas/keyboard.jsonschema +++ b/data/schemas/keyboard.jsonschema @@ -190,7 +190,7 @@ "properties": { "driver": { "type": "string", - "enum": ["bluefruit_le", "custom", "rn42"] + "enum": ["bluefruit_le", "custom", "rn42", "iton_bt"] } } }, diff --git a/drivers/bluetooth/bluetooth.c b/drivers/bluetooth/bluetooth.c index d5382401e7e5..abb20d144881 100644 --- a/drivers/bluetooth/bluetooth.c +++ b/drivers/bluetooth/bluetooth.c @@ -21,6 +21,8 @@ # include "bluefruit_le.h" #elif defined(BLUETOOTH_RN42) # include "rn42.h" +#elif defined(BLUETOOTH_ITON_BT) +# include "iton_bt.h" #endif void bluetooth_init(void) { @@ -28,6 +30,8 @@ void bluetooth_init(void) { bluefruit_le_init(); #elif defined(BLUETOOTH_RN42) rn42_init(); +#elif defined(BLUETOOTH_ITON_BT) + iton_bt_init(); #endif } @@ -42,6 +46,8 @@ void bluetooth_send_keyboard(report_keyboard_t *report) { bluefruit_le_send_keyboard(report); #elif defined(BLUETOOTH_RN42) rn42_send_keyboard(report); +#elif defined(BLUETOOTH_ITON_BT) + iton_bt_send_keyboard(report); #endif } @@ -58,5 +64,7 @@ void bluetooth_send_consumer(uint16_t usage) { bluefruit_le_send_consumer(usage); #elif defined(BLUETOOTH_RN42) rn42_send_consumer(usage); +#elif defined(BLUETOOTH_ITON_BT) + iton_bt_send_consumer(usage); #endif } diff --git a/drivers/bluetooth/iton_bt.c b/drivers/bluetooth/iton_bt.c new file mode 100644 index 000000000000..3a6fcbb930a0 --- /dev/null +++ b/drivers/bluetooth/iton_bt.c @@ -0,0 +1,245 @@ +// Copyright 2023 1Conan (@1Conan) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include "gpio.h" +#include "config.h" +#include "iton_bt.h" + +#ifndef ITON_BT_SPI_PORT +# define ITON_BT_SPI_PORT SPID0 +#endif + +#ifndef ITON_BT_IRQ_LINE +# define ITON_BT_IRQ_LINE A0 +#endif + +#ifndef ITON_BT_INT_LINE +# define ITON_BT_INT_LINE A1 +#endif + +#ifndef ITON_BT_BUFFER_LEN +# define ITON_BT_BUFFER_LEN 16 +#endif + +/** + * Driver Macros + */ +#define HIGH_BITS(x) ((uint8_t)(x >> 8)) +#define LOW_BITS(x) ((uint8_t)(x & 0x00FF)) + +/** + * Function definitions + */ +void iton_bt_data_cb(SPIDriver *spip); + +/** + * 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 + */ +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; + +const SPIConfig iton_bt_spicfg = { + .slave = true, + .data_cb = iton_bt_data_cb, +#if defined(SN32) + .ctrl0 = SPI_DATA_LENGTH(8), +#endif +}; + +/** + * Callbacks + */ +#if defined(PAL_USE_CALLBACKS) || defined(PAL_USE_WAIT) +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; + } +} + +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_cb(void *arg) { + if (readPin(ITON_BT_INT_LINE)) { + chSysLockFromISR(); + spiStartReceiveI(&ITON_BT_SPI_PORT, ITON_BT_BUFFER_LEN, &iton_bt_buffer[0]); + chSysUnlockFromISR(); + } else { + chSysLockFromISR(); + spiStopTransferI(&ITON_BT_SPI_PORT, NULL); + 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); +} + +/** + * Driver Functions + */ +void iton_bt_init(void) { + setPinOutput(ITON_BT_IRQ_LINE); + setPinInput(ITON_BT_INT_LINE); + + 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); +#endif + + spiStart(&ITON_BT_SPI_PORT, &iton_bt_spicfg); +} + +void iton_bt_send(uint8_t cmd, uint8_t *data, uint8_t len) { + while (readPin(ITON_BT_IRQ_LINE)); + + writePinHigh(ITON_BT_IRQ_LINE); + 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) { + while (readPin(ITON_BT_IRQ_LINE)); + + writePinHigh(ITON_BT_IRQ_LINE); + iton_bt_buffer[0] = cmd; + iton_bt_buffer[1] = b1; + iton_bt_buffer[2] = b2; + + spiStartSend(&ITON_BT_SPI_PORT, 3, &iton_bt_buffer[0]); +} + +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_send_fn(bool pressed) { + uint8_t data = pressed ? 0xA3 : 0x00; + + iton_bt_send(report_fn, &data, 1); +} + +void iton_bt_send_system(uint16_t data) { + iton_bt_send(report_system, (uint8_t *)&data, 1); +} + +void iton_bt_send_consumer(uint16_t data) { + iton_bt_send2(report_consumer, HIGH_BITS(data), LOW_BITS(data)); +} + +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[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_send(report_nkro, &nkro_report[0], 15); + } + + iton_bt_send(report_hid, &report->mods, 8); +} diff --git a/drivers/bluetooth/iton_bt.h b/drivers/bluetooth/iton_bt.h new file mode 100644 index 000000000000..cdbf48cb3e95 --- /dev/null +++ b/drivers/bluetooth/iton_bt.h @@ -0,0 +1,147 @@ +// Copyright 2023 1Conan (@1Conan) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "report.h" + +#pragma once + +/** + * Driver Structures + */ +enum iton_bt_cmd { + // mcu to iton + report_hid = 0xA1, + report_nkro = 0xA2, + report_consumer = 0xA3, + report_system = 0xA4, + report_fn = 0xA5, + control = 0xA6, + set_name = 0xA7, + set_alarm_volt = 0xA8, + + // iton to mcu + led_state = 0xB1, + notification = 0xB6, +}; + +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, + + // control_bt + mode_bt = 0x62, + reset_pairing = 0x70, + enter_pairing = 0x89, + 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 { + notif_battery = 0x5A, + notif_bluetooth = 0x51, +}; + +enum iton_bt_notification_param { + // notif_battery + batt_voltage_low = 0x06, + 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, + bt_disconected = 0x78, + bt_enters_connection = 0x79, +}; + +/** + * 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_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_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_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_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 b986ba274e9d..bb88f9765a42 100644 --- a/drivers/bluetooth/outputselect.c +++ b/drivers/bluetooth/outputselect.c @@ -19,6 +19,10 @@ along with this program. If not, see . # include "bluefruit_le.h" #endif +#ifdef BLUETOOTH_ITON_BT +# include "iton_bt.h" +#endif + uint8_t desired_output = OUTPUT_DEFAULT; /** \brief Set Output @@ -51,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 diff --git a/quantum/keyboard.c b/quantum/keyboard.c index df1dc1c3ee09..77e69f8c132a 100644 --- a/quantum/keyboard.c +++ b/quantum/keyboard.c @@ -479,7 +479,7 @@ void keyboard_init(void) { // init after split init pointing_device_init(); #endif -#ifdef BLUETOOTH_ENABLE +#if defined(BLUETOOTH_ENABLE) && !defined(BLUETOOTH_MANUAL_INIT) bluetooth_init(); #endif #ifdef HAPTIC_ENABLE