#include #include #include #include #include #include #include #include #include #include #include #include "components/bluetooth/bk_dm_bluetooth_types.h" #include "components/bluetooth/bk_dm_gap_ble_types.h" #include "components/bluetooth/bk_dm_gap_ble.h" #include "components/bluetooth/bk_dm_gatt_types.h" #include "components/bluetooth/bk_dm_gatts.h" #include "dm_gatts.h" #include "hogpd_demo.h" #include #if HOGPD_DEMO_ENABLE #define MIN_VALUE(x, y) (((x) < (y)) ? (x): (y)) typedef struct { uint8_t status; //0 idle 1 connected } hogpd_app_env_t; static uint8_t s_hogpd_is_init; static uint8_t s_protpcol_mode = 1; static const uint8_t s_hid_rprtmap[] = { 0x05U, 0x01U, 0x09U, 0x06U, 0xA1U, 0x01U, 0x05U, 0x07U, 0x19U, 0xE0U, 0x29U, 0xE7U, 0x15U, 0x00U, 0x25U, 0x01U, 0x75U, 0x01U, 0x95U, 0x08U, 0x81U, 0x02U, 0x95U, 0x01U, 0x75U, 0x08U, 0x81U, 0x03U, 0x95U, 0x05U, 0x75U, 0x01U, 0x05U, 0x08U, 0x19U, 0x01U, 0x29U, 0x05U, 0x91U, 0x02U, 0x95U, 0x01U, 0x75U, 0x03U, 0x91U, 0x03U, 0x95U, 0x06U, 0x75U, 0x08U, 0x15U, 0x00U, 0x25U, 0x65U, 0x05U, 0x07U, 0x19U, 0x00U, 0x29U, 0x65U, 0x81U, 0x00U, 0xC0U }; static uint16_t s_report_map_desc; static uint8_t s_input_hid_rprt[] = {0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; static uint16_t s_input_hid_rprt_client_conf; static const uint8_t s_input_hid_rprt_desc[] = {0, 1}; static uint8_t s_output_hid_rprt[] = {0x00U, 0x00U, 0x00U}; static const uint8_t s_output_hid_rprt_desc[] = { 0x00U, 0x02U }; static uint8_t s_feature_hid_rprt[] = {0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; static const uint8_t s_feature_hid_rprt_desc[] = { 0x00U, 0x03U }; static const uint8_t s_hid_info[] = {0x13U, 0x02U, 0x40U, 0x01U}; static uint8_t s_boot_kbd_input_rprt[] = {0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; static uint16_t s_boot_kbd_input_rprt_client_conf; static uint8_t s_boot_kbd_output_rprt[] = {0x00U, 0x00U, 0x00U}; //static uint8_t s_boot_mouse_input_rprt[] = {0x00U, 0x00U, 0x00U}; static const bk_gatts_attr_db_t s_gatts_attr_db_service_hidd[] = { { BK_GATT_PRIMARY_SERVICE_DECL(BK_GATT_UUID_HID_SVC), }, //proto mode { BK_GATT_CHAR_DECL(BK_GATT_UUID_HID_PROTO_MODE, sizeof(s_protpcol_mode), &s_protpcol_mode, BK_GATT_CHAR_PROP_BIT_READ | BK_GATT_CHAR_PROP_BIT_WRITE_NR, BK_GATT_PERM_READ | BK_GATT_PERM_WRITE, //BK_GATT_PERM_READ_ENCRYPTED | BK_GATT_PERM_WRITE_ENCRYPTED, BK_GATT_RSP_BY_APP), }, //report map { BK_GATT_CHAR_DECL(BK_GATT_UUID_HID_REPORT_MAP, sizeof(s_hid_rprtmap), (uint8_t *)s_hid_rprtmap, BK_GATT_CHAR_PROP_BIT_READ, BK_GATT_PERM_READ_ENCRYPTED, //BK_GATT_PERM_READ_ENCRYPTED | BK_GATT_PERM_WRITE_ENCRYPTED, BK_GATT_AUTO_RSP), }, { BK_GATT_CHAR_DESC_DECL(BK_GATT_UUID_EXT_RPT_REF_DESCR, sizeof(s_report_map_desc), (uint8_t *)&s_report_map_desc, BK_GATT_PERM_READ, BK_GATT_AUTO_RSP), }, //input report { BK_GATT_CHAR_DECL(BK_GATT_UUID_HID_REPORT, sizeof(s_input_hid_rprt), s_input_hid_rprt, BK_GATT_CHAR_PROP_BIT_READ | BK_GATT_CHAR_PROP_BIT_WRITE | BK_GATT_CHAR_PROP_BIT_NOTIFY, BK_GATT_PERM_READ | BK_GATT_PERM_WRITE, BK_GATT_AUTO_RSP), }, { BK_GATT_CHAR_DESC_DECL(BK_GATT_UUID_CHAR_CLIENT_CONFIG, sizeof(s_input_hid_rprt_client_conf), (uint8_t *)&s_input_hid_rprt_client_conf, BK_GATT_PERM_READ | BK_GATT_PERM_WRITE, BK_GATT_AUTO_RSP), }, { BK_GATT_CHAR_DESC_DECL(BK_GATT_UUID_RPT_REF_DESCR, sizeof(s_input_hid_rprt_desc), (uint8_t *)s_input_hid_rprt_desc, BK_GATT_PERM_READ, BK_GATT_AUTO_RSP), }, //output report { BK_GATT_CHAR_DECL(BK_GATT_UUID_HID_REPORT, sizeof(s_output_hid_rprt), s_output_hid_rprt, BK_GATT_CHAR_PROP_BIT_READ | BK_GATT_CHAR_PROP_BIT_WRITE | BK_GATT_CHAR_PROP_BIT_WRITE_NR, BK_GATT_PERM_READ | BK_GATT_PERM_WRITE, BK_GATT_AUTO_RSP), }, { BK_GATT_CHAR_DESC_DECL(BK_GATT_UUID_RPT_REF_DESCR, sizeof(s_output_hid_rprt_desc), (uint8_t *)s_output_hid_rprt_desc, BK_GATT_PERM_READ, BK_GATT_AUTO_RSP), }, //feature report { BK_GATT_CHAR_DECL(BK_GATT_UUID_HID_REPORT, sizeof(s_feature_hid_rprt), s_feature_hid_rprt, BK_GATT_CHAR_PROP_BIT_READ | BK_GATT_CHAR_PROP_BIT_WRITE, BK_GATT_PERM_READ | BK_GATT_PERM_WRITE, BK_GATT_AUTO_RSP), }, { BK_GATT_CHAR_DESC_DECL(BK_GATT_UUID_RPT_REF_DESCR, sizeof(s_feature_hid_rprt_desc), (uint8_t *)s_feature_hid_rprt_desc, BK_GATT_PERM_READ, BK_GATT_AUTO_RSP), }, //control point { BK_GATT_CHAR_DECL(BK_GATT_UUID_HID_CONTROL_POINT, 0, NULL, BK_GATT_CHAR_PROP_BIT_WRITE_NR, BK_GATT_PERM_WRITE, BK_GATT_AUTO_RSP), }, //info { BK_GATT_CHAR_DECL(BK_GATT_UUID_HID_INFORMATION, sizeof(s_hid_info), (uint8_t *)s_hid_info, BK_GATT_CHAR_PROP_BIT_READ, BK_GATT_PERM_READ, BK_GATT_AUTO_RSP), }, //bootkeyboardinput report { BK_GATT_CHAR_DECL(BK_GATT_UUID_HID_BT_KB_INPUT, sizeof(s_boot_kbd_input_rprt), s_boot_kbd_input_rprt, BK_GATT_CHAR_PROP_BIT_READ | BK_GATT_CHAR_PROP_BIT_WRITE | BK_GATT_CHAR_PROP_BIT_NOTIFY, BK_GATT_PERM_READ | BK_GATT_PERM_WRITE, BK_GATT_AUTO_RSP), }, { BK_GATT_CHAR_DESC_DECL(BK_GATT_UUID_CHAR_CLIENT_CONFIG, sizeof(s_boot_kbd_input_rprt_client_conf), (uint8_t *)&s_boot_kbd_input_rprt_client_conf, BK_GATT_PERM_READ | BK_GATT_PERM_WRITE, BK_GATT_AUTO_RSP), }, //bootkeyboardoutput report { BK_GATT_CHAR_DECL(BK_GATT_UUID_HID_BT_KB_OUTPUT, sizeof(s_boot_kbd_output_rprt), s_boot_kbd_output_rprt, BK_GATT_CHAR_PROP_BIT_READ | BK_GATT_CHAR_PROP_BIT_WRITE | BK_GATT_CHAR_PROP_BIT_WRITE_NR, BK_GATT_PERM_READ | BK_GATT_PERM_WRITE, BK_GATT_AUTO_RSP), }, }; static uint16_t s_hogpd_attr_handle_list[sizeof(s_gatts_attr_db_service_hidd) / sizeof(s_gatts_attr_db_service_hidd[0])]; static int32_t hogpd_demo_gatts_cb(bk_gatts_cb_event_t event, bk_gatt_if_t gatts_if, bk_ble_gatts_cb_param_t *comm_param) { ble_err_t ret = 0; dm_gatt_app_env_t *common_env_tmp = NULL; hogpd_app_env_t *app_env_tmp = NULL; switch (event) { case BK_GATTS_CONNECT_EVT: { struct gatts_connect_evt_param *param = (typeof(param))comm_param; hogpd_logi("BK_GATTS_CONNECT_EVT %d role %d %02X:%02X:%02X:%02X:%02X:%02X", param->conn_id, param->link_role, param->remote_bda[5], param->remote_bda[4], param->remote_bda[3], param->remote_bda[2], param->remote_bda[1], param->remote_bda[0]); common_env_tmp = dm_ble_alloc_addition_data_by_addr(param->remote_bda, sizeof(hogpd_app_env_t)); if (!common_env_tmp) { hogpd_loge("alloc addition data err !!!!"); break; } app_env_tmp = (typeof(app_env_tmp))common_env_tmp->addition_data; app_env_tmp->status = 1; } break; case BK_GATTS_DISCONNECT_EVT: { struct gatts_disconnect_evt_param *param = (typeof(param))comm_param; hogpd_logi("BK_GATTS_DISCONNECT_EVT %02X:%02X:%02X:%02X:%02X:%02X", param->remote_bda[5], param->remote_bda[4], param->remote_bda[3], param->remote_bda[2], param->remote_bda[1], param->remote_bda[0]); common_env_tmp = dm_ble_find_app_env_by_addr(param->remote_bda); if (!common_env_tmp) { hogpd_loge("cant find app env"); break; } if (common_env_tmp->addition_data) { os_free(common_env_tmp->addition_data); common_env_tmp->addition_data = NULL; } common_env_tmp->addition_data_len = 0; } break; case BK_GATTS_CONF_EVT: { hogpd_logi("BK_GATTS_CONF_EVT"); } break; case BK_GATTS_RESPONSE_EVT: { hogpd_logi("BK_GATTS_RESPONSE_EVT"); } break; case BK_GATTS_READ_EVT: { struct gatts_read_evt_param *param = (typeof(param))comm_param; bk_gatt_rsp_t rsp; uint16_t final_len = 0; memset(&rsp, 0, sizeof(rsp)); hogpd_logi("read attr handle %d need rsp %d", param->handle, param->need_rsp); uint8_t *tmp_buff = NULL; uint32_t buff_size = 0; uint32_t index = 0; if (dm_gatts_get_buff_from_attr_handle((bk_gatts_attr_db_t *)s_gatts_attr_db_service_hidd, s_hogpd_attr_handle_list, sizeof(s_hogpd_attr_handle_list) / sizeof(s_hogpd_attr_handle_list[0]), param->handle, &index, &tmp_buff, &buff_size)) { hogpd_logi("handle invalid"); break; } hogpd_logi("index %d size %d buff %p", index, buff_size, tmp_buff); if (param->need_rsp) { final_len = buff_size - param->offset; rsp.attr_value.auth_req = BK_GATT_AUTH_REQ_NONE; rsp.attr_value.handle = param->handle; rsp.attr_value.offset = param->offset; rsp.attr_value.len = final_len; rsp.attr_value.value = tmp_buff + param->offset; ret = bk_ble_gatts_send_response(gatts_if, param->conn_id, param->trans_id, BK_GATT_OK, &rsp); } } break; case BK_GATTS_WRITE_EVT: { struct gatts_write_evt_param *param = (typeof(param))comm_param; bk_gatt_rsp_t rsp; uint16_t final_len = 0; memset(&rsp, 0, sizeof(rsp)); hogpd_logi("write attr handle %d need rsp %d", param->handle, param->need_rsp); uint8_t *tmp_buff = NULL; uint32_t buff_size = 0; uint32_t index = 0; if (dm_gatts_get_buff_from_attr_handle((bk_gatts_attr_db_t *)s_gatts_attr_db_service_hidd, s_hogpd_attr_handle_list, sizeof(s_hogpd_attr_handle_list) / sizeof(s_hogpd_attr_handle_list[0]), param->handle, &index, &tmp_buff, &buff_size)) { hogpd_logi("handle invalid"); break; } hogpd_logi("index %d size %d buff %p", index, buff_size, tmp_buff); if (param->handle == s_hogpd_attr_handle_list[1]) { hogpd_logi("write proto mode"); } else if (param->handle == s_hogpd_attr_handle_list[4]) { hogpd_logi("write input report"); } else if (param->handle == s_hogpd_attr_handle_list[5]) { uint16_t config = (((uint16_t)(param->value[1])) << 8) | param->value[0]; hogpd_logi("write input report ccc"); if (config & 1) { hogpd_logi("client notify open"); } else { hogpd_logi("client write invalid data 0x%x", config); } } else if (param->handle == s_hogpd_attr_handle_list[7]) { hogpd_logi("write output report"); } else if (param->handle == s_hogpd_attr_handle_list[9]) { hogpd_logi("write feature report"); } else if (param->handle == s_hogpd_attr_handle_list[11]) { hogpd_logi("write control point"); } else if (param->handle == s_hogpd_attr_handle_list[13]) { hogpd_logi("write bootkeyboardinput report"); } else if (param->handle == s_hogpd_attr_handle_list[14]) { uint16_t config = (((uint16_t)(param->value[1])) << 8) | param->value[0]; hogpd_logi("write bootkeyboardinput report ccc"); if (config & 1) { hogpd_logi("client notify open"); } else { hogpd_logi("client write invalid data 0x%x", config); } } else if (param->handle == s_hogpd_attr_handle_list[15]) { hogpd_logi("write bootkeyboardoutput report"); } if (param->need_rsp) { final_len = MIN_VALUE(param->len, buff_size - param->offset); memcpy(tmp_buff + param->offset, param->value, final_len); rsp.attr_value.auth_req = BK_GATT_AUTH_REQ_NONE; rsp.attr_value.handle = param->handle; rsp.attr_value.offset = param->offset; rsp.attr_value.len = final_len; rsp.attr_value.value = tmp_buff + param->offset; ret = bk_ble_gatts_send_response(gatts_if, param->conn_id, param->trans_id, BK_GATT_OK, &rsp); } } break; case BK_GATTS_EXEC_WRITE_EVT: { struct gatts_exec_write_evt_param *param = (typeof(param))comm_param; hogpd_logi("exec write"); } break; default: break; } return 0; } static int32_t hogpd_demo_reg_db(void) { int32_t ret = dm_gatts_reg_db((bk_gatts_attr_db_t *)s_gatts_attr_db_service_hidd, sizeof(s_gatts_attr_db_service_hidd) / sizeof(s_gatts_attr_db_service_hidd[0]), s_hogpd_attr_handle_list, hogpd_demo_gatts_cb); if (ret) { hogpd_loge("reg db err"); return ret; } return ret; } #endif int32_t hogpd_demo_init(void) { #if HOGPD_DEMO_ENABLE if (!dm_gatts_is_init()) { hogpd_loge("gatts is not init"); return -1; } if (s_hogpd_is_init) { hogpd_loge("already init"); return -1; } s_hogpd_is_init = 1; hogpd_demo_reg_db(); hogpd_logi("done"); #else hogpd_loge("hogpd not enable"); #endif return 0; }