Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ItonBT Driver #292

Open
wants to merge 19 commits into
base: sn32_develop
Choose a base branch
from
7 changes: 6 additions & 1 deletion builddefs/common_features.mk
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,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)
Expand All @@ -908,6 +908,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
Expand Down
2 changes: 1 addition & 1 deletion data/schemas/keyboard.jsonschema
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
"properties": {
"driver": {
"type": "string",
"enum": ["bluefruit_le", "custom", "rn42"]
"enum": ["bluefruit_le", "custom", "rn42", "iton_bt"]
}
}
},
Expand Down
8 changes: 8 additions & 0 deletions drivers/bluetooth/bluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@
# 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) {
#if defined(BLUETOOTH_BLUEFRUIT_LE)
bluefruit_le_init();
#elif defined(BLUETOOTH_RN42)
rn42_init();
#elif defined(BLUETOOTH_ITON_BT)
iton_bt_init();
#endif
}

Expand All @@ -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
}

Expand All @@ -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
}
245 changes: 245 additions & 0 deletions drivers/bluetooth/iton_bt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
// Copyright 2023 1Conan (@1Conan)

Check failure on line 1 in drivers/bluetooth/iton_bt.c

View workflow job for this annotation

GitHub Actions / lint

Requires Formatting
// SPDX-License-Identifier: GPL-2.0-or-later

#include <string.h>
#include <hal.h>
#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)
1Conan marked this conversation as resolved.
Show resolved Hide resolved
.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) {
1Conan marked this conversation as resolved.
Show resolved Hide resolved
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);
}
Loading
Loading