doubao_chat/apps/common/ble/le_net_central.c

1427 lines
43 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_server_module.c
* Description :
* Author :
* Email : zh-jieli.com
* Last modifiled : 2017-01-17 11:14
* Copyright:(c)JIELI 2011-2016 @ , All Rights Reserved.
*********************************************************************************************/
// *****************************************************************************
/* EXAMPLE_START(le_counter): LE Peripheral - Heartbeat Counter over GATT
*
* @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/includes.h"
#include "app_config.h"
#include "btstack/btstack_task.h"
#include "btstack/bluetooth.h"
#include "btcontroller_modules.h"
#include "bt_common.h"
#include "le_net_central.h"
#include "le_common.h"
#include "third_party/common/ble_user.h"
#include "syscfg/syscfg_id.h"
/* #if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_NET_CENTRAL) */
#if BT_NET_CENTRAL_EN
#define SUPPORT_TEST_BOX_BLE_MASTER_TEST_EN 0
#define SHOW_RX_DATA_RATE 0
#define EXT_ADV_MODE_EN 0
#if 1
#define log_info printf
#define log_info_hexdump put_buf
#else
#define log_info(...)
#define log_info_hexdump(...)
#endif
//------
#define ATT_LOCAL_MTU_SIZE (64*2) //note: need >= 20
#define ATT_SEND_CBUF_SIZE (512) //note: need >= 20,缓存大小,可修改
#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)));
#define SEARCH_PROFILE_BUFSIZE (512) //note:
static u8 search_ram_buffer[SEARCH_PROFILE_BUFSIZE] __attribute__((aligned(4)));
#define scan_buffer search_ram_buffer
//---------------
//搜索类型
#define SET_SCAN_TYPE SCAN_ACTIVE
//搜索 周期大小
#define SET_SCAN_INTERVAL 24 //(unit:0.625ms)
//搜索 窗口大小
#define SET_SCAN_WINDOW 8 //(unit:0.625ms)
//连接周期
#define SET_CONN_INTERVAL 24 //(unit:1.25ms)
//连接latency
#define SET_CONN_LATENCY 0 //(unit:conn_interval)
//连接超时
#define SET_CONN_TIMEOUT 400 //(unit:10ms)
//----------------------------------------------------------------------------
static u8 scan_ctrl_en;
static u8 ble_work_state = 0;
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 *channel_priv;
static OS_MUTEX mutex;
static hci_con_handle_t con_handle;
#define BLE_VM_HEAD_TAG (0xB95C)
#define BLE_VM_TAIL_TAG (0x5CB9)
struct pair_info_t {
u16 head_tag;
u8 pair_flag;
u8 peer_address_info[7];
u16 tail_tag;
};
static struct pair_info_t conn_pair_info;
static u8 pair_bond_enable = 0;
//-------------------------------------------------------------------------------
typedef struct {
uint16_t read_handle;
uint16_t read_long_handle;
uint16_t write_handle;
uint16_t write_no_respond;
uint16_t notify_handle;
uint16_t indicate_handle;
} target_hdl_t;
//记录handle 使用
static target_hdl_t target_handle;
static opt_handle_t opt_handle_table[OPT_HANDLE_MAX];
static u8 opt_handle_used_cnt;
static u8 force_seach_onoff = 0;
static s8 force_seach_rssi = -127;
static const client_conn_cfg_t *client_config;
//----------------------------------------------------------------------------
static void bt_ble_create_connection(u8 *conn_addr, u8 addr_type);
static int bt_ble_scan_enable(void *priv, u32 en);
static int client_write_send(void *priv, u8 *data, u16 len);
static int client_operation_send(u16 handle, u8 *data, u16 len, u8 att_op_type);
static void reset_passkey_cb(u32 *key);
static int client_create_connect_api(u8 *addr, u8 addr_type, u8 mode);
static int client_create_cannel_api(void);
static const struct conn_update_param_t connection_param_table[] = {
{16, 24, 0, 600},//11
{12, 28, 0, 600},//3.7
{8, 20, 0, 600},
{50, 60, 0, 600},
};
static const u8 send_param_index = 3;
void client_send_conn_param_update(void)
{
struct conn_update_param_t *param = (void *)&connection_param_table[send_param_index];//for test
log_info("client update param:-%d-%d-%d-%d-\n", param->interval_min, param->interval_max, param->latency, param->timeout);
if (con_handle) {
ble_user_cmd_prepare(BLE_CMD_ONNN_PARAM_UPDATA, 2, con_handle, param);
}
}
static void client_event_report(le_client_event_e event, void *packet, int size)
{
if (client_config->event_callback) {
client_config->event_callback(event, packet, size);
}
}
static bool check_device_is_match(u8 info_type, u8 *data, int size)
{
int i;
u8 conn_mode = BIT(info_type);
const client_match_cfg_t *cfg;
/* log_info_hexdump(data,size); */
for (i = 0; i < CLIENT_MATCH_CONN_MAX; i++) {
cfg = client_config->match_dev_cfg[i];
if (cfg == NULL) {
continue;
}
/* log_info("cfg = %08x\n",cfg); */
/* log_info_hexdump(cfg,sizeof(client_match_cfg_t)); */
if (cfg->create_conn_mode == conn_mode && size == cfg->compare_data_len) {
log_info("match check\n");
log_info_hexdump(data, size);
log_info_hexdump(cfg->compare_data, size);
if (0 == memcmp(data, cfg->compare_data, cfg->compare_data_len)) {
log_info("match ok\n");
pair_bond_enable = cfg->bonding_flag;
client_event_report(CLI_EVENT_MATCH_DEV, (void *)cfg, sizeof(client_match_cfg_t));
return true;
}
}
}
return false;
}
static void conn_pair_vm_do(struct pair_info_t *info, u8 rw_flag)
{
/* return; */
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);
} else {
memset(info, 0, vm_len);
info->head_tag = BLE_VM_HEAD_TAG;
info->tail_tag = BLE_VM_TAIL_TAG;
}
} else {
syscfg_write(CFG_BLE_MODE_INFO, (u8 *)info, vm_len);
}
}
void client_clear_bonding_info(void)
{
log_info("client_clear_bonding_info\n");
conn_pair_vm_do(&conn_pair_info, 0);
if (conn_pair_info.pair_flag) {
//del pair bond
memset(&conn_pair_info, 0, sizeof(struct pair_info_t));
conn_pair_vm_do(&conn_pair_info, 1);
}
}
//------------------------------------------------------------
static void set_ble_work_state(ble_state_e state)
{
if (state != ble_work_state) {
log_info("ble_client_work_st:%x->%x\n", ble_work_state, state);
ble_work_state = state;
if (app_ble_state_callback) {
app_ble_state_callback(channel_priv, state);
}
}
}
//------------------------------------------------------------
static int get_ble_work_state(void)
{
return ble_work_state;
}
//-------------------------------------------------------------------------------
static void check_target_uuid_match(search_result_t *result_info)
{
u32 i;
const target_uuid_t *t_uuid;
for (i = 0; i < client_config->search_uuid_cnt; i++) {
t_uuid = &client_config->search_uuid_table[i];
if (result_info->services.uuid16) {
if (result_info->services.uuid16 != t_uuid->services_uuid16) {
/* log_info("b1"); */
continue;
}
} else {
if (memcmp(result_info->services.uuid128, t_uuid->services_uuid128, 16)) {
/* log_info("b2"); */
continue;
}
}
if (result_info->characteristic.uuid16) {
if (result_info->characteristic.uuid16 != t_uuid->characteristic_uuid16) {
/* log_info("b3"); */
/* log_info("%d: %04x--%04x",result_info->characteristic.uuid16,t_uuid->characteristic_uuid16); */
continue;
}
} else {
if (memcmp(result_info->characteristic.uuid128, t_uuid->characteristic_uuid128, 16)) {
/* log_info("b4"); */
continue;
}
}
break;//match one
}
if (i >= client_config->search_uuid_cnt) {
return;
}
if (opt_handle_used_cnt >= OPT_HANDLE_MAX) {
log_info("opt_handle is full!!!\n");
return;
}
if ((t_uuid->opt_type & result_info->characteristic.properties) != t_uuid->opt_type) {
log_info("properties not match!!!\n");
return;
}
log_info("match one uuid\n");
opt_handle_t *opt_get = &opt_handle_table[opt_handle_used_cnt++];
opt_get->value_handle = result_info->characteristic.value_handle;
opt_get->search_uuid = t_uuid;
switch (t_uuid->opt_type) {
case ATT_PROPERTY_READ:
target_handle.read_handle = result_info->characteristic.value_handle;
break;
case ATT_PROPERTY_WRITE_WITHOUT_RESPONSE:
target_handle.write_no_respond = result_info->characteristic.value_handle;
break;
case ATT_PROPERTY_WRITE:
target_handle.write_handle = result_info->characteristic.value_handle;
break;
case ATT_PROPERTY_NOTIFY:
target_handle.notify_handle = result_info->characteristic.value_handle;
break;
case ATT_PROPERTY_INDICATE:
target_handle.indicate_handle = result_info->characteristic.value_handle;
break;
default:
break;
}
client_event_report(CLI_EVENT_MATCH_UUID, opt_get, sizeof(opt_handle_t));
}
//操作handle,完成 write ccc
static void do_operate_search_handle(void)
{
u16 tmp_16;
u16 i, cur_opt_type;
opt_handle_t *opt_hdl_pt;
log_info("opt_handle_used_cnt= %d\n", opt_handle_used_cnt);
/* log_info("find target_handle:"); */
/* log_info_hexdump(&target_handle, sizeof(target_hdl_t)); */
if (0 == opt_handle_used_cnt) {
return;
/* goto opt_end; */
}
/* test_send_conn_update();//for test */
for (i = 0; i < opt_handle_used_cnt; i++) {
opt_hdl_pt = &opt_handle_table[i];
cur_opt_type = opt_hdl_pt->search_uuid->opt_type;
switch ((u8)cur_opt_type) {
case ATT_PROPERTY_READ:
if (1) {
tmp_16 = 0x55A2;//fixed
log_info("read_long:%04x\n", opt_hdl_pt->value_handle);
client_operation_send(opt_hdl_pt->value_handle, (u8 *)&tmp_16, 2, ATT_OP_READ_LONG);
} else {
tmp_16 = 0x55A1;//fixed
log_info("read:%04x\n", opt_hdl_pt->value_handle);
client_operation_send(opt_hdl_pt->value_handle, (u8 *)&tmp_16, 2, ATT_OP_READ);
}
break;
case ATT_PROPERTY_NOTIFY:
tmp_16 = 0x01;//fixed
log_info("write_ntf_ccc:%04x\n", opt_hdl_pt->value_handle);
client_operation_send(opt_hdl_pt->value_handle + 1, (u8 *)&tmp_16, 2, ATT_OP_WRITE);
break;
case ATT_PROPERTY_INDICATE:
tmp_16 = 0x02;//fixed
log_info("write_ind_ccc:%04x\n", opt_hdl_pt->value_handle);
client_operation_send(opt_hdl_pt->value_handle + 1, (u8 *)&tmp_16, 2, ATT_OP_WRITE);
break;
default:
break;
}
}
opt_end:
set_ble_work_state(BLE_ST_SEARCH_COMPLETE);
}
//协议栈内部调用
//return: 0--accept,1--reject
int l2cap_connection_update_request_just(u8 *packet, hci_con_handle_t handle)
{
log_info("slave request conn_update:\n-interval_min= %d,\n-interval_max= %d,\n-latency= %d,\n-timeout= %d\n",
little_endian_read_16(packet, 0), little_endian_read_16(packet, 2),
little_endian_read_16(packet, 4), little_endian_read_16(packet, 6));
return 0;
/* return 1; */
}
//协议栈内部调用
void user_client_report_search_result(search_result_t *result_info)
{
if (result_info == (void *) - 1) {
log_info("client_report_search_result finish!!!\n");
do_operate_search_handle();
client_event_report(CLI_EVENT_SEARCH_PROFILE_COMPLETE, 0, 0);
return;
}
log_info("\n*** services, uuid16:%04x,index=%d ***\n", result_info->services.uuid16, result_info->service_index);
log_info("{charactc, uuid16:%04x,index=%d,handle:%04x~%04x,value_handle=%04x}\n",
result_info->characteristic.uuid16, result_info->characteristic_index,
result_info->characteristic.start_handle, result_info->characteristic.end_handle,
result_info->characteristic.value_handle
);
if (!result_info->services.uuid16) {
log_info("######services_uuid128:");
log_info_hexdump(result_info->services.uuid128, 16);
}
if (!result_info->characteristic.uuid16) {
log_info("######charact_uuid128:");
log_info_hexdump(result_info->characteristic.uuid128, 16);
}
check_target_uuid_match(result_info);
}
#if SHOW_RX_DATA_RATE
static u32 client_timer_handle = 0;
static u32 test_data_count;
static void client_timer_handler(void *priv)
{
if (!con_handle) {
test_data_count = 0;
return;
}
log_info("peer_rssi = %d\n", ble_vendor_get_peer_rssi(con_handle));
if (test_data_count) {
/* log_info("\n-ble_data_rate: %d bps-\n", test_data_count * 8); */
log_info("\n%d bytes receive: %d.%02d KB/s \n", test_data_count, test_data_count / 1000, test_data_count % 1000);
test_data_count = 0;
}
}
static void client_timer_start(void)
{
client_timer_handle = sys_timer_add(NULL, client_timer_handler, 1000);
}
#endif /* SHOW_RX_DATA_RATE */
static const target_uuid_t *get_match_handle_target(u16 handle)
{
for (int i = 0; i < opt_handle_used_cnt; i++) {
if (opt_handle_table[i].value_handle == handle) {
return opt_handle_table[i].search_uuid;
}
}
return NULL;
}
//协议栈内部调用
void user_client_report_data_callback(att_data_report_t *report_data)
{
/* log_info("\n-report_data:type %02x,handle %04x,offset %d,len %d:",report_data->packet_type, */
/* report_data->value_handle,report_data->value_offset,report_data->blob_length); */
/* log_info_hexdump(report_data->blob,report_data->blob_length); */
#if SHOW_RX_DATA_RATE
test_data_count += report_data->blob_length;
#endif /* SHOW_RX_DATA_RATE */
const target_uuid_t *search_uuid = get_match_handle_target(report_data->value_handle);
if (client_config->report_data_callback) {
client_config->report_data_callback(report_data, search_uuid);
return;
}
switch (report_data->packet_type) {
case GATT_EVENT_NOTIFICATION://notify
case GATT_EVENT_INDICATION://indicate
case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT://read
case GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT://read long
break;
default:
break;
}
}
static void client_search_profile_start(void)
{
opt_handle_used_cnt = 0;
memset(&target_handle, 0, sizeof(target_hdl_t));
user_client_init(con_handle, search_ram_buffer, SEARCH_PROFILE_BUFSIZE);
if (client_config->search_uuid_cnt) {
ble_op_search_profile_all();
} else {
user_client_set_search_complete();
}
}
//------------------------------------------------------------
static bool resolve_adv_report(u8 *adv_address, u8 data_length, u8 *data, s8 rssi)
{
u8 i, lenght, ad_type;
u8 *adv_data_pt;
u8 find_remoter = 0;
/* u8 tmp_addr[6]; */
u32 tmp32;
if (check_device_is_match(CLI_CREAT_BY_ADDRESS, adv_address, 6)) {
find_remoter = 1;
}
adv_data_pt = data;
for (i = 0; i < data_length;) {
if (*adv_data_pt == 0) {
/* log_info("analyze end\n"); */
break;
}
lenght = *adv_data_pt++;
ad_type = *adv_data_pt++;
i += (lenght + 1);
switch (ad_type) {
case HCI_EIR_DATATYPE_FLAGS:
/* log_info("flags:%02x\n",adv_data_pt[0]); */
break;
case HCI_EIR_DATATYPE_MORE_16BIT_SERVICE_UUIDS:
case HCI_EIR_DATATYPE_COMPLETE_16BIT_SERVICE_UUIDS:
case HCI_EIR_DATATYPE_MORE_32BIT_SERVICE_UUIDS:
case HCI_EIR_DATATYPE_COMPLETE_32BIT_SERVICE_UUIDS:
case HCI_EIR_DATATYPE_MORE_128BIT_SERVICE_UUIDS:
case HCI_EIR_DATATYPE_COMPLETE_128BIT_SERVICE_UUIDS:
/* log_info("service uuid:"); */
/* log_info_hexdump(adv_data_pt, lenght - 1); */
break;
case HCI_EIR_DATATYPE_COMPLETE_LOCAL_NAME:
case HCI_EIR_DATATYPE_SHORTENED_LOCAL_NAME:
tmp32 = adv_data_pt[lenght - 1];
adv_data_pt[lenght - 1] = 0;;
log_info("remoter_name: %s,rssi:%d\n", adv_data_pt, rssi);
log_info_hexdump(adv_address, 6);
adv_data_pt[lenght - 1] = tmp32;
//-------
#if SUPPORT_TEST_BOX_BLE_MASTER_TEST_EN
#define TEST_BOX_BLE_NAME "JLBT_TESTBOX"
#define TEST_BOX_BLE_NAME_LEN 0xc
if (0 == memcmp(adv_data_pt, TEST_BOX_BLE_NAME, TEST_BOX_BLE_NAME_LEN)) {
find_remoter = 1;
break;
}
#endif
/* log_info("target name:%s", client_config->compare_data); */
if (check_device_is_match(CLI_CREAT_BY_NAME, adv_data_pt, lenght - 1)) {
find_remoter = 1;
log_info("catch name ok\n");
}
break;
case HCI_EIR_DATATYPE_MANUFACTURER_SPECIFIC_DATA:
if (check_device_is_match(CLI_CREAT_BY_TAG, adv_data_pt, lenght - 1)) {
log_info("get_tag_string!\n");
find_remoter = 1;
}
break;
case HCI_EIR_DATATYPE_APPEARANCE_DATA:
/* log_info("get_class_type:%04x\n",little_endian_read_16(adv_data_pt,0)); */
break;
default:
/* log_info("unknow ad_type:"); */
break;
}
if (find_remoter) {
log_info_hexdump(adv_data_pt, lenght - 1);
}
adv_data_pt += (lenght - 1);
}
return find_remoter;
}
static void client_report_adv_data(adv_report_t *report_pt, u16 len)
{
bool find_remoter;
/* log_info("event_type,addr_type: %x,%x; ",report_pt->event_type,report_pt->address_type); */
/* log_info_hexdump(report_pt->address,6); */
/* log_info("adv_data_display:"); */
/* log_info_hexdump(report_pt->data,report_pt->length); */
// log_info("rssi:%d\n",report_pt->rssi);
find_remoter = resolve_adv_report(report_pt->address, report_pt->length, report_pt->data, report_pt->rssi);
if (find_remoter) {
if (force_seach_onoff && force_seach_rssi > report_pt->rssi) {
log_info("match but rssi fail!!!:%d,%d\n", force_seach_rssi, report_pt->rssi);
return;
}
log_info("rssi:%d\n", report_pt->rssi);
log_info("\n*********create_connection***********\n");
log_info("***remote type %d,addr:", report_pt->address_type);
log_info_hexdump(report_pt->address, 6);
os_mutex_pend(&mutex, 0);
bt_ble_scan_enable(0, 0);
os_mutex_post(&mutex);
client_create_connect_api(report_pt->address, report_pt->address_type, 0);
log_info("*create_finish\n");
}
}
#if EXT_ADV_MODE_EN
#define GET_STRUCT_MEMBER_OFFSET(type, member) \
(u32)&(((struct type*)0)->member)
struct __ext_adv_report_event {
u8 Subevent_Code;
u8 Num_Reports;
u16 Event_Type;
u8 Address_Type;
u8 Address[6];
u8 Primary_PHY;
u8 Secondary_PHY;
u8 Advertising_SID;
u8 Tx_Power;
u8 RSSI;
u16 Periodic_Advertising_Interval;
u8 Direct_Address_Type;
u8 Direct_Address[6];
u8 Data_Length;
u8 Data[0];
} _GNU_PACKED_;
static void client_report_ext_adv_data(u8 *report_pt, u16 len)
{
bool find_remoter;
u8 address_type = report_pt[GET_STRUCT_MEMBER_OFFSET(__ext_adv_report_event, Address_Type)];
u8 address[6];
/* log_info("--func=%s", __FUNCTION__); */
/* log_info_hexdump(report_pt, len); */
memcpy(address, &report_pt[GET_STRUCT_MEMBER_OFFSET(__ext_adv_report_event, Address)], 6);
find_remoter = resolve_adv_report(\
address, \
report_pt[GET_STRUCT_MEMBER_OFFSET(__ext_adv_report_event, Data_Length)], \
&report_pt[GET_STRUCT_MEMBER_OFFSET(__ext_adv_report_event, Data)], 0 \
);
if (find_remoter) {
if (force_seach_onoff && force_seach_rssi > report_pt[GET_STRUCT_MEMBER_OFFSET(__ext_adv_report_event, RSSI)]) {
log_info("match but rssi fail!!!:%d,%d\n", force_seach_rssi, report_pt[GET_STRUCT_MEMBER_OFFSET(__ext_adv_report_event, RSSI)]);
return;
}
log_info("\n*********ext create_connection***********\n");
log_info("***remote type %d, addr:", address_type);
log_info_hexdump(address, 6);
os_mutex_pend(&mutex, 0);
bt_ble_scan_enable(0, 0);
os_mutex_post(&mutex);
client_create_connect_api(address, address_type, 0);
log_info("*create_finish\n");
}
}
struct __ext_init {
u8 Initiating_Filter_Policy;
u8 Own_Address_Type;
u8 Peer_Address_Type;
u8 Peer_Address[6];
u8 Initiating_PHYs;
u16 Scan_Interval;
u16 Scan_Window;
u16 Conn_Interval_Min;
u16 Conn_Interval_Max;
u16 Conn_Latency;
u16 Supervision_Timeout;
u16 Minimum_CE_Length;
u16 Maximum_CE_Length;
} _GNU_PACKED_;
static void client_ext_create_connection(u8 *conn_addr, u8 addr_type)
{
struct __ext_init *create_conn_par = (struct __ext_init *)scan_buffer;
if (get_ble_work_state() == BLE_ST_CREATE_CONN) {
log_info("already create conn!!!\n");
return;
}
memset(create_conn_par, 0, sizeof(*create_conn_par));
create_conn_par->Conn_Interval_Min = SET_CONN_INTERVAL;
create_conn_par->Conn_Interval_Max = SET_CONN_INTERVAL;
create_conn_par->Conn_Latency = SET_CONN_LATENCY;
create_conn_par->Supervision_Timeout = SET_CONN_TIMEOUT;
create_conn_par->Peer_Address_Type = addr_type;
create_conn_par->Initiating_PHYs = INIT_SET_1M_PHY;
memcpy(create_conn_par->Peer_Address, conn_addr, 6);
set_ble_work_state(BLE_ST_CREATE_CONN);
/* log_info_hexdump(create_conn_par, sizeof(*create_conn_par)); */
ble_op_ext_create_conn(create_conn_par, sizeof(*create_conn_par));
}
#endif /* EXT_ADV_MODE_EN */
static void client_create_connection(u8 *conn_addr, u8 addr_type)
{
struct create_conn_param_t *create_conn_par = (struct create_conn_param_t *)scan_buffer;
if (get_ble_work_state() == BLE_ST_CREATE_CONN) {
log_info("already create conn!!!\n");
return;
}
create_conn_par->conn_interval = SET_CONN_INTERVAL;
create_conn_par->conn_latency = SET_CONN_LATENCY;
create_conn_par->supervision_timeout = SET_CONN_TIMEOUT;
memcpy(create_conn_par->peer_address, conn_addr, 6);
create_conn_par->peer_address_type = addr_type;
set_ble_work_state(BLE_ST_CREATE_CONN);
//log_info_hexdump(create_conn_par, sizeof(struct create_conn_param_t));
ble_op_create_connection(create_conn_par);
}
static void bt_ble_create_connection(u8 *conn_addr, u8 addr_type)
{
#if EXT_ADV_MODE_EN
client_ext_create_connection(conn_addr, addr_type);
#else
client_create_connection(conn_addr, addr_type);
#endif /* EXT_ADV_MODE_EN */
}
static void client_create_connection_cannel(void)
{
if (get_ble_work_state() == BLE_ST_CREATE_CONN) {
set_ble_work_state(BLE_ST_SEND_CREATE_CONN_CANNEL);
ble_op_create_connection_cancel();
}
}
static int client_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);
ble_op_disconnect(con_handle);
} else {
log_info(">>>ble wait disconnect...\n");
}
return APP_BLE_NO_ERROR;
} else {
return APP_BLE_OPERATION_ERROR;
}
}
static void connection_update_complete_success(u8 *packet)
{
int con_handle, 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);
}
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");
break;
case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
log_info_hexdump(packet, size);
memcpy(&tmp32, event->data, 4);
log_info("Passkey display: %06u.\n", tmp32);
break;
case SM_EVENT_PASSKEY_INPUT_NUMBER:
/*IO_CAPABILITY_KEYBOARD_ONLY 方式*/
reset_passkey_cb(&tmp32);
log_info("%04x->Passkey input: %06u.\n", event->con_handle, tmp32);
sm_passkey_input(event->con_handle, tmp32); /*update passkey*/
break;
case SM_EVENT_PAIR_PROCESS:
log_info("======PAIR_PROCESS: %02x\n", event->data[0]);
put_buf(event->data, 4);
break;
}
break;
}
}
static void can_send_now_wakeup(void)
{
putchar('E');
}
static const char *const phy_result[] = {
"None",
"1M",
"2M",
"Coded",
};
static void set_connection_data_length(u16 tx_octets, u16 tx_time)
{
if (con_handle) {
ble_op_set_data_length(con_handle, tx_octets, tx_time);
}
}
static void set_connection_data_phy(u8 tx_phy, u8 rx_phy)
{
if (0 == con_handle) {
return;
}
u8 all_phys = 0;
u16 phy_options = 0;
ble_op_set_ext_phy(con_handle, all_phys, tx_phy, rx_phy, phy_options);
}
static void client_profile_start(u16 con_handle)
{
ble_op_att_send_init(con_handle, att_ram_buffer, ATT_RAM_BUFSIZE, ATT_LOCAL_MTU_SIZE);
set_ble_work_state(BLE_ST_CONNECT);
if (0 == client_config->security_en) {
client_search_profile_start();
}
}
/* 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;
u8 status;
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_ENHANCED_CONNECTION_COMPLETE:
status = hci_subevent_le_enhanced_connection_complete_get_status(packet);
if (status) {
log_info("LE_MASTER CREATE CONNECTION FAIL!!! %0x\n", status);
set_ble_work_state(BLE_ST_DISCONN);
break;
}
con_handle = hci_subevent_le_enhanced_connection_complete_get_connection_handle(packet);
log_info("HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE : 0x%0x\n", con_handle);
log_info("conn_interval = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_interval(packet));
log_info("conn_latency = %d\n", hci_subevent_le_enhanced_connection_complete_get_conn_latency(packet));
log_info("conn_timeout = %d\n", hci_subevent_le_enhanced_connection_complete_get_supervision_timeout(packet));
client_profile_start(con_handle);
break;
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
if (packet[3]) {
log_info("LE_MASTER CREATE CONNECTION FAIL!!! %0x\n", packet[3]);
set_ble_work_state(BLE_ST_DISCONN);
break;
}
con_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
log_info("HCI_SUBEVENT_LE_CONNECTION_COMPLETE : %0x\n", con_handle);
connection_update_complete_success(packet + 8);
client_profile_start(con_handle);
client_event_report(CLI_EVENT_CONNECTED, packet, size);
if (pair_bond_enable) {
conn_pair_info.pair_flag = 1;
memcpy(&conn_pair_info.peer_address_info, &packet[7], 7);
conn_pair_vm_do(&conn_pair_info, 1);
pair_bond_enable = 0;
}
break;
case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
connection_update_complete_success(packet);
break;
case HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE:
log_info("APP HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE");
break;
case HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE:
log_info("APP HCI_SUBEVENT_LE_PHY_UPDATE %s\n", hci_event_le_meta_get_phy_update_complete_status(packet) ? "Fail" : "Succ");
log_info("Tx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_tx_phy(packet)]);
log_info("Rx PHY: %s\n", phy_result[hci_event_le_meta_get_phy_update_complete_rx_phy(packet)]);
break;
#if EXT_ADV_MODE_EN
case HCI_SUBEVENT_LE_EXTENDED_ADVERTISING_REPORT:
/* log_info("APP HCI_SUBEVENT_LE_EXTENDED_ADVERTISING_REPORT"); */
/* log_info_hexdump(packet, size); */
if (BLE_ST_SCAN == get_ble_work_state()) {
client_report_ext_adv_data(&packet[2], packet[1]);
} else {
log_info("drop ext_adv_report!!!\n");
}
break;
#endif /* EXT_ADV_MODE_EN */
}
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
log_info("HCI_EVENT_DISCONNECTION_COMPLETE: %0x\n", packet[5]);
con_handle = 0;
ble_op_att_send_init(con_handle, 0, 0, 0);
set_ble_work_state(BLE_ST_DISCONN);
client_event_report(CLI_EVENT_DISCONNECT, packet, size);
os_mutex_pend(&mutex, 0);
//auto to do
if (conn_pair_info.pair_flag) {
client_create_connect_api(0, 0, 1);
} else {
bt_ble_scan_enable(0, 1);
}
os_mutex_post(&mutex);
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);
break;
case GAP_EVENT_ADVERTISING_REPORT:
/* putchar('@'); */
if (BLE_ST_SCAN == get_ble_work_state()) {
client_report_adv_data((void *)&packet[2], packet[1]);
} else {
log_info("drop adv_report!!!\n");
}
break;
case HCI_EVENT_ENCRYPTION_CHANGE:
log_info("HCI_EVENT_ENCRYPTION_CHANGE= %d\n", packet[2]);
if (client_config->security_en) {
client_search_profile_start();
}
break;
}
break;
}
}
static int get_buffer_vaild_len(void *priv)
{
u32 vaild_len = 0;
ble_op_att_get_remain(&vaild_len);
return vaild_len;
}
static int client_operation_send(u16 handle, u8 *data, u16 len, u8 att_op_type)
{
int ret = APP_BLE_NO_ERROR;
if (!con_handle) {
return APP_BLE_OPERATION_ERROR;
}
if (!handle) {
log_info("handle is null\n");
return APP_BLE_OPERATION_ERROR;
}
if (get_buffer_vaild_len(0) < len) {
log_info("opt_buff_full!!!\n");
return APP_BLE_BUFF_FULL;
}
ret = ble_op_att_send_data(handle, data, len, att_op_type);
if (ret == BLE_BUFFER_FULL) {
ret = APP_BLE_BUFF_FULL;
}
return ret;
}
//-----------------------------------------------
static int client_write_send(void *priv, u8 *data, u16 len)
{
return client_operation_send(target_handle.write_handle, data, len, ATT_OP_WRITE);
}
static int client_write_without_respond_send(void *priv, u8 *data, u16 len)
{
return client_operation_send(target_handle.write_no_respond, data, len, ATT_OP_WRITE_WITHOUT_RESPOND);
}
static int client_read_value_send(void *priv)
{
u16 tmp_flag = 0x55A1;
return client_operation_send(target_handle.read_handle, (u8 *)&tmp_flag, 2, ATT_OP_READ);
}
static int client_read_long_value_send(void *priv)
{
u16 tmp_flag = 0x55A2;
return client_operation_send(target_handle.read_handle, (u8 *)&tmp_flag, 2, ATT_OP_READ_LONG);
}
#if EXT_ADV_MODE_EN
struct __ext_scan_param {
u8 Own_Address_Type;
u8 Scanning_Filter_Policy;
u8 Scanning_PHYs;
u8 Scan_Type;
u16 Scan_Interval;
u16 Scan_Window;
} _GNU_PACKED_;
struct __ext_scan_enable {
u8 Enable;
u8 Filter_Duplicates;
u16 Duration;
u16 Period;
} _GNU_PACKED_;
static const struct __ext_scan_param ext_scan_param = {
.Own_Address_Type = 0,
.Scanning_Filter_Policy = 0,
.Scanning_PHYs = SCAN_SET_1M_PHY,
.Scan_Type = SET_SCAN_TYPE,
.Scan_Interval = SET_SCAN_INTERVAL,
.Scan_Window = SET_SCAN_WINDOW,
};
static const struct __ext_scan_enable ext_scan_enable = {
.Enable = 1,
.Filter_Duplicates = 0,
.Duration = 0,
.Period = 0,
};
static const struct __ext_scan_enable ext_scan_disable = {
.Enable = 0,
.Filter_Duplicates = 0,
.Duration = 0,
.Period = 0,
};
#endif /* EXT_ADV_MODE_EN */
//扫描数设置
static void scanning_setup_init(void)
{
ble_op_set_scan_param(SET_SCAN_TYPE, SET_SCAN_INTERVAL, SET_SCAN_WINDOW);
}
static int bt_ble_scan_enable(void *priv, u32 en)
{
ble_state_e next_state, cur_state;
if (!scan_ctrl_en && en) {
return APP_BLE_OPERATION_ERROR;
}
if (en) {
next_state = BLE_ST_SCAN;
} else {
next_state = BLE_ST_IDLE;
}
cur_state = get_ble_work_state();
switch (cur_state) {
case BLE_ST_SCAN:
case BLE_ST_IDLE:
case BLE_ST_INIT_OK:
case BLE_ST_NULL:
case BLE_ST_DISCONN:
case BLE_ST_CONNECT_FAIL:
case BLE_ST_SEND_CREATE_CONN_CANNEL:
break;
default:
return APP_BLE_OPERATION_ERROR;
break;
}
if (cur_state == next_state) {
return APP_BLE_NO_ERROR;
}
log_info("scan_en:%d\n", en);
set_ble_work_state(next_state);
#if EXT_ADV_MODE_EN
if (en) {
ble_op_set_ext_scan_param(&ext_scan_param, sizeof(ext_scan_param));
ble_op_ext_scan_enable(&ext_scan_enable, sizeof(ext_scan_enable));
} else {
ble_op_ext_scan_enable(&ext_scan_disable, sizeof(ext_scan_disable));
}
#else
if (en) {
scanning_setup_init();
}
ble_op_scan_enable2(en, 0);
#endif /* EXT_ADV_MODE_EN */
return APP_BLE_NO_ERROR;
}
static int client_regiest_wakeup_send(void *priv, void *cbk)
{
/* att_regist_wakeup_send(cbk); */
return APP_BLE_NO_ERROR;
}
static int client_regiest_recieve_cbk(void *priv, void *cbk)
{
channel_priv = priv;
app_recieve_callback = cbk;
return APP_BLE_NO_ERROR;
}
static int client_regiest_state_cbk(void *priv, void *cbk)
{
channel_priv = priv;
app_ble_state_callback = cbk;
return APP_BLE_NO_ERROR;
}
//该接口重新配置搜索的配置项
static int client_init_config(void *priv, void *cfg)
{
log_info("client_init_config\n");
client_config = (const client_conn_cfg_t *)cfg;//reset config
return APP_BLE_NO_ERROR;
}
//可配置进入强制搜索方式连接,更加信号强度过滤设备
static int client_force_search(u8 onoff, s8 rssi)
{
force_seach_rssi = rssi;
if (force_seach_onoff != onoff) {
force_seach_onoff = onoff;
//强制搜索前后,关创建监听
if (get_ble_work_state() == BLE_ST_CREATE_CONN) {
client_create_connection_cannel();
}
}
return 0;
}
static int client_create_connect_api(u8 *addr, u8 addr_type, u8 mode)
{
u8 cur_state = get_ble_work_state();
switch (cur_state) {
case BLE_ST_SCAN:
case BLE_ST_IDLE:
case BLE_ST_INIT_OK:
case BLE_ST_NULL:
case BLE_ST_DISCONN:
case BLE_ST_CONNECT_FAIL:
case BLE_ST_SEND_CREATE_CONN_CANNEL:
break;
default:
return APP_BLE_OPERATION_ERROR;
break;
}
if (cur_state == BLE_ST_SCAN) {
log_info("stop scan\n");
bt_ble_scan_enable(0, 0);
}
//pair mode
if (mode == 1) {
if (conn_pair_info.pair_flag) {
if (conn_pair_info.pair_flag) {
//有配对,跳过搜索,直接创建init_creat
log_info("pair to creat!\n");
log_info_hexdump(conn_pair_info.peer_address_info, 7);
bt_ble_create_connection(&conn_pair_info.peer_address_info[1], conn_pair_info.peer_address_info[0]);
return 0;
}
} else {
log_info("no pair to creat!\n");
return APP_BLE_OPERATION_ERROR;
}
} else {
log_info("addr to creat!\n");
log_info_hexdump(addr, 7);
bt_ble_create_connection(addr, addr_type);
}
return 0;
}
static int client_create_cannel_api(void)
{
if (get_ble_work_state() == BLE_ST_CREATE_CONN) {
client_create_connection_cannel();
return 0;
}
return 1;
}
static const struct ble_client_operation_t client_operation = {
.scan_enable = bt_ble_scan_enable,
.disconnect = client_disconnect,
.get_buffer_vaild = get_buffer_vaild_len,
.write_data = (void *)client_write_without_respond_send,
.read_do = (void *)client_read_value_send,
.regist_wakeup_send = client_regiest_wakeup_send,
.regist_recieve_cbk = client_regiest_recieve_cbk,
.regist_state_cbk = client_regiest_state_cbk,
.init_config = client_init_config,
.opt_comm_send = client_operation_send,
.set_force_search = client_force_search,
.create_connect = client_create_connect_api,
.create_connect_cannel = client_create_cannel_api,
.get_work_state = get_ble_work_state,
};
struct ble_client_operation_t *ble_get_client_operation_table(void)
{
return &client_operation;
}
#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
}
//协议栈内部调用
extern void sm_set_master_request_pair(int enable);
__attribute__((weak)) 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_master_request_pair(security_en);
sm_event_callback_set(&cbk_sm_packet_handler);
if (io_type == IO_CAPABILITY_DISPLAY_ONLY) {
reset_PK_cb_register(reset_passkey_cb);
}
}
extern void gatt_client_init(void);
extern void gatt_client_register_packet_handler(btstack_packet_handler_t handler);
extern void le_device_db_init(void);
extern u8 get_ble_gatt_role(void);
//协议栈内部调用
__attribute__((weak)) void ble_profile_init(void)
{
log_info("ble profile init\n");
le_device_db_init();
ble_stack_gatt_role(1);
#if PASSKEY_ENTER_ENABLE
ble_sm_setup_init(IO_CAPABILITY_KEYBOARD_ONLY, SM_AUTHREQ_MITM_PROTECTION | SM_AUTHREQ_BONDING, 7, client_config->security_en);
#else
ble_sm_setup_init(IO_CAPABILITY_NO_INPUT_NO_OUTPUT, SM_AUTHREQ_BONDING, 7, client_config->security_en);
#endif
/* setup ATT client */
gatt_client_init();
gatt_client_register_packet_handler(cbk_packet_handler);
// register for HCI events
hci_event_callback_set(&cbk_packet_handler);
le_l2cap_register_packet_handler(&cbk_packet_handler);
ble_vendor_set_default_att_mtu(ATT_LOCAL_MTU_SIZE);
}
static void device_bonding_init(void)
{
int i;
int cfg_bonding = 0;
const client_match_cfg_t *cfg;
for (i = 0; i < CLIENT_MATCH_CONN_MAX; i++) {
cfg = client_config->match_dev_cfg[i];
if (cfg == NULL) {
continue;
}
if (cfg->bonding_flag) {
cfg_bonding = 1;
}
}
if (!cfg_bonding) {
client_clear_bonding_info();
}
}
__attribute__((weak)) void bt_ble_init(void)
{
}
__attribute__((weak)) void bt_ble_exit(void)
{
}
static void ble_module_enable(u8 en)
{
log_info("mode_en:%d\n", en);
if (en) {
if (0 == get_ble_gatt_role()) {
#if CONFIG_POWER_ON_ENABLE_BLE
bt_ble_exit();
os_time_dly(200);
#endif
ble_stack_gatt_role(1);
hci_event_callback_set(&cbk_packet_handler);
le_l2cap_register_packet_handler(&cbk_packet_handler);
}
os_mutex_pend(&mutex, 0);
scan_ctrl_en = 1;
bt_ble_scan_enable(0, 1);
os_mutex_post(&mutex);
} else {
if (con_handle) {
scan_ctrl_en = 0;
client_disconnect(NULL);
} else {
os_mutex_pend(&mutex, 0);
bt_ble_scan_enable(0, 0);
scan_ctrl_en = 0;
os_mutex_post(&mutex);
}
#if CONFIG_POWER_ON_ENABLE_BLE
os_time_dly(200);
bt_ble_init();
#endif
}
}
void bt_master_ble_init(void)
{
if (!os_mutex_valid(&mutex)) {
os_mutex_create(&mutex);
if (0 == get_ble_gatt_role()) {
/* setup ATT client */
gatt_client_init();
gatt_client_register_packet_handler(cbk_packet_handler);
}
}
log_info("******ble_master_init******\n");
set_ble_work_state(BLE_ST_INIT_OK);
conn_pair_vm_do(&conn_pair_info, 0);
device_bonding_init();
ble_module_enable(1);
#if SHOW_RX_DATA_RATE
client_timer_start();
#endif /* SHOW_RX_DATA_RATE */
}
void bt_master_ble_exit(void)
{
log_info("******ble_master_exit******\n");
if (!os_mutex_valid(&mutex)) {
return;
}
ble_module_enable(0);
}
#endif