#include "ble_port_hid_service.h" /* Human Interface Device UUID */ #define BLE_UUID_HUMAN_INTERFACE_DEVICE 0x1812 /* HID Information UUID */ #define BLE_UUID_HID_INFORMATION 0x2A4A /* Report Map UUID */ #define BLE_UUID_REPORT_MAP 0x2A4B /* HID Control Point UUID */ #define BLE_UUID_HID_CONTROL_POINT 0x2A4C /* Boot Keyboard Input Report UUID */ #define BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT 0x2A22 /* Boot Keyboard Output Report UUID */ #define BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT 0x2A32 /* Report UUID */ #define BLE_UUID_REPORT 0x2A4D /* Protocol Mode UUID */ #define BLE_UUID_PROTOCOL_MODE 0x2A4E /* Client Characteristic Configuration UUID */ #define BLE_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION 0x2902 /* External Report Reference UUID */ #define BLE_UUID_EXTERNAL_REPORT_REFERENCE 0x2907 /* Report Reference UUID */ #define BLE_UUID_REPORT_REFERENCE 0x2908 /* HID character value handle offset */ #define BLE_HID_CHARACTER_INPUT_REPORT_VALUE_HANDLE_OFFSET 8 /* HID information flag remote wakeup */ #define BLE_HID_INFO_FLAG_REMOTE_WAKE_UP_MSK 0x01 /* HID information flag normally connectable */ #define BLE_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK 0x02 /* HID information country code */ #define BLE_HID_INFO_COUNTRY_CODE 0x00 /* HID spec version 1.11 */ #define BLE_HID_VERSION 0x0101 /* HID input report id */ #define BLE_HID_REPORT_ID 1 /* HID input report id 2*/ #define BLE_HID_REPORT_ID_2 2 /* HID input report id 3*/ #define BLE_HID_REPORT_ID_3 3 /* HID input report type */ #define BLE_REPORT_REFERENCE_REPORT_TYPE_INPUT_REPORT 1 /* HID output report type */ #define BLE_REPORT_REFERENCE_REPORT_TYPE_OUTPUT_REPORT 2 /* HID gatt server id */ #define BLE_HID_SERVER_ID 1 /* HID ble connect id */ #define BLE_SINGLE_LINK_CONNECT_ID 1 /* HID gatt attribute num */ #define BLE_HID_ATTRIBUTE_NUM 10 /* HID gatt notification flag, do not need confirm */ #define GATT_NOTIFICATION_FLAG 0 /* HID gatt indication flag, need confirm */ #define GATT_INDICATION_FLAG 1 #define uint16_to_byte(n) ((uint8_t)(n)), ((uint8_t)((n) >> 8)) #define ENABLE_PRINT_INFO 1 #if ENABLE_PRINT_INFO #define static_print_debug(...) sys_bt_log_d(__VA_ARGS__) // 一般信息打印宏控制 #define static_print_warn(...) sys_bt_log_w(__VA_ARGS__) // 警告信息打印一般常开 #define static_print_error(...) sys_bt_log_e(__VA_ARGS__) // 错误信息打印一般常开 #else #define static_print_debug(...) #define static_print_warn(...) #define static_print_error(...) #endif enum { /* HID information characteristic properties */ HID_INFORMATION_PROPERTIES = GATT_CHARACTER_PROPERTY_BIT_READ, /* HID protocol mode characteristic properties */ HID_PROTOCOL_MODE_PROPERTIES = GATT_CHARACTER_PROPERTY_BIT_READ | GATT_CHARACTER_PROPERTY_BIT_WRITE_NO_RSP, /* HID report map characteristic properties */ HID_REPORT_MAP_PROPERTIES = GATT_CHARACTER_PROPERTY_BIT_READ, /* HID input report characteristic properties */ HID_INPUT_REPORT_PROPERTIES = GATT_CHARACTER_PROPERTY_BIT_READ | GATT_CHARACTER_PROPERTY_BIT_NOTIFY | GATT_CHARACTER_PROPERTY_BIT_WRITE, /* HID output report characteristic properties */ HID_OUTPUT_REPORT_PROPERTIES = GATT_CHARACTER_PROPERTY_BIT_READ | GATT_CHARACTER_PROPERTY_BIT_WRITE | GATT_CHARACTER_PROPERTY_BIT_WRITE_NO_RSP, /* HID control point characteristic properties */ HID_CONTROL_POINT_PROPERTIES = GATT_CHARACTER_PROPERTY_BIT_WRITE_NO_RSP, }; // const uint8_t tjd_srv_hid_report_map[] = { // 0x05, 0x0C, // 用法页(消费者设备) // 0x09, 0x01, // 用法(消费者控制) // 0xA1, 0x01, // 集合(应用) // 0x15, 0x00, // 逻辑最小值(0) // 0x25, 0x01, // 逻辑最大值(1) // 0x09, 0xCD, // 用法(播放/暂停) // 0x09, 0xB5, // 用法(下一曲目) // 0x09, 0xB6, // 用法(上一曲目) // 0x09, 0xE9, // 用法(音量增加) // 0x09, 0xEA, // 用法(音量减少) // 0x95, 0x05, // 报告计数(5) // 0x75, 0x01, // 报告大小(1) // 0x81, 0x02, // 输入(数据,变量,绝对) // 0x95, 0x01, // 报告计数(1) // 0x75, 0x03, // 报告大小(3) // 0x81, 0x03, // 输入(常量,变量,绝对) // 0xC0 // 结束集合 // }; // const uint8_t tjd_srv_hid_report_map[] = { // 0x05, 0x0C, // Usage Page (Consumer) // 0x09, 0x01, // Usage (Consumer Control) // 0xA1, 0x01, // Collection (Application) // 0x85, 0x01, // Report Id (1) // 0x15, 0x00, // Logical minimum (0) // 0x25, 0x01, // Logical maximum (1) // 0x75, 0x01, // Report Size (1) // 0x95, 0x01, // Report Count (1) // 0x09, 0xCD, // Usage (Play/Pause) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x0A, 0x83, 0x01, // Usage (AL Consumer Control Configuration) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xB5, // Usage (Scan Next Track) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xB6, // Usage (Scan Previous Track) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xEA, // Usage (Volume Down) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xE9, // Usage (Volume Up) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x0A, 0x25, 0x02, // Usage (AC Forward) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x0A, 0x24, 0x02, // Usage (AC Back) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0xC0 // End Collection // }; // const uint8_t tjd_srv_hid_report_map[] = { // // Report ID 1: Advanced buttons // 0x05, 0x0C, // Usage Page (Consumer) // 0x09, 0x01, // Usage (Consumer Control) // 0xA1, 0x01, // Collection (Application) // 0x85, 0x01, // Report Id (1) // 0x15, 0x00, // Logical minimum (0) // 0x25, 0x01, // Logical maximum (1) // 0x75, 0x01, // Report Size (1) // 0x95, 0x01, // Report Count (1) // 0x09, 0x94, // (Quit) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0x95, // (Help) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xEA, // (Volume Down) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xE9, // (Volume Up) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xCB, // (Tracking Decrement) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xCA, // (tracking Increment) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xB6, // (Scan Previous Track) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xB5, // (Scan Next Track) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xB1, // (Pause) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xB0, // (Play) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x75, 0x01, // Report Size (1) // 0x95, 0x06, // Report Count (6) // 0x81, 0x07, // Input (Data,Value,Relative,Bit Field) // 0xC0 // End Collection // }; // const uint8_t tjd_srv_hid_report_map[] = { // 0x05,0x0c, //USAGE PAGE(Consumer Devices) // 0x09,0x01, //USAGE (Consumer Control) // 0xA1,0x01, //COLLECTION (Application) // 0x85,0x01, //REPORT ID (1) // 0x15,0x00, //LOGICAL MINIMUM(0) // 0x25,0x01, //LOGICAL MAXIMUM(1) // 0x75,0x01, //REPORT SIZE (1) // 0x95,0x01, //REPORT COUNT (1) // 0x09,0xcd, //USAGE(Play/Pause) // 0x81,0x06, //INPUT(Data,Var,Rel) // 0x09,0x6f, //USAGE(Display Brightness Increment) // 0x81,0x06, //INPUT(Data,Var,Rel // 0x09,0x70, //USAGE(Display BrightnessDecrement) // 0x81,0x06, //INPUT(Data,Var,Rel) // 0x09,0xb5, //USAGE(Scan Next Track) // 0x81,0x06, //INPUT(Data,Var,Rel) // 0x09,0xb6, //USAGE(Scan Previous Track) // 0x81,0x06, //INPUT(Data,Var,Rel) // 0x09,0xe9, //USAGE(Volume Up) // 0x81,0x06, //INPUT(Data,Var,Rel) // 0x09,0xEA, //USAGE(Volume Down) // 0x81,0x06, //INPUT(Data,Var,Rel) // 0x95,0x01, //REPORT COUNT(1) // 0x75,0x01, //REPORT SIZE(1) // 0x81,0x01, //INPUT(Cnst,Ary,Abs) // 0xc0 //END COLLECTION // }; // static const uint8_t tjd_srv_hid_report_map[] = { // // Report ID 1: Advanced buttons // 0x05, 0x0C, // Usage Page (Consumer) // 0x09, 0x01, // Usage (Consumer Control) // 0xA1, 0x01, // Collection (Application) // 0x85, 0x01, // Report Id (1) // 0x15, 0x00, // Logical minimum (0) // 0x25, 0x01, // Logical maximum (1) // 0x75, 0x01, // Report Size (1) // 0x95, 0x01, // Report Count (1) // 0x09, 0x94, // (Quit) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0x95, // (Help) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xEA, // (Volume Down) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xE9, // (Volume Up) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xCB, // (Tracking Decrement) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xCA, // (tracking Increment) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xB6, // (Scan Previous Track) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xB5, // (Scan Next Track) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xB1, // (Pause) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x09, 0xB0, // (Play) // 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) // 0x75, 0x01, // Report Size (1) // 0x95, 0x06, // Report Count (6) // 0x81, 0x07, // Input (Data,Value,Relative,Bit Field) // 0xC0 // End Collection // }; static const uint8_t tjd_srv_hid_report_map[] = { 0x05, 0x01,// Usage Page (Generic Desktop) 0x09, 0x02,// Usage (Mouse) 0xA1, 0x01, // Collection (Application) // Report ID 1: Mouse buttons + scroll/ pan 0x85, 0x01, // Report Id 1 0x09, 0x01, // Usage (Pointer) 0xA1, 0x00, // Collection (Physical) 0x95, 0x05, // Report Count (3) 0x75, 0x01, // Report Size (1) 0x05, 0x09, // Usage Page (Buttons) 0x19, 0x01, // Usage Minimum (01) 0x29, 0x05, // Usage Maximum (05) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x81, 0x02, // Input (Data, Variable, Absolute) 0x95, 0x01, // Report Count (1) 0x75, 0x03, // Report Size (3) 0x81, 0x01, // Input (Constant) for padding 0x75, 0x08, // Report Size (8) 0x95, 0x01, // Report Count (1) 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x38, // Usage (Wheel) 0x15, 0x81, // Logical Minimum (-127) 0x25, 0x7F, // Loaical Maximum (127) 0x81, 0x06, // Input (Data, Variable, Relative) 0x05, 0x0C, // Usage Page (Consumer) 0x0A, 0x38, 0x02, //Usage(AC Pan) 0x95, 0x01, // Report Count (1) 0x81, 0x06, // Input (Data, Value, Relative, Bit Field) 0xC0, //End Collection(Physical) // Report ID 2: Mouse motion 0x85, 0x02, // Report Id 2 0x09, 0x01, // Usage (Pointer) 0xA1, 0x00, // Collection (Physical) 0x75, 0x0c, // Report Size (12) 0x95, 0x02, // Report Count (2) 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x30, // Usage (X) 0x09, 0x31, // Usage (Y) 0x25, 0x7F, // Logical maximum (2047) 0x15, 0x81, // Logical minimum (-2047) 0x81, 0x06, // Input (Data, Variable, Relative) 0xC0, // End Collection (Physical) 0xC0, // End Collection (Application) // Report ID 3: Advanced buttons 0x05, 0x0C, // Usage Page (Consumer) 0x09, 0x01, // Usage (Consumer Control) 0xA1, 0x01, // Collection (Application) 0x85, 0x03, // Report Id (3) 0x15, 0x00, // Logical minimum (0) 0x25, 0x01, // Logical maximum(1) 0x75, 0x01, // Report Size (1) 0x95, 0x01, // Report Count (1) 0x09, 0xCD, // Usage (Play/ Pause) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x0A, 0x83, 0x01, // Usage (AL Consumer Control Configuration) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x09, 0xB5, // Usage (Scan Next Track) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x09, 0xB6, // Usage (Scan Previous Track) 0x81, 0x06, // Input (Data,Value,Relative,Bit Fieid) 0x09, 0xEA, // Usage (Volume Down) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x09, 0xE9, // Usage (Volume Up) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x0A, 0x25, 0x02, // Usage (AC Forward) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0x0A, 0x24, 0x02,// Usage (AC Back) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field) 0xC0 // End Collection }; // /* Hid Report Map (Descriptor) */ // uint8_t tjd_srv_hid_report_map[] = { // 0x05, 0x0C, /* Usage Page (Consumer) */ // 0x09, 0x01, /* Usage (Consumer Control) */ // 0xA1, 0x01, /* Collection (Application) */ // 0x85, 0x01, /* Report ID (1) */ // 0x09, 0xE9, /* Usage (Volume Increment) */ // 0x09, 0xEA, /* Usage (Volume Decrement) */ // 0x09, 0xE2, /* Usage (Mute) */ // 0x09, 0x30, /* Usage (Power) */ // 0x15, 0x01, /* Logical minimum (1) */ // 0x25, 0x0C, /* Logical maximum (12) */ // 0x75, 0x10, /* Report Size (16) */ // 0x95, 0x01, /* Report Count (1) */ // 0x81, 0x00, /* INPUT (Data,Array,Absolute,Bit Field) */ // 0xC0, /* End Collection */ // }; // /* 添加特征:HID information */ static void tjd_ble_hid_add_character_hid_information(uint8_t server_id, uint16_t srvc_handle) { /* HID information value for test */ static uint8_t hid_information_val[] = {uint16_to_byte(BLE_HID_VERSION), BLE_HID_INFO_COUNTRY_CODE, BLE_HID_INFO_FLAG_REMOTE_WAKE_UP_MSK | BLE_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK}; gatts_add_chara_info_t character; bts_data_to_uuid_len2(BLE_UUID_HID_INFORMATION, &character.chara_uuid); character.permissions = GATT_ATTRIBUTE_PERMISSION_READ; character.properties = HID_INFORMATION_PROPERTIES; // character.properties = GATT_CHARACTER_PROPERTY_BIT_READ; character.value_len = (uint16_t)sizeof(hid_information_val); character.value = hid_information_val; gatts_add_characteristic(server_id, srvc_handle, &character); } // /* 添加特征:HID report map */ static void tjd_ble_hid_add_character_report_map(uint8_t server_id, uint16_t srvc_handle) { gatts_add_chara_info_t character; bts_data_to_uuid_len2(BLE_UUID_REPORT_MAP, &character.chara_uuid); character.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_ATTRIBUTE_PERMISSION_AUTHENTICATION_NEED; character.properties = HID_REPORT_MAP_PROPERTIES; character.value_len = (uint16_t)sizeof(tjd_srv_hid_report_map); character.value = tjd_srv_hid_report_map; gatts_add_characteristic(server_id, srvc_handle, &character); } // /* 添加特征:HID control point */ static void tjd_ble_hid_add_character_hid_control_point(uint8_t server_id, uint16_t srvc_handle) { /* HID control point value for test */ static uint8_t control_point_val[] = {0x00, 0x00}; gatts_add_chara_info_t character; bts_data_to_uuid_len2(BLE_UUID_HID_CONTROL_POINT, &character.chara_uuid); character.permissions = GATT_ATTRIBUTE_PERMISSION_READ; character.properties = HID_CONTROL_POINT_PROPERTIES; character.value_len = (uint16_t)sizeof(control_point_val); character.value = control_point_val; gatts_add_characteristic(server_id, srvc_handle, &character); } // /* 添加描述符:客户端特性配置 */ static void tjd_ble_hid_add_descriptor_ccc(uint8_t server_id, uint16_t srvc_handle) { /* HID client characteristic configuration value for test */ static uint8_t ccc_val[] = {0x00, 0x00}; gatts_add_desc_info_t descriptor; bts_data_to_uuid_len2(BLE_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION, &descriptor.desc_uuid); descriptor.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_ATTRIBUTE_PERMISSION_WRITE; descriptor.value_len = (uint16_t)sizeof(ccc_val); descriptor.value = ccc_val; gatts_add_descriptor(server_id, srvc_handle, &descriptor); } // /* 添加描述符:HID report reference */ static void tjd_ble_hid_add_descriptor_report_reference(uint8_t server_id, uint16_t srvc_handle, bool is_input_flag) { /* HID output report reference value for test [report id 1, output] */ static uint8_t report_reference_val_output[] = {BLE_HID_REPORT_ID, BLE_REPORT_REFERENCE_REPORT_TYPE_OUTPUT_REPORT}; /* HID input report reference value for test [report id 1, input] */ static uint8_t report_reference_val_input[] = {BLE_HID_REPORT_ID, BLE_REPORT_REFERENCE_REPORT_TYPE_INPUT_REPORT, BLE_HID_REPORT_ID_2,BLE_REPORT_REFERENCE_REPORT_TYPE_INPUT_REPORT, BLE_HID_REPORT_ID_3,BLE_REPORT_REFERENCE_REPORT_TYPE_INPUT_REPORT}; gatts_add_desc_info_t descriptor; bts_data_to_uuid_len2(BLE_UUID_REPORT_REFERENCE, &descriptor.desc_uuid); descriptor.permissions = GATT_ATTRIBUTE_PERMISSION_READ; if (is_input_flag) { descriptor.value = report_reference_val_input; descriptor.value_len = (uint16_t)sizeof(report_reference_val_input); } else { descriptor.value = report_reference_val_output; descriptor.value_len = (uint16_t)sizeof(report_reference_val_output); } gatts_add_descriptor(server_id, srvc_handle, &descriptor); } // /* 添加特征:HID input report(device to host) */ static void tjd_ble_hid_add_character_input_report(uint8_t server_id, uint16_t srvc_handle) { // static uint8_t input_report_value[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t input_report_value[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; gatts_add_chara_info_t character; bts_data_to_uuid_len2(BLE_UUID_REPORT, &character.chara_uuid); character.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_ATTRIBUTE_PERMISSION_WRITE; character.properties = HID_INPUT_REPORT_PROPERTIES; // character.properties = // GATT_CHARACTER_PROPERTY_BIT_READ | GATT_CHARACTER_PROPERTY_BIT_NOTIFY | GATT_CHARACTER_PROPERTY_BIT_WRITE; character.value_len = (uint16_t)sizeof(input_report_value); character.value = input_report_value; gatts_add_characteristic(server_id, srvc_handle, &character); tjd_ble_hid_add_descriptor_ccc(server_id, srvc_handle); tjd_ble_hid_add_descriptor_report_reference(server_id, srvc_handle, true); } // /* 添加特征:HID output report(host to device) */ static void tjd_ble_hid_add_character_output_report(uint8_t server_id, uint16_t srvc_handle) { /* HID output report value for test */ static uint8_t output_report_value[] = {0x00}; gatts_add_chara_info_t character; bts_data_to_uuid_len2(BLE_UUID_REPORT, &character.chara_uuid); character.permissions = GATT_ATTRIBUTE_PERMISSION_READ; character.properties = HID_OUTPUT_REPORT_PROPERTIES; character.value_len = (uint16_t)sizeof(output_report_value); character.value = output_report_value; gatts_add_characteristic(server_id, srvc_handle, &character); tjd_ble_hid_add_descriptor_report_reference(server_id, srvc_handle, false); } // /* 添加特征:HID protocol mode */ static void tjd_ble_hid_add_character_protocol_mode(uint8_t server_id, uint16_t srvc_handle) { /* HID protocol mode value for test */ static uint8_t protocol_mode_val[] = {0x00, 0x00}; // static uint8_t protocol_mode_val[] = {0x00,0x01}; gatts_add_chara_info_t character; bts_data_to_uuid_len2(BLE_UUID_PROTOCOL_MODE, &character.chara_uuid); character.permissions = GATT_ATTRIBUTE_PERMISSION_READ | GATT_ATTRIBUTE_PERMISSION_WRITE; character.properties = HID_PROTOCOL_MODE_PROPERTIES; character.value_len = (uint16_t)sizeof(protocol_mode_val); character.value = protocol_mode_val; gatts_add_characteristic(server_id, srvc_handle, &character); } // /* 添加HID服务的所有特征和描述符 */ void tjd_ble_hid_add_characters_and_descriptors(uint8_t server_id, uint16_t srvc_handle) { /* HID Information */ tjd_ble_hid_add_character_hid_information(server_id, srvc_handle); /* Report Map */ tjd_ble_hid_add_character_report_map(server_id, srvc_handle); /* Protocol Mode */ tjd_ble_hid_add_character_protocol_mode(server_id, srvc_handle); /* Input Report */ tjd_ble_hid_add_character_input_report(server_id, srvc_handle); /* Output Report */ tjd_ble_hid_add_character_output_report(server_id, srvc_handle); /* HID Control Point */ tjd_ble_hid_add_character_hid_control_point(server_id, srvc_handle); }