doubao_chat/apps/common/ble/le_hogp.c

1455 lines
46 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*********************************************************************************************
* Filename : le_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 "asm/power_interface.h"
#include "app_config.h"
#include "event/bt_event.h"
#include "syscfg/syscfg_id.h"
#include "btstack/btstack_task.h"
#include "btstack/le/ble_api.h"
#include "btstack/bluetooth.h"
#include "btstack/le/le_user.h"
#include "btcontroller_modules.h"
#include "bt_common.h"
#include "ble_user.h"
#include "le_common.h"
#include "le_hogp.h"
#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_HOGP)
#include "standard_hid.h"
/* #if RCSP_BTMATE_EN */
/* #include "btstack/JL_rcsp_api.h" */
/* #include "rcsp_bluetooth.h" */
/* #endif */
#if 1
extern void printf_buf(u8 *buf, u32 len);
#define log_info printf
#define log_info_hexdump printf_buf
#else
#define log_info(...)
#define log_info_hexdump(...)
#endif
#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};
/* #define LOG_TAG_CONST BT_BLE */
/* #define LOG_TAG "[LE_S_DEMO]" */
/* #define LOG_ERROR_ENABLE */
/* #define LOG_DEBUG_ENABLE */
/* #define LOG_INFO_ENABLE */
/* #define LOG_DUMP_ENABLE */
/* #define LOG_CLI_ENABLE */
/* #include "debug.h" */
//------
//ATT发送的包长, note: 20 <=need >= MTU
#define ATT_LOCAL_MTU_SIZE (64)
//ATT缓存的buffer大小, note: need >= 20,可修改
#define ATT_SEND_CBUF_SIZE (256)
//共配置的RAM
#define ATT_RAM_BUFSIZE (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE) //note:
static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
//---------------
int ble_hid_timer_handle = 0;
//---------------
// 广播周期 (unit:0.625ms)
#define ADV_INTERVAL_MIN (160 * 1)//
static volatile hci_con_handle_t con_handle;
static u16 cur_conn_latency;
//加密设置
/* static const uint8_t sm_min_key_size = 7; */
//连接参数更新请求设置
//是否使能参数请求更新,0--disable, 1--enable
static uint8_t connection_update_enable = 1;
static uint8_t connection_update_cnt = 0; //当前请求的参数表index
static uint8_t connection_update_waiting = 0; //请求已被接收,等待主机更新参数
//参数表
static const struct conn_update_param_t Peripheral_Preferred_Connection_Parameters[] = {
{6, 9, 100, 600}, //android
{12, 12, 30, 400}, //ios
};
//共可用的参数组数
#define CONN_PARAM_TABLE_CNT (sizeof(Peripheral_Preferred_Connection_Parameters)/sizeof(struct conn_update_param_t))
#if (ATT_RAM_BUFSIZE < 64)
#error "adv_data & rsp_data buffer error!!!!!!!!!!!!"
#endif
/* #define adv_data &att_ram_buffer[0] */
/* #define scan_rsp_data &att_ram_buffer[32] */
static u8 adv_data_len;
static u8 adv_data[ADV_RSP_PACKET_MAX];//max is 31
static u8 scan_rsp_data_len;
static u8 scan_rsp_data[ADV_RSP_PACKET_MAX];//max is 31
static char gap_device_name[BT_NAME_LEN_MAX] = "jl_ble_test";
static u8 gap_device_name_len = 0; //名字长度,不包含结束符
static u8 ble_work_state = 0; //ble 状态变化
static u8 first_pair_flag = 0; //第一次配对标记
static u8 adv_ctrl_en; //广播控制
static u16 adv_interval_val; //广播周期 (unit:0.625ms)
//--------------------------------------------
//配置有配对绑定时,先定向广播快连,再普通广播;否则只作普通广播
#define PAIR_DIREDT_ADV_EN 1
#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_flag: 1; //是否需要定向广播
u8 direct_adv_cnt: 5; //定向广播次数
u8 peer_address_info[7]; //绑定的对方地址信息
u16 tail_tag;//尾标识
};
//配对信息表
static struct pair_info_t conn_pair_info;
static u8 cur_peer_addr_info[7];//当前连接对方地址信息
#define REPEAT_DIRECT_ADV_COUNT (2)// *1.28s
#define REPEAT_DIRECT_ADV_TIMER (100)//
//为了及时响应手机数据包,某些流程会忽略进入latency的控制
//如下是定义忽略进入的interval个数
#define LATENCY_SKIP_INTERVAL_MIN (3)
#define LATENCY_SKIP_INTERVAL_KEEP (15)
#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 const 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 *report_map; //描述符
static u16 report_map_size;//描述符大小
#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 void (*app_recieve_callback)(void *priv, void *buf, u16 len) = NULL;
static void (*app_ble_state_callback)(void *priv, ble_state_e state) = NULL;
static void (*ble_resume_send_wakeup)(void) = NULL;
static void (*le_hogp_output_callback)(u8 *buffer, u16 size) = NULL;
static u32 channel_priv;//保留未用
static void resume_all_ccc_enable(u8 update_request);
extern void ble_module_enable(u8 en);
extern void auto_shutdown_disable(void);
extern bool get_remote_test_flag();
void ble_hid_transfer_channel_recieve(u8 *packet, u16 size);
static int app_send_user_data_do(void *priv, u8 *data, u16 len);
//------------------------------------------------------
int bt_is_connect(void)
{
return (ble_work_state == BLE_ST_NOTIFY_IDICATE ? 1 : 0);
}
int bt_tx_data(void *priv, u8 *data, u16 len)
{
return app_send_user_data_do(priv, data, len);
}
static void ble_bt_evnet_post(u8 arg_type, u8 priv_event, u8 *args, u32 value)
{
struct bt_event e = {0};
if (args) {
memcpy(e.args, args, 7);
}
e.event = priv_event;
e.value = value;
bt_event_notify(arg_type, &e);
}
static void ble_state_to_user(u8 state, u8 reason)
{
ble_bt_evnet_post(BT_EVENT_FROM_BLE, state, NULL, reason);
}
//@function 检测连接参数是否需要更新
static void check_connetion_updata_deal(void)
{
static struct conn_update_param_t param;
if (connection_update_enable) {
if (connection_update_cnt < CONN_PARAM_TABLE_CNT) {
memcpy(&param, &Peripheral_Preferred_Connection_Parameters[connection_update_cnt], sizeof(struct conn_update_param_t)); //static ram
log_info("update_request:-%d-%d-%d-%d-\n", param.interval_min, param.interval_max, param.latency, param.timeout);
if (con_handle) {
ble_op_conn_param_request(con_handle, (u32)&param);
}
}
}
}
//@function 接参数更新信息
static void connection_update_complete_success(u8 *packet, u8 connected_init)
{
int conn_interval, conn_latency, conn_timeout;
conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet);
conn_latency = hci_subevent_le_connection_update_complete_get_conn_latency(packet);
conn_timeout = hci_subevent_le_connection_update_complete_get_supervision_timeout(packet);
log_info("conn_interval = %d\n", conn_interval);
log_info("conn_latency = %d\n", conn_latency);
log_info("conn_timeout = %d\n", conn_timeout);
if (connected_init) {
if (conn_pair_info.pair_flag
&& (conn_latency && (0 == memcmp(conn_pair_info.peer_address_info, packet - 1, 7)))) { //
//有配对信息,带latency连接,快速enable ccc 发数
log_info("reconnect ok\n");
resume_all_ccc_enable(0);
}
} else {
//not creat connection,judge
if ((conn_interval == 12) && (conn_latency == 4)) {
log_info("do update_again\n");
connection_update_cnt = 1;
check_connetion_updata_deal();
} else if ((conn_latency == 0)
&& (connection_update_cnt == CONN_PARAM_TABLE_CNT)
&& (Peripheral_Preferred_Connection_Parameters[0].latency != 0)) {
log_info("latency is 0,update_again\n");
connection_update_cnt = 0;
check_connetion_updata_deal();
}
}
cur_conn_latency = conn_latency;
if (ble_hid_timer_handle) {
sys_s_hi_timer_modify(ble_hid_timer_handle, (u32)(conn_interval * 1.25));
}
}
static void set_ble_work_state(ble_state_e state, u8 reason)
{
if (state != ble_work_state) {
log_info("ble_work_st:%x->%x\n", ble_work_state, state);
ble_work_state = state;
if (app_ble_state_callback) {
app_ble_state_callback((void *)channel_priv, state);
}
ble_state_to_user(state, reason);
}
}
static ble_state_e get_ble_work_state(void)
{
return ble_work_state;
}
static void conn_pair_vm_do(struct pair_info_t *info, u8 rw_flag)
{
#if PAIR_DIREDT_ADV_EN
int ret;
int vm_len = sizeof(struct pair_info_t);
log_info("-conn_pair_info vm_do:%d\n", rw_flag);
if (rw_flag == 0) {
ret = syscfg_read(CFG_BLE_MODE_INFO, (u8 *)info, vm_len);
if (!ret) {
log_info("-null--\n");
}
if ((BLE_VM_HEAD_TAG == info->head_tag) && (BLE_VM_TAIL_TAG == info->tail_tag)) {
log_info("-exist--\n");
log_info_hexdump((u8 *)info, vm_len);
info->direct_adv_flag = 1;
} else {
memset(info, 0, vm_len);
info->head_tag = BLE_VM_HEAD_TAG;
info->tail_tag = BLE_VM_TAIL_TAG;
}
} else {
info->direct_adv_flag = 1;
syscfg_write(CFG_BLE_MODE_INFO, (u8 *)info, vm_len);
}
#endif
}
//检测是否需要定向广播
static void ble_check_need_pair_adv(void)
{
#if PAIR_DIREDT_ADV_EN
log_info("%s\n", __FUNCTION__);
if (conn_pair_info.pair_flag && conn_pair_info.direct_adv_flag) {
conn_pair_info.direct_adv_cnt = REPEAT_DIRECT_ADV_COUNT;
}
#endif
}
//协议栈sm 消息回调处理
static void cbk_sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
sm_just_event_t *event = (void *)packet;
u32 tmp32;
switch (packet_type) {
case HCI_EVENT_PACKET:
switch (hci_event_packet_get_type(packet)) {
case SM_EVENT_JUST_WORKS_REQUEST:
sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
log_info("Just Works Confirmed.\n");
first_pair_flag = 1;
memcpy(conn_pair_info.peer_address_info, &packet[4], 7);
conn_pair_info.pair_flag = 0;
ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_KEEP); //
ble_state_to_user(BLE_PRIV_MSG_PAIR_CONFIRM, 0);
break;
case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
log_info_hexdump(packet, size);
memcpy(&tmp32, event->data, 4);
log_info("Passkey display: %06u.\n", tmp32);
ble_state_to_user(BLE_PRIV_MSG_PAIR_CONFIRM, 1);
break;
}
break;
}
}
static void check_report_map_change(void)
{
#if 0 //部分手机不支持
static const u16 change_handle_table[2] = {ATT_CHARACTERISTIC_2a4b_01_VALUE_HANDLE, ATT_CHARACTERISTIC_2a4b_01_VALUE_HANDLE};
if (hid_report_change && first_pair_flag && att_get_ccc_config(ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE)) {
log_info("###send services changed\n");
app_send_user_data(ATT_CHARACTERISTIC_2a05_01_VALUE_HANDLE, change_handle_table, 4, ATT_OP_INDICATE);
hid_report_change = 0;
}
#endif
}
//回连状态,主动使能通知
static void resume_all_ccc_enable(u8 update_request)
{
log_info("resume_all_ccc_enable\n");
att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_01_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_02_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_04_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_05_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_06_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
att_set_ccc_config(ATT_CHARACTERISTIC_2a4d_07_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
att_set_ccc_config(ATT_CHARACTERISTIC_ae42_01_CLIENT_CONFIGURATION_HANDLE, ATT_OP_NOTIFY);
set_ble_work_state(BLE_ST_NOTIFY_IDICATE, 0);
if (update_request) {
check_connetion_updata_deal();
ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_MIN); //
}
}
//协议栈回调唤醒数据发送
static void can_send_now_wakeup(void)
{
/* putchar('E'); */
if (ble_resume_send_wakeup) {
ble_resume_send_wakeup();
}
}
//参考识别手机系统
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
}
/*
* @section Packet Handler
*
* @text The packet handler is used to:
* - stop the counter after a disconnect
* - send a notification when the requested ATT_EVENT_CAN_SEND_NOW is received
*/
/* LISTING_START(packetHandler): Packet Handler */
//协议栈事件消息处理
static void cbk_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
int mtu;
u32 tmp;
switch (packet_type) {
case HCI_EVENT_PACKET:
switch (hci_event_packet_get_type(packet)) {
/* case DAEMON_EVENT_HCI_PACKET_SENT: */
/* break; */
case ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE:
log_info("ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE\n");
case ATT_EVENT_CAN_SEND_NOW:
can_send_now_wakeup();
break;
case HCI_EVENT_LE_META:
switch (hci_event_le_meta_get_subevent_code(packet)) {
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: {
switch (packet[3]) {
case BT_OP_SUCCESS:
//init
first_pair_flag = 0;
connection_update_cnt = 0;
connection_update_waiting = 0;
cur_conn_latency = 0;
connection_update_enable = 1;
con_handle = little_endian_read_16(packet, 4);
log_info("HCI_SUBEVENT_LE_CONNECTION_COMPLETE: %0x\n", con_handle);
ble_op_att_send_init(con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_MTU_SIZE);
log_info_hexdump(packet + 7, 7);
memcpy(cur_peer_addr_info, packet + 7, 7);
ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_KEEP); //
set_ble_work_state(BLE_ST_CONNECT, 0);
connection_update_complete_success(packet + 8, 1);
//清除PC端历史键值
/* extern void clear_mouse_packet_data(void); */
/* sys_timeout_add(NULL, clear_mouse_packet_data, 50); */
#if RCSP_BTMATE_EN
#if (0 == BT_CONNECTION_VERIFY)
JL_rcsp_auth_reset();
#endif
/* rcsp_dev_select(RCSP_BLE); */
rcsp_init();
#endif
/* att_server_set_exchange_mtu(con_handle); //主动请求交换MTU */
/* ble_vendor_interval_event_enable(con_handle, 1); //enable interval事件-->HCI_SUBEVENT_LE_VENDOR_INTERVAL_COMPLETE */
break;
case BT_ERR_ADVERTISING_TIMEOUT:
//定向广播超时结束
log_info("BT_ERR_ADVERTISING_TIMEOUT\n");
set_ble_work_state(BLE_ST_IDLE, 0);
bt_ble_adv_enable(1);
break;
default:
break;
}
}
break;
case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
connection_update_waiting = 0;
connection_update_complete_success(packet, 0);
break;
case HCI_SUBEVENT_LE_VENDOR_INTERVAL_COMPLETE:
log_info("INTERVAL_EVENT:%04x,%04x\n", little_endian_read_16(packet, 4), little_endian_read_16(packet, 6));
/* put_buf(packet, size + 1); */
break;
}
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
log_info("HCI_EVENT_DISCONNECTION_COMPLETE: %0x\n", packet[5]);
#if RCSP_BTMATE_EN
rcsp_exit();
#endif
con_handle = 0;
ble_op_att_send_init(con_handle, 0, 0, 0);
/* bt_ble_adv_enable(1); */
set_ble_work_state(BLE_ST_DISCONN, packet[5]);
#if 0
if (UPDATE_MODULE_IS_SUPPORT(UPDATE_BLE_TEST_EN)) {
if (!ble_update_get_ready_jump_flag()) {
if (packet[5] == 0x08) {
//超时断开,检测是否配对广播
ble_check_need_pair_adv();
}
bt_ble_adv_enable(1);
} else {
log_info("no open adv\n");
}
}
#else
if (packet[5] == 0x08) {
//超时断开,检测是否配对广播
ble_check_need_pair_adv();
}
bt_ble_adv_enable(1);
#endif
break;
case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
log_info("ATT MTU = %u\n", mtu);
ble_op_att_set_send_mtu(mtu);
break;
case HCI_EVENT_VENDOR_REMOTE_TEST:
log_info("--- HCI_EVENT_VENDOR_REMOTE_TEST\n");
break;
case L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE:
tmp = little_endian_read_16(packet, 4);
log_info("-update_rsp: %02x\n", tmp);
if (tmp) {
connection_update_cnt++;
log_info("remoter reject!!!\n");
check_connetion_updata_deal();
} else {
connection_update_waiting = 1;
connection_update_cnt = CONN_PARAM_TABLE_CNT;
}
break;
case HCI_EVENT_ENCRYPTION_CHANGE:
log_info("HCI_EVENT_ENCRYPTION_CHANGE= %d\n", packet[2]);
if (!packet[2]) {
if (first_pair_flag) {
//只在配对时启动检查
att_server_set_check_remote(con_handle, att_check_remote_result);
#if PAIR_DIREDT_ADV_EN
conn_pair_info.pair_flag = 1;
conn_pair_vm_do(&conn_pair_info, 1);
#endif
} else {
if ((!conn_pair_info.pair_flag) || memcmp(cur_peer_addr_info, conn_pair_info.peer_address_info, 7)) {
log_info("record reconnect peer\n");
put_buf(cur_peer_addr_info, 7);
put_buf(conn_pair_info.peer_address_info, 7);
memcpy(conn_pair_info.peer_address_info, cur_peer_addr_info, 7);
conn_pair_info.pair_flag = 1;
conn_pair_vm_do(&conn_pair_info, 1);
}
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(con_handle, remote_type);
}
check_report_map_change();
ble_state_to_user(BLE_PRIV_PAIR_ENCRYPTION_CHANGE, first_pair_flag);
}
break;
}
break;
}
}
/* LISTING_END */
/*
* @section ATT Read
*
* @text The ATT Server handles all reads to constant data. For dynamic data like the custom characteristic, the registered
* att_read_callback is called. To handle long characteristics and long reads, the att_read_callback is first called
* with buffer == NULL, to request the total value length. Then it will be called again requesting a chunk of the value.
* See Listing attRead.
*/
/* LISTING_START(attRead): ATT Read */
// 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 offset defines start of attribute value
//主机操作ATT read,协议栈回调处理
static uint16_t 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\n", handle, (u32)buffer);
switch (handle) {
case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
att_value_len = gap_device_name_len;
if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
break;
}
if (buffer) {
memcpy(buffer, &gap_device_name[offset], buffer_size);
att_value_len = buffer_size;
log_info("\n------read gap_name: %s \n", gap_device_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) {
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_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] = att_get_ccc_config(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;
}
/* LISTING_END */
/*
* @section ATT Write
*
* @text The only valid ATT write in this example is to the Client Characteristic Configuration, which configures notification
* and indication. If the ATT handle matches the client configuration handle, the new configuration value is stored and used
* in the heartbeat handler to decide if a new value should be sent. See Listing attWrite.
*/
/* LISTING_START(attWrite): ATT Write */
//主机操作ATT write,协议栈回调处理
static int 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:
att_set_ccc_config(handle, buffer[0]);
if (buffer[0]) {
check_report_map_change();
}
break;
#if RCSP_BTMATE_EN
case ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE:
#if (0 == BT_CONNECTION_VERIFY)
JL_rcsp_auth_reset(); //hid设备试能nofity的时候reset auth保证APP可以重新连接
#endif
#if (TCFG_HID_AUTO_SHUTDOWN_TIME)
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:
set_ble_work_state(BLE_ST_NOTIFY_IDICATE, 0);
ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_MIN); //
case ATT_CHARACTERISTIC_2a19_01_CLIENT_CONFIGURATION_HANDLE:
if ((cur_conn_latency == 0)
&& (connection_update_waiting == 0)
&& (connection_update_cnt == CONN_PARAM_TABLE_CNT)
&& (Peripheral_Preferred_Connection_Parameters[0].latency != 0)) {
connection_update_cnt = 0;//update again
}
check_connetion_updata_deal();
log_info("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
att_set_ccc_config(handle, buffer[0]);
break;
#if RCSP_BTMATE_EN
case ATT_CHARACTERISTIC_ae01_01_VALUE_HANDLE:
log_info("rcsp_read:%x 0x%x\n", buffer_size, app_recieve_callback);
connection_update_enable = 0;
ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_LONG); //
if (app_recieve_callback) {
app_recieve_callback(0, buffer, buffer_size);
}
break;
#endif
case ATT_CHARACTERISTIC_ae41_01_VALUE_HANDLE:
ble_hid_transfer_channel_recieve(buffer, buffer_size);
break;
default:
break;
}
return 0;
}
//att handle操作,notify or indicate
static int app_send_user_data(u16 handle, u8 *data, u16 len, att_op_type_e handle_type)
{
u32 ret = APP_BLE_NO_ERROR;
if (!con_handle) {
return APP_BLE_OPERATION_ERROR;
}
putchar('@');
/* put_buf(data, len); */
ret = ble_op_att_send_data(handle, data, len, handle_type);
if (ret == BLE_BUFFER_FULL) {
ret = APP_BLE_BUFF_FULL;
}
if (ret) {
log_info("app_send_fail:%d !!!\n", ret);
}
return ret;
}
//------------------------------------------------------
static u8 adv_name_ok = 0; //名字优先放入adv包
static int make_set_adv_data(void)
{
u8 offset = 0;
u8 *buf = adv_data;
offset += make_eir_packet_val(&buf[offset], offset, HCI_EIR_DATATYPE_FLAGS, 0x06, 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);
//check set name is ok?
u8 name_len = gap_device_name_len;
u8 vaild_len = ADV_RSP_PACKET_MAX - (offset + 2);
if (name_len <= vaild_len) {
adv_name_ok = 1;
offset += make_eir_packet_data(&buf[offset], offset, HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME, (void *)gap_device_name, name_len);
log_info("name in adv_data\n");
} else {
adv_name_ok = 0;
}
if (offset > ADV_RSP_PACKET_MAX) {
puts("***adv_data overflow!!!!!!\n");
return -1;
}
log_info("adv_data(%d):", offset);
log_info_hexdump(buf, offset);
adv_data_len = offset;
ble_op_set_adv_data(offset, buf);
return 0;
}
static int make_set_rsp_data(void)
{
u8 offset = 0;
u8 *buf = 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_name_ok) {
u8 name_len = gap_device_name_len;
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_device_name, name_len);
log_info("name in rsp_data\n");
}
if (offset > ADV_RSP_PACKET_MAX) {
puts("***rsp_data overflow!!!!!!\n");
return -1;
}
log_info("rsp_data(%d):", offset);
log_info_hexdump(buf, offset);
scan_rsp_data_len = offset;
ble_op_set_rsp_data(offset, buf);
return 0;
}
//广播参数设置
static void advertisements_setup_init()
{
uint8_t adv_type = ADV_IND;
uint8_t adv_channel = ADV_CHANNEL_ALL;
int ret = 0;
ret |= make_set_adv_data();
ret |= make_set_rsp_data();
if (ret) {
puts("adv_setup_init fail !!!!!!\n");
ASSERT(0);
}
if (conn_pair_info.pair_flag && conn_pair_info.direct_adv_flag && conn_pair_info.direct_adv_cnt) {
log_info(">>>direct_adv......\n");
adv_type = ADV_DIRECT_IND;
conn_pair_info.direct_adv_cnt--;
ble_op_set_adv_param_ext(adv_interval_val, adv_type, adv_channel, conn_pair_info.peer_address_info);
} else {
ble_op_set_adv_param(adv_interval_val, adv_type, adv_channel);
}
}
#define PASSKEY_ENTER_ENABLE 0 //输入passkey使能,可修改passkey
//重设passkey回调函数,在这里可以重新设置passkey
//passkey为6个数字组成,十万位、万位。。。。个位 各表示一个数字 高位不够为0
static void reset_passkey_cb(u32 *key)
{
#if 1
u32 newkey = rand32();//获取随机数
newkey &= 0xfffff;
if (newkey > 999999) {
newkey = newkey - 999999; //不能大于999999
}
*key = newkey; //小于或等于六位数
log_info("set new_key= %06u\n", *key);
#else
*key = 123456; //for debug
#endif
}
void ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en)
{
//setup SM: Display only
sm_init();
sm_set_io_capabilities(io_type);
sm_set_authentication_requirements(auth_req);
sm_set_encryption_key_size_range(min_key_size, 16);
sm_set_request_security(security_en);
sm_event_callback_set(&cbk_sm_packet_handler);
if (io_type == IO_CAPABILITY_DISPLAY_ONLY) {
reset_PK_cb_register(reset_passkey_cb);
}
}
static int set_adv_enable(void *priv, u32 en)
{
ble_state_e next_state, cur_state;
if (!adv_ctrl_en && en) {
return APP_BLE_OPERATION_ERROR;
}
if (con_handle) {
return APP_BLE_OPERATION_ERROR;
}
if (en) {
next_state = BLE_ST_ADV;
} else {
next_state = BLE_ST_IDLE;
}
cur_state = get_ble_work_state();
switch (cur_state) {
case BLE_ST_ADV:
case BLE_ST_IDLE:
case BLE_ST_INIT_OK:
case BLE_ST_NULL:
case BLE_ST_DISCONN:
break;
default:
return APP_BLE_OPERATION_ERROR;
break;
}
if (cur_state == next_state) {
return APP_BLE_NO_ERROR;
}
log_info("adv_en:%d\n", en);
set_ble_work_state(next_state, 0);
if (en) {
advertisements_setup_init();//need to do before adv_en
}
ble_op_adv_enable(en);
return APP_BLE_NO_ERROR;
}
void ble_profile_init(void)
{
log_info("ble profile init\n");
le_device_db_init();
#if PASSKEY_ENTER_ENABLE
ble_sm_setup_init(IO_CAPABILITY_DISPLAY_ONLY, SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION, 7, TCFG_BLE_SECURITY_EN);
#else
ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION, 7, TCFG_BLE_SECURITY_EN);
#endif
/* setup ATT server */
att_server_init(profile_data, att_read_callback, att_write_callback);
att_server_register_packet_handler(cbk_packet_handler);
/* gatt_client_register_packet_handler(packet_cbk); */
// register for HCI events
hci_event_callback_set(&cbk_packet_handler);
/* ble_l2cap_register_packet_handler(packet_cbk); */
/* sm_event_packet_handler_register(packet_cbk); */
le_l2cap_register_packet_handler(&cbk_packet_handler);
/* att_server_flow_enable(1); */
ble_vendor_set_default_att_mtu(ATT_LOCAL_MTU_SIZE);
}
static int ble_disconnect(void *priv)
{
if (con_handle) {
if (BLE_ST_SEND_DISCONN != get_ble_work_state()) {
log_info(">>>ble send disconnect\n");
set_ble_work_state(BLE_ST_SEND_DISCONN, 0);
ble_op_disconnect(con_handle);
} else {
log_info(">>>ble wait disconnect...\n");
}
return APP_BLE_NO_ERROR;
} else {
return APP_BLE_OPERATION_ERROR;
}
}
static int get_buffer_remain_len(void *priv)
{
u32 vaild_len = 0;
ble_op_att_get_remain(&vaild_len);
return vaild_len;
}
static int app_send_user_data_do(void *priv, u8 *data, u16 len)
{
return app_send_user_data(HID_REPORT_ID_01_SEND_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
}
#if RCSP_BTMATE_EN
static int rcsp_send_user_data_do(void *priv, u8 *data, u16 len)
{
log_info("rcsp_tx:%x\n", len);
return app_send_user_data(ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, data, len, ATT_OP_AUTO_READ_CCC);
}
#endif
static int app_send_user_data_check(u16 len)
{
u32 buf_space = get_buffer_remain_len(0);
if (len <= buf_space) {
return 1;
}
return 0;
}
static int regiest_wakeup_send(void *priv, void *cbk)
{
ble_resume_send_wakeup = cbk;
return APP_BLE_NO_ERROR;
}
static int regiest_recieve_cbk(void *priv, void *cbk)
{
channel_priv = (u32)priv;
app_recieve_callback = cbk;
return APP_BLE_NO_ERROR;
}
static int regiest_state_cbk(void *priv, void *cbk)
{
channel_priv = (u32)priv;
app_ble_state_callback = cbk;
return APP_BLE_NO_ERROR;
}
void modify_ble_name(const char *name)
{
if (strlen(name) <= BT_NAME_LEN_MAX) {
memset(gap_device_name, 0x0, BT_NAME_LEN_MAX);
memcpy(gap_device_name, name, strlen(name));
gap_device_name_len = strlen(gap_device_name);
log_info(">>>modify_ble_name:%s\n", gap_device_name);
}
}
static const char ble_ext_name[] = "(BLE)";
void bt_ble_init(void)
{
log_info("***** ble_init******\n");
adv_ctrl_en = 0;
con_handle = 0;
adv_interval_val = ADV_INTERVAL_MIN;
#if 1
#define LOCAL_NAME_LEN 32
char name_p[LOCAL_NAME_LEN] = "JL_HID";
u8 ext_name_len = sizeof(ble_ext_name) - 1;
int ret = syscfg_read(CFG_BT_NAME, name_p, 32);
if (ret < 0) {
log_info("read bt name err\n");
} else {
}
gap_device_name_len = strlen(name_p);
if (gap_device_name_len > (BT_NAME_LEN_MAX - ext_name_len)) {
gap_device_name_len = BT_NAME_LEN_MAX - ext_name_len;
}
//增加后缀,区分名字
memcpy(gap_device_name, name_p, gap_device_name_len);
memcpy(&gap_device_name[gap_device_name_len], ble_ext_name, ext_name_len);
gap_device_name_len += ext_name_len;
#else
const char name_p[] = "std_mouse";
u8 ext_name_len = sizeof(ble_ext_name);
gap_device_name_len = sizeof(name_p) - 1;
memcpy(gap_device_name, name_p, gap_device_name_len);
memcpy(&gap_device_name[gap_device_name_len], ble_ext_name, ext_name_len);
gap_device_name_len += ext_name_len;
#endif
log_info("ble name(%d): %s \n", gap_device_name_len, gap_device_name);
memset(&conn_pair_info, 0, sizeof(struct pair_info_t));
conn_pair_vm_do(&conn_pair_info, 0);
adv_interval_val = ADV_INTERVAL_MIN;
set_ble_work_state(BLE_ST_INIT_OK, 0);
ble_module_enable(1);
}
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;
}
ble_module_enable(0);
}
void bt_ble_adv_enable(u8 enable)
{
set_adv_enable(0, enable);
}
u8 *ble_get_scan_rsp_ptr(u16 *len)
{
if (len) {
*len = scan_rsp_data_len;
}
return scan_rsp_data;
}
u8 *ble_get_adv_data_ptr(u16 *len)
{
if (len) {
*len = adv_data_len;
}
return adv_data;
}
u8 *ble_get_gatt_profile_data(u16 *len)
{
*len = sizeof(profile_data);
return (u8 *)profile_data;
}
void ble_app_disconnect(void)
{
ble_disconnect(NULL);
}
void ble_module_enable(u8 en)
{
log_info("mode_en:%d\n", en);
if (en) {
adv_ctrl_en = 1;
ble_check_need_pair_adv();
bt_ble_adv_enable(1);
} else {
if (con_handle) {
adv_ctrl_en = 0;
ble_op_latency_skip(con_handle, LATENCY_SKIP_INTERVAL_KEEP); //
ble_app_disconnect();
} else {
bt_ble_adv_enable(0);
adv_ctrl_en = 0;
}
}
}
#if RCSP_BTMATE_EN
static const struct ble_server_operation_t mi_ble_operation = {
.adv_enable = set_adv_enable,
.disconnect = ble_disconnect,
.get_buffer_vaild = get_buffer_remain_len,
.send_data = (void *)rcsp_send_user_data_do,
.regist_wakeup_send = regiest_wakeup_send,
.regist_recieve_cbk = regiest_recieve_cbk,
.regist_state_cbk = regiest_state_cbk,
};
#else
static const struct ble_server_operation_t mi_ble_operation = {
.adv_enable = set_adv_enable,
.disconnect = ble_disconnect,
.get_buffer_vaild = get_buffer_remain_len,
.send_data = (void *)app_send_user_data_do,
.regist_wakeup_send = regiest_wakeup_send,
.regist_recieve_cbk = regiest_recieve_cbk,
.regist_state_cbk = regiest_state_cbk,
};
#endif
void ble_get_server_operation_table(struct ble_server_operation_t **interface_pt)
{
*interface_pt = (void *)&mi_ble_operation;
}
void ble_server_send_test_key_num(u8 key_num)
{
if (con_handle) {
if (get_remote_test_flag()) {
ble_op_test_key_num(con_handle, key_num);
} else {
log_info("-not conn testbox\n");
}
}
}
void le_hogp_set_icon(u16 class_type)
{
memcpy(Appearance, &class_type, 2);
}
void le_hogp_set_ReportMap(const u8 *map, u16 size)
{
report_map = map;
report_map_size = size;
hid_report_change = 1;
}
void le_hogp_set_output_callback(void *cb)
{
le_hogp_output_callback = cb;
}
//配对绑定配置
void le_hogp_set_pair_config(u8 pair_max, u8 is_allow_cover)
{
ble_list_config_reset(pair_max, is_allow_cover); //开1对1配对绑定
}
//开可配对绑定允许
void le_hogp_set_pair_allow(void)
{
conn_pair_info.pair_flag = 0;
conn_pair_vm_do(&conn_pair_info, 1);
ble_list_clear_all();
}
int ble_hid_is_connected(void)
{
return con_handle;
}
u8 *ble_cur_connect_addrinfo(void)
{
return cur_peer_addr_info;
}
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,
};
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;
}
return app_send_user_data(report_id_handle_table[report_id], data, len, ATT_OP_AUTO_READ_CCC);
}
void ble_hid_key_deal_test(u16 key_msg)
{
if (key_msg) {
ble_hid_data_send(1, (u8 *)&key_msg, 2);
key_msg = 0;//key release
ble_hid_data_send(1, (u8 *)&key_msg, 2);
}
}
int ble_hid_transfer_channel_send(u8 *packet, u16 size)
{
/* log_info("transfer_tx(%d):", size); */
/* log_info_hexdump(packet, size); */
return app_send_user_data(ATT_CHARACTERISTIC_ae42_01_VALUE_HANDLE, packet, size, ATT_OP_AUTO_READ_CCC);
}
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
}
//控制配对模式
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);
}
#endif