| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- #include "ble_hid_svc.h"
- #include "app_common.h"
- #include <ble/ble.h>
- #include <furi_ble/event_dispatcher.h>
- #include <furi_ble/gatt.h>
- #include <furi.h>
- #include <stdint.h>
- #define TAG "BleHid"
- #define BLE_SVC_HID_REPORT_MAP_MAX_LEN (255)
- #define BLE_SVC_HID_REPORT_MAX_LEN (255)
- #define BLE_SVC_HID_REPORT_REF_LEN (2)
- #define BLE_SVC_HID_INFO_LEN (4)
- #define BLE_SVC_HID_CONTROL_POINT_LEN (1)
- #define BLE_SVC_HID_INPUT_REPORT_COUNT (3)
- #define BLE_SVC_HID_OUTPUT_REPORT_COUNT (0)
- #define BLE_SVC_HID_FEATURE_REPORT_COUNT (0)
- #define BLE_SVC_HID_REPORT_COUNT \
- (BLE_SVC_HID_INPUT_REPORT_COUNT + BLE_SVC_HID_OUTPUT_REPORT_COUNT + \
- BLE_SVC_HID_FEATURE_REPORT_COUNT)
- typedef enum {
- HidSvcGattCharacteristicProtocolMode = 0,
- HidSvcGattCharacteristicReportMap,
- HidSvcGattCharacteristicInfo,
- HidSvcGattCharacteristicCtrlPoint,
- HidSvcGattCharacteristicCount,
- } HidSvcGattCharacteristicId;
- typedef struct {
- uint8_t report_idx;
- uint8_t report_type;
- } HidSvcReportId;
- static_assert(sizeof(HidSvcReportId) == sizeof(uint16_t), "HidSvcReportId must be 2 bytes");
- static const Service_UUID_t ble_svc_hid_uuid = {
- .Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID,
- };
- static bool ble_svc_hid_char_desc_data_callback(
- const void* context,
- const uint8_t** data,
- uint16_t* data_len) {
- const HidSvcReportId* report_id = context;
- *data_len = sizeof(HidSvcReportId);
- if(data) {
- *data = (const uint8_t*)report_id;
- }
- return false;
- }
- typedef struct {
- const void* data_ptr;
- uint16_t data_len;
- } HidSvcDataWrapper;
- static bool ble_svc_hid_report_data_callback(
- const void* context,
- const uint8_t** data,
- uint16_t* data_len) {
- const HidSvcDataWrapper* report_data = context;
- if(data) {
- *data = report_data->data_ptr;
- *data_len = report_data->data_len;
- } else {
- *data_len = BLE_SVC_HID_REPORT_MAP_MAX_LEN;
- }
- return false;
- }
- static const BleGattCharacteristicParams ble_svc_hid_chars[HidSvcGattCharacteristicCount] = {
- [HidSvcGattCharacteristicProtocolMode] =
- {.name = "Protocol Mode",
- .data_prop_type = FlipperGattCharacteristicDataFixed,
- .data.fixed.length = 1,
- .uuid.Char_UUID_16 = PROTOCOL_MODE_CHAR_UUID,
- .uuid_type = UUID_TYPE_16,
- .char_properties = CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP,
- .security_permissions = ATTR_PERMISSION_NONE,
- .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE,
- .is_variable = CHAR_VALUE_LEN_CONSTANT},
- [HidSvcGattCharacteristicReportMap] =
- {.name = "Report Map",
- .data_prop_type = FlipperGattCharacteristicDataCallback,
- .data.callback.fn = ble_svc_hid_report_data_callback,
- .data.callback.context = NULL,
- .uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID,
- .uuid_type = UUID_TYPE_16,
- .char_properties = CHAR_PROP_READ,
- .security_permissions = ATTR_PERMISSION_NONE,
- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS,
- .is_variable = CHAR_VALUE_LEN_VARIABLE},
- [HidSvcGattCharacteristicInfo] =
- {.name = "HID Information",
- .data_prop_type = FlipperGattCharacteristicDataFixed,
- .data.fixed.length = BLE_SVC_HID_INFO_LEN,
- .data.fixed.ptr = NULL,
- .uuid.Char_UUID_16 = HID_INFORMATION_CHAR_UUID,
- .uuid_type = UUID_TYPE_16,
- .char_properties = CHAR_PROP_READ,
- .security_permissions = ATTR_PERMISSION_NONE,
- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS,
- .is_variable = CHAR_VALUE_LEN_CONSTANT},
- [HidSvcGattCharacteristicCtrlPoint] =
- {.name = "HID Control Point",
- .data_prop_type = FlipperGattCharacteristicDataFixed,
- .data.fixed.length = BLE_SVC_HID_CONTROL_POINT_LEN,
- .uuid.Char_UUID_16 = HID_CONTROL_POINT_CHAR_UUID,
- .uuid_type = UUID_TYPE_16,
- .char_properties = CHAR_PROP_WRITE_WITHOUT_RESP,
- .security_permissions = ATTR_PERMISSION_NONE,
- .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE,
- .is_variable = CHAR_VALUE_LEN_CONSTANT},
- };
- static const BleGattCharacteristicDescriptorParams ble_svc_hid_char_descr_template = {
- .uuid_type = UUID_TYPE_16,
- .uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID,
- .max_length = BLE_SVC_HID_REPORT_REF_LEN,
- .data_callback.fn = ble_svc_hid_char_desc_data_callback,
- .security_permissions = ATTR_PERMISSION_NONE,
- .access_permissions = ATTR_ACCESS_READ_WRITE,
- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS,
- .is_variable = CHAR_VALUE_LEN_CONSTANT,
- };
- static const BleGattCharacteristicParams ble_svc_hid_report_template = {
- .name = "Report",
- .data_prop_type = FlipperGattCharacteristicDataCallback,
- .data.callback.fn = ble_svc_hid_report_data_callback,
- .data.callback.context = NULL,
- .uuid.Char_UUID_16 = REPORT_CHAR_UUID,
- .uuid_type = UUID_TYPE_16,
- .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY,
- .security_permissions = ATTR_PERMISSION_NONE,
- .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS,
- .is_variable = CHAR_VALUE_LEN_VARIABLE,
- };
- struct BleServiceHid {
- uint16_t svc_handle;
- BleGattCharacteristicInstance chars[HidSvcGattCharacteristicCount];
- BleGattCharacteristicInstance input_report_chars[BLE_SVC_HID_INPUT_REPORT_COUNT];
- BleGattCharacteristicInstance output_report_chars[BLE_SVC_HID_OUTPUT_REPORT_COUNT];
- BleGattCharacteristicInstance feature_report_chars[BLE_SVC_HID_FEATURE_REPORT_COUNT];
- GapSvcEventHandler* event_handler;
- };
- static BleEventAckStatus ble_svc_hid_event_handler(void* event, void* context) {
- UNUSED(context);
- BleEventAckStatus ret = BleEventNotAck;
- hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data);
- evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data;
- // aci_gatt_attribute_modified_event_rp0* attribute_modified;
- if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
- if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
- // Process modification events
- ret = BleEventAckFlowEnable;
- } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) {
- // Process notification confirmation
- ret = BleEventAckFlowEnable;
- }
- }
- return ret;
- }
- BleServiceHid* ble_svc_hid_start() {
- BleServiceHid* hid_svc = malloc(sizeof(BleServiceHid));
- // Register event handler
- hid_svc->event_handler =
- ble_event_dispatcher_register_svc_handler(ble_svc_hid_event_handler, hid_svc);
- /**
- * Add Human Interface Device Service
- */
- if(!ble_gatt_service_add(
- UUID_TYPE_16,
- &ble_svc_hid_uuid,
- PRIMARY_SERVICE,
- 2 + /* protocol mode */
- (4 * BLE_SVC_HID_INPUT_REPORT_COUNT) + (3 * BLE_SVC_HID_OUTPUT_REPORT_COUNT) +
- (3 * BLE_SVC_HID_FEATURE_REPORT_COUNT) + 1 + 2 + 2 +
- 2, /* Service + Report Map + HID Information + HID Control Point */
- &hid_svc->svc_handle)) {
- free(hid_svc);
- return NULL;
- }
- // Maintain previously defined characteristic order
- ble_gatt_characteristic_init(
- hid_svc->svc_handle,
- &ble_svc_hid_chars[HidSvcGattCharacteristicProtocolMode],
- &hid_svc->chars[HidSvcGattCharacteristicProtocolMode]);
- uint8_t protocol_mode = 1;
- ble_gatt_characteristic_update(
- hid_svc->svc_handle,
- &hid_svc->chars[HidSvcGattCharacteristicProtocolMode],
- &protocol_mode);
- // reports
- BleGattCharacteristicDescriptorParams ble_svc_hid_char_descr;
- BleGattCharacteristicParams report_char;
- HidSvcReportId report_id;
- memcpy(
- &ble_svc_hid_char_descr, &ble_svc_hid_char_descr_template, sizeof(ble_svc_hid_char_descr));
- memcpy(&report_char, &ble_svc_hid_report_template, sizeof(report_char));
- ble_svc_hid_char_descr.data_callback.context = &report_id;
- report_char.descriptor_params = &ble_svc_hid_char_descr;
- typedef struct {
- uint8_t report_type;
- uint8_t report_count;
- BleGattCharacteristicInstance* chars;
- } HidSvcReportCharProps;
- HidSvcReportCharProps hid_report_chars[] = {
- {0x01, BLE_SVC_HID_INPUT_REPORT_COUNT, hid_svc->input_report_chars},
- {0x02, BLE_SVC_HID_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars},
- {0x03, BLE_SVC_HID_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars},
- };
- for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars);
- report_type_idx++) {
- report_id.report_type = hid_report_chars[report_type_idx].report_type;
- for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count;
- report_idx++) {
- report_id.report_idx = report_idx + 1;
- ble_gatt_characteristic_init(
- hid_svc->svc_handle,
- &report_char,
- &hid_report_chars[report_type_idx].chars[report_idx]);
- }
- }
- // Setup remaining characteristics
- for(size_t i = HidSvcGattCharacteristicReportMap; i < HidSvcGattCharacteristicCount; i++) {
- ble_gatt_characteristic_init(
- hid_svc->svc_handle, &ble_svc_hid_chars[i], &hid_svc->chars[i]);
- }
- return hid_svc;
- }
- bool ble_svc_hid_update_report_map(BleServiceHid* hid_svc, const uint8_t* data, uint16_t len) {
- furi_assert(data);
- furi_assert(hid_svc);
- HidSvcDataWrapper report_data = {
- .data_ptr = data,
- .data_len = len,
- };
- return ble_gatt_characteristic_update(
- hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicReportMap], &report_data);
- }
- bool ble_svc_hid_update_input_report(
- BleServiceHid* hid_svc,
- uint8_t input_report_num,
- uint8_t* data,
- uint16_t len) {
- furi_assert(data);
- furi_assert(hid_svc);
- furi_assert(input_report_num < BLE_SVC_HID_INPUT_REPORT_COUNT);
- HidSvcDataWrapper report_data = {
- .data_ptr = data,
- .data_len = len,
- };
- return ble_gatt_characteristic_update(
- hid_svc->svc_handle, &hid_svc->input_report_chars[input_report_num], &report_data);
- }
- bool ble_svc_hid_update_info(BleServiceHid* hid_svc, uint8_t* data) {
- furi_assert(data);
- furi_assert(hid_svc);
- return ble_gatt_characteristic_update(
- hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicInfo], &data);
- }
- void ble_svc_hid_stop(BleServiceHid* hid_svc) {
- furi_assert(hid_svc);
- ble_event_dispatcher_unregister_svc_handler(hid_svc->event_handler);
- // Delete characteristics
- for(size_t i = 0; i < HidSvcGattCharacteristicCount; i++) {
- ble_gatt_characteristic_delete(hid_svc->svc_handle, &hid_svc->chars[i]);
- }
- typedef struct {
- uint8_t report_count;
- BleGattCharacteristicInstance* chars;
- } HidSvcReportCharProps;
- HidSvcReportCharProps hid_report_chars[] = {
- {BLE_SVC_HID_INPUT_REPORT_COUNT, hid_svc->input_report_chars},
- {BLE_SVC_HID_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars},
- {BLE_SVC_HID_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars},
- };
- for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars);
- report_type_idx++) {
- for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count;
- report_idx++) {
- ble_gatt_characteristic_delete(
- hid_svc->svc_handle, &hid_report_chars[report_type_idx].chars[report_idx]);
- }
- }
- // Delete service
- ble_gatt_service_delete(hid_svc->svc_handle);
- free(hid_svc);
- }
|