furi-hal-bt-hid.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #include "furi-hal-bt-hid.h"
  2. #include "dev_info_service.h"
  3. #include "battery_service.h"
  4. #include "hid_service.h"
  5. #include <furi.h>
  6. #define FURI_HAL_BT_INFO_BASE_USB_SPECIFICATION (0x0101)
  7. #define FURI_HAL_BT_INFO_COUNTRY_CODE (0x00)
  8. #define FURI_HAL_BT_HID_INFO_FLAG_REMOTE_WAKE_MSK (0x01)
  9. #define FURI_HAL_BT_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK (0x02)
  10. #define FURI_HAL_BT_HID_KB_KEYS_MAX (6)
  11. typedef struct {
  12. uint8_t mods;
  13. uint8_t reserved;
  14. uint8_t key[FURI_HAL_BT_HID_KB_KEYS_MAX];
  15. } FuriHalBtHidKbReport;
  16. // TODO rework with HID defines
  17. static uint8_t furi_hal_bt_hid_report_map_data[] = {
  18. 0x05, 0x01, // Usage Page (Generic Desktop)
  19. 0x09, 0x06, // Usage (Keyboard)
  20. 0xA1, 0x01, // Collection (Application)
  21. 0x05, 0x07, // Usage Page (Key Codes)
  22. 0x19, 0xe0, // Usage Minimum (224)
  23. 0x29, 0xe7, // Usage Maximum (231)
  24. 0x15, 0x00, // Logical Minimum (0)
  25. 0x25, 0x01, // Logical Maximum (1)
  26. 0x75, 0x01, // Report Size (1)
  27. 0x95, 0x08, // Report Count (8)
  28. 0x81, 0x02, // Input (Data, Variable, Absolute)
  29. 0x95, 0x01, // Report Count (1)
  30. 0x75, 0x08, // Report Size (8)
  31. 0x81, 0x01, // Input (Constant) reserved byte(1)
  32. 0x95, 0x05, // Report Count (5)
  33. 0x75, 0x01, // Report Size (1)
  34. 0x05, 0x08, // Usage Page (Page# for LEDs)
  35. 0x19, 0x01, // Usage Minimum (1)
  36. 0x29, 0x05, // Usage Maximum (5)
  37. 0x91, 0x02, // Output (Data, Variable, Absolute), Led report
  38. 0x95, 0x01, // Report Count (1)
  39. 0x75, 0x03, // Report Size (3)
  40. 0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding
  41. 0x95, 0x06, // Report Count (6)
  42. 0x75, 0x08, // Report Size (8)
  43. 0x15, 0x00, // Logical Minimum (0)
  44. 0x25, 0x65, // Logical Maximum (101)
  45. 0x05, 0x07, // Usage Page (Key codes)
  46. 0x19, 0x00, // Usage Minimum (0)
  47. 0x29, 0x65, // Usage Maximum (101)
  48. 0x81, 0x00, // Input (Data, Array) Key array(6 bytes)
  49. 0x09, 0x05, // Usage (Vendor Defined)
  50. 0x15, 0x00, // Logical Minimum (0)
  51. 0x26, 0xFF, 0x00, // Logical Maximum (255)
  52. 0x75, 0x08, // Report Size (8 bit)
  53. 0x95, 0x02, // Report Count (2)
  54. 0xB1, 0x02, // Feature (Data, Variable, Absolute)
  55. 0xC0 // End Collection (Application)
  56. };
  57. FuriHalBtHidKbReport* kb_report = NULL;
  58. void furi_hal_bt_hid_start() {
  59. // Start device info
  60. if(!dev_info_svc_is_started()) {
  61. dev_info_svc_start();
  62. }
  63. // Start battery service
  64. if(!battery_svc_is_started()) {
  65. battery_svc_start();
  66. }
  67. // Start HID service
  68. if(!hid_svc_is_started()) {
  69. hid_svc_start();
  70. }
  71. // Configure HID Keyboard
  72. kb_report = furi_alloc(sizeof(FuriHalBtHidKbReport));
  73. // Configure Report Map characteristic
  74. hid_svc_update_report_map(furi_hal_bt_hid_report_map_data, sizeof(furi_hal_bt_hid_report_map_data));
  75. // Configure HID Information characteristic
  76. uint8_t hid_info_val[4] = {
  77. FURI_HAL_BT_INFO_BASE_USB_SPECIFICATION & 0x00ff,
  78. (FURI_HAL_BT_INFO_BASE_USB_SPECIFICATION & 0xff00) >> 8,
  79. FURI_HAL_BT_INFO_COUNTRY_CODE,
  80. FURI_HAL_BT_HID_INFO_FLAG_REMOTE_WAKE_MSK | FURI_HAL_BT_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK,
  81. };
  82. hid_svc_update_info(hid_info_val, sizeof(hid_info_val));
  83. }
  84. void furi_hal_bt_hid_stop() {
  85. furi_assert(kb_report);
  86. // Stop all services
  87. if(dev_info_svc_is_started()) {
  88. dev_info_svc_stop();
  89. }
  90. if(battery_svc_is_started()) {
  91. battery_svc_stop();
  92. }
  93. if(hid_svc_is_started()) {
  94. hid_svc_stop();
  95. }
  96. free(kb_report);
  97. kb_report = NULL;
  98. }
  99. bool furi_hal_bt_hid_kb_press(uint16_t button) {
  100. furi_assert(kb_report);
  101. for (uint8_t i = 0; i < FURI_HAL_BT_HID_KB_KEYS_MAX; i++) {
  102. if (kb_report->key[i] == 0) {
  103. kb_report->key[i] = button & 0xFF;
  104. break;
  105. }
  106. }
  107. kb_report->mods |= (button >> 8);
  108. return hid_svc_update_input_report((uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport));
  109. }
  110. bool furi_hal_bt_hid_kb_release(uint16_t button) {
  111. furi_assert(kb_report);
  112. for (uint8_t i = 0; i < FURI_HAL_BT_HID_KB_KEYS_MAX; i++) {
  113. if (kb_report->key[i] == (button & 0xFF)) {
  114. kb_report->key[i] = 0;
  115. break;
  116. }
  117. }
  118. kb_report->mods &= ~(button >> 8);
  119. return hid_svc_update_input_report((uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport));
  120. }
  121. bool furi_hal_bt_hid_kb_release_all() {
  122. furi_assert(kb_report);
  123. memset(kb_report, 0, sizeof(FuriHalBtHidKbReport));
  124. return hid_svc_update_input_report((uint8_t*)kb_report, sizeof(FuriHalBtHidKbReport));
  125. }