#include "include.h" #include "utils_hid_usage.h" #include "ble_hid_service.h" #define TRACE_EN 1 #if TRACE_EN #define TRACE(...) my_printf("[BLE] ");my_printf(__VA_ARGS__) #define TRACE_R(...) my_print_r(__VA_ARGS__) #else // !TRACE_EN #define TRACE(...) #define TRACE_R(...) #endif // TRACE_EN #define BLE_HID_HANDLE_MAP ATT_CHARACTERISTIC_2a4b_01_VALUE_HANDLE #define BLE_HID_HANDLE_CTRL_POINT ATT_CHARACTERISTIC_2a4c_01_VALUE_HANDLE #define BLE_HID_HANDLE_REP_CONSUMER ATT_CHARACTERISTIC_2a4d_01_VALUE_HANDLE #define BLE_HID_HANDLE_REP_CONSUMER_CCC ATT_CHARACTERISTIC_2a4d_01_CLIENT_CONFIGURATION_HANDLE #define BLE_HID_HANDLE_REP_KEYBOARD ATT_CHARACTERISTIC_2a4d_02_VALUE_HANDLE #define BLE_HID_HANDLE_REP_KEYBOARD_CCC ATT_CHARACTERISTIC_2a4d_02_CLIENT_CONFIGURATION_HANDLE #define BLE_HID_HANDLE_REP_LED ATT_CHARACTERISTIC_2a4d_03_VALUE_HANDLE //#define BLE_HID_HANDLE_REP_MOUSE ATT_CHARACTERISTIC_2a4d_04_VALUE_HANDLE //#define BLE_HID_HANDLE_REP_MOUSE_CCC ATT_CHARACTERISTIC_2a4d_04_CLIENT_CONFIGURATION_HANDLE static att_service_handler_t hid_service; static uint16_t hid_report_client_config_consumer; static uint16_t hid_report_client_config_keyboard; static uint16_t hid_report_client_config_mouse; static uint16_t hid_connect_handle; static struct { bool ready; hid_rep_info_t data; } ble_hid_state AT(.ble_buf.hid.comm); #if 0 static u8 report_map[] = { HID_REP_MAP_CONSUMER(1), HID_REP_MAP_KEYBOARD(2), HID_REP_MAP_MOUSE(3), #if 0 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) 0xA1, 0x01, // COLLECTION (Application) 0x85, 0x01, // Report Id (1) 0x09, 0x01, // USAGE (Pointer) 0xA1, 0x00, // COLLECTION (Physical) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x05, // USAGE_MAXIMUM (Button 5) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x05, // REPORT_COUNT (5) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x75, 0x03, // REPORT_SIZE (3) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x38, // USAGE (Wheel) 0x09, 0x30, // USAGE (X) 0x09, 0x31, // USAGE (Y) 0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x25, 0x7F, // LOGICAL_MAXIMUM (127) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x03, // REPORT_COUNT (3) 0x81, 0x06, // INPUT (Data,Var,Rel) 0xC0, // END_COLLECTION 0xC0, // END_COLLECTION #endif }; #endif // 0 static void hid_service_event_packet_handle(uint8_t event_type, uint8_t *param, uint16_t size) { switch(event_type){ case BLE_EVT_CONNECT:{ memcpy(&hid_connect_handle, ¶m[7], 2); TRACE("Connected - con_handle: 0x%04x\n", hid_connect_handle); ble_hid_state.ready = true; } break; case BLE_EVT_DISCONNECT:{ uint16_t con_handle; memcpy(&con_handle, ¶m[0], 2); TRACE("Disconnected - con_handle: 0x%04x\n", con_handle); if (con_handle == hid_connect_handle) { hid_connect_handle = 0; // TODO: The CCCD value shall be persistent across connections for bonded devices. hid_report_client_config_consumer = CCCD_DFT; hid_report_client_config_keyboard = CCCD_DFT; hid_report_client_config_mouse = CCCD_DFT; } ble_hid_state.ready = false; } break; default: break; } } static uint16_t hid_service_read_callback(uint16_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size) { u8 data_len = 0; //u8 hid_report_map_len = sizeof(report_map); switch (attribute_handle) { #if 0 case BLE_HID_HANDLE_MAP: if (buffer) { data_len = (buffer_size < (hid_report_map_len - offset))? buffer_size: (hid_report_map_len - offset); memcpy(buffer, report_map + offset, data_len); TRACE("Read Request - handle: 0x%04x len: %d data:\n", attribute_handle, buffer_size); TRACE_R(buffer, buffer_size); } else { data_len = hid_report_map_len; } break; case BLE_HID_HANDLE_REP_CONSUMER_CCC: if (buffer) { TRACE("Read CCC Consumer - val: 0x%04x\n", hid_report_client_config_consumer); data_len = 2; memcpy(buffer, (u8 *)&hid_report_client_config_consumer, 2); } else { data_len = 2; } break; case BLE_HID_HANDLE_REP_KEYBOARD_CCC: if (buffer) { TRACE("Read CCC Keyboard - val: 0x%04x\n", hid_report_client_config_keyboard); data_len = 2; memcpy(buffer, (u8 *)&hid_report_client_config_keyboard, 2); } else { data_len = 2; } break; case BLE_HID_HANDLE_REP_MOUSE_CCC: if (buffer) { TRACE("Read CCC Mouse - val: 0x%04x\n", hid_report_client_config_mouse); data_len = 2; memcpy(buffer, (u8 *)&hid_report_client_config_mouse, 2); } else { data_len = 2; } break; case BLE_HID_HANDLE_REP_CONSUMER: case BLE_HID_HANDLE_REP_KEYBOARD: case BLE_HID_HANDLE_REP_MOUSE: if (buffer) { /* Response default value that all zere */ hid_rep_info_t hid_rep_info; memset(&hid_rep_info, 0x00, sizeof(hid_rep_info)); data_len = sizeof(hid_rep_info.pdu); TRACE("Read Val - handle: 0x%04x val[%d]: ", attribute_handle, data_len); TRACE_R(&hid_rep_info.pdu, data_len); } else { hid_rep_info_t hid_rep_info; data_len = sizeof(hid_rep_info.pdu); } break; #endif // 0 default: TRACE("No process read - handle: 0x%04x\n", attribute_handle); break; } return data_len; } static int hid_service_write_callback(uint16_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size) { switch (attribute_handle) { case BLE_HID_HANDLE_CTRL_POINT: /* 0: suspend 1: exit suspend, maybe not used because some central will disc when sleep */ TRACE("Write Suspend status - val: 0x%02x\n", buffer[0]); break; case BLE_HID_HANDLE_REP_CONSUMER_CCC: hid_report_client_config_consumer = GET_LE16(buffer); TRACE("Write CCC Consumer - val: 0x%04x\n", hid_report_client_config_consumer); break; case BLE_HID_HANDLE_REP_KEYBOARD_CCC: hid_report_client_config_keyboard = GET_LE16(buffer); TRACE("Write CCC Keyboard - val: 0x%04x\n", hid_report_client_config_keyboard); break; //case BLE_HID_HANDLE_REP_MOUSE_CCC: // hid_report_client_config_mouse = GET_LE16(buffer); // TRACE("Write CCC Mouse - val: 0x%04x\n", hid_report_client_config_mouse); // break; case BLE_HID_HANDLE_REP_LED: break; default: TRACE("No process write - handle: 0x%04x\n", attribute_handle); break; } return ATT_ERR_NO_ERR; } int ble_hid_mouse_report(hid_rep_info_t *param) { //uint16_t handle; int ret = -1; //if (param->report_id == HID_REP_ID_CONSUMER) { // handle = BLE_HID_HANDLE_REP_CONSUMER; //} else if (param->report_id == HID_REP_ID_KEYBOARD) { // handle = BLE_HID_HANDLE_REP_KEYBOARD; //} else if (param->report_id == HID_REP_ID_MOUSE) { // handle = BLE_HID_HANDLE_REP_MOUSE; //} else { // return ret; //} // TRACE("Report - handle: 0x%04x data[%d]: ", handle, sizeof(param->pdu)); // TRACE_R(¶m->pdu, sizeof(param->pdu)); /* Some Central-Device do not subscribe again after being connected back. Do not determine the client config here */ // TODO: The CCCD value shall be persistent across connections for bonded devices. lowpwr_pwroff_delay_reset(); lowpwr_sleep_delay_reset(); /*Prevent acl buffer is full before connection really success when report mouse data*/ //if (!hid_report_client_config_mouse && (handle == BLE_HID_HANDLE_REP_MOUSE)) { // return ret; //} /*Prevent acl buffer is full before connection really success*/ //if (!txpkt_is_full(&ble_tx)) { // ret = ble_notify_for_handle(hid_connect_handle, handle, (u8 *)¶m->pdu, sizeof(param->pdu)); //} return ret; } void ble_hid_service_init(void) { printf("%s\n", __func__); hid_service.start_handle = ATT_SERVICE_1812_START_HANDLE; hid_service.end_handle = ATT_SERVICE_1812_END_HANDLE; hid_service.read_callback = &hid_service_read_callback; hid_service.write_callback = &hid_service_write_callback; hid_service.event_handler = &hid_service_event_packet_handle; att_server_register_service_handler(&hid_service); hid_report_client_config_consumer = CCCD_DFT; hid_report_client_config_keyboard = CCCD_DFT; hid_report_client_config_mouse = CCCD_DFT; memset(&ble_hid_state, 0x00, sizeof(ble_hid_state)); } void ble_hid_service_proc(void) { if (hid_connect_handle) { if (ble_hid_state.ready) { } else { /* Retry */ ble_hid_state.ready = (0 == ble_hid_mouse_report(&ble_hid_state.data)); } } } void ble_hid_set_mouse_cccd() { hid_report_client_config_mouse = 1; }