ble_hid_svc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #include "ble_hid_svc.h"
  2. #include "app_common.h"
  3. #include <ble/ble.h>
  4. #include <furi_ble/event_dispatcher.h>
  5. #include <furi_ble/gatt.h>
  6. #include <furi.h>
  7. #include <stdint.h>
  8. #define TAG "BleHid"
  9. #define BLE_SVC_HID_REPORT_MAP_MAX_LEN (255)
  10. #define BLE_SVC_HID_REPORT_MAX_LEN (255)
  11. #define BLE_SVC_HID_REPORT_REF_LEN (2)
  12. #define BLE_SVC_HID_INFO_LEN (4)
  13. #define BLE_SVC_HID_CONTROL_POINT_LEN (1)
  14. #define BLE_SVC_HID_INPUT_REPORT_COUNT (3)
  15. #define BLE_SVC_HID_OUTPUT_REPORT_COUNT (0)
  16. #define BLE_SVC_HID_FEATURE_REPORT_COUNT (0)
  17. #define BLE_SVC_HID_REPORT_COUNT \
  18. (BLE_SVC_HID_INPUT_REPORT_COUNT + BLE_SVC_HID_OUTPUT_REPORT_COUNT + \
  19. BLE_SVC_HID_FEATURE_REPORT_COUNT)
  20. typedef enum {
  21. HidSvcGattCharacteristicProtocolMode = 0,
  22. HidSvcGattCharacteristicReportMap,
  23. HidSvcGattCharacteristicInfo,
  24. HidSvcGattCharacteristicCtrlPoint,
  25. HidSvcGattCharacteristicCount,
  26. } HidSvcGattCharacteristicId;
  27. typedef struct {
  28. uint8_t report_idx;
  29. uint8_t report_type;
  30. } HidSvcReportId;
  31. static_assert(sizeof(HidSvcReportId) == sizeof(uint16_t), "HidSvcReportId must be 2 bytes");
  32. static const Service_UUID_t ble_svc_hid_uuid = {
  33. .Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID,
  34. };
  35. static bool ble_svc_hid_char_desc_data_callback(
  36. const void* context,
  37. const uint8_t** data,
  38. uint16_t* data_len) {
  39. const HidSvcReportId* report_id = context;
  40. *data_len = sizeof(HidSvcReportId);
  41. if(data) {
  42. *data = (const uint8_t*)report_id;
  43. }
  44. return false;
  45. }
  46. typedef struct {
  47. const void* data_ptr;
  48. uint16_t data_len;
  49. } HidSvcDataWrapper;
  50. static bool ble_svc_hid_report_data_callback(
  51. const void* context,
  52. const uint8_t** data,
  53. uint16_t* data_len) {
  54. const HidSvcDataWrapper* report_data = context;
  55. if(data) {
  56. *data = report_data->data_ptr;
  57. *data_len = report_data->data_len;
  58. } else {
  59. *data_len = BLE_SVC_HID_REPORT_MAP_MAX_LEN;
  60. }
  61. return false;
  62. }
  63. static const BleGattCharacteristicParams ble_svc_hid_chars[HidSvcGattCharacteristicCount] = {
  64. [HidSvcGattCharacteristicProtocolMode] =
  65. {.name = "Protocol Mode",
  66. .data_prop_type = FlipperGattCharacteristicDataFixed,
  67. .data.fixed.length = 1,
  68. .uuid.Char_UUID_16 = PROTOCOL_MODE_CHAR_UUID,
  69. .uuid_type = UUID_TYPE_16,
  70. .char_properties = CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP,
  71. .security_permissions = ATTR_PERMISSION_NONE,
  72. .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE,
  73. .is_variable = CHAR_VALUE_LEN_CONSTANT},
  74. [HidSvcGattCharacteristicReportMap] =
  75. {.name = "Report Map",
  76. .data_prop_type = FlipperGattCharacteristicDataCallback,
  77. .data.callback.fn = ble_svc_hid_report_data_callback,
  78. .data.callback.context = NULL,
  79. .uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID,
  80. .uuid_type = UUID_TYPE_16,
  81. .char_properties = CHAR_PROP_READ,
  82. .security_permissions = ATTR_PERMISSION_NONE,
  83. .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS,
  84. .is_variable = CHAR_VALUE_LEN_VARIABLE},
  85. [HidSvcGattCharacteristicInfo] =
  86. {.name = "HID Information",
  87. .data_prop_type = FlipperGattCharacteristicDataFixed,
  88. .data.fixed.length = BLE_SVC_HID_INFO_LEN,
  89. .data.fixed.ptr = NULL,
  90. .uuid.Char_UUID_16 = HID_INFORMATION_CHAR_UUID,
  91. .uuid_type = UUID_TYPE_16,
  92. .char_properties = CHAR_PROP_READ,
  93. .security_permissions = ATTR_PERMISSION_NONE,
  94. .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS,
  95. .is_variable = CHAR_VALUE_LEN_CONSTANT},
  96. [HidSvcGattCharacteristicCtrlPoint] =
  97. {.name = "HID Control Point",
  98. .data_prop_type = FlipperGattCharacteristicDataFixed,
  99. .data.fixed.length = BLE_SVC_HID_CONTROL_POINT_LEN,
  100. .uuid.Char_UUID_16 = HID_CONTROL_POINT_CHAR_UUID,
  101. .uuid_type = UUID_TYPE_16,
  102. .char_properties = CHAR_PROP_WRITE_WITHOUT_RESP,
  103. .security_permissions = ATTR_PERMISSION_NONE,
  104. .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE,
  105. .is_variable = CHAR_VALUE_LEN_CONSTANT},
  106. };
  107. static const BleGattCharacteristicDescriptorParams ble_svc_hid_char_descr_template = {
  108. .uuid_type = UUID_TYPE_16,
  109. .uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID,
  110. .max_length = BLE_SVC_HID_REPORT_REF_LEN,
  111. .data_callback.fn = ble_svc_hid_char_desc_data_callback,
  112. .security_permissions = ATTR_PERMISSION_NONE,
  113. .access_permissions = ATTR_ACCESS_READ_WRITE,
  114. .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS,
  115. .is_variable = CHAR_VALUE_LEN_CONSTANT,
  116. };
  117. static const BleGattCharacteristicParams ble_svc_hid_report_template = {
  118. .name = "Report",
  119. .data_prop_type = FlipperGattCharacteristicDataCallback,
  120. .data.callback.fn = ble_svc_hid_report_data_callback,
  121. .data.callback.context = NULL,
  122. .uuid.Char_UUID_16 = REPORT_CHAR_UUID,
  123. .uuid_type = UUID_TYPE_16,
  124. .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY,
  125. .security_permissions = ATTR_PERMISSION_NONE,
  126. .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS,
  127. .is_variable = CHAR_VALUE_LEN_VARIABLE,
  128. };
  129. struct BleServiceHid {
  130. uint16_t svc_handle;
  131. BleGattCharacteristicInstance chars[HidSvcGattCharacteristicCount];
  132. BleGattCharacteristicInstance input_report_chars[BLE_SVC_HID_INPUT_REPORT_COUNT];
  133. BleGattCharacteristicInstance output_report_chars[BLE_SVC_HID_OUTPUT_REPORT_COUNT];
  134. BleGattCharacteristicInstance feature_report_chars[BLE_SVC_HID_FEATURE_REPORT_COUNT];
  135. GapSvcEventHandler* event_handler;
  136. };
  137. static BleEventAckStatus ble_svc_hid_event_handler(void* event, void* context) {
  138. UNUSED(context);
  139. BleEventAckStatus ret = BleEventNotAck;
  140. hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data);
  141. evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data;
  142. // aci_gatt_attribute_modified_event_rp0* attribute_modified;
  143. if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
  144. if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
  145. // Process modification events
  146. ret = BleEventAckFlowEnable;
  147. } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
  148. // Process notification confirmation
  149. ret = BleEventAckFlowEnable;
  150. }
  151. }
  152. return ret;
  153. }
  154. BleServiceHid* ble_svc_hid_start() {
  155. BleServiceHid* hid_svc = malloc(sizeof(BleServiceHid));
  156. // Register event handler
  157. hid_svc->event_handler =
  158. ble_event_dispatcher_register_svc_handler(ble_svc_hid_event_handler, hid_svc);
  159. /**
  160. * Add Human Interface Device Service
  161. */
  162. if(!ble_gatt_service_add(
  163. UUID_TYPE_16,
  164. &ble_svc_hid_uuid,
  165. PRIMARY_SERVICE,
  166. 2 + /* protocol mode */
  167. (4 * BLE_SVC_HID_INPUT_REPORT_COUNT) + (3 * BLE_SVC_HID_OUTPUT_REPORT_COUNT) +
  168. (3 * BLE_SVC_HID_FEATURE_REPORT_COUNT) + 1 + 2 + 2 +
  169. 2, /* Service + Report Map + HID Information + HID Control Point */
  170. &hid_svc->svc_handle)) {
  171. free(hid_svc);
  172. return NULL;
  173. }
  174. // Maintain previously defined characteristic order
  175. ble_gatt_characteristic_init(
  176. hid_svc->svc_handle,
  177. &ble_svc_hid_chars[HidSvcGattCharacteristicProtocolMode],
  178. &hid_svc->chars[HidSvcGattCharacteristicProtocolMode]);
  179. uint8_t protocol_mode = 1;
  180. ble_gatt_characteristic_update(
  181. hid_svc->svc_handle,
  182. &hid_svc->chars[HidSvcGattCharacteristicProtocolMode],
  183. &protocol_mode);
  184. // reports
  185. BleGattCharacteristicDescriptorParams ble_svc_hid_char_descr;
  186. BleGattCharacteristicParams report_char;
  187. HidSvcReportId report_id;
  188. memcpy(
  189. &ble_svc_hid_char_descr, &ble_svc_hid_char_descr_template, sizeof(ble_svc_hid_char_descr));
  190. memcpy(&report_char, &ble_svc_hid_report_template, sizeof(report_char));
  191. ble_svc_hid_char_descr.data_callback.context = &report_id;
  192. report_char.descriptor_params = &ble_svc_hid_char_descr;
  193. typedef struct {
  194. uint8_t report_type;
  195. uint8_t report_count;
  196. BleGattCharacteristicInstance* chars;
  197. } HidSvcReportCharProps;
  198. HidSvcReportCharProps hid_report_chars[] = {
  199. {0x01, BLE_SVC_HID_INPUT_REPORT_COUNT, hid_svc->input_report_chars},
  200. {0x02, BLE_SVC_HID_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars},
  201. {0x03, BLE_SVC_HID_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars},
  202. };
  203. for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars);
  204. report_type_idx++) {
  205. report_id.report_type = hid_report_chars[report_type_idx].report_type;
  206. for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count;
  207. report_idx++) {
  208. report_id.report_idx = report_idx + 1;
  209. ble_gatt_characteristic_init(
  210. hid_svc->svc_handle,
  211. &report_char,
  212. &hid_report_chars[report_type_idx].chars[report_idx]);
  213. }
  214. }
  215. // Setup remaining characteristics
  216. for(size_t i = HidSvcGattCharacteristicReportMap; i < HidSvcGattCharacteristicCount; i++) {
  217. ble_gatt_characteristic_init(
  218. hid_svc->svc_handle, &ble_svc_hid_chars[i], &hid_svc->chars[i]);
  219. }
  220. return hid_svc;
  221. }
  222. bool ble_svc_hid_update_report_map(BleServiceHid* hid_svc, const uint8_t* data, uint16_t len) {
  223. furi_assert(data);
  224. furi_assert(hid_svc);
  225. HidSvcDataWrapper report_data = {
  226. .data_ptr = data,
  227. .data_len = len,
  228. };
  229. return ble_gatt_characteristic_update(
  230. hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicReportMap], &report_data);
  231. }
  232. bool ble_svc_hid_update_input_report(
  233. BleServiceHid* hid_svc,
  234. uint8_t input_report_num,
  235. uint8_t* data,
  236. uint16_t len) {
  237. furi_assert(data);
  238. furi_assert(hid_svc);
  239. furi_assert(input_report_num < BLE_SVC_HID_INPUT_REPORT_COUNT);
  240. HidSvcDataWrapper report_data = {
  241. .data_ptr = data,
  242. .data_len = len,
  243. };
  244. return ble_gatt_characteristic_update(
  245. hid_svc->svc_handle, &hid_svc->input_report_chars[input_report_num], &report_data);
  246. }
  247. bool ble_svc_hid_update_info(BleServiceHid* hid_svc, uint8_t* data) {
  248. furi_assert(data);
  249. furi_assert(hid_svc);
  250. return ble_gatt_characteristic_update(
  251. hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicInfo], &data);
  252. }
  253. void ble_svc_hid_stop(BleServiceHid* hid_svc) {
  254. furi_assert(hid_svc);
  255. ble_event_dispatcher_unregister_svc_handler(hid_svc->event_handler);
  256. // Delete characteristics
  257. for(size_t i = 0; i < HidSvcGattCharacteristicCount; i++) {
  258. ble_gatt_characteristic_delete(hid_svc->svc_handle, &hid_svc->chars[i]);
  259. }
  260. typedef struct {
  261. uint8_t report_count;
  262. BleGattCharacteristicInstance* chars;
  263. } HidSvcReportCharProps;
  264. HidSvcReportCharProps hid_report_chars[] = {
  265. {BLE_SVC_HID_INPUT_REPORT_COUNT, hid_svc->input_report_chars},
  266. {BLE_SVC_HID_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars},
  267. {BLE_SVC_HID_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars},
  268. };
  269. for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars);
  270. report_type_idx++) {
  271. for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count;
  272. report_idx++) {
  273. ble_gatt_characteristic_delete(
  274. hid_svc->svc_handle, &hid_report_chars[report_type_idx].chars[report_idx]);
  275. }
  276. }
  277. // Delete service
  278. ble_gatt_service_delete(hid_svc->svc_handle);
  279. free(hid_svc);
  280. }