2025-02-18 15:40:42 +08:00

1854 lines
59 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 : 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