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

Host driver (wireless) rework, phase 1. #24365

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions drivers/bluetooth/bluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdlib.h>
#include "host_driver.h"
#include "bluetooth.h"

#if defined(BLUETOOTH_BLUEFRUIT_LE)
Expand Down Expand Up @@ -53,10 +55,50 @@ void bluetooth_send_mouse(report_mouse_t *report) {
#endif
}

void bluetooth_send_consumer(uint16_t usage) {
void bluetooth_send_extra(report_extra_t *report) {
#if defined(BLUETOOTH_BLUEFRUIT_LE)
bluefruit_le_send_consumer(usage);
switch (report->report_id) {
case REPORT_ID_CONSUMER:
bluefruit_le_send_consumer(report->usage);
break;
case REPORT_ID_SYSTEM:
// bluefruit_le_send_system(report->usage);
break;
}
#elif defined(BLUETOOTH_RN42)
rn42_send_consumer(usage);
switch (report->report_id) {
case REPORT_ID_CONSUMER:
rn42_send_consumer(report->usage);
break;
case REPORT_ID_SYSTEM:
// rn42_send_system(report->usage);
break;
}
#endif
}

static host_driver_t bluetooth_driver = {
.has_init_executed = false,
.init = NULL,
.connect = NULL,
.disconnect = NULL,
.is_connected = NULL,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My proposal is to move has_init_executed and is_connected flags and probably others not implemented yet into a state enum. Like it is already done for usb_device_state with callbacks for state changes. As the driver can hardly be connected without running init first.

.keyboard_leds = NULL,
.send_keyboard = bluetooth_send_keyboard,
.send_nkro = NULL,
.send_mouse = bluetooth_send_mouse,
.send_extra = bluetooth_send_extra,
#ifdef JOYSTICK_ENABLE
.send_joystick = NULL,
#endif // JOYSTICK_ENABLE
#ifdef DIGITIZER_ENABLE
.send_digitizer = NULL,
#endif // DIGITIZER_ENABLE
#ifdef PROGRAMMABLE_BUTTON_ENABLE
.send_programmable_button = NULL,
#endif // PROGRAMMABLE_BUTTON_ENABLE
};
sigprof marked this conversation as resolved.
Show resolved Hide resolved

host_driver_t *host_bluetooth_driver(void) {
return &bluetooth_driver;
}
21 changes: 0 additions & 21 deletions drivers/bluetooth/bluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,3 @@ void bluetooth_init(void);
* \brief Perform housekeeping tasks.
*/
void bluetooth_task(void);

/**
* \brief Send a keyboard report.
*
* \param report The keyboard report to send.
*/
void bluetooth_send_keyboard(report_keyboard_t *report);

/**
* \brief Send a mouse report.
*
* \param report The mouse report to send.
*/
void bluetooth_send_mouse(report_mouse_t *report);

/**
* \brief Send a consumer usage.
*
* \param usage The consumer usage to send.
*/
void bluetooth_send_consumer(uint16_t usage);
3 changes: 2 additions & 1 deletion drivers/bluetooth/outputselect.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ enum outputs {

OUTPUT_NONE,
OUTPUT_USB,
OUTPUT_BLUETOOTH
OUTPUT_BLUETOOTH,
OUTPUT_2P4GHZ,
};

#ifndef OUTPUT_DEFAULT
Expand Down
33 changes: 26 additions & 7 deletions keyboards/annepro2/annepro2_ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,26 @@ static void ap2_ble_swtich_ble_driver(void);

/* -------------------- Static Local Variables ------------------------------ */
static host_driver_t ap2_ble_driver = {
ap2_ble_leds, ap2_ble_keyboard, NULL, ap2_ble_mouse, ap2_ble_extra
.has_init_executed = false,
.init = NULL,
.connect = NULL,
.disconnect = NULL,
.is_connected = NULL,
.keyboard_leds = ap2_ble_leds,
.send_keyboard = ap2_ble_keyboard,
.send_nkro = NULL,
.send_mouse = ap2_ble_mouse,
.send_extra = ap2_ble_extra,
#ifdef JOYSTICK_ENABLE
.send_joystick = NULL,
#endif // JOYSTICK_ENABLE
#ifdef DIGITIZER_ENABLE
.send_digitizer = NULL,
#endif // DIGITIZER_ENABLE
#ifdef PROGRAMMABLE_BUTTON_ENABLE
.send_programmable_button = NULL,
#endif // PROGRAMMABLE_BUTTON_ENABLE

};

static uint8_t ble_mcu_wakeup[11] = {0x7b, 0x12, 0x53, 0x00, 0x03, 0x00, 0x01, 0x7d, 0x02, 0x01, 0x02};
Expand All @@ -58,7 +77,6 @@ static uint8_t ble_mcu_unpair[10] = {

static 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;
#ifdef NKRO_ENABLE
static bool lastNkroStatus = false;
#endif // NKRO_ENABLE
Expand Down Expand Up @@ -96,34 +114,35 @@ void annepro2_ble_connect(uint8_t port) {

void annepro2_ble_disconnect(void) {
/* Skip if the driver is already enabled */
if (host_get_driver() != &ap2_ble_driver) {
if (host_get_driver() != host_bluetooth_driver()) {
return;
}

clear_keyboard();
#ifdef NKRO_ENABLE
keymap_config.nkro = lastNkroStatus;
#endif
host_set_driver(last_host_driver);
host_set_driver(host_usb_driver());
}

void annepro2_ble_unpair(void) {
// sdPut(&SD1, 0x0);
sdWrite(&SD1, ble_mcu_unpair, sizeof(ble_mcu_unpair));
}

host_driver_t *host_bluetooth_driver(void) { return &ap2_ble_driver; }

/* ------------------- Static Function Implementation ----------------------- */
static void ap2_ble_swtich_ble_driver(void) {
if (host_get_driver() == &ap2_ble_driver) {
if (host_get_driver() == host_bluetooth_driver()) {
return;
}
clear_keyboard();
last_host_driver = host_get_driver();
#ifdef NKRO_ENABLE
lastNkroStatus = keymap_config.nkro;
#endif
keymap_config.nkro = false;
host_set_driver(&ap2_ble_driver);
host_set_driver(host_bluetooth_driver());
}

static uint8_t ap2_ble_leds(void) {
Expand Down
39 changes: 35 additions & 4 deletions keyboards/bioi/bluetooth_custom.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "bluetooth.h"
#include "host_driver.h"
#include "uart.h"
#include "progmem.h"
#include "wait.h"
Expand Down Expand Up @@ -75,7 +76,7 @@ void bluetooth_init(void) {

void bluetooth_task(void) {}

void bluetooth_send_keyboard(report_keyboard_t *report)
static void bluetooth_send_keyboard(report_keyboard_t *report)
{
#ifdef BLUEFRUIT_TRACE_SERIAL
bluefruit_trace_header();
Expand All @@ -98,7 +99,7 @@ void bluetooth_send_keyboard(report_keyboard_t *report)
#endif
}

void bluetooth_send_mouse(report_mouse_t *report)
static void bluetooth_send_mouse(report_mouse_t *report)
{
#ifdef BLUEFRUIT_TRACE_SERIAL
bluefruit_trace_header();
Expand Down Expand Up @@ -139,9 +140,12 @@ void bluetooth_send_mouse(report_mouse_t *report)
#define CONSUMER2BLUEFRUIT(usage) \
(usage == AUDIO_MUTE ? 0x00e2 : (usage == AUDIO_VOL_UP ? 0x00e9 : (usage == AUDIO_VOL_DOWN ? 0x00ea : (usage == TRANSPORT_NEXT_TRACK ? 0x00b5 : (usage == TRANSPORT_PREV_TRACK ? 0x00b6 : (usage == TRANSPORT_STOP ? 0x00b7 : (usage == TRANSPORT_STOP_EJECT ? 0x00b8 : (usage == TRANSPORT_PLAY_PAUSE ? 0x00b1 : (usage == AL_CC_CONFIG ? 0x0183 : (usage == AL_EMAIL ? 0x018c : (usage == AL_CALCULATOR ? 0x0192 : (usage == AL_LOCAL_BROWSER ? 0x0196 : (usage == AC_SEARCH ? 0x021f : (usage == AC_HOME ? 0x0223 : (usage == AC_BACK ? 0x0224 : (usage == AC_FORWARD ? 0x0225 : (usage == AC_STOP ? 0x0226 : (usage == AC_REFRESH ? 0x0227 : (usage == AC_BOOKMARKS ? 0x022a : 0)))))))))))))))))))

void bluetooth_send_consumer(uint16_t usage)
static void bluetooth_send_extra(report_extra_t *report)
{
uint16_t bitmap = CONSUMER2BLUEFRUIT(usage);
if(report->report_id != REPORT_ID_CONSUMER)
return;

uint16_t bitmap = CONSUMER2BLUEFRUIT(report->usage);

#ifdef BLUEFRUIT_TRACE_SERIAL
dprintf("\nData: %04X; bitmap: %04X\n", data, bitmap);
Expand All @@ -155,3 +159,30 @@ void bluetooth_send_consumer(uint16_t usage)
bluefruit_trace_footer();
#endif
}

static host_driver_t bluetooth_driver = {
.has_init_executed = false,
.init = NULL,
.connect = NULL,
.disconnect = NULL,
.is_connected = NULL,
.keyboard_leds = NULL,
.send_keyboard = bluetooth_send_keyboard,
.send_nkro = NULL,
.send_mouse = bluetooth_send_mouse,
.send_extra = bluetooth_send_extra,
#ifdef JOYSTICK_ENABLE
.send_joystick = NULL,
#endif // JOYSTICK_ENABLE
#ifdef DIGITIZER_ENABLE
.send_digitizer = NULL,
#endif // DIGITIZER_ENABLE
#ifdef PROGRAMMABLE_BUTTON_ENABLE
.send_programmable_button = NULL,
#endif // PROGRAMMABLE_BUTTON_ENABLE
};

host_driver_t *host_bluetooth_driver(void)
{
return &bluetooth_driver;
}
2 changes: 1 addition & 1 deletion keyboards/sirius/unigo66/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ int main(void)
debug_enable = true;
debug_keyboard = true;

host_set_driver(&lufa_driver);
host_set_driver(host_usb_driver());
keyboard_init();

LUFA_setup();
Expand Down
71 changes: 63 additions & 8 deletions quantum/process_keycode/process_connection.c
Original file line number Diff line number Diff line change
@@ -1,24 +1,79 @@
// Copyright 2024 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#include <stdlib.h>
#include "host_driver.h"
#include "host.h"
#include "outputselect.h"
#include "process_connection.h"

static void cycle_connection(bool forwards) {
int driver_types[] = {OUTPUT_USB, OUTPUT_BLUETOOTH, OUTPUT_2P4GHZ};
host_driver_t *drivers[] = {host_usb_driver(), host_bluetooth_driver(), host_2pt4Ghz_driver()};

host_driver_t *driver = host_get_driver();
int start_idx;
for (int i = 0; i < ARRAY_SIZE(drivers); ++i) {
if (drivers[i] == driver) {
start_idx = i;
}
}
for (int i = 1; i < ARRAY_SIZE(drivers); ++i) {
int idx = (ARRAY_SIZE(drivers) + start_idx + (forwards ? i : -i)) % ARRAY_SIZE(drivers);
if (drivers[idx] != NULL) {
host_set_driver(drivers[idx]);
set_output(driver_types[idx]);
break;
}
}
}

bool process_connection(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
switch (keycode) {
case QK_OUTPUT_NEXT:
set_output(OUTPUT_AUTO); // This should cycle through the outputs going forward. Ensure `docs/keycodes.md`, `docs/features/bluetooth.md` are updated when it does.
cycle_connection(true);
return false;
case QK_OUTPUT_USB:
set_output(OUTPUT_USB);

case QK_OUTPUT_PREV:
cycle_connection(false);
return false;
case QK_OUTPUT_BLUETOOTH:
set_output(OUTPUT_BLUETOOTH);

case QK_OUTPUT_NONE: {
host_driver_t *driver = NULL;
if (host_get_driver() != driver) {
host_set_driver(driver);
set_output(OUTPUT_NONE);
}
return false;
}

case QK_OUTPUT_USB: {
host_driver_t *driver = host_usb_driver();
if (driver && host_get_driver() != driver) {
host_set_driver(driver);
set_output(OUTPUT_USB);
}
return false;
}

case QK_OUTPUT_BLUETOOTH: {
host_driver_t *driver = host_bluetooth_driver();
if (driver && host_get_driver() != driver) {
host_set_driver(driver);
set_output(OUTPUT_BLUETOOTH);
}
Comment on lines +61 to +64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably would need to be refactored to a helper function, and do a bit more:

  1. clear_keyboard(), so that keys are not left reported as held down when the output is off.
  2. Something needs to be done with the NKRO state (many older implementations don't support NKRO over wireless connections). Although the proper way to handle that may be to add a bool (*nkro_enabled)(void) function to the host driver interface, and change all non-USB code to use that function instead of the keyboard_protocol global variable (the variable itself would still be needed inside the USB driver, but may become static there). In that case we may not need to touch keymap_config.nkro in the output switching code (if the wireless connection does not support NKRO, it would look as if the host is using the boot keyboard protocol).

Also what would be the role of set_output() now — just something which triggers the set_output_user() hook? Or should we make set_output() actually switch the host driver, and have just a bunch of set_output() calls in this keycode processing function?

return false;
}

case QK_OUTPUT_2P4GHZ: {
host_driver_t *driver = host_2pt4Ghz_driver();
if (driver && host_get_driver() != driver) {
host_set_driver(driver);
set_output(OUTPUT_2P4GHZ);
}
return false;
}

case QK_OUTPUT_PREV:
case QK_OUTPUT_NONE:
case QK_OUTPUT_2P4GHZ:
case QK_BLUETOOTH_PROFILE_NEXT:
case QK_BLUETOOTH_PROFILE_PREV:
case QK_BLUETOOTH_UNPAIR:
Expand Down
Loading
Loading