/********************************************************************************************* * Filename : ble_hogp.c * Description : * Author : * Email : zh-jieli.com * Last modifiled : 2020-09-01 11:14 * Copyright:(c)JIELI 2011-2020 @ , All Rights Reserved. *********************************************************************************************/ // ***************************************************************************** /* EXAMPLE_START * * @text All newer operating systems provide GATT Client functionality. * The LE Counter examples demonstrates how to specify a minimal GATT Database * with a custom GATT Service and a custom Characteristic that sends periodic * notifications. */ // ***************************************************************************** #include "system/app_core.h" #include "system/includes.h" #include "app_config.h" #include "app_action.h" #include "btstack/btstack_task.h" #include "btstack/bluetooth.h" #include "user_cfg.h" #include "vm.h" #include "btcontroller_modules.h" #include "bt_common.h" #include "le_common.h" #include "standard_hid.h" #include "rcsp_bluetooth.h" #include "JL_rcsp_api.h" #include "update_loader_download.h" #include "custom_cfg.h" #include "ble_hogp_profile.h" #include "gatt_common/le_gatt_common.h" #include "app_comm_bt.h" #if (TCFG_USER_BLE_ENABLE && CONFIG_HOGP_COMMON_ENABLE) /* #if RCSP_BTMATE_EN */ /* #include "btstack/JL_rcsp_api.h" */ /* #include "rcsp_bluetooth.h" */ /* #endif */ #if LE_DEBUG_PRINT_EN //#define log_info y_printf #define log_info(x, ...) printf("[BLE_HOGP]" x " ", ## __VA_ARGS__) #define log_info_hexdump put_buf #else #define log_info(...) #define log_info_hexdump(...) #endif static u8 remote_ble_addr[7] = {0}; static void hid_timer_mouse_handler(void); extern get_cur_bt_idx(); extern u8 get_key_timeout_flag(); #define EIR_TAG_STRING 0xd6, 0x05, 0x08, 0x00, 'J', 'L', 'A', 'I', 'S', 'D','K' static const char user_tag_string[] = {EIR_TAG_STRING}; //用户可配对的,这是样机跟客户开发的app配对的秘钥 //const u8 link_key_data[16] = {0x06, 0x77, 0x5f, 0x87, 0x91, 0x8d, 0xd4, 0x23, 0x00, 0x5d, 0xf1, 0xd8, 0xcf, 0x0c, 0x14, 0x2b}; #if CONFIG_BLE_HIGH_SPEED //ATT发送的包长, note: 23 <=need >= MTU #define ATT_LOCAL_MTU_SIZE (247) #else #define ATT_LOCAL_MTU_SIZE (64) #endif //ATT缓存的buffer支持缓存数据包个数 #define ATT_PACKET_NUMS_MAX (2) //ATT缓存的buffer大小, note: need >= 23,可修改 #define ATT_SEND_CBUF_SIZE (ATT_PACKET_NUMS_MAX * (ATT_PACKET_HEAD_SIZE + ATT_LOCAL_MTU_SIZE)) static volatile hci_con_handle_t hogp_con_handle; int ble_hid_timer_handle = 0; //是否使能参数请求更新,0--disable, 1--enable static uint8_t hogp_connection_update_enable = 1; //连接参数表,按顺序优先请求,主机接受了就中止 static const struct conn_update_param_t Peripheral_Preferred_Connection_Parameters[] = { {6, 9, 100, 600}, //android /* {7, 7, 20, 300}, //mosue */ /* {20, 20, 20, 300}, //kb */ {12, 12, 30, 600}, //ios {6, 12, 30, 600},// ios fast }; //共可用的参数组数 #define CONN_PARAM_TABLE_CNT (sizeof(Peripheral_Preferred_Connection_Parameters)/sizeof(struct conn_update_param_t)) static u8 hogp_adv_data[ADV_RSP_PACKET_MAX];//max is 31 static u8 hogp_scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31 static u8 first_pair_flag; //第一次配对标记 static u8 is_hogp_active = 0; //不可进入sleep状态 static adv_cfg_t hogp_server_adv_config; /*--------------------------------------------*/ //普通未连接广播周期 (unit:0.625ms) #define ADV_INTERVAL_MIN (160 * 5) /*------------------------------ 配置有配对绑定时,先回连广播快连,再普通广播;否则只作普通广播 定向广播只带对方的地址,不带adv和rsp包 */ #define PAIR_RECONNECT_ADV_EN 1 /*是否上电使用定向广播,优先绑定回连*/ //可选两种定向广播类型, //ADV_DIRECT_IND (1.28s超时,interval 固定2ms) //ADV_DIRECT_IND_LOW (interval 和 channel 跟普通广播设置一样) //ADV_IND (无定向广播:interval 和 channel 跟普通广播设置一样) static u8 pair_reconnect_adv_type = ADV_DIRECT_IND; //等待回连状态下的广播周期 (unit:0.625ms) #define PAIR_RECONNECT_ADV_INTERVAL (32) /*>=32, ADV_IND,ADV_DIRECT_IND_LOW,interval*/ static u32 pair_reconnect_adv_timeout = 5000;/*回连广播持续时间,ms*/ //广播通道设置置 static u8 le_adv_channel_sel = ADV_CHANNEL_ALL; //-------------------------------------------- #define BLE_VM_HEAD_TAG (0xB35C) #define BLE_VM_TAIL_TAG (0x5CB3) struct pair_info_t { u16 head_tag; //头标识 u8 pair_flag: 2; //配对信息是否有效 u8 direct_adv_cnt: 6; //定向广播次数 u8 direct_adv_flag: 1; u8 peer_address_info[7]; //绑定的对方地址信息 u16 tail_tag;//尾标识 }; //配对信息表 static struct pair_info_t hogp_pair_info; static u8 cur_peer_addr_info[7];//当前连接对方地址信息 #define REPEAT_DIRECT_ADV_COUNT (2)// *1.28s //为了及时响应手机数据包,某些流程会忽略进入latency的控制 //如下是定义忽略进入的interval个数 #define LATENCY_SKIP_INTERVAL_MIN (3) #define LATENCY_SKIP_INTERVAL_KEEP (20) #define LATENCY_SKIP_INTERVAL_LONG (0xffff) //hid device infomation static u8 Appearance[] = {BLE_APPEARANCE_GENERIC_HID & 0xff, BLE_APPEARANCE_GENERIC_HID >> 8}; // static const char Manufacturer_Name_String[] = "zhuhai_jieli"; static const char Model_Number_String[] = "hid_mouse"; static const char Serial_Number_String[] = "000000"; static const char Hardware_Revision_String[] = "0.0.1"; static const char Firmware_Revision_String[] = "0.0.1"; static const char Software_Revision_String[] = "0.0.1"; static const u8 System_ID[] = {0, 0, 0, 0, 0, 0, 0, 0}; //定义的产品信息,for test #define PNP_VID_SOURCE 0x02 #define PNP_VID 0x05ac //0x05d6 #define PNP_PID 0x022C // #define PNP_PID_VERSION 0x011b //1.1.11 static u8 PnP_ID[] = {PNP_VID_SOURCE, PNP_VID & 0xFF, PNP_VID >> 8, PNP_PID & 0xFF, PNP_PID >> 8, PNP_PID_VERSION & 0xFF, PNP_PID_VERSION >> 8}; /* static const u8 PnP_ID[] = {0x02, 0x17, 0x27, 0x40, 0x00, 0x23, 0x00}; */ /* static const u8 PnP_ID[] = {0x02, 0xac, 0x05, 0x2c, 0x02, 0x1b, 0x01}; */ /* static const u8 hid_information[] = {0x11, 0x01, 0x00, 0x01}; */ /* static const u8 hid_information[] = {0x01, 0x01, 0x00, 0x03}; */ static const u8 hid_information[] = {0x11, 0x01, 0x00, 0x03}; static const u8 hid_information1[] = {0x00, 0x00, 0x00, 0x00}; static u8 *report_map; //描述符 static u16 report_map_size;//描述符大小 static u16 hogp_adv_timeout_number = 0; #define HID_REPORT_MAP_DATA report_map #define HID_REPORT_MAP_SIZE report_map_size //report 发生变化,通过service change 通知主机重新获取 static u8 hid_report_change = 0; static u8 hid_battery_level = 88; static u32 hid_battery_level_add_sum;/*电量采集累加*/ static u32 hid_battery_level_add_cnt;/*电量采集次数*/ #define HID_BATTERY_TIMER_SET (60000) /*定时检测电量变化的时间30~60*/ static u16 hid_battery_notify_timer_id; static u8(*get_vbat_percent_call)(void) = NULL; static void (*le_hogp_output_callback)(u8 *buffer, u16 size) = NULL; //------------------------------------------------------ static void __hogp_resume_all_ccc_enable(u8 update_request); static void __check_report_map_change(void); void ble_hid_transfer_channel_recieve(u8 *packet, u16 size); void ble_hid_transfer_channel_recieve1(u8 *packet, u16 size); static uint16_t hogp_att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size); static int hogp_att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size); static int hogp_event_packet_handler(int event, u8 *packet, u16 size, u8 *ext_param); static void hogp_adv_config_set(void); static u8 hid_get_vbat_handle(void); //------------------------------------------------------ static u8 multi_dev_adv_flag = 0; /*多地址设备切换广播*/ void set_multi_devices_adv_flag(u8 adv_flag) { multi_dev_adv_flag = adv_flag; } //输入passkey 加密 #define PASSKEY_ENABLE 0 static const sm_cfg_t hogp_sm_init_config = { .slave_security_auto_req = 0, .slave_set_wait_security = 0, #if PASSKEY_ENABLE .io_capabilities = IO_CAPABILITY_DISPLAY_ONLY, #else .io_capabilities = IO_CAPABILITY_NO_INPUT_NO_OUTPUT, #endif .authentication_req_flags = SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION, .min_key_size = 7, .max_key_size = 16, .sm_cb_packet_handler = NULL, }; const gatt_server_cfg_t hogp_server_init_cfg = { .att_read_cb = &hogp_att_read_callback, .att_write_cb = &hogp_att_write_callback, .event_packet_handler = &hogp_event_packet_handler, }; static gatt_ctrl_t hogp_gatt_control_block = { //public .mtu_size = ATT_LOCAL_MTU_SIZE, .cbuffer_size = ATT_SEND_CBUF_SIZE, .multi_dev_flag = 0, //config #if CONFIG_BT_GATT_SERVER_NUM .server_config = &hogp_server_init_cfg, #else .server_config = NULL, #endif .client_config = NULL, #if CONFIG_BT_SM_SUPPORT_ENABLE .sm_config = &hogp_sm_init_config, #else .sm_config = NULL, #endif //cbk,event handle .hci_cb_packet_handler = NULL, }; /*************************************************************************************************/ /*! * \brief 推送消息给app * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static void __ble_bt_evnet_post(u32 arg_type, u8 priv_event, u8 *args, u32 value) { struct sys_event e; e.type = SYS_BT_EVENT; e.arg = (void *)arg_type; e.u.bt.event = priv_event; if (args) { memcpy(e.u.bt.args, args, 7); } e.u.bt.value = value; sys_event_notify(&e); } /*************************************************************************************************/ /*! * \brief 推送ble状态 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static void __ble_state_to_user(u8 state, u8 reason) { static u8 ble_state = 0xff; if (state != ble_state) { log_info("ble_state:%02x===>%02x\n", ble_state, state); ble_state = state; __ble_bt_evnet_post(SYS_BT_EVENT_BLE_STATUS, state, NULL, reason); } } /*************************************************************************************************/ /*! * \brief 配置发起连接参数更新 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static void __hogp_send_connetion_update_deal(u16 conn_handle) { if (hogp_connection_update_enable) { if (0 == ble_gatt_server_connetion_update_request(conn_handle, Peripheral_Preferred_Connection_Parameters, CONN_PARAM_TABLE_CNT)) { hogp_connection_update_enable = 0; } } } /*************************************************************************************************/ /*! * \brief vm 绑定对方信息 读写 * * \param [in] rw_flag: 0--read, 1--write * * \return * * \note */ /*************************************************************************************************/ static void __hogp_conn_pair_vm_do(struct pair_info_t *info, u8 rw_flag) { int ret; int vm_len = sizeof(struct pair_info_t); log_info("-hogp_pair_info vm_do:%d\n", rw_flag); if (rw_flag == 0) { if (multi_dev_adv_flag) { ret = syscfg_read(CFG_BLE_BONDING_REMOTE_INFO + get_cur_bt_idx(), (u8 *)info, vm_len); } else { ret = syscfg_read(CFG_BLE_BONDING_REMOTE_INFO, (u8 *)info, vm_len); } if (vm_len != ret) { log_info("-null--\n"); memset(info, 0, vm_len); } if ((BLE_VM_HEAD_TAG == info->head_tag) && (BLE_VM_TAIL_TAG == info->tail_tag)) { log_info("-exist--\n"); } else { log_info("-reset vm--\n"); memset(info, 0, vm_len); info->head_tag = BLE_VM_HEAD_TAG; info->tail_tag = BLE_VM_TAIL_TAG; } } else { if (multi_dev_adv_flag) { syscfg_write(CFG_BLE_BONDING_REMOTE_INFO + get_cur_bt_idx(), (u8 *)info, vm_len); } else { syscfg_write(CFG_BLE_BONDING_REMOTE_INFO, (u8 *)info, vm_len); } } log_info_hexdump(info, vm_len); } /*************************************************************************************************/ /*! * \brief 配置hid描述符 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static const u16 change_handle_table[2] = {ATT_CHARACTERISTIC_2a4b_01_VALUE_HANDLE, ATT_CHARACTERISTIC_2a4b_01_VALUE_HANDLE}; static void __check_report_map_change(void) { #if 0 //部分手机不支持 if (hid_report_change && first_pair_flag && ble_gatt_server_characteristic_ccc_get(hogp_con_handle, ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE)) { log_info("###send services changed\n"); ble_comm_att_send_data(hogp_con_handle, ATT_CHARACTERISTIC_2a05_01_VALUE_HANDLE, change_handle_table, 4, ATT_OP_INDICATE); hid_report_change = 0; } #endif } /*************************************************************************************************/ /*! * \brief 回连状态,主动使能通知 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static void __hogp_resume_all_ccc_enable(u8 update_request) { log_info("__hogp_resume_all_ccc_enable\n"); ble_gatt_server_characteristic_ccc_set(hogp_con_handle, ATT_CHARACTERISTIC_2a4d_01_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY); ble_gatt_server_characteristic_ccc_set(hogp_con_handle, ATT_CHARACTERISTIC_2a4d_02_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY); ble_gatt_server_characteristic_ccc_set(hogp_con_handle, ATT_CHARACTERISTIC_2a4d_04_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY); ble_gatt_server_characteristic_ccc_set(hogp_con_handle, ATT_CHARACTERISTIC_2a4d_05_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY); ble_gatt_server_characteristic_ccc_set(hogp_con_handle, ATT_CHARACTERISTIC_2a4d_06_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY); ble_gatt_server_characteristic_ccc_set(hogp_con_handle, ATT_CHARACTERISTIC_2a4d_07_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY); ble_gatt_server_characteristic_ccc_set(hogp_con_handle, ATT_CHARACTERISTIC_ae42_01_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY); ble_gatt_server_characteristic_ccc_set(hogp_con_handle, ATT_CHARACTERISTIC_2a19_01_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY); #if RCSP_BTMATE_EN /* ble_gatt_server_characteristic_ccc_set(hogp_con_handle, ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY); */ /* ble_gatt_server_set_update_send(hogp_con_handle, ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, ATT_OP_AUTO_READ_CCC); */ /* set_rcsp_conn_handle(hogp_con_handle); */ #endif if (update_request) { __hogp_send_connetion_update_deal(hogp_con_handle); } } /*************************************************************************************************/ /*! * \brief 反馈检查对方的操作系统 * * \param [in] * * \return * * \note 参考识别手机系统 */ /*************************************************************************************************/ static void __att_check_remote_result(u16 con_handle, remote_type_e remote_type) { log_info("le_hogp %02x:remote_type= %02x\n", con_handle, remote_type); __ble_bt_evnet_post(SYS_BT_EVENT_FORM_COMMON, COMMON_EVENT_BLE_REMOTE_TYPE, NULL, remote_type); //to do } /*************************************************************************************************/ /*! * \brief 处理 gatt common 事件,hci & gatt * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static int hogp_event_packet_handler(int event, u8 *packet, u16 size, u8 *ext_param) { /* log_info("event: %02x,size= %d\n",event,size); */ switch (event) { case GATT_COMM_EVENT_CAN_SEND_NOW: #if TEST_AUDIO_DATA_UPLOAD hogp_test_send_audio_data(0); #endif break; case GATT_COMM_EVENT_SERVER_INDICATION_COMPLETE: log_info("INDICATION_COMPLETE:con_handle= %04x,att_handle= %04x\n", \ little_endian_read_16(packet, 0), little_endian_read_16(packet, 2)); break; case GATT_COMM_EVENT_CONNECTION_COMPLETE: hogp_con_handle = little_endian_read_16(packet, 0); first_pair_flag = 0; memcpy(cur_peer_addr_info, ext_param + 7, 7); log_info("connection_handle:%04x, rssi= %d\n", hogp_con_handle, ble_vendor_get_peer_rssi(hogp_con_handle)); log_info("peer_address_info:"); put_buf(cur_peer_addr_info, 7); log_info("con_interval = %d\n", little_endian_read_16(ext_param, 14 + 0)); log_info("con_latency = %d\n", little_endian_read_16(ext_param, 14 + 2)); log_info("cnn_timeout = %d\n", little_endian_read_16(ext_param, 14 + 4)); if (little_endian_read_16(ext_param, 14 + 2)) { //latency非0值 hogp_connection_update_enable = 0; /* __hogp_resume_all_ccc_enable(0); */ } else { hogp_connection_update_enable = 1; } if (ble_hid_timer_handle) { log_info("mdy_timer= %d\n", (u32)(little_endian_read_16(ext_param, 14 + 0) * 1.25)); sys_s_hi_timer_modify(ble_hid_timer_handle, (u32)(little_endian_read_16(ext_param, 14 + 0) * 1.25)); } if (little_endian_read_16(ext_param, 14 + 2)) { ble_op_latency_skip(hogp_con_handle, LATENCY_SKIP_INTERVAL_KEEP); // } break; case GATT_COMM_EVENT_DISCONNECT_COMPLETE: log_info("disconnect_handle:%04x,reason= %02x\n", little_endian_read_16(packet, 0), packet[2]); hogp_con_handle = 0; if (8 == packet[2] && hogp_pair_info.pair_flag) { //超时断开,有配对发定向广播 hogp_pair_info.direct_adv_cnt = REPEAT_DIRECT_ADV_COUNT; hogp_adv_config_set(); } break; case GATT_COMM_EVENT_ENCRYPTION_CHANGE: log_info("ENCRYPTION_CHANGE:handle=%04x,state=%d,process =%02x", little_endian_read_16(packet, 0), packet[2], packet[3]); if (packet[3] == LINK_ENCRYPTION_RECONNECT) { log_info("reconnect...\n"); if ((!hogp_pair_info.pair_flag) || memcmp(cur_peer_addr_info, hogp_pair_info.peer_address_info, 7)) { log_info("update reconnect peer\n"); put_buf(cur_peer_addr_info, 7); memcpy(hogp_pair_info.peer_address_info, cur_peer_addr_info, 7); hogp_pair_info.pair_flag = 1; __hogp_conn_pair_vm_do(&hogp_pair_info, 1); } __hogp_resume_all_ccc_enable(1); //回连时,从配对表中获取 u8 tmp_buf[6]; u8 remote_type = 0; swapX(&cur_peer_addr_info[1], tmp_buf, 6); ble_list_get_remote_type(tmp_buf, cur_peer_addr_info[0], &remote_type); log_info("list's remote_type:%d\n", remote_type); __att_check_remote_result(hogp_con_handle, remote_type); } else { //只在配对时启动检查 log_info("first pair...\n"); memcpy(hogp_pair_info.peer_address_info, cur_peer_addr_info, 7); att_server_set_check_remote(hogp_con_handle, __att_check_remote_result); hogp_pair_info.pair_flag = 1; __hogp_conn_pair_vm_do(&hogp_pair_info, 1); } __ble_state_to_user(BLE_PRIV_PAIR_ENCRYPTION_CHANGE, first_pair_flag); break; case GATT_COMM_EVENT_CONNECTION_UPDATE_COMPLETE: log_info("conn_param update_complete:%04x\n", little_endian_read_16(packet, 0)); log_info("update_interval = %d\n", little_endian_read_16(ext_param, 6 + 0)); log_info("update_latency = %d\n", little_endian_read_16(ext_param, 6 + 2)); log_info("update_timeout = %d\n", little_endian_read_16(ext_param, 6 + 4)); if (ble_hid_timer_handle) { log_info("mdy_timer= %d\n", (u32)(little_endian_read_16(ext_param, 6 + 0) * 1.25)); sys_s_hi_timer_modify(ble_hid_timer_handle, (u32)(little_endian_read_16(ext_param, 6 + 0) * 1.25)); } break; case GATT_COMM_EVENT_DIRECT_ADV_TIMEOUT: log_info("DIRECT_ADV_TIMEOUT\n"); if (hogp_pair_info.direct_adv_cnt) { hogp_pair_info.direct_adv_cnt--; } hogp_adv_config_set(); break; case GATT_COMM_EVENT_ENCRYPTION_REQUEST: first_pair_flag = 1; memcpy(hogp_pair_info.peer_address_info, &packet[4], 7); hogp_pair_info.pair_flag = 0; __ble_state_to_user(BLE_PRIV_MSG_PAIR_CONFIRM, 0); break; case GATT_COMM_EVENT_SERVER_STATE: log_info("server_state: %02x,%02x\n", little_endian_read_16(packet, 1), packet[0]); __ble_state_to_user(packet[0], hogp_con_handle); break; case GATT_COMM_EVENT_CONNECTION_UPDATE_REQUEST_RESULT: case GATT_COMM_EVENT_MTU_EXCHANGE_COMPLETE: break; default: break; } return 0; } /*************************************************************************************************/ /*! * \brief 处理client 读操作 * * \param [in] * * \return * * \note profile的读属性uuid 有配置 DYNAMIC 关键字,就有read_callback 回调 */ /*************************************************************************************************/ // ATT Client Read Callback for Dynamic Data // - if buffer == NULL, don't copy data, just return size of value // - if buffer != NULL, copy data and return number bytes copied // @param con_handle of hci le connection // @param attribute_handle to be read // @param offset defines start of attribute value // @param buffer // @param buffer_size //主机操作ATT read,协议栈回调处理 static uint16_t hogp_att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size) { uint16_t att_value_len = 0; uint16_t handle = att_handle; log_info("read_callback, handle= 0x%04x,buffer= %08x,offset= %04x\n", handle, (u32)buffer, offset); switch (handle) { case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE: { char *gap_name = ble_comm_get_gap_name(); att_value_len = strlen(gap_name); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &gap_name[offset], buffer_size); att_value_len = buffer_size; log_info("\n------read gap_name: %s\n", gap_name); } } break; case ATT_CHARACTERISTIC_2a01_01_VALUE_HANDLE: att_value_len = sizeof(Appearance); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &Appearance[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a04_01_VALUE_HANDLE: att_value_len = 8;//fixed if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { log_info("\n------get Peripheral_Preferred_Connection_Parameters\n"); memcpy(buffer, &Peripheral_Preferred_Connection_Parameters[0], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a29_01_VALUE_HANDLE: att_value_len = strlen(Manufacturer_Name_String); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &Manufacturer_Name_String[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a24_01_VALUE_HANDLE: att_value_len = strlen(Model_Number_String); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &Model_Number_String[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a25_01_VALUE_HANDLE: att_value_len = strlen(Serial_Number_String); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &Serial_Number_String[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a27_01_VALUE_HANDLE: att_value_len = strlen(Hardware_Revision_String); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &Hardware_Revision_String[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a26_01_VALUE_HANDLE: att_value_len = strlen(Firmware_Revision_String); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &Firmware_Revision_String[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a28_01_VALUE_HANDLE: att_value_len = strlen(Software_Revision_String); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &Software_Revision_String[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a23_01_VALUE_HANDLE: att_value_len = sizeof(System_ID); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &System_ID[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a50_01_VALUE_HANDLE: log_info("read PnP_ID\n"); att_value_len = sizeof(PnP_ID); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &PnP_ID[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a19_01_VALUE_HANDLE: att_value_len = 1; if (buffer) { if (get_vbat_percent_call) { hid_battery_level = hid_get_vbat_handle(); log_info("read vbat:%d\n", hid_battery_level); } buffer[0] = hid_battery_level; } break; case ATT_CHARACTERISTIC_2a4b_01_VALUE_HANDLE: att_value_len = HID_REPORT_MAP_SIZE; if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &HID_REPORT_MAP_DATA[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_2a4a_01_VALUE_HANDLE: att_value_len = sizeof(hid_information); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { break; } if (buffer) { memcpy(buffer, &hid_information[offset], buffer_size); att_value_len = buffer_size; } break; case ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE: att_value_len = sizeof(hid_information1); if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) { log_info("len is err"); break; } if (buffer) { memcpy(buffer, &hid_information1[offset], buffer_size); att_value_len = buffer_size; put_buf(buffer, att_value_len); } /* __hogp_send_connetion_update_deal(connection_handle); */ break; case ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a19_01_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_01_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_02_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_04_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_05_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_06_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_07_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_ae42_01_CLIENT_CONFIGURATION_HANDLE: if (buffer) { buffer[0] = ble_gatt_server_characteristic_ccc_get(hogp_con_handle, handle); buffer[1] = 0; } att_value_len = 2; break; default: break; } log_info("att_value_len= %d\n", att_value_len); return att_value_len; } /*************************************************************************************************/ /*! * \brief 处理client 读操作 * * \param [in] * * \return * * \note profile的读属性uuid 有配置 DYNAMIC 关键字,就有read_callback 回调 */ /*************************************************************************************************/ // ATT Client Write Callback for Dynamic Data // @param con_handle of hci le connection // @param attribute_handle to be written // @param transaction - ATT_TRANSACTION_MODE_NONE for regular writes, ATT_TRANSACTION_MODE_ACTIVE for prepared writes and ATT_TRANSACTION_MODE_EXECUTE // @param offset into the value - used for queued writes and long attributes // @param buffer // @param buffer_size // @param signature used for signed write commmands // @returns 0 if write was ok, ATT_ERROR_PREPARE_QUEUE_FULL if no space in queue, ATT_ERROR_INVALID_OFFSET if offset is larger than max buffer //主机操作ATT write,协议栈回调处理 static int hogp_att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size) { int result = 0; u16 tmp16; u16 handle = att_handle; log_info("write_callback, handle= 0x%04x,size = %d\n", handle, buffer_size); switch (handle) { case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE: break; case ATT_CHARACTERISTIC_2a4d_03_VALUE_HANDLE: put_buf(buffer, buffer_size); //键盘led灯状态 if (le_hogp_output_callback) { le_hogp_output_callback(buffer, buffer_size); } break; case ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE: ble_gatt_server_characteristic_ccc_set(connection_handle, handle, buffer[0]); if (buffer[0]) { __check_report_map_change(); } break; #if RCSP_BTMATE_EN case ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE: ble_gatt_server_set_update_send(connection_handle, ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, ATT_OP_AUTO_READ_CCC); set_rcsp_conn_handle(connection_handle); #if (0 == BT_CONNECTION_VERIFY) JL_rcsp_auth_reset(); //hid设备试能nofity的时候reset auth保证APP可以重新连接 #endif #if (TCFG_HID_AUTO_SHUTDOWN_TIME) __ble_bt_evnet_post(SYS_BT_EVENT_FORM_COMMON, COMMON_EVENT_SHUTDOWN_DISABLE, NULL, 0); /* auto_shutdown_disable(); */ #endif #endif case ATT_CHARACTERISTIC_ae42_01_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_01_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_02_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_04_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_05_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_06_CLIENT_CONFIGURATION_HANDLE: case ATT_CHARACTERISTIC_2a4d_07_CLIENT_CONFIGURATION_HANDLE: ble_op_latency_skip(hogp_con_handle, LATENCY_SKIP_INTERVAL_MIN); // case ATT_CHARACTERISTIC_2a19_01_CLIENT_CONFIGURATION_HANDLE: __hogp_send_connetion_update_deal(hogp_con_handle); log_info("\n------write ccc:%04x,%02x\n", handle, buffer[0]); #if RCSP_BTMATE_EN //-----如果主机notify RCSP协议,从机告知主机存在此协议 if (handle == ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE) { u8 data[1] = {0xff}; ble_comm_att_send_data(connection_handle, ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, &data, 1, ATT_OP_NOTIFY); } #endif ble_gatt_server_characteristic_ccc_set(hogp_con_handle, handle, buffer[0]); break; #if RCSP_BTMATE_EN case ATT_CHARACTERISTIC_ae01_01_VALUE_HANDLE: log_info("rcsp_read:%x\n", buffer_size); put_buf(buffer, (buffer_size > 30) ? 30 : buffer_size); hogp_connection_update_enable = 0; ble_gatt_server_receive_update_data(NULL, buffer, buffer_size); break; #endif case ATT_CHARACTERISTIC_ae41_01_VALUE_HANDLE: ble_hid_transfer_channel_recieve(buffer, buffer_size); break; case ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE: tmp16 = sizeof(hid_information1); if ((offset >= tmp16) || (offset + buffer_size) > tmp16) { break; } log_info("cur_state:"); put_buf(hid_information1, tmp16); memcpy(&hid_information1[offset], buffer, buffer_size); log_info("new_state:"); put_buf(hid_information1, tmp16); ble_hid_transfer_channel_recieve1(hid_information1, tmp16); break; default: break; } return 0; } /*************************************************************************************************/ /*! * \brief 生成adv包,放入buff * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static u8 adv_name_ok; //name 优先存放在ADV包 static int hogp_make_set_adv_data(u8 adv_reconnect) { u8 offset = 0; u8 *buf = hogp_adv_data; offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, FLAGS_GENERAL_DISCOVERABLE_MODE | FLAGS_EDR_NOT_SUPPORTED, 1); offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS, HID_UUID_16, 2); offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_APPEARANCE_DATA, Appearance, 2); if (!adv_reconnect) {/*回连广播默认不填入名字*/ char *gap_name = ble_comm_get_gap_name(); u8 name_len = strlen(gap_name); u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2); if (name_len < vaild_len) { offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_name, name_len); adv_name_ok = 1; } else { adv_name_ok = 0; } } if (offset > ADV_RSP_PACKET_MAX) { puts("***hogp_adv_data overflow!!!!!!\n"); return -1; } log_info("hogp_adv_data(%d):", offset); log_info_hexdump(buf, offset); hogp_server_adv_config.adv_data_len = offset; hogp_server_adv_config.adv_data = hogp_adv_data; return 0; } /*************************************************************************************************/ /*! * \brief 生成rsp包,放入buff * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static int hogp_make_set_rsp_data(u8 adv_reconnect) { u8 offset = 0; u8 *buf = hogp_scan_rsp_data; #if RCSP_BTMATE_EN u8 tag_len = sizeof(user_tag_string); offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA, (void *)user_tag_string, tag_len); #endif if (!adv_reconnect) {/*回连广播默认不填入名字*/ if (!adv_name_ok) { char *gap_name = ble_comm_get_gap_name(); u8 name_len = strlen(gap_name); u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2); if (name_len > vaild_len) { name_len = vaild_len; } offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_name, name_len); } } if (offset > ADV_RSP_PACKET_MAX) { puts("***rsp_data overflow!!!!!!\n"); return -1; } log_info("rsp_data(%d):", offset); log_info_hexdump(buf, offset); hogp_server_adv_config.rsp_data_len = offset; hogp_server_adv_config.rsp_data = hogp_scan_rsp_data; return 0; } /*************************************************************************************************/ /*! * \brief 修改gatt name * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void modify_ble_name(const char *name) { log_info(">>>modify_ble_name:%s\n", name); ble_comm_set_config_name(bt_get_local_name(), 1); } static void wait_to_open_adv(void) { if (!hogp_con_handle) { log_info("allow open adv"); ble_gatt_server_adv_enable(1); } else { log_info("no allow open adv"); } } static void __hogp_reconnect_low_timeout_handle(void) { if (0 == hogp_con_handle && ble_gatt_server_get_work_state() == BLE_ST_ADV) { log_info("ADV_RECONNECT timeout!!!\n"); ble_gatt_server_adv_enable(0); hogp_pair_info.direct_adv_cnt = 0; hogp_adv_config_set(); #if RCSP_BTMATE_EN sys_timeout_add(NULL, wait_to_open_adv, 20); #else ble_gatt_server_adv_enable(1); #endif } else { /*其他情况,要取消定向广播*/ log_info("Set Switch to ADV_IND Config\n"); hogp_pair_info.direct_adv_cnt = 0; hogp_adv_config_set(); } } /*************************************************************************************************/ /*! * \brief 广播参数设置 * * \param [in] * * \return * * \note 回连可默认用无定向广播,兼容某些主机不支持定向广播连接 */ /*************************************************************************************************/ static void hogp_adv_config_set(void) { int ret = 0; int adv_reconnect_flag = 0; hogp_server_adv_config.adv_interval = ADV_INTERVAL_MIN; hogp_server_adv_config.adv_auto_do = 1; hogp_server_adv_config.adv_channel = le_adv_channel_sel; if (PAIR_RECONNECT_ADV_EN && hogp_pair_info.pair_flag && hogp_pair_info.direct_adv_cnt) { hogp_server_adv_config.adv_type = pair_reconnect_adv_type; memcpy(hogp_server_adv_config.direct_address_info, hogp_pair_info.peer_address_info, 7); if (pair_reconnect_adv_type != ADV_DIRECT_IND) { hogp_server_adv_config.adv_interval = PAIR_RECONNECT_ADV_INTERVAL; if (pair_reconnect_adv_timeout) { if (hogp_adv_timeout_number) { sys_timeout_del(hogp_adv_timeout_number); hogp_adv_timeout_number = 0; } hogp_adv_timeout_number = sys_timeout_add(0, __hogp_reconnect_low_timeout_handle, pair_reconnect_adv_timeout); } } log_info("RECONNECT_ADV1= %02x, address:", pair_reconnect_adv_type); put_buf(hogp_server_adv_config.direct_address_info, 7); adv_reconnect_flag = 1; } else { hogp_server_adv_config.adv_type = ADV_IND; memset(hogp_server_adv_config.direct_address_info, 0, 7); } log_info("adv_type:%d,channel=%02x\n", hogp_server_adv_config.adv_type, hogp_server_adv_config.adv_channel); ret |= hogp_make_set_adv_data(adv_reconnect_flag); ret |= hogp_make_set_rsp_data(adv_reconnect_flag); if (ret) { log_info("adv_setup_init fail!!!\n"); return; } ble_gatt_server_set_adv_config(&hogp_server_adv_config); } /*************************************************************************************************/ /*! * \brief 定向广播参数设置 * * \param [in] * * \return * * \note 回连可默认用无定向广播,兼容某些主机不支持定向广播连接 */ /*************************************************************************************************/ void hogp_reconnect_adv_config_set(u8 adv_type, u32 adv_timeout) { int ret = 0; int adv_reconnect_flag = 0; hogp_server_adv_config.adv_interval = PAIR_RECONNECT_ADV_INTERVAL; hogp_server_adv_config.adv_auto_do = 1; hogp_server_adv_config.adv_channel = ADV_CHANNEL_ALL; __hogp_conn_pair_vm_do(&hogp_pair_info, 0); if (hogp_pair_info.pair_flag) { adv_reconnect_flag = 1; /*已配对*/ hogp_server_adv_config.adv_type = adv_type; } else { hogp_server_adv_config.adv_type = ADV_IND;/*强制切换可发现广播*/ } if (PAIR_RECONNECT_ADV_EN && hogp_pair_info.pair_flag) { memcpy(hogp_server_adv_config.direct_address_info, &hogp_pair_info.peer_address_info, 7); log_info("RECONNECT_ADV2= %02x, address:", adv_type); put_buf(hogp_server_adv_config.direct_address_info, 7); if (adv_type == ADV_DIRECT_IND) { hogp_pair_info.direct_adv_cnt = (adv_timeout + 1279) / 1280; /*定向次数*/ } else { if (adv_timeout) { /*设置超时切换到无定向广播*/ if (hogp_adv_timeout_number) { sys_timeout_del(hogp_adv_timeout_number); hogp_adv_timeout_number = 0; } hogp_adv_timeout_number = sys_timeout_add(0, __hogp_reconnect_low_timeout_handle, adv_timeout); } } } else { memset(hogp_server_adv_config.direct_address_info, 0, 7); hogp_server_adv_config.adv_interval = ADV_INTERVAL_MIN; } log_info("adv_type:%d,channel=%02x\n", hogp_server_adv_config.adv_type, hogp_server_adv_config.adv_channel); ret |= hogp_make_set_adv_data(adv_reconnect_flag); ret |= hogp_make_set_rsp_data(adv_reconnect_flag); if (ret) { log_info("adv_setup_init fail!!!\n"); return; } ble_gatt_server_set_adv_config(&hogp_server_adv_config); } /*************************************************************************************************/ /*! * \brief init * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static void hogp_server_init(void) { log_info("%s", __FUNCTION__); ble_gatt_server_set_profile(hogp_profile_data, sizeof(hogp_profile_data)); hogp_adv_config_set(); } /*************************************************************************************************/ /*! * \brief bt_ble_before_start_init * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void bt_ble_before_start_init(void) { log_info("%s", __FUNCTION__); ble_comm_init(&hogp_gatt_control_block); } /*************************************************************************************************/ /*! * \brief 电量累计求平均计算方法 * * \param [in] * * \return vbat percent * * \note */ /*************************************************************************************************/ static u8 hid_get_vbat_handle(void) { if (!get_vbat_percent_call) { return 0; } u8 cur_val, avg_val, val; if (hid_battery_level_add_cnt > 10) { /*超过10次,取平均值*/ hid_battery_level_add_sum = hid_battery_level_add_sum / hid_battery_level_add_cnt; hid_battery_level_add_cnt = 1; } cur_val = get_vbat_percent_call(); if (hid_battery_level_add_cnt) { avg_val = hid_battery_level_add_sum / hid_battery_level_add_cnt; if (cur_val > (avg_val + 2) || (cur_val + 2) < avg_val) { /*变化较大*/ hid_battery_level_add_sum = 0; hid_battery_level_add_cnt = 0; } } hid_battery_level_add_sum += cur_val; hid_battery_level_add_cnt++; /*简单的累加求平均值计算*/ val = (u8)(hid_battery_level_add_sum / hid_battery_level_add_cnt); log_info("vbat: avg=%d,cur=%d,val=%d\n", avg_val, cur_val, val); return val; } /*************************************************************************************************/ /*! * \brief 定时检测电量变化,推送通知给主机 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static void hid_battery_timer_handler(void *priev) { #if TCFG_SYS_LVD_EN if (hogp_con_handle && get_vbat_percent_call) { u8 tmp_val = hid_get_vbat_handle(); /* tmp_val = (tmp_val +10)%101; */ if (hid_battery_level != tmp_val) { hid_battery_level = tmp_val; if (ble_gatt_server_characteristic_ccc_get(hogp_con_handle, ATT_CHARACTERISTIC_2a19_01_CLIENT_CONFIGURATION_HANDLE)) { log_info("notify battery: %d\n", hid_battery_level); ble_comm_att_send_data(hogp_con_handle, ATT_CHARACTERISTIC_2a19_01_VALUE_HANDLE, &hid_battery_level, 1, ATT_OP_AUTO_READ_CCC); } } } #endif // TCFG_SYS_LVD_EN } /*************************************************************************************************/ /*! * \brief 模块初始化 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void bt_ble_init(void) { log_info("%s\n", __FUNCTION__); log_info("ble_file: %s", __FILE__); hogp_con_handle = 0; __hogp_conn_pair_vm_do(&hogp_pair_info, 0); if (hogp_pair_info.pair_flag) { hogp_pair_info.direct_adv_cnt = REPEAT_DIRECT_ADV_COUNT; } #if TCFG_SYS_LVD_EN if (!hid_battery_notify_timer_id && HID_BATTERY_TIMER_SET) { log_info("add hid_battery_notify_timer_id\n"); hid_battery_notify_timer_id = sys_timer_add((void *)0, hid_battery_timer_handler, HID_BATTERY_TIMER_SET); } #endif // TCFG_SYS_LVD_EN #if DOUBLE_BT_SAME_NAME ble_comm_set_config_name(bt_get_local_name(), 0); #else ble_comm_set_config_name(bt_get_local_name(), 1); #endif hogp_server_init(); #if CONFIG_APP_STANDARD_KEYBOARD ble_module_enable(0); #else ble_module_enable(1); #endif } /*************************************************************************************************/ /*! * \brief 模块退出 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void bt_ble_exit(void) { log_info("***** ble_exit******\n"); if (ble_hid_timer_handle) { sys_s_hi_timer_del(ble_hid_timer_handle); ble_hid_timer_handle = 0; } #if TCFG_SYS_LVD_EN if (hid_battery_notify_timer_id) { sys_timer_del(hid_battery_notify_timer_id); hid_battery_notify_timer_id = 0; } #endif // TCFG_SYS_LVD_EN log_info("%s\n", __FUNCTION__); ble_module_enable(0); ble_comm_exit(); } /*************************************************************************************************/ /*! * \brief 模块开关使能 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void ble_module_enable(u8 en) { log_info("mode_en:%d\n", en); ble_comm_module_enable(en); } /*************************************************************************************************/ /*! * \brief 注册控制是否进入sleep * * \param [in] * * \return * * \note */ /*************************************************************************************************/ static u8 hogp_idle_query(void) { return !is_hogp_active; } REGISTER_LP_TARGET(le_hogp_target) = { .name = "ble_hogp", .is_idle = hogp_idle_query, }; /*************************************************************************************************/ /*! * \brief 设置设备的图标 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void le_hogp_set_icon(u16 class_type) { memcpy(Appearance, &class_type, 2); } /*************************************************************************************************/ /*! * \brief 设置hid描述符 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void le_hogp_set_ReportMap(u8 *map, u16 size) { report_map = map; report_map_size = size; hid_report_change = 1; } /*************************************************************************************************/ /*! * \brief set callback * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void le_hogp_set_output_callback(void *cb) { le_hogp_output_callback = cb; } /*************************************************************************************************/ /*! * \brief 配对表绑定配置 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void le_hogp_set_pair_config(u8 pair_max, u8 is_allow_cover) { ble_list_config_reset(pair_max, is_allow_cover); //开1对1配对绑定 } /*************************************************************************************************/ /*! * \brief 开可配对绑定允许 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void le_hogp_set_pair_allow(void) { hogp_pair_info.pair_flag = 0; __hogp_conn_pair_vm_do(&hogp_pair_info, 1); ble_list_clear_all(); } /*************************************************************************************************/ /*! * \brief 获取电量 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void le_hogp_regiest_get_battery(u8(*get_battery_cbk)(void)) { get_vbat_percent_call = get_battery_cbk; } /*************************************************************************************************/ /*! * \brief 配置回连广播使用的参数 * * \param type [in] ADV_DIRECT_IND, ADV_DIRECT_IND_LOW,ADV_IND * * ADV_DIRECT_IND (密集定向广播:1.28s超时,interval 固定2ms) * ADV_DIRECT_IND_LOW (定向广播:interval 和 channel 跟普通广播设置一样) * ADV_IND (无定向广播:interval 和 channel 跟普通广播设置一样) * \param adv_timeout [in] * \return * * \note */ /*************************************************************************************************/ void le_hogp_set_reconnect_adv_cfg(u8 adv_type, u32 adv_timeout) { pair_reconnect_adv_type = adv_type; pair_reconnect_adv_timeout = adv_timeout; } /*************************************************************************************************/ /*! * \brief 广播通道配置 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void le_hogp_set_adv_channel(int channel) { le_adv_channel_sel = channel; } /*************************************************************************************************/ /*! * \brief set PNP_PID * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void le_hogp_set_PNP_info(const u8 *info) { memcpy(PnP_ID, info, sizeof(PnP_ID)); } /*************************************************************************************************/ /*! * \brief is connect * * \param [in] * * \return * * \note */ /*************************************************************************************************/ int ble_hid_is_connected(void) { return hogp_con_handle; } /*************************************************************************************************/ /*! * \brief disconnect * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void le_hogp_disconnect(void) { if (hogp_con_handle) { ble_comm_disconnect(hogp_con_handle); } } /*************************************************************************************************/ /*! * \brief 获取当前连接对方的地址信息 * * \param [in] * * \return addr_type + address * * \note */ /*************************************************************************************************/ u8 *ble_cur_connect_addrinfo(void) { return cur_peer_addr_info; } /*************************************************************************************************/ /*! * \brief 设置绑定地址 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void ble_set_pair_addrinfo(u8 *addr_info) { log_info("ble_set_pair_addrinfo\n"); if (addr_info) { put_buf(addr_info, 7); memcpy(hogp_pair_info.peer_address_info, addr_info, 7); hogp_pair_info.head_tag = BLE_VM_HEAD_TAG; hogp_pair_info.tail_tag = BLE_VM_TAIL_TAG; hogp_pair_info.pair_flag = 1; hogp_pair_info.direct_adv_flag = 1; hogp_pair_info.direct_adv_cnt = REPEAT_DIRECT_ADV_COUNT; __hogp_conn_pair_vm_do(&hogp_pair_info, 1); } else { memset(&hogp_pair_info, 0, sizeof(struct pair_info_t)); } } //profile 支持的report id static const u16 report_id_handle_table[] = { 0, HID_REPORT_ID_01_SEND_HANDLE, HID_REPORT_ID_02_SEND_HANDLE, HID_REPORT_ID_03_SEND_HANDLE, HID_REPORT_ID_04_SEND_HANDLE, HID_REPORT_ID_05_SEND_HANDLE, HID_REPORT_ID_06_SEND_HANDLE, }; /*************************************************************************************************/ /*! * \brief hid 数据发送 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ int ble_hid_data_send(u8 report_id, u8 *data, u16 len) { if (report_id == 0 || report_id > 6) { log_info("report_id %d,err!!!\n", report_id); return -1; } putchar('@'); return ble_comm_att_send_data(hogp_con_handle, report_id_handle_table[report_id], data, len, ATT_OP_AUTO_READ_CCC); } /*************************************************************************************************/ /*! * \brief hid 数据发送 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void ble_hid_key_deal_test(u16 key_msg) { if (key_msg) { ble_hid_data_send(1, &key_msg, 2); key_msg = 0;//key release ble_hid_data_send(1, &key_msg, 2); } } /*************************************************************************************************/ /*! * \brief * * \param [in] * * \return * * \note */ /*************************************************************************************************/ int ble_hid_transfer_channel_send(u8 *packet, u16 size) { /* log_info("transfer_tx(%d):", size); */ /* log_info_hexdump(packet, size); */ return ble_comm_att_send_data(hogp_con_handle, ATT_CHARACTERISTIC_ae42_01_VALUE_HANDLE, packet, size, ATT_OP_AUTO_READ_CCC); } /*************************************************************************************************/ /*! * \brief * * \param [in] * * \return * * \note */ /*************************************************************************************************/ int ble_hid_transfer_channel_send1(u8 *packet, u16 size) { /* log_info("transfer_tx(%d):", size); */ /* log_info_hexdump(packet, size); */ return ble_comm_att_send_data(hogp_con_handle, ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE, packet, size, ATT_OP_AUTO_READ_CCC); } /*************************************************************************************************/ /*! * \brief * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void __attribute__((weak)) ble_hid_transfer_channel_recieve(u8 *packet, u16 size) { log_info("transfer_rx(%d):", size); log_info_hexdump(packet, size); //ble_hid_transfer_channel_send(packet,size);//for test } /*************************************************************************************************/ /*! * \brief * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void __attribute__((weak)) ble_hid_transfer_channel_recieve1(u8 *packet, u16 size) { log_info("transfer_rx1(%d):", size); log_info_hexdump(packet, size); } /*************************************************************************************************/ /*! * \brief 控制配对模式 * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void ble_set_pair_list_control(u8 mode) { bool ret = 0; u8 connect_address[6]; switch (mode) { case 0: //close pair,关配对 ret = ble_list_pair_accept(0); break; case 1: //open pair,开配对 ret = ble_list_pair_accept(1); break; case 2: //绑定已配对设备,不再接受新的配对 swapX(&cur_peer_addr_info[1], connect_address, 6); //bond current's device ret = ble_list_bonding_remote(connect_address, cur_peer_addr_info[0]); //close pair ble_list_pair_accept(0); break; default: break; } log_info("%s: %02x,ret=%02x\n", __FUNCTION__, mode, ret); } /*************************************************************************************************/ /*! * \brief testbox,key test * * \param [in] * * \return * * \note */ /*************************************************************************************************/ void ble_server_send_test_key_num(u8 key_num) { if (hogp_con_handle) { if (get_remote_test_flag()) { ble_op_test_key_num(hogp_con_handle, key_num); } else { log_info("-not conn testbox\n"); } } } void call_hogp_adv_config_set() { return hogp_adv_config_set(); } #endif