/**
|
*******************************************************************************
|
* @file app_ble_central.c
|
* @create 2023-08-01
|
* @author Panchip BLE GROUP
|
* @note
|
* Copyright (c) 2022 Shanghai Panchip Microelectronics Co.,Ltd.
|
*
|
*******************************************************************************
|
*/
|
#include "app.h"
|
#include "pan_ble.h"
|
#include "app_log.h"
|
#include "ble_dev_filt.h"
|
|
/*******************************************************************************
|
* Macro
|
******************************************************************************/
|
/**@brief ble device filter. */
|
#define APP_BLE_DEV_FLT_EN 1
|
// filt device name
|
#define APP_FILT_DEV_NAME_EN 1
|
#define APP_FILT_DEV_NAME "ble_hr"
|
// filt device address
|
#define APP_FILT_DEV_ADDR_EN 0
|
#define APP_FILT_DEV_ADDR_LEN 5 //address match length; range 1~6
|
#define APP_FILT_DEV_ADDR 0x66, 0x66, 0x66, 0x66, 0x33, 0xC2
|
// filt UUID16
|
#define APP_FILT_UUID16_EN 0
|
#define APP_FILT_UUID16 BLE_SVC_HRS_UUID16
|
|
/*******************************************************************************
|
* Function Declaration
|
******************************************************************************/
|
static void app_ble_connect_create(const struct ble_gap_disc_desc *disc);
|
|
|
/*******************************************************************************
|
* Service Discovery(SDP) API
|
******************************************************************************/
|
static int app_ble_on_read(uint16_t conn_handle,
|
const struct ble_gatt_error *error,
|
struct ble_gatt_attr *attr,
|
void *arg)
|
{
|
APP_LOG_INFO("Read complete; status=%d conn_handle=%d\n", error->status, conn_handle);
|
|
uint8_t buf[250];
|
uint16_t len = 0;
|
|
if (error->status == 0) {
|
APP_LOG_INFO(" attr_handle=%d len:%d value=\n", attr->handle, OS_MBUF_PKTLEN(attr->om));
|
|
int rc = ble_hs_mbuf_to_flat(attr->om, buf, sizeof(buf), &len); //must
|
if(rc == 0){
|
APP_LOG_DATA(buf, len);
|
}
|
}
|
|
return 0;
|
}
|
|
static int app_ble_on_write(uint16_t conn_handle,
|
const struct ble_gatt_error *error,
|
struct ble_gatt_attr *attr,
|
void *arg)
|
{
|
APP_LOG_INFO("Write complete; status=%d conn_handle=%d attr_handle=%d\n",
|
error->status, conn_handle, attr->handle);
|
return 0;
|
}
|
|
static int app_ble_on_subscribe(uint16_t conn_handle,
|
const struct ble_gatt_error *error,
|
struct ble_gatt_attr *attr,
|
void *arg)
|
{
|
APP_LOG_INFO("Subscribe complete; status=%d conn_handle=%d " "attr_handle=%d\n",
|
error->status, conn_handle, attr->handle);
|
|
return 0;
|
}
|
|
/**
|
* Performs three concurrent GATT operations against the specified peer:
|
* 1. Reads the ANS Supported New Alert Category characteristic.
|
* 2. Writes the ANS Alert Notification Control Point characteristic.
|
* 3. Subscribes to notifications for the ANS Unread Alert Status
|
* characteristic.
|
*
|
* If the peer does not support a required service, characteristic, or
|
* descriptor, then the peer lied when it claimed support for the alert
|
* notification service! When this happens, or if a GATT procedure fails,
|
* this function immediately terminates the connection.
|
*/
|
static void app_ble_read_write_subscribe(const struct peer *peer)
|
{
|
const struct peer_chr *chr;
|
const struct peer_dsc *dsc;
|
uint8_t value[2];
|
int rc;
|
|
/* Get characteristic of user specific. */
|
chr = peer_chr_find_uuid(peer,
|
BLE_UUID16_DECLARE(BLE_SVC_HRS_UUID16),
|
BLE_UUID16_DECLARE(BLE_SVC_HRS_CHR_UUID16_MEASUREMENT));
|
if (chr == NULL) {
|
APP_LOG_WRN("Peer doesn't support the user specific characteristic\n");
|
goto err;
|
}
|
|
/* Read characteristic data. */
|
rc = ble_gattc_read(peer->conn_handle, chr->chr.val_handle,
|
app_ble_on_read, NULL);
|
if (rc != 0) {
|
APP_LOG_WRN("Failed to read characteristic; rc=%d\n", rc);
|
goto err;
|
}
|
|
/* Write characteristic data. */
|
memset(value, 0, sizeof(value));
|
rc = ble_gattc_write_flat(peer->conn_handle, chr->chr.val_handle,
|
value, sizeof value, app_ble_on_write, NULL);
|
if (rc != 0) {
|
APP_LOG_WRN("Failed to write characteristic; rc=%d\n", rc);
|
}
|
|
/* Get CCCD of user specific. */
|
dsc = peer_dsc_find_uuid(peer,
|
BLE_UUID16_DECLARE(BLE_SVC_HRS_UUID16),
|
BLE_UUID16_DECLARE(BLE_SVC_HRS_CHR_UUID16_MEASUREMENT),
|
BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16));
|
if (dsc == NULL) {
|
APP_LOG_WRN("Peer doesn't support the user specific CCCD\n");
|
goto err;
|
}
|
|
/* Subscribe notify. */
|
Uint16ToBytes(value, 0x0001);
|
rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle,
|
value, sizeof value, app_ble_on_subscribe, NULL);
|
if (rc != 0) {
|
APP_LOG_WRN("Failed to subscribe to characteristic; rc=%d\n", rc);
|
goto err;
|
}
|
|
return;
|
|
err:
|
#if 0
|
APP_LOG_WRN("Chr read write err - disconnect\r\n");
|
/* Terminate the connection. */
|
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
#else
|
APP_LOG("\n");
|
#endif
|
}
|
|
static void app_ble_sdp_complete_cb(const struct peer *peer, int status, void *arg)
|
{
|
if (status != 0) {
|
/* Service discovery failed. Terminate the connection. */
|
APP_LOG_WRN("Service discovery failed; status=%d conn_handle=%d\n", status, peer->conn_handle);
|
APP_LOG_INFO("Send disconnect cmd \r\n");
|
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
return;
|
}
|
|
/* Service discovery has completed successfully. Now we have a complete
|
* list of services, characteristics, and descriptors that the peer
|
* supports.
|
*/
|
APP_LOG_INFO("Service discovery complete; status=%d conn_handle=%d\n", status, peer->conn_handle);
|
|
/* Now perform three concurrent GATT procedures against the peer: read,
|
* write, and subscribe to notifications.
|
*/
|
app_ble_read_write_subscribe(peer);
|
}
|
|
struct queue //½á¹¹ÌåÀàÐÍ
|
{
|
uint8_t totalnum;//»ùÕ¾×ÜÊý
|
uint8_t flag_newanchor[anchor_max_num];//ÐÂÀÏ»ùÕ¾±íʾ
|
uint16_t id[anchor_max_num]; /*ID*/
|
uint16_t time[anchor_max_num]; /*ʱ¼ä*/
|
uint16_t fail_num[anchor_max_num]; //uwb½ÓÊÜʧ°ÜµÄ´ÎÊý
|
uint16_t rssi[anchor_max_num];//À¶ÑÀ²â³öµÄ¾àÀë
|
uint8_t uwb_tongxun_flag[anchor_max_num];//ÓëuwbͨѶ³É¹¦Ê§°ÜµÄ±ê־λ
|
uint16_t u16id[anchor_max_num]; /*u16ID*/
|
}blequeue;
|
static char ble_anchor_name[20]="HFGD_XB";
|
uint16_t u16ble_id_fen[30];
|
uint8_t u16ble_id_fen1[50];
|
uint16_t rssidata;
|
uint8_t a;
|
void print_adv_fields(const struct ble_hs_adv_fields *fields,const struct ble_gap_disc_desc *disc)
|
{
|
char s[BLE_HS_ADV_MAX_SZ];
|
char mac[100];
|
const uint8_t *u8p;
|
int i;
|
uint16_t ble_id=0;
|
uint16_t rssi=0;
|
uint8_t repeat_flag=0;
|
uint8_t ble_id_fen[2];
|
|
if (fields->name != NULL)
|
{
|
assert(fields->name_len < sizeof s - 1);
|
memcpy(s, fields->name, fields->name_len);
|
|
if(!memcmp(s,ble_anchor_name,fields->name_len))
|
{
|
// memcpy(mac, fields->public_tgt_addr, fields->num_public_tgt_addrs);
|
// s[fields->name_len] = '\0';
|
// printf(" name(complete)=%s\n",
|
// s);
|
/*²âÊÔģʽ
|
rssidata=rssidata+abs(disc->rssi);
|
a++;
|
if(a==10)
|
{
|
printf(" name(complete)=%s\n",
|
s);
|
printf("RSSI:%d\r\n",rssidata/10);
|
a=0;
|
rssidata=0;
|
}
|
*/
|
// printf("\n");
|
// uart_data_send(&UART0_OBJ, mac,fields->num_public_tgt_addrs);
|
// printf("\n");
|
// memset(mac,0,100);
|
// ble_id_fen[0]=fields->svc_data_uuid16[1];
|
// ble_id_fen[1]=fields->svc_data_uuid16[0];
|
// u16ble_id_fen[0]=fields->svc_data_uuid16[1];
|
// u16ble_id_fen[1]=fields->svc_data_uuid16[0];
|
|
memcpy(&ble_id,&disc->addr.val[0],2);//´ÓɨÃèµÄÊý¾ÝÖÐÄóöid
|
rssi=abs(disc->rssi);
|
for(i=0;i<anchor_max_num;i++) //УÑé½á¹¹ÌåÖÐÊÇ·ñÒѾÓÐidÐÅÏ¢
|
{
|
if(ble_id==blequeue.id[i])
|
{
|
repeat_flag=1;//ÒѾÓÐidÐÅÏ¢
|
break;
|
}
|
}
|
if(repeat_flag==1)
|
{
|
blequeue.id[i]=ble_id;
|
blequeue.rssi[i]=rssi;
|
blequeue.u16id[2*i]=u16ble_id_fen[0];
|
blequeue.u16id[2*i+1]=u16ble_id_fen[1];
|
blequeue.time[i]=0;
|
}
|
if(repeat_flag==0)
|
{
|
blequeue.id[blequeue.totalnum]=ble_id;//°ÑidÐÅϢдÈë¶ÓÁÐ
|
blequeue.u16id[2*blequeue.totalnum]=u16ble_id_fen[0];
|
blequeue.u16id[2*blequeue.totalnum+1]=u16ble_id_fen[1];
|
blequeue.rssi[blequeue.totalnum]=rssi;//°ÑrssiÐÅϢдÈë¶ÓÁÐ
|
blequeue.time[blequeue.totalnum]=0;
|
blequeue.totalnum++;
|
}
|
}
|
}
|
|
}
|
static int app_ble_central_gap_event_cb(struct ble_gap_event *event, void *arg)
|
{
|
struct ble_gap_conn_desc desc;
|
struct ble_hs_adv_fields fields;
|
int rc;
|
|
switch (event->type)
|
{
|
case BLE_GAP_EVENT_DISC:
|
rc = ble_hs_adv_parse_fields(&fields, event->disc.data, event->disc.length_data);
|
if (rc != 0) {
|
return 0;
|
}
|
print_adv_fields(&fields,&event->disc);
|
#if 0
|
APP_LOG_INFO("Device Found peer_addr_type:%d peer_addr: %s\r\n", event->disc.addr.type, addr_to_str(event->disc.addr.val));
|
#endif
|
|
app_ble_connect_create(&event->disc);
|
return 0;
|
|
case BLE_GAP_EVENT_CONNECT:
|
if(event->connect.status){
|
APP_LOG_WRN("Central Connection failed; status=%d\n", event->connect.status);
|
|
app_ble_scan_start();
|
break;
|
}
|
|
APP_LOG_INFO("Central Connection established \r\n");
|
|
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
app_assert(rc == 0);
|
APP_LOG("\t-peer_ota_addr:%s(at:%d)\r\n"
|
"\t-peer_id_addr:%s(at:%d)\r\n"
|
"\t-conn_intvl:%d us\r\n"
|
"\t-latency:%d\r\n"
|
"\t-to:%d ms\r\n",
|
addr_to_str(desc.peer_ota_addr.val),
|
desc.peer_ota_addr.type,
|
addr_to_str(desc.peer_id_addr.val),
|
desc.peer_id_addr.type,
|
desc.conn_itvl*1250,
|
desc.conn_latency,
|
desc.supervision_timeout*10);
|
|
#if 0
|
// start pair
|
rc = ble_gap_pair_initiate(event->connect.conn_handle);
|
if(rc != 0){
|
APP_LOG_WRN("start security failed - rc:%d\n", rc);
|
}
|
#endif
|
|
/* Remember peer. */
|
rc = peer_add(event->connect.conn_handle);
|
if (rc != 0) {
|
APP_LOG_ERR("Failed to add peer; rc=%d\n", rc);
|
return 0;
|
}
|
|
/* Perform service discovery(SDP). */
|
rc = peer_disc_all(event->connect.conn_handle, app_ble_sdp_complete_cb, NULL);
|
if (rc != 0) {
|
APP_LOG_ERR("Failed to discover services; rc=%d\n", rc);
|
return 0;
|
}
|
|
return 0;
|
|
case BLE_GAP_EVENT_DISCONNECT:
|
APP_LOG_INFO("disconnect; reason=0x%02x\n", (uint8_t)event->disconnect.reason);
|
|
/* Forget about peer. */
|
peer_delete(event->disconnect.conn.conn_handle);
|
|
/* Resume scanning. */
|
app_ble_scan_start();
|
|
return 0;
|
|
case BLE_GAP_EVENT_DISC_COMPLETE:
|
APP_LOG_INFO("discovery duration expires; reason=%d\n", event->disc_complete.reason);
|
return 0;
|
|
case BLE_GAP_EVENT_ENC_CHANGE:
|
/* Encryption has been enabled or disabled for this connection. */
|
APP_LOG_INFO("encryption change event; status=%d \r\n", event->enc_change.status);
|
return 0;
|
|
case BLE_GAP_EVENT_NOTIFY_RX:
|
/* Peer sent us a notification or indication. */
|
APP_LOG_INFO("received %s; conn_handle=%d,attr_handle=%d,attr_len=%d\n",
|
event->notify_rx.indication ? "indication" : "notification",
|
event->notify_rx.conn_handle,
|
event->notify_rx.attr_handle,
|
OS_MBUF_PKTLEN(event->notify_rx.om));
|
|
/* Attribute data is contained in event->notify_rx.attr_data. */
|
return 0;
|
|
case BLE_GAP_EVENT_MTU:
|
APP_LOG_INFO("mtu update event; conn_handle=%d cid=%d mtu=%d\n",
|
event->mtu.conn_handle,
|
event->mtu.channel_id,
|
event->mtu.value);
|
return 0;
|
|
case BLE_GAP_EVENT_REPEAT_PAIRING:
|
/* We already have a bond with the peer, but it is attempting to
|
* establish a new secure link. This app sacrifices security for
|
* convenience: just throw away the old bond and accept the new link.
|
*/
|
|
/* Delete the old bond. */
|
rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
|
app_assert(rc == 0);
|
ble_store_util_delete_peer(&desc.peer_id_addr);
|
|
/* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
|
* continue with the pairing operation.
|
*/
|
return BLE_GAP_REPEAT_PAIRING_RETRY;
|
|
default:
|
return 0;
|
}
|
|
return 0;
|
}
|
|
/*******************************************************************************
|
* Scan API
|
******************************************************************************/
|
static void app_ble_connect_create(const struct ble_gap_disc_desc *disc)
|
{
|
uint8_t own_addr_type;
|
int rc;
|
|
/*Filter adv by rssi*/
|
if (disc->rssi < -70){
|
return;
|
}
|
|
/* The device has to be advertising connectability. */
|
if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND &&
|
disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) {
|
return;
|
}
|
|
/* Check if device is match. */
|
#if APP_BLE_DEV_FLT_EN
|
if(!ble_dev_filt_is_match(disc)){
|
return;
|
}
|
#else
|
return;
|
#endif
|
|
/* Scanning must be stopped before a connection can be initiated. */
|
rc = ble_gap_disc_cancel();
|
if (rc != 0) {
|
APP_LOG_ERR("Failed to cancel scan; rc=%d\n", rc);
|
return;
|
}
|
|
/* Figure out address to use for connect (no privacy for now) */
|
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
if (rc != 0) {
|
APP_LOG_ERR("error determining address type; rc=%d\n", rc);
|
return;
|
}
|
|
/* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for timeout. */
|
rc = ble_gap_connect(own_addr_type, &disc->addr, 30000, NULL,
|
app_ble_central_gap_event_cb, NULL);
|
if (rc != 0) {
|
APP_LOG_ERR("Error: Failed to connect to device; addr_type=%d addr=%s\n; rc=%d",
|
disc->addr.type, addr_to_str(disc->addr.val), rc);
|
return;
|
}
|
}
|
|
void app_ble_scan_start(void)
|
{
|
uint8_t own_addr_type;
|
struct ble_gap_disc_params disc_params;
|
int rc;
|
|
/* get local id address type */
|
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
if (rc != 0) {
|
APP_LOG_ERR("error determining address type; rc=%d\n", rc);
|
return;
|
}
|
|
disc_params.filter_duplicates = 0;
|
disc_params.passive = 0;
|
disc_params.itvl = BLE_GAP_SCAN_ITVL_MS(1000);
|
disc_params.window = BLE_GAP_SCAN_ITVL_MS(1000);;
|
disc_params.filter_policy = 0;
|
disc_params.limited = 0;
|
|
rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params,
|
app_ble_central_gap_event_cb, NULL);
|
if (rc != 0) {
|
APP_LOG_ERR("Error initiating GAP discovery procedure; rc=%d\n", rc);
|
}
|
|
APP_LOG_INFO("Scan start...\r\n");
|
}
|
|
void app_ble_central_init(void)
|
{
|
/* SDP initialization */
|
int rc = peer_init(CONFIG_BT_MAX_NUM_OF_CENTRAL, 32, 32, 32);
|
app_assert(rc == 0);
|
|
/* BLE Device Filter initialization. */
|
#if APP_BLE_DEV_FLT_EN
|
ble_dev_filt_init();
|
|
// Set Filter RSSI
|
ble_dev_filt_set_rssi(-60);
|
|
// Set Filter Device Name
|
#if APP_FILT_DEV_NAME_EN
|
ble_dev_filt_set_device_name(APP_FILT_DEV_NAME, strlen(APP_FILT_DEV_NAME));
|
#endif
|
|
// Set Filter Device Address
|
#if APP_FILT_DEV_ADDR_EN
|
ble_dev_filt_add_addr((uint8_t[]){APP_FILT_DEV_ADDR}, APP_FILT_DEV_ADDR_LEN);
|
#endif
|
|
// Set Filter UUID16
|
#if APP_FILT_UUID16_EN
|
ble_dev_filt_set_uuid16(APP_FILT_UUID16);
|
#endif
|
#endif
|
}
|