[FL-2119] BT HID App (#888)

* view_dispatcher: add default back processing for Long events
* assets: add ble connected and disconnected assets
* bt keyboard: introduce new application
* bt keyboard: add logic to keyboard mode
* bt: remove debug ble hid application
* bt hid: introduce media controller
* gui canvas: rename CanvasFontDirection -> CanvasDirection
* gui canvas: add arrow element
* assets: update finilized assets
* bt hid: finalise keynote GUI
* bt hid: finalise media player GUI
* bt: add media key buttons support
* bt: add exit confirm view
* bt: change Clicker -> Remote
* bt: support f6 target
* bt: hopefully final bt hid design
* bt hid: add blue led notification when device is connected
* bt: leave only bt clicker for now
* bt: add display notification on pin code show event
This commit is contained in:
gornekich
2021-12-15 20:39:06 +03:00
committed by GitHub
parent 63642617ee
commit f0d4584b40
36 changed files with 1319 additions and 579 deletions

View File

@@ -75,7 +75,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt )
}
if(gap->enable_adv) {
// Restart advertising
gap_advertise_start(GapCommandAdvFast);
gap_advertise_start(GapStateAdvFast);
furi_hal_power_insomnia_exit();
}
BleEvent event = {.type = BleEventTypeDisconnected};
@@ -446,7 +446,11 @@ void gap_thread_stop() {
static int32_t gap_app(void *context) {
GapCommand command;
while(1) {
furi_check(osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever) == osOK);
osStatus status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever);
if(status != osOK) {
FURI_LOG_E(TAG, "Message queue get error: %d", status);
continue;
}
osMutexAcquire(gap->state_mutex, osWaitForever);
if(command == GapCommandKillThread) {
break;

View File

@@ -3,8 +3,8 @@
#include <stdint.h>
#include <stdbool.h>
#define HID_SVC_REPORT_MAP_MAX_LEN (80)
#define HID_SVC_REPORT_MAX_LEN (8)
#define HID_SVC_REPORT_MAP_MAX_LEN (120)
#define HID_SVC_REPORT_MAX_LEN (9)
#define HID_SVC_BOOT_KEYBOARD_INPUT_REPORT_MAX_LEN (8)
#define HID_SVC_REPORT_REF_LEN (2)
#define HID_SVC_INFO_LEN (4)

View File

@@ -13,16 +13,23 @@
#define FURI_HAL_BT_HID_KB_KEYS_MAX (6)
typedef struct {
// uint8_t report_id;
uint8_t mods;
uint8_t reserved;
uint8_t key[FURI_HAL_BT_HID_KB_KEYS_MAX];
} FuriHalBtHidKbReport;
// TODO rework with HID defines
typedef struct {
uint8_t report_id;
uint8_t key;
} FuriHalBtHidMediaReport;
// TODO make composite HID device
static uint8_t furi_hal_bt_hid_report_map_data[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
// 0x85, 0x01, // Report ID (1)
0x05, 0x07, // Usage Page (Key Codes)
0x19, 0xe0, // Usage Minimum (224)
0x29, 0xe7, // Usage Maximum (231)
@@ -62,10 +69,31 @@ static uint8_t furi_hal_bt_hid_report_map_data[] = {
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data, Variable, Absolute)
0xC0 // End Collection (Application)
0xC0, // End Collection (Application)
// 0x05, 0x0C, // Usage Page (Consumer)
// 0x09, 0x01, // Usage (Consumer Control)
// 0xA1, 0x01, // Collection (Application)
// 0x85, 0x02, // Report ID (2)
// 0x05, 0x0C, // Usage Page (Consumer)
// 0x15, 0x00, // Logical Minimum (0)
// 0x25, 0x01, // Logical Maximum (1)
// 0x75, 0x01, // Report Size (1)
// 0x95, 0x07, // Report Count (7)
// 0x09, 0xB5, // Usage (Scan Next Track)
// 0x09, 0xB6, // Usage (Scan Previous Track)
// 0x09, 0xB7, // Usage (Stop)
// 0x09, 0xB8, // Usage (Eject)
// 0x09, 0xCD, // Usage (Play/Pause)
// 0x09, 0xE2, // Usage (Mute)
// 0x09, 0xE9, // Usage (Volume Increment)
// 0x09, 0xEA, // Usage (Volume Decrement)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0xC0, // End Collection
};
FuriHalBtHidKbReport* kb_report = NULL;
FuriHalBtHidMediaReport* media_report = NULL;
void furi_hal_bt_hid_start() {
// Start device info
@@ -82,6 +110,7 @@ void furi_hal_bt_hid_start() {
}
// Configure HID Keyboard
kb_report = furi_alloc(sizeof(FuriHalBtHidKbReport));
media_report = furi_alloc(sizeof(FuriHalBtHidMediaReport));
// Configure Report Map characteristic
hid_svc_update_report_map(furi_hal_bt_hid_report_map_data, sizeof(furi_hal_bt_hid_report_map_data));
// Configure HID Information characteristic
@@ -107,11 +136,14 @@ void furi_hal_bt_hid_stop() {
hid_svc_stop();
}
free(kb_report);
free(media_report);
media_report = NULL;
kb_report = NULL;
}
bool furi_hal_bt_hid_kb_press(uint16_t button) {
furi_assert(kb_report);
// kb_report->report_id = 0x01;
for (uint8_t i = 0; i < FURI_HAL_BT_HID_KB_KEYS_MAX; i++) {
if (kb_report->key[i] == 0) {
kb_report->key[i] = button & 0xFF;
@@ -124,6 +156,7 @@ bool furi_hal_bt_hid_kb_press(uint16_t button) {
bool furi_hal_bt_hid_kb_release(uint16_t button) {
furi_assert(kb_report);
// kb_report->report_id = 0x01;
for (uint8_t i = 0; i < FURI_HAL_BT_HID_KB_KEYS_MAX; i++) {
if (kb_report->key[i] == (button & 0xFF)) {
kb_report->key[i] = 0;
@@ -136,6 +169,28 @@ bool furi_hal_bt_hid_kb_release(uint16_t button) {
bool furi_hal_bt_hid_kb_release_all() {
furi_assert(kb_report);
// kb_report->report_id = 0x01;
memset(kb_report, 0, sizeof(FuriHalBtHidKbReport));
return hid_svc_update_input_report((uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport));
}
bool furi_hal_bt_hid_media_press(uint8_t button) {
furi_assert(media_report);
media_report->report_id = 0x02;
media_report->key |= (0x01 << button);
return hid_svc_update_input_report((uint8_t*)media_report, sizeof(FuriHalBtHidMediaReport));
}
bool furi_hal_bt_hid_media_release(uint8_t button) {
furi_assert(media_report);
media_report->report_id = 0x02;
media_report->key &= ~(0x01 << button);
return hid_svc_update_input_report((uint8_t*)media_report, sizeof(FuriHalBtHidMediaReport));
}
bool furi_hal_bt_hid_media_release_all() {
furi_assert(media_report);
media_report->report_id = 0x02;
media_report->key = 0x00;
return hid_svc_update_input_report((uint8_t*)media_report, sizeof(FuriHalBtHidMediaReport));
}

View File

@@ -126,9 +126,9 @@ bool furi_hal_bt_start_app(FuriHalBtProfile profile, BleEventCallback event_cb,
} else if(profile == FuriHalBtProfileHidKeyboard) {
// Change MAC address for HID profile
config->mac_address[2]++;
// Change name Flipper -> Clicker
const char* clicker_str = "Clicker";
memcpy(&config->adv_name[1], clicker_str, strlen(clicker_str) - 1);
// Change name Flipper -> Keynote
const char* clicker_str = "Keynote";
memcpy(&config->adv_name[1], clicker_str, strlen(clicker_str));
}
ret = gap_init(config, event_cb, context);
if(!ret) {

View File

@@ -75,7 +75,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt )
}
if(gap->enable_adv) {
// Restart advertising
gap_advertise_start(GapCommandAdvFast);
gap_advertise_start(GapStateAdvFast);
furi_hal_power_insomnia_exit();
}
BleEvent event = {.type = BleEventTypeDisconnected};
@@ -446,7 +446,11 @@ void gap_thread_stop() {
static int32_t gap_app(void *context) {
GapCommand command;
while(1) {
furi_check(osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever) == osOK);
osStatus status = osMessageQueueGet(gap->command_queue, &command, NULL, osWaitForever);
if(status != osOK) {
FURI_LOG_E(TAG, "Message queue get error: %d", status);
continue;
}
osMutexAcquire(gap->state_mutex, osWaitForever);
if(command == GapCommandKillThread) {
break;

View File

@@ -3,8 +3,8 @@
#include <stdint.h>
#include <stdbool.h>
#define HID_SVC_REPORT_MAP_MAX_LEN (80)
#define HID_SVC_REPORT_MAX_LEN (8)
#define HID_SVC_REPORT_MAP_MAX_LEN (120)
#define HID_SVC_REPORT_MAX_LEN (9)
#define HID_SVC_BOOT_KEYBOARD_INPUT_REPORT_MAX_LEN (8)
#define HID_SVC_REPORT_REF_LEN (2)
#define HID_SVC_INFO_LEN (4)

View File

@@ -13,16 +13,23 @@
#define FURI_HAL_BT_HID_KB_KEYS_MAX (6)
typedef struct {
// uint8_t report_id;
uint8_t mods;
uint8_t reserved;
uint8_t key[FURI_HAL_BT_HID_KB_KEYS_MAX];
} FuriHalBtHidKbReport;
// TODO rework with HID defines
typedef struct {
uint8_t report_id;
uint8_t key;
} FuriHalBtHidMediaReport;
// TODO make composite HID device
static uint8_t furi_hal_bt_hid_report_map_data[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
// 0x85, 0x01, // Report ID (1)
0x05, 0x07, // Usage Page (Key Codes)
0x19, 0xe0, // Usage Minimum (224)
0x29, 0xe7, // Usage Maximum (231)
@@ -62,10 +69,31 @@ static uint8_t furi_hal_bt_hid_report_map_data[] = {
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data, Variable, Absolute)
0xC0 // End Collection (Application)
0xC0, // End Collection (Application)
// 0x05, 0x0C, // Usage Page (Consumer)
// 0x09, 0x01, // Usage (Consumer Control)
// 0xA1, 0x01, // Collection (Application)
// 0x85, 0x02, // Report ID (2)
// 0x05, 0x0C, // Usage Page (Consumer)
// 0x15, 0x00, // Logical Minimum (0)
// 0x25, 0x01, // Logical Maximum (1)
// 0x75, 0x01, // Report Size (1)
// 0x95, 0x07, // Report Count (7)
// 0x09, 0xB5, // Usage (Scan Next Track)
// 0x09, 0xB6, // Usage (Scan Previous Track)
// 0x09, 0xB7, // Usage (Stop)
// 0x09, 0xB8, // Usage (Eject)
// 0x09, 0xCD, // Usage (Play/Pause)
// 0x09, 0xE2, // Usage (Mute)
// 0x09, 0xE9, // Usage (Volume Increment)
// 0x09, 0xEA, // Usage (Volume Decrement)
// 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
// 0xC0, // End Collection
};
FuriHalBtHidKbReport* kb_report = NULL;
FuriHalBtHidMediaReport* media_report = NULL;
void furi_hal_bt_hid_start() {
// Start device info
@@ -82,6 +110,7 @@ void furi_hal_bt_hid_start() {
}
// Configure HID Keyboard
kb_report = furi_alloc(sizeof(FuriHalBtHidKbReport));
media_report = furi_alloc(sizeof(FuriHalBtHidMediaReport));
// Configure Report Map characteristic
hid_svc_update_report_map(furi_hal_bt_hid_report_map_data, sizeof(furi_hal_bt_hid_report_map_data));
// Configure HID Information characteristic
@@ -107,11 +136,14 @@ void furi_hal_bt_hid_stop() {
hid_svc_stop();
}
free(kb_report);
free(media_report);
media_report = NULL;
kb_report = NULL;
}
bool furi_hal_bt_hid_kb_press(uint16_t button) {
furi_assert(kb_report);
// kb_report->report_id = 0x01;
for (uint8_t i = 0; i < FURI_HAL_BT_HID_KB_KEYS_MAX; i++) {
if (kb_report->key[i] == 0) {
kb_report->key[i] = button & 0xFF;
@@ -124,6 +156,7 @@ bool furi_hal_bt_hid_kb_press(uint16_t button) {
bool furi_hal_bt_hid_kb_release(uint16_t button) {
furi_assert(kb_report);
// kb_report->report_id = 0x01;
for (uint8_t i = 0; i < FURI_HAL_BT_HID_KB_KEYS_MAX; i++) {
if (kb_report->key[i] == (button & 0xFF)) {
kb_report->key[i] = 0;
@@ -136,6 +169,28 @@ bool furi_hal_bt_hid_kb_release(uint16_t button) {
bool furi_hal_bt_hid_kb_release_all() {
furi_assert(kb_report);
// kb_report->report_id = 0x01;
memset(kb_report, 0, sizeof(FuriHalBtHidKbReport));
return hid_svc_update_input_report((uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport));
}
bool furi_hal_bt_hid_media_press(uint8_t button) {
furi_assert(media_report);
media_report->report_id = 0x02;
media_report->key |= (0x01 << button);
return hid_svc_update_input_report((uint8_t*)media_report, sizeof(FuriHalBtHidMediaReport));
}
bool furi_hal_bt_hid_media_release(uint8_t button) {
furi_assert(media_report);
media_report->report_id = 0x02;
media_report->key &= ~(0x01 << button);
return hid_svc_update_input_report((uint8_t*)media_report, sizeof(FuriHalBtHidMediaReport));
}
bool furi_hal_bt_hid_media_release_all() {
furi_assert(media_report);
media_report->report_id = 0x02;
media_report->key = 0x00;
return hid_svc_update_input_report((uint8_t*)media_report, sizeof(FuriHalBtHidMediaReport));
}

View File

@@ -126,9 +126,9 @@ bool furi_hal_bt_start_app(FuriHalBtProfile profile, BleEventCallback event_cb,
} else if(profile == FuriHalBtProfileHidKeyboard) {
// Change MAC address for HID profile
config->mac_address[2]++;
// Change name Flipper -> Clicker
const char* clicker_str = "Clicker";
memcpy(&config->adv_name[1], clicker_str, strlen(clicker_str) - 1);
// Change name Flipper -> Keynote
const char* clicker_str = "Keynote";
memcpy(&config->adv_name[1], clicker_str, strlen(clicker_str));
}
ret = gap_init(config, event_cb, context);
if(!ret) {

View File

@@ -3,6 +3,17 @@
#include <stdint.h>
#include <stdbool.h>
enum FuriHalBtHidMediKeys{
FuriHalBtHidMediaScanNext,
FuriHalBtHidMediaScanPrevious,
FuriHalBtHidMediaStop,
FuriHalBtHidMediaEject,
FuriHalBtHidMediaPlayPause,
FuriHalBtHidMediaMute,
FuriHalBtHidMediaVolumeUp,
FuriHalBtHidMediaVolumeDown,
};
/** Start Hid Keyboard Profile
*/
void furi_hal_bt_hid_start();
@@ -11,7 +22,7 @@ void furi_hal_bt_hid_start();
*/
void furi_hal_bt_hid_stop();
/** Press key button
/** Press keyboard button
*
* @param button button code from HID specification
*
@@ -19,7 +30,7 @@ void furi_hal_bt_hid_stop();
*/
bool furi_hal_bt_hid_kb_press(uint16_t button);
/** Release key button
/** Release keyboard button
*
* @param button button code from HID specification
*
@@ -27,8 +38,26 @@ bool furi_hal_bt_hid_kb_press(uint16_t button);
*/
bool furi_hal_bt_hid_kb_release(uint16_t button);
/** Release all key buttons
/** Release all keyboard buttons
*
* @return true on success
*/
bool furi_hal_bt_hid_kb_release_all();
/** Release all media buttons
*
* @return true on success
*/
bool furi_hal_bt_hid_media_press(uint8_t button);
/** Release all media buttons
*
* @return true on success
*/
bool furi_hal_bt_hid_media_release(uint8_t button);
/** Release all media buttons
*
* @return true on success
*/
bool furi_hal_bt_hid_media_release_all();