mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-03 20:35:33 +02:00
feat(nimble): Base support for Channel sounding HCI command and events
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(blecent)
|
||||
@@ -0,0 +1,137 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
|
||||
|
||||
# BLE Central Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example creates GATT client and performs passive scan, it then connects to peripheral device if the device advertises connectability and the device advertises support for the Alert Notification service (0x1811) as primary service UUID.
|
||||
|
||||
After connection it enables bonding and link encryprion if the `Enable Link Encryption` flag is set in the example config.
|
||||
|
||||
It performs six GATT operations against the specified peer:
|
||||
|
||||
* Reads the ANS Supported New Alert Category characteristic.
|
||||
|
||||
* After the read operation is completed, writes the ANS Alert Notification Control Point characteristic.
|
||||
|
||||
* After the write operation is completed, subscribes to notifications for the ANS Unread Alert Status characteristic.
|
||||
|
||||
* After the subscribe operation is completed, it subscribes to notifications for a user defined characteristic.
|
||||
|
||||
* After this subscribe operation is completed, it writes to the user defined characteristic.
|
||||
|
||||
* After the write operation is completed, it reads from the user defined 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.
|
||||
|
||||
It uses ESP32's Bluetooth controller and NimBLE stack based BLE host.
|
||||
|
||||
This example aims at understanding BLE service discovery, connection, encryption and characteristic operations.
|
||||
|
||||
To test this demo, use any BLE GATT server app that advertises support for the Alert Notification service (0x1811) and includes it in the GATT database.
|
||||
|
||||
Note :
|
||||
|
||||
* To install the dependency packages needed, please refer to the top level [README file](../../../README.md#running-test-python-script-pytest).
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
```bash
|
||||
idf.py set-target <chip_name>
|
||||
```
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with ESP32/ESP32-C2/ESP32-C3/ESP32-S3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
|
||||
* A USB cable for Power supply and programming
|
||||
|
||||
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
|
||||
|
||||
### Configure the Project
|
||||
|
||||
Open the project configuration menu:
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
In the `Example Configuration` menu:
|
||||
|
||||
* Change the `Peer Address` option if needed.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
This is the console output on successful connection:
|
||||
|
||||
```
|
||||
I (202) BTDM_INIT: BT controller compile version [0b60040]
|
||||
I (202) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
W (212) phy_init: failed to load RF calibration data (0xffffffff), falling back to full calibration
|
||||
I (422) phy: phy_version: 4007, 9c6b43b, Jan 11 2019, 16:45:07, 0, 2
|
||||
I (722) NimBLE_BLE_CENT: BLE Host Task Started
|
||||
GAP procedure initiated: stop advertising.
|
||||
GAP procedure initiated: discovery; own_addr_type=0 filter_policy=0 passive=1 limited=0 filter_duplicates=1 duration=forever
|
||||
GAP procedure initiated: connect; peer_addr_type=1 peer_addr=xx:xx:xx:xx:xx:xx scan_itvl=16 scan_window=16 itvl_min=24 itvl_max=40 latency=0 supervision_timeout=256 min_ce_len=16 max_ce_len=768 own_addr_type=0
|
||||
Connection established
|
||||
Connection secured
|
||||
encryption change event; status=0
|
||||
GATT procedure initiated: discover all services
|
||||
GATT procedure initiated: discover all characteristics; start_handle=1 end_handle=3
|
||||
GATT procedure initiated: discover all characteristics; start_handle=20 end_handle=26
|
||||
GATT procedure initiated: discover all characteristics; start_handle=40 end_handle=65535
|
||||
GATT procedure initiated: discover all descriptors; chr_val_handle=42 end_handle=43
|
||||
GATT procedure initiated: discover all descriptors; chr_val_handle=49 end_handle=65535
|
||||
Service discovery complete; status=0 conn_handle=0
|
||||
GATT procedure initiated: read; att_handle=45
|
||||
GATT procedure initiated: write; att_handle=47 len=2
|
||||
GATT procedure initiated: write; att_handle=43 len=2
|
||||
Read complete; status=0 conn_handle=0 attr_handle=45 value=0x02
|
||||
Write complete; status=0 conn_handle=0 attr_handle=47
|
||||
Subscribe complete; status=0 conn_handle=0 attr_handle=43
|
||||
GATT procedure initiated: write; att_handle=26 len=2
|
||||
GATT procedure initiated: write; att_handle=25 len=1
|
||||
GATT procedure initiated: read; att_handle=25
|
||||
Subscribe to the custom subscribable characteristic complete; status=0 conn_handle=1 attr_handle=26 value=
|
||||
Write to the custom subscribable characteristic complete; status=0 conn_handle=1 attr_handle=25
|
||||
received notification; conn_handle=1 attr_handle=25 attr_len=4
|
||||
Read complete for the subscribable characteristic; status=0 conn_handle=1 attr_handle=25 value=0x19
|
||||
```
|
||||
|
||||
This is the console output on failure (or peripheral does not support New Alert Service category):
|
||||
|
||||
```
|
||||
I (180) BTDM_INIT: BT controller compile version [8e87ec7]
|
||||
I (180) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (250) phy: phy_version: 4000, b6198fa, Sep 3 2018, 15:11:06, 0, 0
|
||||
I (480) NimBLE_BLE_CENT: BLE Host Task Started
|
||||
GAP procedure initiated: stop advertising.
|
||||
GAP procedure initiated: discovery; own_addr_type=0 filter_policy=0 passive=1 limited=0 filter_duplicates=1 duration=forever
|
||||
GAP procedure initiated: connect; peer_addr_type=1 peer_addr=xx:xx:xx:xx:xx:xx scan_itvl=16 scan_window=16 itvl_min=24 itvl_max=40 latency=0 supervision_timeout=256 min_ce_len=16 max_ce_len=768 own_addr_type=0
|
||||
Connection established
|
||||
GATT procedure initiated: discover all services
|
||||
GATT procedure initiated: discover all characteristics; start_handle=1 end_handle=3
|
||||
GATT procedure initiated: discover all characteristics; start_handle=20 end_handle=26
|
||||
GATT procedure initiated: discover all characteristics; start_handle=40 end_handle=65535
|
||||
GATT procedure initiated: discover all descriptors; chr_val_handle=42 end_handle=43
|
||||
GATT procedure initiated: discover all descriptors; chr_val_handle=47 end_handle=65535
|
||||
Service discovery complete; status=0 conn_handle=0
|
||||
Error: Peer doesn't support the Supported New Alert Category characteristic
|
||||
GAP procedure initiated: terminate connection; conn_handle=0 hci_reason=19
|
||||
disconnect; reason=534
|
||||
```
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
||||
@@ -0,0 +1,4 @@
|
||||
set(srcs "main.c")
|
||||
|
||||
idf_component_register(SRCS "gatt_svr.c" "${srcs}"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,39 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_PEER_ADDR
|
||||
string "Peer Address"
|
||||
default "ADDR_ANY"
|
||||
help
|
||||
Enter the peer address in aa:bb:cc:dd:ee:ff form to connect to a specific peripheral
|
||||
|
||||
config EXAMPLE_EXTENDED_ADV
|
||||
bool
|
||||
depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT
|
||||
default y if SOC_ESP_NIMBLE_CONTROLLER
|
||||
select BT_NIMBLE_EXT_ADV
|
||||
prompt "Enable Extended Adv"
|
||||
help
|
||||
Use this option to enable extended advertising in the example.
|
||||
If this option is disabled, ensure config BT_NIMBLE_EXT_ADV is
|
||||
also disabled from Nimble stack menuconfig
|
||||
|
||||
config EXAMPLE_INIT_DEINIT_LOOP
|
||||
bool
|
||||
prompt "Perform init deinit of nimble stack in a loop"
|
||||
help
|
||||
Enable this flag, to perform only stack Init and Deinit in a loop.
|
||||
|
||||
config EXAMPLE_ENCRYPTION
|
||||
bool
|
||||
prompt "Enable Link Encryption"
|
||||
help
|
||||
This enables bonding and encryption after connection has been established.
|
||||
|
||||
config EXAMPLE_USE_CI_ADDRESS
|
||||
bool
|
||||
default n
|
||||
prompt "Advertise using Test address(Internal Test ONLY)"
|
||||
help
|
||||
Used for internal test ONLY.
|
||||
Use this option to advertise in a specific random address.
|
||||
endmenu
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLECENT_
|
||||
#define H_BLECENT_
|
||||
|
||||
#include "modlog/modlog.h"
|
||||
#include "esp_central.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ble_hs_adv_fields;
|
||||
struct ble_gap_conn_desc;
|
||||
struct ble_hs_cfg;
|
||||
union ble_store_value;
|
||||
union ble_store_key;
|
||||
|
||||
#define BLECENT_SVC_ALERT_UUID 0x1811
|
||||
#define BLECENT_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47
|
||||
#define BLECENT_CHR_NEW_ALERT 0x2A46
|
||||
#define BLECENT_CHR_SUP_UNR_ALERT_CAT_UUID 0x2A48
|
||||
#define BLECENT_CHR_UNR_ALERT_STAT_UUID 0x2A45
|
||||
#define BLECENT_CHR_ALERT_NOT_CTRL_PT 0x2A44
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLEHR_SENSOR_
|
||||
#define H_BLEHR_SENSOR_
|
||||
|
||||
#include "nimble/ble.h"
|
||||
#include "modlog/modlog.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Heart-rate configuration */
|
||||
#define GATT_HRS_UUID 0x180D
|
||||
#define GATT_HRS_MEASUREMENT_UUID 0x2A37
|
||||
#define GATT_HRS_BODY_SENSOR_LOC_UUID 0x2A38
|
||||
#define GATT_DEVICE_INFO_UUID 0x180A
|
||||
#define GATT_MANUFACTURER_NAME_UUID 0x2A29
|
||||
#define GATT_MODEL_NUMBER_UUID 0x2A24
|
||||
|
||||
|
||||
#define BLE_UUID_RANGING_SERVICE_VAL (0x185B)
|
||||
|
||||
/** @brief UUID of the RAS Features Characteristic. **/
|
||||
#define BLE_UUID_RAS_FEATURES_VAL (0x2C14)
|
||||
|
||||
/** @brief UUID of the Real-time Ranging Data Characteristic. **/
|
||||
#define BLE_UUID_RAS_REALTIME_RD_VAL (0x2C15)
|
||||
|
||||
/** @brief UUID of the On-demand Ranging Data Characteristic. **/
|
||||
#define BLE_UUID_RAS_ONDEMAND_RD_VAL (0x2C16)
|
||||
|
||||
/** @brief UUID of the RAS Control Point Characteristic. **/
|
||||
#define BLE_UUID_RAS_CP_VAL (0x2C17)
|
||||
|
||||
/** @brief UUID of the Ranging Data Ready Characteristic. **/
|
||||
#define BLE_UUID_RAS_RD_READY_VAL (0x2C18)
|
||||
|
||||
/** @brief UUID of the Ranging Data Overwritten Characteristic. **/
|
||||
#define BLE_UUID_RAS_RD_OVERWRITTEN_VAL (0x2C19)
|
||||
|
||||
|
||||
extern uint16_t hrs_hrm_handle;
|
||||
|
||||
struct ble_hs_cfg;
|
||||
struct ble_gatt_register_ctxt;
|
||||
|
||||
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
int gatt_svr_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
#include "blehr_sens.h"
|
||||
|
||||
static const char *manuf_name = "Apache Mynewt ESP32 devkitC";
|
||||
static const char *model_num = "Mynewt RAS Service";
|
||||
|
||||
static uint8_t ras_feat_val;
|
||||
static uint16_t ras_feat_val_handle;
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_ras_val(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
||||
{
|
||||
/* Service: Ranging Data Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RANGING_SERVICE_VAL),
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{ {
|
||||
/* Characteristic: Feature Value */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_FEATURES_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.val_handle = &ras_feat_val_handle,
|
||||
.flags = BLE_GATT_CHR_F_READ|BLE_GATT_CHR_F_READ_ENC,
|
||||
},{
|
||||
/* Characteristic: On demand ranging data */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_ONDEMAND_RD_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE |BLE_GATT_CHR_F_READ_ENC
|
||||
,
|
||||
},{
|
||||
/* Characteristic: RAS Control Point */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_CP_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_INDICATE |BLE_GATT_CHR_F_READ_ENC ,
|
||||
},{
|
||||
/* Characteristic: RAS Data Ready */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_RD_READY_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_READ_ENC,
|
||||
},{
|
||||
/* Characteristic: RAS data overwritten */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_RD_OVERWRITTEN_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_READ_ENC,
|
||||
},{
|
||||
0, /* No more characteristics in this service */
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
0, /* No more services */
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_ras_val(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
const ble_uuid_t *uuid;
|
||||
int rc;
|
||||
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
MODLOG_DFLT(INFO, "Characteristic read; conn_handle=%d attr_handle=%d\n",
|
||||
conn_handle, attr_handle);
|
||||
} else {
|
||||
MODLOG_DFLT(INFO, "Characteristic read by NimBLE stack; attr_handle=%d\n",
|
||||
attr_handle);
|
||||
}
|
||||
uuid = ctxt->chr->uuid;
|
||||
if(uuid == BLE_UUID_RAS_FEATURES_VAL){
|
||||
if (attr_handle == ras_feat_val_handle) {
|
||||
rc = os_mbuf_append(ctxt->om,
|
||||
&ras_feat_val,
|
||||
sizeof(ras_feat_val));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
}
|
||||
goto unknown;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
MODLOG_DFLT(INFO, "Characteristic write; conn_handle=%d attr_handle=%d",
|
||||
conn_handle, attr_handle);
|
||||
} else {
|
||||
MODLOG_DFLT(INFO, "Characteristic write by NimBLE stack; attr_handle=%d",
|
||||
attr_handle);
|
||||
}
|
||||
return 0;
|
||||
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
|
||||
unknown:
|
||||
/* Unknown characteristic/descriptor;
|
||||
* The NimBLE host should not have called this function;
|
||||
*/
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_REGISTER_OP_SVC:
|
||||
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
|
||||
ctxt->svc.handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_CHR:
|
||||
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
|
||||
"def_handle=%d val_handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||
ctxt->chr.def_handle,
|
||||
ctxt->chr.val_handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_DSC:
|
||||
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
|
||||
ctxt->dsc.handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gatt_svr_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
nimble_central_utils:
|
||||
path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils
|
||||
@@ -0,0 +1,998 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
/* BLE */
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_cs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "console/console.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/hid/ble_svc_hid.h"
|
||||
#include "services/ras/ble_svc_ras.h"
|
||||
#include "blecent.h"
|
||||
|
||||
//#include "services/ras/src/rreq/ble_svc_ras_rreq.c"
|
||||
|
||||
#if CONFIG_EXAMPLE_USE_CI_ADDRESS
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define TEST_CI_ADDRESS_CHIP_OFFSET (0)
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2
|
||||
#define TEST_CI_ADDRESS_CHIP_OFFSET (1)
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define TEST_CI_ADDRESS_CHIP_OFFSET (2)
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||
#define TEST_CI_ADDRESS_CHIP_OFFSET (3)
|
||||
#elif CONFIG_IDF_TARGET_ESP32C5
|
||||
#define TEST_CI_ADDRESS_CHIP_OFFSET (4)
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#define TEST_CI_ADDRESS_CHIP_OFFSET (5)
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#define TEST_CI_ADDRESS_CHIP_OFFSET (6)
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define TEST_CI_ADDRESS_CHIP_OFFSET (7)
|
||||
#elif CONFIG_IDF_TARGET_ESP32C61
|
||||
#define TEST_CI_ADDRESS_CHIP_OFFSET (8)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define BLE_UUID_RANGING_SERVICE_VAL (0x185B)
|
||||
|
||||
/** @brief UUID of the RAS Features Characteristic. **/
|
||||
#define BLE_UUID_RAS_FEATURES_VAL (0x2C14)
|
||||
|
||||
/** @brief UUID of the Real-time Ranging Data Characteristic. **/
|
||||
#define BLE_UUID_RAS_REALTIME_RD_VAL (0x2C15)
|
||||
|
||||
/** @brief UUID of the On-demand Ranging Data Characteristic. **/
|
||||
#define BLE_UUID_RAS_ONDEMAND_RD_VAL (0x2C16)
|
||||
|
||||
/** @brief UUID of the RAS Control Point Characteristic. **/
|
||||
#define BLE_UUID_RAS_CP_VAL (0x2C17)
|
||||
|
||||
/** @brief UUID of the Ranging Data Ready Characteristic. **/
|
||||
#define BLE_UUID_RAS_RD_READY_VAL (0x2C18)
|
||||
|
||||
/** @brief UUID of the Ranging Data Overwritten Characteristic. **/
|
||||
#define BLE_UUID_RAS_RD_OVERWRITTEN_VAL (0x2C19)
|
||||
|
||||
|
||||
/*** The UUID of the service containing the subscribable characteristic ***/
|
||||
static const ble_uuid_t * remote_svc_uuid =
|
||||
BLE_UUID128_DECLARE(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
|
||||
0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59);
|
||||
|
||||
/*** The UUID of the subscribable chatacteristic ***/
|
||||
static const ble_uuid_t * remote_chr_uuid =
|
||||
BLE_UUID128_DECLARE(0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,
|
||||
0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33);
|
||||
|
||||
static const char *tag = "NimBLE_RAS_INITIATOR";
|
||||
static int blecent_gap_event(struct ble_gap_event *event, void *arg);
|
||||
static uint8_t peer_addr[6];
|
||||
|
||||
|
||||
void ble_store_config_init(void);
|
||||
|
||||
static uint8_t connh;
|
||||
static uint16_t ble_svc_ras_feat_val_handle;
|
||||
static uint16_t ble_svc_ras_rd_val_handle;
|
||||
static uint16_t ble_svc_ras_rd_ov_val_handle;
|
||||
static uint16_t ble_svc_ras_cp_val_handle;
|
||||
static uint16_t ble_svc_ras_od_val_handle;
|
||||
|
||||
static int32_t most_recent_peer_ranging_counter = -1;
|
||||
static int32_t most_recent_local_ranging_counter= -1 ;
|
||||
static int32_t dropped_ranging_counter = -1;
|
||||
static void
|
||||
blecent_on_disc_complete(const struct peer *peer, int status, void *arg);
|
||||
int blecent_on_subscribe(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
struct peer *peer;
|
||||
MODLOG_DFLT(INFO, "Subscribe complete; status=%d conn_handle=%d "
|
||||
"attr_handle=%d\n",
|
||||
error->status, conn_handle, attr->handle);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int
|
||||
blecent_on_custom_read(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
MODLOG_DFLT(INFO,
|
||||
"Read complete for the subscribable characteristic; "
|
||||
"status=%d conn_handle=%d", error->status, conn_handle);
|
||||
int rc=0;
|
||||
extern void bt_hci_log_hci_data_show(void);
|
||||
bt_hci_log_hci_data_show();
|
||||
if (error->status == 0) {
|
||||
MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle);
|
||||
print_mbuf(attr->om);
|
||||
extern void bt_hci_log_hci_adv_show(void);
|
||||
|
||||
//extern void bt_hci_log_hci_data_show(void);
|
||||
bt_hci_log_hci_data_show();
|
||||
//bt_hci_log_hci_adv_show();
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if(error->status==261){
|
||||
// MODLOG_DFLT(INFO, "Error: Insufficient authentication to read the characteristic\n");
|
||||
// printf("Error: Insufficient authentication to read the characteristic\n");
|
||||
// rc = ble_gap_security_initiate(connh);
|
||||
|
||||
// if (rc != 0) {
|
||||
// MODLOG_DFLT(INFO, "Security could not be initiated, rc = %d\n", rc);
|
||||
// return ble_gap_terminate(connh,
|
||||
// BLE_ERR_REM_USER_CONN_TERM);
|
||||
// }
|
||||
|
||||
// rc = peer_disc_all(connh,
|
||||
// blecent_on_disc_complete, NULL);
|
||||
// if(rc != 0) {
|
||||
// MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
|
||||
// return 0;
|
||||
// }
|
||||
// vTaskDelay(1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int ble_chan_ras_subsribe_by_uuid(ble_uuid_t *char_uuid,const struct peer *peer, uint8_t conn_handle)
|
||||
{
|
||||
int rc;
|
||||
int value[2];
|
||||
const struct peer_dsc *dsc;
|
||||
dsc = peer_dsc_find_uuid(peer,
|
||||
BLE_UUID16_DECLARE(BLE_UUID_RANGING_SERVICE_VAL),
|
||||
char_uuid,
|
||||
BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16));
|
||||
if (dsc == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error: Peer lacks a CCCD for RAS Feature characteristic\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
value[0] = 1;
|
||||
value[1] = 0;
|
||||
rc = ble_gattc_write_flat(conn_handle, dsc->dsc.handle,
|
||||
value, sizeof value, blecent_on_subscribe, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to subscribe to characteristic ,rc=%d\n", rc);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ble_chan_ras_subscribe(const struct peer *peer, uint8_t conn_handle)
|
||||
{
|
||||
|
||||
int rc;
|
||||
/* Read the supported-new-alert-category characteristic. */
|
||||
const struct peer_svc* svc = peer_svc_find_uuid(peer,BLE_UUID16_DECLARE(BLE_UUID_RANGING_SERVICE_VAL));
|
||||
if (svc == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the RAS \n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
// subscribe the on demad ranging data char
|
||||
rc = ble_chan_ras_subsribe_by_uuid(BLE_UUID16_DECLARE(BLE_UUID_RAS_ONDEMAND_RD_VAL),peer,conn_handle);
|
||||
|
||||
if(rc!=0){
|
||||
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the RAS on demand raging data or fail to subscribe \n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
// control point char
|
||||
rc = ble_chan_ras_subsribe_by_uuid(BLE_UUID16_DECLARE(BLE_UUID_RAS_CP_VAL),peer,conn_handle);
|
||||
|
||||
if(rc!=0){
|
||||
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the RAS CP or fail to subscribe \n");
|
||||
goto err;
|
||||
}else{
|
||||
MODLOG_DFLT(INFO, "Subscribed to the RAS Control Point characteristic\n");
|
||||
}
|
||||
|
||||
|
||||
rc = ble_chan_ras_subsribe_by_uuid(BLE_UUID16_DECLARE(BLE_UUID_RAS_RD_READY_VAL),peer,conn_handle);
|
||||
|
||||
if(rc!=0){
|
||||
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the RAS Data Ready or fail to subscribe \n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
rc = ble_chan_ras_subsribe_by_uuid(BLE_UUID16_DECLARE(BLE_UUID_RAS_RD_OVERWRITTEN_VAL),peer,conn_handle);
|
||||
|
||||
if(rc!=0){
|
||||
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the RAS Data overwritten or fail to subscribe \n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = ble_gattc_read(conn_handle, ble_svc_ras_cp_val_handle,
|
||||
blecent_on_custom_read, NULL);
|
||||
rc = ble_gattc_read(conn_handle, ble_svc_ras_feat_val_handle,
|
||||
blecent_on_custom_read, NULL);
|
||||
rc = ble_gattc_read(conn_handle, ble_svc_ras_rd_val_handle,
|
||||
blecent_on_custom_read, NULL);
|
||||
rc = ble_gattc_read(conn_handle, ble_svc_ras_rd_ov_val_handle,
|
||||
blecent_on_custom_read, NULL);
|
||||
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to read the custom subscribable characteristic; ""rc=%d\n", rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return ;
|
||||
|
||||
err:
|
||||
/* Terminate the connection. */
|
||||
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
/**
|
||||
* Application callback. Called when the attempt to subscribe to notifications
|
||||
* for the ANS Unread Alert Status characteristic has completed.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Called when service discovery of the specified peer has completed.
|
||||
*/
|
||||
static void
|
||||
blecent_on_disc_complete(const struct peer *peer, int status, void *arg)
|
||||
{
|
||||
|
||||
if (status != 0) {
|
||||
/* Service discovery failed. Terminate the connection. */
|
||||
MODLOG_DFLT(ERROR, "Error: Service discovery failed; status=%d "
|
||||
"conn_handle=%d\n", status, peer->conn_handle);
|
||||
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.
|
||||
*/
|
||||
MODLOG_DFLT(INFO, "Service discovery complete; status=%d "
|
||||
"conn_handle=%d\n", status, peer->conn_handle);
|
||||
|
||||
struct peer_chr * chr = peer_chr_find_uuid(peer,BLE_UUID16_DECLARE(BLE_UUID_RANGING_SERVICE_VAL),BLE_UUID16_DECLARE(BLE_UUID_RAS_CP_VAL));
|
||||
if(chr == NULL){
|
||||
MODLOG_DFLT(ERROR, "Error: Peer lacks the RAS Control Point characteristic\n");
|
||||
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return;
|
||||
}
|
||||
|
||||
ble_svc_ras_cp_val_handle = chr->chr.val_handle;
|
||||
|
||||
chr = peer_chr_find_uuid(peer,BLE_UUID16_DECLARE(BLE_UUID_RANGING_SERVICE_VAL),BLE_UUID16_DECLARE(BLE_UUID_RAS_RD_READY_VAL));
|
||||
if(chr == NULL){
|
||||
MODLOG_DFLT(ERROR, "Error: Peer lacks the RAS Data Ready characteristic\n");
|
||||
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return;
|
||||
}
|
||||
ble_svc_ras_rd_val_handle = chr->chr.val_handle;
|
||||
|
||||
chr = peer_chr_find_uuid(peer,BLE_UUID16_DECLARE(BLE_UUID_RANGING_SERVICE_VAL),BLE_UUID16_DECLARE(BLE_UUID_RAS_RD_OVERWRITTEN_VAL));
|
||||
if(chr == NULL){
|
||||
MODLOG_DFLT(ERROR, "Error: Peer lacks the RAS Data Overwritten characteristic\n");
|
||||
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return;
|
||||
}
|
||||
ble_svc_ras_rd_ov_val_handle = chr->chr.val_handle;
|
||||
|
||||
chr = peer_chr_find_uuid(peer,BLE_UUID16_DECLARE(BLE_UUID_RANGING_SERVICE_VAL),BLE_UUID16_DECLARE(BLE_UUID_RAS_FEATURES_VAL));
|
||||
if(chr == NULL){
|
||||
MODLOG_DFLT(ERROR, "Error: Peer lacks the RAS Feature characteristic\n");
|
||||
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return;
|
||||
}
|
||||
ble_svc_ras_feat_val_handle = chr->chr.val_handle;
|
||||
|
||||
chr = peer_chr_find_uuid(peer,BLE_UUID16_DECLARE(BLE_UUID_RANGING_SERVICE_VAL),BLE_UUID16_DECLARE(BLE_UUID_RAS_ONDEMAND_RD_VAL));
|
||||
if(chr == NULL){
|
||||
MODLOG_DFLT(ERROR, "Error: Peer lacks the RAS On Demand Ranging Data characteristic\n");
|
||||
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return;
|
||||
}
|
||||
ble_svc_ras_od_val_handle = chr->chr.val_handle;
|
||||
|
||||
|
||||
ble_chan_ras_subscribe(peer,peer->conn_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the GAP general discovery procedure.
|
||||
*/
|
||||
static void
|
||||
blecent_scan(void)
|
||||
{
|
||||
uint8_t own_addr_type;
|
||||
struct ble_gap_disc_params disc_params;
|
||||
int rc;
|
||||
|
||||
/* Figure out address to use while advertising (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Tell the controller to filter duplicates; we don't want to process
|
||||
* repeated advertisements from the same device.
|
||||
*/
|
||||
disc_params.filter_duplicates = 1;
|
||||
|
||||
/**
|
||||
* Perform a passive scan. I.e., don't send follow-up scan requests to
|
||||
* each advertiser.
|
||||
*/
|
||||
disc_params.passive = 1;
|
||||
|
||||
/* Use defaults for the rest of the parameters. */
|
||||
disc_params.itvl = 0;
|
||||
disc_params.window = 0;
|
||||
disc_params.filter_policy = 0;
|
||||
disc_params.limited = 0;
|
||||
|
||||
rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params,
|
||||
blecent_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error initiating GAP discovery procedure; rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether we should try to connect to the sender of the specified
|
||||
* advertisement. The function returns a positive result if the device
|
||||
* advertises connectability and support for the Alert Notification service.
|
||||
*/
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
static int
|
||||
ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc)
|
||||
{
|
||||
int offset = 0;
|
||||
int ad_struct_len = 0;
|
||||
#if CONFIG_EXAMPLE_USE_CI_ADDRESS
|
||||
uint32_t *addr_offset;
|
||||
#endif // CONFIG_EXAMPLE_USE_CI_ADDRESS
|
||||
|
||||
if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND &&
|
||||
disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) {
|
||||
return 0;
|
||||
}
|
||||
if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen ("ADDR_ANY")) != 0)) {
|
||||
#if !CONFIG_EXAMPLE_USE_CI_ADDRESS
|
||||
ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR);
|
||||
/* Convert string to address */
|
||||
sscanf(CONFIG_EXAMPLE_PEER_ADDR, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
||||
&peer_addr[5], &peer_addr[4], &peer_addr[3],
|
||||
&peer_addr[2], &peer_addr[1], &peer_addr[0]);
|
||||
#else
|
||||
addr_offset = (uint32_t *)&peer_addr[1];
|
||||
*addr_offset = atoi(CONFIG_EXAMPLE_PEER_ADDR);
|
||||
peer_addr[5] = 0xC3;
|
||||
peer_addr[0] = TEST_CI_ADDRESS_CHIP_OFFSET;
|
||||
#endif // !CONFIG_EXAMPLE_USE_CI_ADDRESS
|
||||
if (memcmp(peer_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* The device has to advertise support for the Alert Notification
|
||||
* service (0x1811).
|
||||
*/
|
||||
do {
|
||||
ad_struct_len = disc->data[offset];
|
||||
|
||||
if (!ad_struct_len) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Search if ANS UUID is advertised */
|
||||
if (disc->data[offset] == 0x03 && disc->data[offset + 1] == 0x03) {
|
||||
if ( disc->data[offset + 2] == 0x18 && disc->data[offset + 3] == 0x11 ) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
offset += ad_struct_len + 1;
|
||||
|
||||
} while ( offset < disc->length_data );
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
blecent_should_connect(const struct ble_gap_disc_desc *disc)
|
||||
{
|
||||
struct ble_hs_adv_fields fields;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
|
||||
/* 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 0;
|
||||
}
|
||||
|
||||
rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data);
|
||||
if (rc != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Connects to the sender of the specified advertisement of it looks
|
||||
* interesting. A device is "interesting" if it advertises connectability and
|
||||
* support for the Alert Notification service.
|
||||
*/
|
||||
static void
|
||||
blecent_connect_if_interesting(void *disc)
|
||||
{
|
||||
uint8_t own_addr_type;
|
||||
int rc;
|
||||
ble_addr_t *addr;
|
||||
|
||||
/* Don't do anything if we don't care about this advertiser. */
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
if (!ext_blecent_should_connect((struct ble_gap_ext_disc_desc *)disc)) {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (!blecent_should_connect((struct ble_gap_disc_desc *)disc)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN))
|
||||
/* Scanning must be stopped before a connection can be initiated. */
|
||||
rc = ble_gap_disc_cancel();
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(DEBUG, "Failed to cancel scan; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Figure out address to use for connect (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
||||
* timeout.
|
||||
*/
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
addr = &((struct ble_gap_ext_disc_desc *)disc)->addr;
|
||||
#else
|
||||
addr = &((struct ble_gap_disc_desc *)disc)->addr;
|
||||
#endif
|
||||
|
||||
rc = ble_gap_connect(own_addr_type, addr, 30000, NULL,
|
||||
blecent_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d "
|
||||
"addr=%s; rc=%d\n",
|
||||
addr->type, addr_str(addr->val), rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#define BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_COMPLETE 0x0
|
||||
#define BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_PARTIAL 0x1
|
||||
#define BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_ABORTED 0xF
|
||||
|
||||
#define LOCAL_PROCEDURE_MEM 1024 // Replace with an appropriate constant value
|
||||
|
||||
|
||||
static struct cs_steps_data local_cs_steps_data[LOCAL_PROCEDURE_MEM];
|
||||
static struct cs_steps_data peer_cs_steps_data[BLE_RAS_PROCEDURE_MEM];
|
||||
static uint8_t nap;
|
||||
|
||||
static int blecs_gap_event(struct ble_cs_event *event, void *arg){
|
||||
int rc=0;
|
||||
rc = peer_disc_all(connh,
|
||||
blecent_on_disc_complete, NULL);
|
||||
if(rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(event->type){
|
||||
case BLE_CS_EVENT_CS_PROCEDURE_COMPLETE:
|
||||
printf("LE CS Procedure Complete , procedure counter");
|
||||
break;
|
||||
case BLE_CS_EVENT_SUBEVET_RESULT:
|
||||
MODLOG_DFLT(INFO, "LE CS Subevent Result , procedure counter: %d\n", event->subev_result.procedure_counter);
|
||||
|
||||
if(event->subev_result.subevent_done_status == BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_ABORTED){
|
||||
MODLOG_DFLT(INFO, "LE CS Subevent Result , status: Aborted\n");
|
||||
dropped_ranging_counter=event->subev_result.procedure_counter;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(dropped_ranging_counter==event->subev_result.procedure_counter){
|
||||
MODLOG_DFLT(INFO, "Ranging procedure was aborted\n");
|
||||
return 0;
|
||||
}
|
||||
if(event->subev_result.num_steps_reported){
|
||||
memcpy(&local_cs_steps_data, event->subev_result.steps, sizeof local_cs_steps_data);
|
||||
|
||||
}
|
||||
nap=event->subev_result.num_antenna_paths;
|
||||
|
||||
if(event->subev_result.procedure_done_status == BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_COMPLETE){
|
||||
most_recent_local_ranging_counter=event->subev_result.procedure_counter;
|
||||
}
|
||||
else if(event->subev_result.procedure_done_status == BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_ABORTED){
|
||||
MODLOG_DFLT(INFO, "LE CS Procedure , status: Aborted\n");
|
||||
memset(&local_cs_steps_data,0,sizeof local_cs_steps_data);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BLE_CS_EVENT_SUBEVET_RESULT_CONTINUE:
|
||||
printf("LE CS Subevent Result Continue , procedure counter:");
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* The nimble host executes this callback when a GAP event occurs. The
|
||||
* application associates a GAP event callback with each connection that is
|
||||
* established. blecent uses the same callback for all connections.
|
||||
*
|
||||
* @param event The event being signalled.
|
||||
* @param arg Application-specified argument; unused by
|
||||
* blecent.
|
||||
*
|
||||
* @return 0 if the application successfully handled the
|
||||
* event; nonzero on failure. The semantics
|
||||
* of the return code is specific to the
|
||||
* particular GAP event being signalled.
|
||||
*/
|
||||
static int
|
||||
blecent_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
struct ble_gap_conn_desc desc;
|
||||
struct ble_hs_adv_fields fields;
|
||||
#if MYNEWT_VAL(BLE_HCI_VS)
|
||||
#if MYNEWT_VAL(BLE_POWER_CONTROL)
|
||||
struct ble_gap_set_auto_pcl_params params;
|
||||
#endif
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
/* An advertisement report was received during GAP discovery. */
|
||||
print_adv_fields(&fields);
|
||||
|
||||
/* Try to connect to the advertiser if it looks interesting. */
|
||||
blecent_connect_if_interesting(&event->disc);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
/* A new connection was established or a connection attempt failed. */
|
||||
if (event->connect.status == 0) {
|
||||
/* Connection successfully established. */
|
||||
MODLOG_DFLT(INFO, "Connection established ");
|
||||
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
print_conn_desc(&desc);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
/* Remember peer. */
|
||||
rc = peer_add(event->connect.conn_handle);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Failed to add peer; rc=%d\n", rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = peer_disc_all(event->connect.conn_handle,
|
||||
blecent_on_disc_complete, NULL);
|
||||
if(rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
|
||||
return 0;
|
||||
}
|
||||
connh = event->connect.conn_handle;
|
||||
// vTaskDelay(1000);
|
||||
|
||||
/** Initiate security - It will perform
|
||||
* Pairing (Exchange keys)
|
||||
* Bonding (Store keys)
|
||||
* Encryption (Enable encryption)
|
||||
* Will invoke event BLE_GAP_EVENT_ENC_CHANGE
|
||||
**/
|
||||
// struct ble_cs_initiator_procedure_start_params param;
|
||||
// memset(¶m,0,sizeof param);
|
||||
// param.conn_handle=event->enc_change.conn_handle;
|
||||
// param.cb=blecs_gap_event;
|
||||
// param.cb_arg=NULL;
|
||||
|
||||
// ble_cs_initiator_procedure_start(¶m);
|
||||
|
||||
// vTaskDelay(1000);
|
||||
|
||||
|
||||
// extern void bt_hci_log_hci_data_show(void);
|
||||
// bt_hci_log_hci_data_show();
|
||||
//bt_hci_log_hci_adv_show();
|
||||
|
||||
|
||||
rc = ble_gap_security_initiate(event->connect.conn_handle);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(INFO, "Security could not be initiated, rc = %d\n", rc);
|
||||
return ble_gap_terminate(event->connect.conn_handle,
|
||||
BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Connection attempt failed; resume scanning. */
|
||||
MODLOG_DFLT(ERROR, "Error: Connection failed; status=%d\n",
|
||||
event->connect.status);
|
||||
blecent_scan();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
/* Connection terminated. */
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
|
||||
print_conn_desc(&event->disconnect.conn);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
/* Forget about peer. */
|
||||
peer_delete(event->disconnect.conn.conn_handle);
|
||||
|
||||
#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0
|
||||
/* Reset EATT config */
|
||||
bearers = 0;
|
||||
for (int i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_NUM); i++) {
|
||||
cids[i] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Resume scanning. */
|
||||
blecent_scan();
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_DISC_COMPLETE:
|
||||
MODLOG_DFLT(INFO, "discovery complete; reason=%d\n",
|
||||
event->disc_complete.reason);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_ENC_CHANGE:
|
||||
/* Encryption has been enabled or disabled for this connection. */
|
||||
MODLOG_DFLT(INFO, "encryption change event; status=%d ",
|
||||
event->enc_change.status);
|
||||
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
print_conn_desc(&desc);
|
||||
/* Perform service discovery */
|
||||
// rc = peer_disc_all(event->connect.conn_handle,
|
||||
// blecent_on_disc_complete, NULL);
|
||||
// if(rc != 0) {
|
||||
// MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
printf("conn-handle = %x\n",event->enc_change.conn_handle);
|
||||
// struct ble_cs_initiator_procedure_start_params param;
|
||||
// memset(¶m,0,sizeof param);
|
||||
// param.conn_handle=event->enc_change.conn_handle;
|
||||
// param.cb=blecs_gap_event;
|
||||
// param.cb_arg=NULL;
|
||||
|
||||
// ble_cs_initiator_procedure_start(¶m);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_NOTIFY_RX:
|
||||
|
||||
|
||||
/* Peer sent us a notification or indication. */
|
||||
MODLOG_DFLT(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.om. Use
|
||||
* `os_mbuf_copydata` to copy the data received in notification mbuf */
|
||||
|
||||
if(ble_svc_ras_cp_val_handle == event->notify_rx.attr_handle){
|
||||
|
||||
}
|
||||
else if(ble_svc_ras_rd_val_handle == event->notify_rx.attr_handle){
|
||||
uint16_t ranging_counter;
|
||||
os_mbuf_copydata(event->notify_rx.om, 0, sizeof(uint16_t), &ranging_counter);
|
||||
most_recent_peer_ranging_counter=ranging_counter;
|
||||
|
||||
|
||||
if(most_recent_peer_ranging_counter!=most_recent_local_ranging_counter){
|
||||
MODLOG_DFLT(INFO, "Ranging counter mismatch : %d , %d \n",most_recent_peer_ranging_counter,most_recent_local_ranging_counter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
else if(ble_svc_ras_rd_ov_val_handle == event->notify_rx.attr_handle){
|
||||
|
||||
}
|
||||
else if(ble_svc_ras_od_val_handle == event->notify_rx.attr_handle){
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
MODLOG_DFLT(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);
|
||||
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;
|
||||
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
case BLE_GAP_EVENT_EXT_DISC:
|
||||
/* An advertisement report was received during GAP discovery. */
|
||||
ext_print_adv_report(&event->disc);
|
||||
|
||||
blecent_connect_if_interesting(&event->disc);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_POWER_CONTROL)
|
||||
case BLE_GAP_EVENT_TRANSMIT_POWER:
|
||||
MODLOG_DFLT(INFO, "Transmit power event : status=%d conn_handle=%d reason=%d "
|
||||
"phy=%d power_level=%d power_level_flag=%d delta=%d",
|
||||
event->transmit_power.status,
|
||||
event->transmit_power.conn_handle,
|
||||
event->transmit_power.reason,
|
||||
event->transmit_power.phy,
|
||||
event->transmit_power.transmit_power_level,
|
||||
event->transmit_power.transmit_power_level_flag,
|
||||
event->transmit_power.delta);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_PATHLOSS_THRESHOLD:
|
||||
MODLOG_DFLT(INFO, "Pathloss threshold event : conn_handle=%d current path loss=%d "
|
||||
"zone_entered =%d",
|
||||
event->pathloss_threshold.conn_handle,
|
||||
event->pathloss_threshold.current_path_loss,
|
||||
event->pathloss_threshold.zone_entered);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0
|
||||
case BLE_GAP_EVENT_EATT:
|
||||
int i;
|
||||
MODLOG_DFLT(INFO, "EATT %s : conn_handle=%d cid=%d",
|
||||
event->eatt.status ? "disconnected" : "connected",
|
||||
event->eatt.conn_handle,
|
||||
event->eatt.cid);
|
||||
if (event->eatt.status) {
|
||||
/* Remove CID from the list of saved CIDs */
|
||||
for (i = 0; i < bearers; i++) {
|
||||
if (cids[i] == event->eatt.cid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (i < (bearers - 1)) {
|
||||
cids[i] = cids[i + 1];
|
||||
i += 1;
|
||||
}
|
||||
cids[i] = 0;
|
||||
|
||||
/* Now Abort */
|
||||
return 0;
|
||||
}
|
||||
cids[bearers] = event->eatt.cid;
|
||||
bearers += 1;
|
||||
if (bearers != MYNEWT_VAL(BLE_EATT_CHAN_NUM)) {
|
||||
/* Wait until all EATT bearers are connected before proceeding */
|
||||
return 0;
|
||||
}
|
||||
/* Set the default bearer to use for further procedures */
|
||||
rc = ble_att_set_default_bearer_using_cid(event->eatt.conn_handle, cids[0]);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(INFO, "Cannot set default EATT bearer, rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Perform service discovery */
|
||||
rc = peer_disc_all(event->eatt.conn_handle,
|
||||
blecent_on_disc_complete, NULL);
|
||||
if(rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
blecent_on_reset(int reason)
|
||||
{
|
||||
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static void
|
||||
blecent_on_sync(void)
|
||||
{
|
||||
printf("on sync \n");
|
||||
int rc;
|
||||
rc = ble_gap_set_host_feat(47,0x01);
|
||||
printf("rc = %d\n",rc);
|
||||
/* Make sure we have proper identity address set (public preferred) */
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
|
||||
/* Begin scanning for a peripheral to connect to. */
|
||||
blecent_scan();
|
||||
}
|
||||
|
||||
void blecent_host_task(void *param)
|
||||
{
|
||||
ESP_LOGI(tag, "BLE Host Task Started");
|
||||
/* This function will return only when nimble_port_stop() is executed */
|
||||
nimble_port_run();
|
||||
|
||||
nimble_port_freertos_deinit();
|
||||
}
|
||||
|
||||
#if CONFIG_EXAMPLE_INIT_DEINIT_LOOP
|
||||
/* This function showcases stack init and deinit procedure. */
|
||||
static void stack_init_deinit(void)
|
||||
{
|
||||
int rc;
|
||||
while(1) {
|
||||
|
||||
vTaskDelay(1000);
|
||||
|
||||
ESP_LOGI(tag, "Deinit host");
|
||||
|
||||
rc = nimble_port_stop();
|
||||
if (rc == 0) {
|
||||
nimble_port_deinit();
|
||||
} else {
|
||||
ESP_LOGI(tag, "Nimble port stop failed, rc = %d", rc);
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay(1000);
|
||||
|
||||
ESP_LOGI(tag, "Init host");
|
||||
|
||||
rc = nimble_port_init();
|
||||
if (rc != ESP_OK) {
|
||||
ESP_LOGI(tag, "Failed to init nimble %d ", rc);
|
||||
break;
|
||||
}
|
||||
|
||||
nimble_port_freertos_init(blecent_host_task);
|
||||
|
||||
ESP_LOGI(tag, "Waiting for 1 second");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
app_main(void)
|
||||
{
|
||||
int rc;
|
||||
/* Initialize NVS — it is used to store PHY calibration data */
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ret = nimble_port_init();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(tag, "Failed to init nimble %d ", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Configure the host. */
|
||||
ble_hs_cfg.reset_cb = blecent_on_reset;
|
||||
ble_hs_cfg.sync_cb = blecent_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
/* Initialize data structures to track connected peers. */
|
||||
rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Set the default device name. */
|
||||
rc = ble_svc_gap_device_name_set("nimble-blecent");
|
||||
assert(rc == 0);
|
||||
|
||||
/* XXX Need to have template for store */
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(blecent_host_task);
|
||||
|
||||
#if CONFIG_EXAMPLE_INIT_DEINIT_LOOP
|
||||
stack_init_deinit();
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0
|
||||
bearers = 0;
|
||||
for (int i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_NUM); i++) {
|
||||
cids[i] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
CONFIG_EXAMPLE_USE_CI_ADDRESS=y
|
||||
CONFIG_EXAMPLE_PEER_ADDR="${CI_PIPELINE_ID}"
|
||||
@@ -0,0 +1,4 @@
|
||||
CONFIG_IDF_TARGET="esp32c2"
|
||||
CONFIG_XTAL_FREQ_26=y
|
||||
CONFIG_EXAMPLE_USE_CI_ADDRESS=y
|
||||
CONFIG_EXAMPLE_PEER_ADDR="${CI_PIPELINE_ID}"
|
||||
@@ -0,0 +1,13 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_CHANNEL_SOUNDING=y
|
||||
@@ -0,0 +1,8 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_IDF_TARGET="esp32c2"
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=y
|
||||
@@ -0,0 +1,8 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=y
|
||||
CONFIG_BT_NIMBLE_CHANNEL_SOUNDING=y
|
||||
@@ -0,0 +1,995 @@
|
||||
# BLE Central Example Walkthrough
|
||||
|
||||
## Introduction
|
||||
|
||||
In this tutorial, we will explore the blecent example code provided by Espressif's ESP-IDF framework. The primary goal of the blecent example is to illustrate how a BLE Central device can interact with multiple BLE Peripheral devices in the vicinity. The Central device initiates the communication by scanning for nearby Peripherals and establishing connections with them. By the end of this tutorial, you will have a comprehensive understanding of how the blecent example code operates as a BLE Central application.
|
||||
|
||||
## Includes
|
||||
|
||||
This example is located in the examples folder of the ESP-IDF under the [blecent/main](../main). The [main.c](../main/main.c) file located in the main folder contains all the functionality that we are going to review. The header files contained in [main.c](../main/main.c) are:
|
||||
|
||||
```c
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
/* BLE */
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "console/console.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "blecent.h"
|
||||
```
|
||||
These `includes` are required for the FreeRTOS and underlying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `“nimble_port.h”`, `“nimble_port_freertos.h”`, `"ble_hs.h"`, `“ble_svc_gap.h”` and `“blecent.h”` which expose the BLE APIs required to implement this example.
|
||||
|
||||
* `nimble_port.h`: Includes the declaration of functions required for the initialization of the nimble stack.
|
||||
* `nimble_port_freertos.h`: Initializes and enables nimble host task.
|
||||
* `ble_hs.h`: Defines the functionalities to handle the host event.
|
||||
* `ble_svc_gap.h`: Defines the macros for device name, and device appearance and declares the function to set them.
|
||||
* `blecent.h`: Provides necessary definitions and forward declarations for the blecent example's functionality, specifically for interacting with BLE services and characteristics related to Alert Notifications.
|
||||
|
||||
## Main Entry Point
|
||||
|
||||
The program's entry point is the app_main() function:
|
||||
```c
|
||||
void
|
||||
app_main(void)
|
||||
{
|
||||
int rc;
|
||||
/* Initialize NVS — it is used to store PHY calibration data */
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ret = nimble_port_init();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(tag, "Failed to init nimble %d ", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Configure the host. */
|
||||
ble_hs_cfg.reset_cb = blecent_on_reset;
|
||||
ble_hs_cfg.sync_cb = blecent_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
/* Initialize data structures to track connected peers. */
|
||||
rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Set the default device name. */
|
||||
rc = ble_svc_gap_device_name_set("nimble-blecent");
|
||||
assert(rc == 0);
|
||||
|
||||
/* XXX Need to have template for store */
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(blecent_host_task);
|
||||
|
||||
#if CONFIG_EXAMPLE_INIT_DEINIT_LOOP
|
||||
stack_init_deinit();
|
||||
#endif
|
||||
|
||||
}
|
||||
```
|
||||
The main function starts by initializing the non-volatile storage library. This library allows us to save the key-value pairs in flash memory. `nvs_flash_init()` stores the PHY calibration data. In a Bluetooth Low Energy (BLE) device, cryptographic keys used for encryption and authentication are often stored in Non-Volatile Storage (NVS). BLE stores the peer keys, CCCD keys, peer records, etc on NVS. By storing these keys in NVS, the BLE device can quickly retrieve them when needed, without the need for time-consuming key generations.
|
||||
```c
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
```
|
||||
|
||||
## BT Controller and Stack Initialization
|
||||
|
||||
The main function calls `nimble_port_init()` to initialize BT Controller and nimble stack. This function initializes the BT controller by first creating its configuration structure named `esp_bt_controller_config_t` with default settings generated by the `BT_CONTROLLER_INIT_CONFIG_DEFAULT()` macro. It implements the Host Controller Interface (HCI) on the controller side, the Link Layer (LL), and the Physical Layer (PHY). The BT Controller is invisible to the user applications and deals with the lower layers of the BLE stack. The controller configuration includes setting the BT controller stack size, priority, and HCI baud rate. With the settings created, the BT controller is initialized and enabled with the `esp_bt_controller_init()` and `esp_bt_controller_enable()` functions:
|
||||
|
||||
```c
|
||||
esp_bt_controller_config_t config_opts = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&config_opts);
|
||||
```
|
||||
Next, the controller is enabled in BLE Mode.
|
||||
|
||||
```c
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
```
|
||||
The controller should be enabled in `ESP_BT_MODE_BLE` if you want to use the BLE mode.
|
||||
|
||||
There are four Bluetooth modes supported:
|
||||
|
||||
1. `ESP_BT_MODE_IDLE`: Bluetooth not running
|
||||
2. `ESP_BT_MODE_BLE`: BLE mode
|
||||
3. `ESP_BT_MODE_CLASSIC_BT`: BT Classic mode
|
||||
4. `ESP_BT_MODE_BTDM`: Dual mode (BLE + BT Classic)
|
||||
|
||||
After the initialization of the BT controller, the nimble stack, which includes the common definitions and APIs for BLE, is initialized by using `esp_nimble_init()`:
|
||||
|
||||
```c
|
||||
esp_err_t esp_nimble_init(void)
|
||||
{
|
||||
#if !SOC_ESP_NIMBLE_CONTROLLER
|
||||
/* Initialize the function pointers for OS porting */
|
||||
npl_freertos_funcs_init();
|
||||
|
||||
npl_freertos_mempool_init();
|
||||
|
||||
if(esp_nimble_hci_init() != ESP_OK) {
|
||||
ESP_LOGE(NIMBLE_PORT_LOG_TAG, "hci inits failed\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Initialize default event queue */
|
||||
ble_npl_eventq_init(&g_eventq_dflt);
|
||||
/* Initialize the global memory pool */
|
||||
os_mempool_module_init();
|
||||
os_msys_init();
|
||||
|
||||
#endif
|
||||
/* Initialize the host */
|
||||
ble_transport_hs_init();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
```
|
||||
|
||||
The host is configured by setting up the callbacks for Stack-reset, Stack-sync, and Storage status.
|
||||
```c
|
||||
ble_hs_cfg.reset_cb = blecent_on_reset;
|
||||
ble_hs_cfg.sync_cb = blecent_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
```
|
||||
|
||||
The main function invokes `peer_init()` to initialize memory pools to manage peer, service, characteristics, and descriptor objects in BLE.
|
||||
```c
|
||||
rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
|
||||
```
|
||||
|
||||
The main function calls `ble_svc_gap_device_name_set()` to set the default device name.
|
||||
```c
|
||||
rc = ble_svc_gap_device_name_set("nimble-blecent");
|
||||
```
|
||||
|
||||
The main function calls `ble_store_config_init()` to configure the host by setting up the storage callbacks which handle the read, write, and deletion of security material.
|
||||
```c
|
||||
/* XXX Need to have a template for store */
|
||||
ble_store_config_init();
|
||||
```
|
||||
|
||||
The main function ends by creating a task where nimble will run using `nimble_port_freertos_init()`. This enables the nimble stack by using `esp_nimble_enable()`.
|
||||
|
||||
```c
|
||||
nimble_port_freertos_init(blecent_host_task);
|
||||
```
|
||||
|
||||
`esp_nimble_enable()` create a task where the nimble host will run. It is not strictly necessary to have a separate task for the nimble host, but to handle the default queue, it is easier to create a separate task.
|
||||
|
||||
|
||||
## CONFIG_EXAMPLE_INIT_DEINIT_LOOP
|
||||
|
||||
```c
|
||||
#if CONFIG_EXAMPLE_INIT_DEINIT_LOOP
|
||||
/* This function showcases stack init and deinit procedure. */
|
||||
static void stack_init_deinit(void)
|
||||
{
|
||||
int rc;
|
||||
while(1) {
|
||||
|
||||
vTaskDelay(1000);
|
||||
|
||||
ESP_LOGI(tag, "Deinit host");
|
||||
|
||||
rc = nimble_port_stop();
|
||||
if (rc == 0) {
|
||||
nimble_port_deinit();
|
||||
} else {
|
||||
ESP_LOGI(tag, "Nimble port stop failed, rc = %d", rc);
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay(1000);
|
||||
|
||||
ESP_LOGI(tag, "Init host");
|
||||
|
||||
rc = nimble_port_init();
|
||||
if (rc != ESP_OK) {
|
||||
ESP_LOGI(tag, "Failed to init nimble %d ", rc);
|
||||
break;
|
||||
}
|
||||
|
||||
nimble_port_freertos_init(blecent_host_task);
|
||||
|
||||
ESP_LOGI(tag, "Waiting for 1 second");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
The `stack_init_deinit` function provides a demonstration of the initialization and deinitialization procedure for the NimBLE stack. It operates within a loop that showcases the following steps:
|
||||
|
||||
* **Delay**: The function starts by introducing a delay of 1000 tick periods using the vTaskDelay function. This allows time for certain operations to complete before moving on.
|
||||
|
||||
* **Deinitialization**: The function logs that the host deinitialization process is beginning. It calls `nimble_port_stop` to halt the NimBLE stack's operation. If the stop operation is successful (returning 0), the function then calls `nimble_port_deinit` to deinitialize the NimBLE stack. If the stop operation fails, an error message is logged, and the loop breaks.
|
||||
|
||||
* **Delay**: Another 1000 tick periods delay is introduced before proceeding with initialization.
|
||||
|
||||
* **Initialization**: The function logs that the host initialization process is starting. It calls `nimble_port_init` to initialize the NimBLE stack. If the initialization fails (returning anything other than `ESP_OK`), an error message is logged, and the loop breaks.
|
||||
|
||||
* **FreeRTOS Initialization**: After successful NimBLE stack initialization, the function calls `nimble_port_freertos_init` and provides the `blecent_host_task` as a parameter. This step sets up the NimBLE stack to work within the FreeRTOS environment.
|
||||
|
||||
|
||||
## blecent_scan()
|
||||
|
||||
```c
|
||||
static void
|
||||
blecent_scan(void)
|
||||
{
|
||||
uint8_t own_addr_type;
|
||||
struct ble_gap_disc_params disc_params;
|
||||
int rc;
|
||||
|
||||
/* Figure out address to use while advertising (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Tell the controller to filter duplicates; we don't want to process
|
||||
* repeated advertisements from the same device.
|
||||
*/
|
||||
disc_params.filter_duplicates = 1;
|
||||
|
||||
/**
|
||||
* Perform a passive scan. I.e., don't send follow-up scan requests to
|
||||
* each advertiser.
|
||||
*/
|
||||
disc_params.passive = 1;
|
||||
|
||||
/* Use defaults for the rest of the parameters. */
|
||||
disc_params.itvl = 0;
|
||||
disc_params.window = 0;
|
||||
disc_params.filter_policy = 0;
|
||||
disc_params.limited = 0;
|
||||
|
||||
rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params,
|
||||
blecent_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error initiating GAP discovery procedure; rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The function `blecent_scan()` initiates the General Discovery Procedure for scanning nearby BLE devices. The function starts by declaring several variables used in the scanning process. These variable include:
|
||||
* `own_addr_type`: A uint8_t variable that stores the type of address (public or random) that the device will use while scanning.
|
||||
* `disc_params`: A struct of type `ble_gap_disc_params` that holds the parameters for the GAP (Generic Access Profile) discovery procedure.
|
||||
|
||||
The function uses `ble_hs_id_infer_auto()` to determine the address type (public or random) that the device should use for scanning. The result is stored in the own_addr_type variable.
|
||||
|
||||
Configure Discovery Parameters: The function configures the disc_params struct with the following settings:
|
||||
|
||||
* `filter_duplicates`: Set to 1, indicating that the controller should filter out duplicate advertisements from the same device. This reduces unnecessary processing of repeated advertisements.
|
||||
* `passive`: Set to 1, indicating that the scan will be a passive scan. In a passive scan, the scanning device only listens for advertisements without sending any follow-up scan requests to advertisers. It's used for general device discovery.
|
||||
|
||||
The function sets some other parameters in the disc_params struct to their default values:
|
||||
|
||||
* `itvl`: The scan interval is set to 0, using the default value.
|
||||
* `window`: The scan window is set to 0, using the default value.
|
||||
* `filter_policy`: The filter policy is set to 0, using the default value.
|
||||
* `limited`: The limited discovery mode is set to 0, using the default value.
|
||||
|
||||
The function then calls `ble_gap_disc()` to initiate the BLE scanning procedure. It passes the following parameters:
|
||||
|
||||
* `own_addr_type`: The address type to use for scanning (determined earlier).
|
||||
* `BLE_HS_FOREVER`: The duration for which the scan should continue (in this case, indefinitely).
|
||||
* `&disc_params`: A pointer to the ble_gap_disc_params struct containing the scan parameters.
|
||||
* `blecent_gap_event`: The callback function to handle the scan events (such as receiving advertisements from nearby devices).
|
||||
* `NULL`: The argument for the callback context, which is not used in this example.
|
||||
|
||||
If an error occurs during the initiation of the scanning procedure, the function prints an error message.
|
||||
|
||||
|
||||
## blecent_gap_event
|
||||
|
||||
The function `blecent_gap_event` is in responsible of managing various GAP (Generic Access Profile) events that arise during the BLE communication.
|
||||
|
||||
The function employs a switch statement to manage diverse types of GAP events that can be received.
|
||||
|
||||
* `BLE_GAP_EVENT_DISC`: This case is activated when a new advertisement report is detected during scanning. The function extracts the advertisement data using `ble_hs_adv_parse_fields` and then displays the advertisement fields using the print_adv_fields function. It subsequently verifies if the discovered device is of interest and attempts to establish a connection with it.
|
||||
|
||||
* `BLE_GAP_EVENT_CONNECT`: This case is triggered when a new connection is established or when a connection attempt fails. If the Connection was established then the connection descriptor is initiated using the `ble_gap_conn_find()` method else advertisement is resumed. If the connection is successful, it displays the connection descriptor through `print_conn_desc` and stores the peer information. Additionally, it handles optional features such as BLE power control, vendor-specific commands, and security initiation. In the event of a connection attempt failure, it resumes scanning.
|
||||
|
||||
* `BLE_GAP_EVENT_DISCONNECT`: This case is activated when a connection is terminated. It prints the reason for disconnection and the connection descriptor before removing information about the peer and resuming scanning.
|
||||
|
||||
* `BLE_GAP_EVENT_DISC_COMPLETE`: This case is triggered upon the completion of the GAP discovery process. It displays the reason for the discovery's completion.
|
||||
|
||||
* `BLE_GAP_EVENT_ENC_CHANGE`: This case is activated when encryption is enabled or disabled for a connection. It displays the status of the encryption change and the connection descriptor. If encryption is enabled (when CONFIG_EXAMPLE_ENCRYPTION is defined), it initiates service discovery.
|
||||
|
||||
* `BLE_GAP_EVENT_NOTIFY_RX`: This case is triggered when the Central device receives a notification or indication from the Peripheral device. It displays information about the received data.
|
||||
|
||||
* `BLE_GAP_EVENT_MTU`: This case is activated when the Maximum Transmission Unit (MTU) is updated for a connection. It prints the new MTU value and related information.
|
||||
|
||||
* `BLE_GAP_EVENT_REPEAT_PAIRING`: This case is triggered when the Peripheral device attempts to establish a new secure link with the Central despite an existing bond. The app prioritizes convenience over security and deletes the old bond, accepting the new link.
|
||||
|
||||
So, event handler function effectively manages various GAP events, handles connection-related tasks, initiates security procedures, performs service discovery, and accommodates optional features based on the configuration settings.
|
||||
|
||||
|
||||
## blecent_should_connect
|
||||
|
||||
```c
|
||||
static int
|
||||
blecent_should_connect(const struct ble_gap_disc_desc *disc)
|
||||
{
|
||||
struct ble_hs_adv_fields fields;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
/* 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 0;
|
||||
}
|
||||
|
||||
rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data);
|
||||
if (rc != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) {
|
||||
ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR);
|
||||
/* Convert string to address */
|
||||
sscanf(CONFIG_EXAMPLE_PEER_ADDR, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
||||
&peer_addr[5], &peer_addr[4], &peer_addr[3],
|
||||
&peer_addr[2], &peer_addr[1], &peer_addr[0]);
|
||||
if (memcmp(peer_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* The device has to advertise support for the Alert Notification
|
||||
* service (0x1811).
|
||||
*/
|
||||
for (i = 0; i < fields.num_uuids16; i++) {
|
||||
if (ble_uuid_u16(&fields.uuids16[i].u) == BLECENT_SVC_ALERT_UUID) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
This function is responsible for determining whether the Central device should establish a connection with a discovered Peripheral device based on the advertisement data received during scanning. Let's break down the code step by step:
|
||||
|
||||
* **Local Variables**: The function declares several local variables, including `fields` of type `struct ble_hs_adv_fields` to hold the parsed advertisement data, `rc` to store the return code of function calls, and `i` for loop iteration.
|
||||
|
||||
* **Checking Advertisement Event Type**: The function begins by checking the event type of the advertisement report stored in the `disc` structure. It verifies whether the event type indicates that the device is advertising its connectability. Specifically, it checks for two event types: `BLE_HCI_ADV_RPT_EVTYPE_ADV_IND` (Connectable Undirected Advertising) and `BLE_HCI_ADV_RPT_EVTYPE_DIR_IND` (Directed Advertising). If the event type is neither of these, it means the device is not connectable, and the function returns 0, indicating that the Central device should not attempt to connect.
|
||||
|
||||
* **Parsing Advertisement Data**: The function then attempts to parse the advertisement data using the `ble_hs_adv_parse_fields` function. The advertisement data is stored in the `disc->data` buffer, and its length is specified by `disc->length_data`. The parsed data is then stored in the `fields` struct.
|
||||
|
||||
* **Checking Peer Address**: This section of the code handles an optional feature where the Central device can specify a specific peer address it wants to connect to. It checks whether the configuration option `CONFIG_EXAMPLE_PEER_ADDR` is set and not equal to `ADDR_ANY` (a special value). If this configuration is set, it means the Central device wants to connect to a specific device based on its address. The function converts the specified peer address from a string representation to a byte array `peer_addr` using the `sscanf` function. If the received device's address (in `disc->addr.val`) does not match the specified peer address, the function returns 0, indicating that the Central device should not connect to this device.
|
||||
|
||||
* **Checking for Alert Notification Service**: Next, the function examines the parsed advertisement data to check for the presence of the Alert Notification service (UUID: 0x1811). The Alert Notification service is used to notify the Central device about alerts or notifications from the Peripheral device. If the advertised service is found in the advertisement data, the function returns 1, indicating that the Central device should proceed with connecting to this device.
|
||||
|
||||
* **Returning 0**: If none of the conditions mentioned above are met (i.e., the event type is not connectable, the peer address check is not enabled, and the Alert Notification service is not advertised), the function returns 0, signaling that the Central device should not establish a connection with this device.
|
||||
|
||||
|
||||
## blecent_connect_if_interesting
|
||||
|
||||
```c
|
||||
/**
|
||||
* Connects to the sender of the specified advertisement of it looks
|
||||
* interesting. A device is "interesting" if it advertises connectability and
|
||||
* support for the Alert Notification service.
|
||||
*/
|
||||
static void
|
||||
blecent_connect_if_interesting(void *disc)
|
||||
{
|
||||
uint8_t own_addr_type;
|
||||
int rc;
|
||||
ble_addr_t *addr;
|
||||
|
||||
/* Don't do anything if we don't care about this advertiser. */
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
if (!ext_blecent_should_connect((struct ble_gap_ext_disc_desc *)disc)) {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (!blecent_should_connect((struct ble_gap_disc_desc *)disc)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Scanning must be stopped before a connection can be initiated. */
|
||||
rc = ble_gap_disc_cancel();
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(DEBUG, "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) {
|
||||
MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
||||
* timeout.
|
||||
*/
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
addr = &((struct ble_gap_ext_disc_desc *)disc)->addr;
|
||||
#else
|
||||
addr = &((struct ble_gap_disc_desc *)disc)->addr;
|
||||
#endif
|
||||
|
||||
rc = ble_gap_connect(own_addr_type, addr, 30000, NULL,
|
||||
blecent_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d "
|
||||
"addr=%s; rc=%d\n",
|
||||
addr->type, addr_str(addr->val), rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Function `blecent_connect_if_interesting` is to handle the connection process to a BLE Peripheral device if certain criteria are met, making the device interesting for the Central to connect to. Let's summarize the code step by step:
|
||||
|
||||
* **Local Variables**: The function declares local variables, including `own_addr_type` of type `uint8_t` to store the own address type of the Central device, `rc` to store the return code of function calls, and `addr` of type `ble_addr_t*` to store the address of the discovered advertiser.
|
||||
|
||||
* **Checking Device Interest**: The function checks if the advertiser meets the criteria for an interesting device to connect to. The criteria are evaluated using either `blecent_should_connect` or `ext_blecent_should_connect`, depending on the presence of the `CONFIG_EXAMPLE_EXTENDED_ADV` configuration. If the advertiser doesn't meet the criteria, the function returns without attempting a connection.
|
||||
|
||||
* **Stopping Scanning**: Before initiating a connection, the function cancels any ongoing BLE scanning using `ble_gap_disc_cancel()`. Scanning must be halted to establish a connection.
|
||||
|
||||
* **Determining Address Type**: The function infers the address type of the Central device for the connection by calling `ble_hs_id_infer_auto`, and the inferred type is stored in `own_addr_type`. If there's an error during address type determination, the function exits without attempting a connection.
|
||||
|
||||
* **Initiating Connection**: With scanning stopped and the address type determined, the function is ready to initiate the connection. It retrieves the advertiser's address from the provided `disc` argument (of type `struct ble_gap_disc_desc*` or `struct ble_gap_ext_disc_desc*`, depending on configuration).
|
||||
|
||||
* **Connecting to the Advertiser**: The function uses `ble_gap_connect` to establish the connection with the advertiser device. It provides the Central's own address type, the advertiser's address, and sets a timeout of 30 seconds (30000 ms) for the connection attempt. Additionally, it designates the `blecent_gap_event` function as the event callback to manage connection-related events.
|
||||
|
||||
* **Error Handling**: If the connection attempt fails (`rc != 0`), the function logs an error message with details about the failed connection attempt and returns.
|
||||
|
||||
|
||||
## blecent_on_disc_complete
|
||||
|
||||
```c
|
||||
/**
|
||||
* Called when service discovery of the specified peer has completed.
|
||||
*/
|
||||
static void
|
||||
blecent_on_disc_complete(const struct peer *peer, int status, void *arg)
|
||||
{
|
||||
|
||||
if (status != 0) {
|
||||
/* Service discovery failed. Terminate the connection. */
|
||||
MODLOG_DFLT(ERROR, "Error: Service discovery failed; status=%d "
|
||||
"conn_handle=%d\n", status, peer->conn_handle);
|
||||
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.
|
||||
*/
|
||||
MODLOG_DFLT(INFO, "Service discovery complete; status=%d "
|
||||
"conn_handle=%d\n", status, peer->conn_handle);
|
||||
|
||||
/* Now perform three GATT procedures against the peer: read,
|
||||
* write, and subscribe to notifications for the ANS service.
|
||||
*/
|
||||
blecent_read_write_subscribe(peer);
|
||||
}
|
||||
```
|
||||
|
||||
The function `blecent_on_disc_complete` is essential for managing service discovery completion and GATT procedures. It's invoked after service discovery on a peer device concludes. The function takes three arguments: a pointer to the `peer` structure (containing peer information), an integer `status` indicating success or failure, and a generic `arg` pointer for potential extra data (not used here).
|
||||
|
||||
* **Handling Discovery Status**: Upon initiation, the function checks the `status` of the service discovery operation. Non-zero status indicates failure. In such cases, an error message is logged using `MODLOG_DFLT(ERROR, ...)` and the connection with the peer is terminated via `ble_gap_terminate()`, assigning the error reason code `BLE_ERR_REM_USER_CONN_TERM`. This ensures a proper connection termination due to the unsuccessful service discovery.
|
||||
|
||||
* **Success Path**: For a status of zero, denoting successful service discovery, a log message is generated, signifying the completion of service discovery. It includes the `status` and the peer's connection handle (`conn_handle`).
|
||||
|
||||
* **GATT Procedures**: Upon successful service discovery, the function proceeds with three GATT (Generic Attribute Profile) procedures performed on the peer. These encompass reading, writing, and subscribing to notifications for the Alert Notification Service (ANS). These specific GATT actions are typically implemented within the `blecent_read_write_subscribe()` function.
|
||||
|
||||
|
||||
## blecent_read_write_subscribe
|
||||
|
||||
```c
|
||||
/**
|
||||
* Performs three GATT operations against the specified peer:
|
||||
* 1. Reads the ANS Supported New Alert Category characteristic.
|
||||
* 2. After read is completed, writes the ANS Alert Notification Control Point characteristic.
|
||||
* 3. After write is completed, 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
|
||||
blecent_read_write_subscribe(const struct peer *peer)
|
||||
{
|
||||
const struct peer_chr *chr;
|
||||
int rc;
|
||||
|
||||
/* Read the supported-new-alert-category characteristic. */
|
||||
chr = peer_chr_find_uuid(peer,
|
||||
BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID),
|
||||
BLE_UUID16_DECLARE(BLECENT_CHR_SUP_NEW_ALERT_CAT_UUID));
|
||||
if (chr == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the Supported New "
|
||||
"Alert Category characteristic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = ble_gattc_read(peer->conn_handle, chr->chr.val_handle,
|
||||
blecent_on_read, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to read characteristic; rc=%d\n",
|
||||
rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
/* Terminate the connection. */
|
||||
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
```
|
||||
|
||||
This function executes the following sequence of actions:
|
||||
|
||||
* **Reading Supported New Alert Category Characteristic:** It initiates by attempting to read the *"Supported New Alert Category"* characteristic within the *"Alert Notification Service"* (ANS). To accomplish this, it employs the `peer_chr_find_uuid` function, which searches for the specified characteristic using its UUID. If the characteristic isn't located within the peer's attributes, the function logs an error message and discontinues the connection.
|
||||
|
||||
* **Carrying Out Characteristic Read**: If the *"Supported New Alert Category"* characteristic is successfully identified, the function endeavors to read its value utilizing the `ble_gattc_read` function. In the event of a failed read operation, an error is logged, and the connection is terminated.
|
||||
|
||||
|
||||
## blecent_on_custom_read
|
||||
|
||||
```c
|
||||
/**
|
||||
* Application Callback. Called when the custom subscribable chatacteristic
|
||||
* in the remote GATT server is read.
|
||||
* Expect to get the recently written data.
|
||||
**/
|
||||
static int
|
||||
blecent_on_custom_read(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
MODLOG_DFLT(INFO,
|
||||
"Read complete for the subscribable characteristic; "
|
||||
"status=%d conn_handle=%d", error->status, conn_handle);
|
||||
if (error->status == 0) {
|
||||
MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle);
|
||||
print_mbuf(attr->om);
|
||||
}
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
`blecent_on_custom_read` function is triggered when data is read from a custom subscribable characteristic in a distant Generic Attribute Profile (GATT) server.
|
||||
|
||||
* **Function Definition**: The callback function `blecent_on_custom_read` is defined with specific parameters. These parameters are supplied by the BLE stack when the callback is invoked:
|
||||
- `uint16_t conn_handle`: The BLE connection handle associated with the read operation.
|
||||
- `const struct ble_gatt_error *error`: A pointer to a structure that holds error information, if any, during the read.
|
||||
- `struct ble_gatt_attr *attr`: A pointer to the read attribute, encompassing its handle and data.
|
||||
- `void *arg`: An optional argument that can be included when registering the callback (not used in this example).
|
||||
|
||||
* **Logging Usage**: The function utilizes the `MODLOG_DFLT` macro to log insights regarding the read operation. This includes details such as the connection handle, operation status (via `error->status`), and attribute handle (via `attr->handle`).
|
||||
|
||||
* **Successful Read Check**: The code assesses the read operation's success by inspecting the status stored in `error->status`. A status of `0` indicates a successful read with no errors.
|
||||
|
||||
* **Value Logging**: If the read operation succeeds, the function logs the attribute's value. This is achieved by employing the `print_mbuf` function, which prints the content of `attr->om` (mbuf) data, representing the read attribute's value.
|
||||
|
||||
|
||||
## blecent_on_custom_write
|
||||
|
||||
```c
|
||||
/**
|
||||
* Application Callback. Called when the custom subscribable characteristic
|
||||
* in the remote GATT server is written to.
|
||||
* Client has previously subscribed to this characeteristic,
|
||||
* so expect a notification from the server.
|
||||
**/
|
||||
static int
|
||||
blecent_on_custom_write(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
const struct peer_chr *chr;
|
||||
const struct peer *peer;
|
||||
int rc;
|
||||
|
||||
MODLOG_DFLT(INFO,
|
||||
"Write to the custom subscribable characteristic complete; "
|
||||
"status=%d conn_handle=%d attr_handle=%d\n",
|
||||
error->status, conn_handle, attr->handle);
|
||||
|
||||
peer = peer_find(conn_handle);
|
||||
chr = peer_chr_find_uuid(peer,
|
||||
remote_svc_uuid,
|
||||
remote_chr_uuid);
|
||||
if (chr == NULL) {
|
||||
MODLOG_DFLT(ERROR,
|
||||
"Error: Peer doesn't have the custom subscribable characteristic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*** Performs a read on the characteristic, the result is handled in blecent_on_new_read callback ***/
|
||||
rc = ble_gattc_read(conn_handle, chr->chr.val_handle,
|
||||
blecent_on_custom_read, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR,
|
||||
"Error: Failed to read the custom subscribable characteristic; "
|
||||
"rc=%d\n", rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
/* Terminate the connection */
|
||||
return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
```
|
||||
|
||||
`blecent_on_custom_write` function is invoked when a remote GATT server's (Generic Attribute Profile) custom subscribable characteristic is successfully written to by the Central device.
|
||||
|
||||
* **Parameters**:
|
||||
- `conn_handle`: BLE connection handle where the write operation took place.
|
||||
- `error`: Contains write operation details, including the status code.
|
||||
- `attr`: Represents the written attribute (characteristic).
|
||||
- `arg`: Optional user-defined argument (unused here).
|
||||
|
||||
* **Logging**:
|
||||
This function logs write operation completion, displaying write status, connection handle, and attribute handle.
|
||||
|
||||
* **Locating Peer and Characteristic**:
|
||||
- The function seeks the relevant `peer` using the connection handle through `peer_find`.
|
||||
- It also searches for a `chr` (characteristic) within the peer's attributes using `remote_svc_uuid` and `remote_chr_uuid`.
|
||||
- If the characteristic isn't found, an error message is logged, and the function proceeds to the error handling section.
|
||||
|
||||
* **Initiating Characteristic Read**:
|
||||
- Upon locating the characteristic, the function begins a read operation using `ble_gattc_read`.
|
||||
- It supplies connection handle, characteristic's value handle (`chr->chr.val_handle`), read handler (`blecent_on_custom_read`), and no user-defined argument (`NULL`).
|
||||
|
||||
* **Error Handling**:
|
||||
- If the read operation faces an issue (non-zero return value), an error message is logged.
|
||||
- The function then navigates to the error handling section (`err`), ending the BLE connection with the remote device via `ble_gap_terminate`.
|
||||
- The termination rationale is marked as `BLE_ERR_REM_USER_CONN_TERM`.
|
||||
|
||||
* **Return Value**:
|
||||
- Successful write and subsequent read return `0`.
|
||||
- Write or read errors lead to connection termination, with the result of `ble_gap_terminate`.
|
||||
|
||||
|
||||
## blecent_on_custom_subscribe
|
||||
|
||||
```c
|
||||
/**
|
||||
* Application Callback. Called when the custom subscribable characteristic
|
||||
* is subscribed to.
|
||||
**/
|
||||
static int
|
||||
blecent_on_custom_subscribe(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
const struct peer_chr *chr;
|
||||
uint8_t value;
|
||||
int rc;
|
||||
const struct peer *peer;
|
||||
|
||||
MODLOG_DFLT(INFO,
|
||||
"Subscribe to the custom subscribable characteristic complete; "
|
||||
"status=%d conn_handle=%d", error->status, conn_handle);
|
||||
|
||||
if (error->status == 0) {
|
||||
MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle);
|
||||
print_mbuf(attr->om);
|
||||
}
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
peer = peer_find(conn_handle);
|
||||
chr = peer_chr_find_uuid(peer,
|
||||
remote_svc_uuid,
|
||||
remote_chr_uuid);
|
||||
if (chr == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error: Peer doesn't have the subscribable characteristic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Write 1 byte to the new characteristic to test if it notifies after subscribing */
|
||||
value = 0x19;
|
||||
rc = ble_gattc_write_flat(conn_handle, chr->chr.val_handle,
|
||||
&value, sizeof(value), blecent_on_custom_write, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR,
|
||||
"Error: Failed to write to the subscribable characteristic; "
|
||||
"rc=%d\n", rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
/* Terminate the connection */
|
||||
return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
```
|
||||
|
||||
`blecent_on_custom_subscribe` function is triggered when a custom subscribable characteristic is subscribed to. Here's a concise breakdown of the code's key aspects:
|
||||
|
||||
* **Function and Parameters**: The function receives parameters including the connection handle `conn_handle`, an error structure `error` for status details, a GATT attribute structure `attr` representing the subscribed attribute, and a generic argument `arg`.
|
||||
|
||||
* **Subscription Log**: Information about the subscription process is logged, including the subscription status, connection handle, and attribute handle. If the subscription is successful (`error->status == 0`), the subscribed attribute's value is printed using the `print_mbuf` function.
|
||||
|
||||
* **Peer and Characteristic Search**: The function searches for a peer structure using `conn_handle` and attempts to locate a specific characteristic within that peer. The desired characteristic is identified by `remote_svc_uuid` and `remote_chr_uuid`.
|
||||
|
||||
* **Characteristic Validation**: If the characteristic isn't found within the peer, an error message is logged to indicate the absence of the expected subscribable characteristic.
|
||||
|
||||
* **Characteristic Write**: Assuming the characteristic is found, the function tries to write a single byte (0x19) to it. This test is performed to determine if the characteristic will notify the Central device after subscribing. The `ble_gattc_write_flat` function handles this operation.
|
||||
|
||||
* **Write Outcome Check**: In case the write operation fails (`rc != 0`), an error message is logged to indicate the failure in writing to the subscribable characteristic.
|
||||
|
||||
* **Return Value**: The function returns `0` to signal the completion of processing. In case of errors, connection termination is initiated within the error-handling segments.
|
||||
|
||||
|
||||
## blecent_custom_gatt_operations
|
||||
```c
|
||||
/**
|
||||
* Performs 3 operations on the remote GATT server.
|
||||
* 1. Subscribes to a characteristic by writing 0x10 to it's CCCD.
|
||||
* 2. Writes to the characteristic and expect a notification from remote.
|
||||
* 3. Reads the characteristic and expect to get the recently written information.
|
||||
**/
|
||||
static void
|
||||
blecent_custom_gatt_operations(const struct peer* peer)
|
||||
{
|
||||
const struct peer_dsc *dsc;
|
||||
int rc;
|
||||
uint8_t value[2];
|
||||
|
||||
dsc = peer_dsc_find_uuid(peer,
|
||||
remote_svc_uuid,
|
||||
remote_chr_uuid,
|
||||
BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16));
|
||||
if (dsc == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error: Peer lacks a CCCD for the subscribable characterstic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*** Write 0x00 and 0x01 (The subscription code) to the CCCD ***/
|
||||
value[0] = 1;
|
||||
value[1] = 0;
|
||||
rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle,
|
||||
value, sizeof(value), blecent_on_custom_subscribe, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR,
|
||||
"Error: Failed to subscribe to the subscribable characteristic; "
|
||||
"rc=%d\n", rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
/* Terminate the connection */
|
||||
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
```
|
||||
|
||||
`blecent_custom_gatt_operations` function demonstrates various GATT interactions, including subscribing to a characteristic, writing to it, and reading from it.
|
||||
|
||||
* **Finding CCCD Descriptor**: The function begins by searching for a specific Client Characteristic Configuration Descriptor (CCCD) associated with a subscribable characteristic. This search employs the `peer_dsc_find_uuid` function using provided UUIDs.
|
||||
|
||||
* **Checking CCCD Availability**: If the CCCD is not found (`dsc` is `NULL`), an error message is logged, and the connection is terminated.
|
||||
|
||||
* **Subscribing to Characteristic**: The function assembles a two-byte value array with `value[0]` indicating subscription (set to 1) and `value[1]` set to 0. It utilizes `ble_gattc_write_flat` to write this value to the CCCD, subscribing to characteristic notifications. If the write operation fails (returns non-zero), an error message is logged, and the connection is terminated.
|
||||
|
||||
* **Successful Execution**: If the subscription write succeeds, the function returns without further actions.
|
||||
|
||||
* **Error Handling**: In case of any failures, the code proceeds to the `err` label, terminating the BLE connection using `ble_gap_terminate` with the relevant error code.
|
||||
|
||||
|
||||
## blecent_on_subscribe
|
||||
|
||||
```c
|
||||
/**
|
||||
* Application callback. Called when the attempt to subscribe to notifications
|
||||
* for the ANS Unread Alert Status characteristic has completed.
|
||||
*/
|
||||
static int
|
||||
blecent_on_subscribe(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
struct peer *peer;
|
||||
|
||||
MODLOG_DFLT(INFO, "Subscribe complete; status=%d conn_handle=%d "
|
||||
"attr_handle=%d\n",
|
||||
error->status, conn_handle, attr->handle);
|
||||
|
||||
peer = peer_find(conn_handle);
|
||||
if (peer == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error in finding peer, aborting...");
|
||||
ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
/* Subscribe to, write to, and read the custom characteristic*/
|
||||
blecent_custom_gatt_operations(peer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
`blecent_on_subscribe` function's purpose is to handle the completion of subscribing to notifications for a specific characteristic in a BLE Peripheral device.
|
||||
|
||||
* **Parameters**:
|
||||
- `conn_handle`: Corresponds to the BLE connection's handle.
|
||||
- `error`: Points to a `struct ble_gatt_error` indicating the outcome of the subscription attempt.
|
||||
- `attr`: Points to the GATT attribute linked with the subscribed characteristic.
|
||||
- `arg`: Represents a user-defined argument passed into the callback.
|
||||
|
||||
* **Logging**: The function logs subscription completion details utilizing `MODLOG_DFLT(INFO, ...)`. It reports subscription status, connection handle, and attribute handle.
|
||||
|
||||
* **Peer Identification**: The function endeavors to locate the associated `peer` (Peripheral device) linked with the provided `conn_handle`. If the peer can't be located, it logs an error message and terminates the BLE connection with the peripheral using `ble_gap_terminate`, coupled with error code `BLE_ERR_REM_USER_CONN_TERM`.
|
||||
|
||||
* **Custom GATT Operations**: Presuming the peer is successfully identified, the code implies the existence of a function named `blecent_custom_gatt_operations`. This function likely performs extra custom GATT (Generic Attribute Profile) operations on the peripheral. Such operations could encompass writing to or reading from custom characteristics or attributes.
|
||||
|
||||
|
||||
## blecent_on_write
|
||||
|
||||
```c
|
||||
/**
|
||||
* Application callback. Called when the write to the ANS Alert Notification
|
||||
* Control Point characteristic has completed.
|
||||
*/
|
||||
static int
|
||||
blecent_on_write(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
MODLOG_DFLT(INFO,
|
||||
"Write complete; status=%d conn_handle=%d attr_handle=%d\n",
|
||||
error->status, conn_handle, attr->handle);
|
||||
|
||||
/* Subscribe to notifications for the Unread Alert Status characteristic.
|
||||
* A central enables notifications by writing two bytes (1, 0) to the
|
||||
* characteristic's client-characteristic-configuration-descriptor (CCCD).
|
||||
*/
|
||||
const struct peer_dsc *dsc;
|
||||
uint8_t value[2];
|
||||
int rc;
|
||||
const struct peer *peer = peer_find(conn_handle);
|
||||
|
||||
dsc = peer_dsc_find_uuid(peer,
|
||||
BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID),
|
||||
BLE_UUID16_DECLARE(BLECENT_CHR_UNR_ALERT_STAT_UUID),
|
||||
BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16));
|
||||
if (dsc == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error: Peer lacks a CCCD for the Unread Alert "
|
||||
"Status characteristic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
value[0] = 1;
|
||||
value[1] = 0;
|
||||
rc = ble_gattc_write_flat(conn_handle, dsc->dsc.handle,
|
||||
value, sizeof value, blecent_on_subscribe, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to subscribe to characteristic; "
|
||||
"rc=%d\n", rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
/* Terminate the connection. */
|
||||
return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
```
|
||||
|
||||
This function gets triggered upon the completion of a write operation to the ANS (Alert Notification Service) Alert Notification Control Point characteristic. Here's a breakdown of the code's components:
|
||||
|
||||
* **Subscription to Notifications**: The primary objective of the function is to subscribe to notifications for the Unread Alert Status characteristic. Notifications are enabled by writing two bytes (1, 0) to the Client Characteristic Configuration Descriptor (CCCD) of the characteristic.
|
||||
|
||||
* **Locating CCCD Descriptor**: The `peer_dsc_find_uuid` function is employed to find the CCCD descriptor associated with the Unread Alert Status characteristic. This entails locating a specific descriptor with a particular UUID linked to CCCD. In case the descriptor isn't found, an error message is logged, and the code proceeds to the `err` label.
|
||||
|
||||
* **Preparing Subscription Value**: The code prepares the subscription value as an array of two bytes: [1, 0]. This value's purpose is to enable notifications for the characteristic.
|
||||
|
||||
* **Initiating Write Operation**: The function then uses `ble_gattc_write_flat` to execute a flat write operation. It writes the subscription value to the CCCD descriptor's handle. The `blecent_on_subscribe` callback function is designated to manage the completion of the subscription write operation.
|
||||
|
||||
* **Error Handling for Write**: If the write operation encounters a failure (as indicated by a non-zero return value from `ble_gattc_write_flat`), an error message is logged, and the code proceeds to the `err` label.
|
||||
|
||||
|
||||
## blecent_on_read
|
||||
|
||||
```c
|
||||
/**
|
||||
* Application callback. Called when the read of the ANS Supported New Alert
|
||||
* Category characteristic has completed.
|
||||
*/
|
||||
static int
|
||||
blecent_on_read(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "Read complete; status=%d conn_handle=%d", error->status,
|
||||
conn_handle);
|
||||
if (error->status == 0) {
|
||||
MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle);
|
||||
print_mbuf(attr->om);
|
||||
}
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
/* Write two bytes (99, 100) to the alert-notification-control-point
|
||||
* characteristic.
|
||||
*/
|
||||
const struct peer_chr *chr;
|
||||
uint8_t value[2];
|
||||
int rc;
|
||||
const struct peer *peer = peer_find(conn_handle);
|
||||
|
||||
chr = peer_chr_find_uuid(peer,
|
||||
BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID),
|
||||
BLE_UUID16_DECLARE(BLECENT_CHR_ALERT_NOT_CTRL_PT));
|
||||
if (chr == NULL) {
|
||||
MODLOG_DFLT(ERROR, "Error: Peer doesn't support the Alert "
|
||||
"Notification Control Point characteristic\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
value[0] = 99;
|
||||
value[1] = 100;
|
||||
rc = ble_gattc_write_flat(conn_handle, chr->chr.val_handle,
|
||||
value, sizeof value, blecent_on_write, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "Error: Failed to write characteristic; rc=%d\n",
|
||||
rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
/* Terminate the connection. */
|
||||
return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
```
|
||||
|
||||
The `blecent_on_read` function is called when a read operation for a certain characteristic is completed.
|
||||
|
||||
* **Logging Read Status**: The function logs information regarding the read operation, including its status and the connection handle. If the read operation is successful (status equals `0`), it also logs the attribute handle and the value read from the characteristic using the `print_mbuf` function.
|
||||
|
||||
* **Writing to a Characteristic**: The code proceeds to write two bytes (`99` and `100`) to the Alert Notification Control Point characteristic. It locates the characteristic using `peer_chr_find_uuid` based on its UUID values. If the characteristic is not found (i.e., `chr` is `NULL`), it logs an error message and proceeds to the `err` label.
|
||||
|
||||
* **Write Operation**: When the Alert Notification Control Point characteristic is found, the code prepares the data to be written (an array called `value` containing two bytes) and employs `ble_gattc_write_flat` to execute the write operation. The completion of the write operation triggers the `blecent_on_write` callback function. If the write operation encounters an error (return code `rc` is non-zero), the code logs an error message and proceeds to the `err` label.
|
||||
|
||||
* **Handling Errors**: If an error occurs (such as not finding the characteristic or a failed write operation), the code terminates the connection using `ble_gap_terminate` with the reason code `BLE_ERR_REM_USER_CONN_TERM`.
|
||||
|
||||
In essence, this callback function handles reading a characteristic's value, logs the result, and potentially performs a subsequent write operation to another characteristic.
|
||||
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this example code, we've explored how to initiate BLE scanning, discover nearby Peripheral devices, establish connections, and interact with their services and characteristics.
|
||||
|
||||
**Key Takeaways**:
|
||||
|
||||
- **Initialization**: The code initializes the BLE stack and sets up event handlers.
|
||||
- **Scanning**: The Central device scans for nearby BLE Peripheral devices and filters interesting devices based on criteria like service UUIDs or peer addresses.
|
||||
- **Connection Management**: When a suitable Peripheral is found, the Central initiates a connection and handles connection events.
|
||||
- **Service Discovery**: After connection, the Central performs service discovery to identify the services and characteristics supported by the Peripheral.
|
||||
- **GATT Procedures**: The code showcases read, write, and subscription procedures with the discovered services and characteristics.
|
||||
- **Error Handling**: Proper error handling ensures termination of connections in case of failures.
|
||||
@@ -0,0 +1,8 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(ble_chan_sound_reflector)
|
||||
@@ -0,0 +1,97 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
|
||||
|
||||
# BLE Peripheral Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example creates GATT server and then starts advertising, waiting to be connected to a GATT client.
|
||||
|
||||
It uses ESP32's Bluetooth controller and NimBLE stack based BLE host.
|
||||
|
||||
This example aims at understanding GATT database configuration, handling GATT reads and writes, handling subscribe events, understanding advertisement and SMP related NimBLE APIs.
|
||||
|
||||
It also demonstrates security features of NimBLE stack. SMP parameters like I/O capabilities of device, Bonding flag, MITM protection flag and Secure Connection only mode, Enabling Link Encryption etc., can be configured through menuconfig options.
|
||||
|
||||
For RPA feature (currently Host based privacy feature is supported), use API `ble_hs_pvcy_rpa_config` to enable/disable host based privacy, `own_addr_type` needs to be set to `BLE_ADDR_RANDOM` to use this feature. Please include `ble_hs_pvcy.h` while using this API. As `ble_hs_pvcy_rpa_config` configures host privacy and sets address in controller, it is necessary to call this API after host-controller are synced (e.g. in `bleprph_on_sync` callback).
|
||||
|
||||
To test this demo, any BLE scanner app can be used.
|
||||
|
||||
Note :
|
||||
|
||||
* To install the dependency packages needed, please refer to the top level [README file](../../../README.md#running-test-python-script-pytest).
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
```bash
|
||||
idf.py set-target <chip_name>
|
||||
```
|
||||
|
||||
### Configure the project
|
||||
|
||||
Open the project configuration menu:
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
In the `Example Configuration` menu:
|
||||
|
||||
* Select I/O capabilities of device from `Example Configuration --> I/O Capability`, default is `Just_works`.
|
||||
* Enable/Disable other security related parameters `Bonding, MITM option, secure connection(SM SC)`.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
There is this console output when bleprph is connected and characteristic is read:
|
||||
|
||||
```
|
||||
I (118) BTDM_INIT: BT controller compile version [fe7ced0]
|
||||
I (118) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
W (128) phy_init: failed to load RF calibration data (0xffffffff), falling back to full calibration
|
||||
I (268) phy: phy_version: 4100, 6fa5e27, Jan 25 2019, 17:02:06, 0, 2
|
||||
I (508) NimBLE_BLE_PRPH: BLE Host Task Started
|
||||
I (508) uart: queue free spaces: 8
|
||||
GAP procedure initiated: stop advertising.
|
||||
Device Address: xx:xx:xx:xx:xx:xx
|
||||
GAP procedure initiated: advertise; disc_mode=2 adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0
|
||||
connection established; status=0 handle=0 our_ota_addr_type=0 our_ota_addr=xx:xx:xx:xx:xx:xx our_id_addr_type=0 our_id_addr=xx:xx:xx:xx:xx:xx peer_ota_addr_type=1 peer_ota_addr=xx:xx:xx:xx:xx:xx peer_id_addr_type=1 peer_id_addr=xx:xx:xx:xx:xx:xx conn_itvl=39 conn_latency=0 supervision_timeout=500 encrypted=0 authenticated=0 bonded=0
|
||||
|
||||
connection updated; status=0 handle=0 our_ota_addr_type=0 our_ota_addr=xx:xx:xx:xx:xx:xx our_id_addr_type=0 our_id_addr=xx:xx:xx:xx:xx:xx peer_ota_addr_type=1 peer_ota_addr=xx:xx:xx:xx:xx:xx peer_id_addr_type=1 peer_id_addr=xx:xx:xx:xx:xx:xx conn_itvl=6 conn_latency=0 supervision_timeout=500 encrypted=0 authenticated=0 bonded=0
|
||||
|
||||
I (50888) NimBLE_BLE_PRPH: PASSKEY_ACTION_EVENT started
|
||||
|
||||
I (50888) NimBLE_BLE_PRPH: Passkey on device's display: xxxxxx
|
||||
I (50888) NimBLE_BLE_PRPH: Accept or reject the passkey through console in this format -> key Y or key N
|
||||
key Y
|
||||
I (50898) NimBLE_BLE_PRPH: ble_sm_inject_io result: 0
|
||||
|
||||
encryption change event; status=0 handle=0 our_ota_addr_type=0 our_ota_addr=xx:xx:xx:xx:xx:xx our_id_addr_type=0 our_id_addr=xx:xx:xx:xx:xx:xx peer_ota_addr_type=1 peer_ota_addr=xx:xx:xx:xx:xx:xx peer_id_addr_type=1
|
||||
peer_id_addr=xx:xx:xx:xx:xx:xx conn_itvl=6 conn_latency=0 supervision_timeout=500 encrypted=1 authenticated=1 bonded=1
|
||||
|
||||
connection updated; status=0 handle=0 our_ota_addr_type=0 our_ota_addr=xx:xx:xx:xx:xx:xx our_id_addr_type=0 our_id_addr=xx:xx:xx:xx:xx:xx
|
||||
peer_ota_addr_type=1 peer_ota_addr=xx:xx:xx:xx:xx:xx peer_id_addr_type=1 peer_id_addr=xx:xx:xx:xx:xx:xx conn_itvl=39 conn_latency=0 supervision_timeout=500 encrypted=1 authenticated=1 bonded=1
|
||||
|
||||
subscribe event; conn_handle=1 attr_handle=19 reason=1 prevn=0 curn=1 previ=0 curi=0
|
||||
Subscribe to attribute (19) successful
|
||||
subscribe event; conn_handle=1 attr_handle=25 reason=1 prevn=0 curn=1 previ=0 curi=0
|
||||
Subscribe to attribute (25) successful
|
||||
GATT procedure initiated: notify; att_handle=25
|
||||
Notification sent successfully
|
||||
```
|
||||
|
||||
## Note
|
||||
* NVS support is not yet integrated to bonding. So, for now, bonding is not persistent across reboot.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
||||
@@ -0,0 +1,5 @@
|
||||
set(srcs "main.c"
|
||||
"gatt_svr.c")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,80 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_USE_IO_TYPE
|
||||
prompt "I/O Capability"
|
||||
default BLE_SM_IO_CAP_NO_IO
|
||||
help
|
||||
I/O capability of device.
|
||||
|
||||
config BLE_SM_IO_CAP_DISP_ONLY
|
||||
bool "DISPLAY ONLY"
|
||||
config BLE_SM_IO_CAP_DISP_YES_NO
|
||||
bool "DISPLAY YESNO"
|
||||
config BLE_SM_IO_CAP_KEYBOARD_ONLY
|
||||
bool "KEYBOARD ONLY"
|
||||
config BLE_SM_IO_CAP_NO_IO
|
||||
bool "Just works"
|
||||
config BLE_SM_IO_CAP_KEYBOARD_DISP
|
||||
bool "Both KEYBOARD & DISPLAY"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_IO_TYPE
|
||||
int
|
||||
default 0 if BLE_SM_IO_CAP_DISP_ONLY
|
||||
default 1 if BLE_SM_IO_CAP_DISP_YES_NO
|
||||
default 2 if BLE_SM_IO_CAP_KEYBOARD_ONLY
|
||||
default 3 if BLE_SM_IO_CAP_NO_IO
|
||||
default 4 if BLE_SM_IO_CAP_KEYBOARD_DISP
|
||||
|
||||
config EXAMPLE_BONDING
|
||||
bool
|
||||
default n
|
||||
prompt "Use Bonding"
|
||||
help
|
||||
Use this option to enable/disable bonding.
|
||||
|
||||
config EXAMPLE_MITM
|
||||
bool
|
||||
default n
|
||||
prompt "MITM security"
|
||||
help
|
||||
Use this option to enable/disable MITM security.
|
||||
|
||||
config EXAMPLE_USE_SC
|
||||
bool
|
||||
depends on BT_NIMBLE_SM_SC
|
||||
default n
|
||||
prompt "Use Secure Connection feature"
|
||||
help
|
||||
Use this option to enable/disable Security Manager Secure Connection 4.2 feature.
|
||||
|
||||
config EXAMPLE_EXTENDED_ADV
|
||||
bool
|
||||
depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT
|
||||
default y if SOC_ESP_NIMBLE_CONTROLLER
|
||||
select BT_NIMBLE_EXT_ADV
|
||||
prompt "Enable Extended Adv"
|
||||
help
|
||||
Use this option to enable extended advertising in the example.
|
||||
If this option is disabled, ensure config BT_NIMBLE_EXT_ADV is
|
||||
also disabled from Nimble stack menuconfig
|
||||
|
||||
config EXAMPLE_RANDOM_ADDR
|
||||
bool
|
||||
prompt "Advertise RANDOM Address"
|
||||
help
|
||||
Use this option to advertise a random address instead of public address
|
||||
|
||||
config EXAMPLE_ENCRYPTION
|
||||
bool
|
||||
prompt "Enable Link Encryption"
|
||||
help
|
||||
This adds Encrypted Read and Write permissions in the custom GATT server.
|
||||
|
||||
config EXAMPLE_RESOLVE_PEER_ADDR
|
||||
bool
|
||||
prompt "Enable resolving peer address"
|
||||
help
|
||||
Use this option to enable resolving peer's address.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef H_BLEPRPH_
|
||||
#define H_BLEPRPH_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "nimble/ble.h"
|
||||
#include "modlog/modlog.h"
|
||||
#include "esp_peripheral.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ble_hs_cfg;
|
||||
struct ble_gatt_register_ctxt;
|
||||
|
||||
/** GATT server. */
|
||||
|
||||
#define BLE_UUID_RANGING_SERVICE_VAL (0x185B)
|
||||
|
||||
/** @brief UUID of the RAS Features Characteristic. **/
|
||||
#define BLE_UUID_RAS_FEATURES_VAL (0x2C14)
|
||||
|
||||
/** @brief UUID of the Real-time Ranging Data Characteristic. **/
|
||||
#define BLE_UUID_RAS_REALTIME_RD_VAL (0x2C15)
|
||||
|
||||
/** @brief UUID of the On-demand Ranging Data Characteristic. **/
|
||||
#define BLE_UUID_RAS_ONDEMAND_RD_VAL (0x2C16)
|
||||
|
||||
/** @brief UUID of the RAS Control Point Characteristic. **/
|
||||
#define BLE_UUID_RAS_CP_VAL (0x2C17)
|
||||
|
||||
/** @brief UUID of the Ranging Data Ready Characteristic. **/
|
||||
#define BLE_UUID_RAS_RD_READY_VAL (0x2C18)
|
||||
|
||||
/** @brief UUID of the Ranging Data Overwritten Characteristic. **/
|
||||
#define BLE_UUID_RAS_RD_OVERWRITTEN_VAL (0x2C19)
|
||||
|
||||
|
||||
extern uint16_t hrs_hrm_handle;
|
||||
|
||||
|
||||
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
int gatt_svr_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
#include "bleprph.h"
|
||||
#include "services/ans/ble_svc_ans.h"
|
||||
|
||||
static uint8_t ras_feat_val;
|
||||
static uint16_t ras_feat_val_handle;
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_ras_val(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
||||
{
|
||||
/* Service: Ranging Data Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RANGING_SERVICE_VAL),
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{ {
|
||||
/* Characteristic: Feature Value */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_FEATURES_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.val_handle = &ras_feat_val_handle,
|
||||
.flags = BLE_GATT_CHR_F_READ|BLE_GATT_CHR_F_READ_ENC,
|
||||
}, {
|
||||
/* Characteristic: On demand ranging data */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_ONDEMAND_RD_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE |BLE_GATT_CHR_F_READ_ENC |BLE_GATT_CHR_F_READ,
|
||||
},{
|
||||
/* Characteristic: RAS Control Point */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_CP_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_INDICATE |BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_READ ,
|
||||
},{
|
||||
/* Characteristic: RAS Data Ready */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_RD_READY_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_READ_ENC|BLE_GATT_CHR_F_READ,
|
||||
},{
|
||||
/* Characteristic: RAS data overwritten */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_RD_OVERWRITTEN_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_READ_ENC|BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
0, /* No more characteristics in this service */
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
0, /* No more services */
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_ras_val(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
const ble_uuid_t *uuid;
|
||||
int rc;
|
||||
printf("ctxt->op = %d\n",ctxt->op);
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
printf("reading call back \n");
|
||||
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
MODLOG_DFLT(INFO, "Characteristic read; conn_handle=%d attr_handle=%d\n",
|
||||
conn_handle, attr_handle);
|
||||
} else {
|
||||
MODLOG_DFLT(INFO, "Characteristic read by NimBLE stack; attr_handle=%d\n",
|
||||
attr_handle);
|
||||
}
|
||||
uuid = ctxt->chr->uuid;
|
||||
if(uuid == BLE_UUID_RAS_FEATURES_VAL){
|
||||
|
||||
if (attr_handle == ras_feat_val_handle) {
|
||||
rc = os_mbuf_append(ctxt->om,
|
||||
&ras_feat_val,
|
||||
sizeof(ras_feat_val));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
MODLOG_DFLT(INFO, "Characteristic write; conn_handle=%d attr_handle=%d",
|
||||
conn_handle, attr_handle);
|
||||
} else {
|
||||
MODLOG_DFLT(INFO, "Characteristic write by NimBLE stack; attr_handle=%d",
|
||||
attr_handle);
|
||||
}
|
||||
uuid = ctxt->chr->uuid;
|
||||
// if (attr_handle == ras_feat_val_handle) {
|
||||
// rc = gatt_svr_write(ctxt->om,
|
||||
// sizeof(ras_feat_val),
|
||||
// sizeof(ras_feat_val),
|
||||
// &ras_feat_val, NULL);
|
||||
// ble_gatts_chr_updated(attr_handle);
|
||||
// MODLOG_DFLT(INFO, "Notification/Indication scheduled for "
|
||||
// "all subscribed peers.\n");
|
||||
// return rc;
|
||||
// }
|
||||
return 0;
|
||||
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
|
||||
unknown:
|
||||
/* Unknown characteristic/descriptor;
|
||||
* The NimBLE host should not have called this function;
|
||||
*/
|
||||
//assert(0);
|
||||
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_REGISTER_OP_SVC:
|
||||
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
|
||||
ctxt->svc.handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_CHR:
|
||||
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
|
||||
"def_handle=%d val_handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||
ctxt->chr.def_handle,
|
||||
ctxt->chr.val_handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_DSC:
|
||||
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
|
||||
ctxt->dsc.handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gatt_svr_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
nimble_peripheral_utils:
|
||||
path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils
|
||||
@@ -0,0 +1,683 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
/* BLE */
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "console/console.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "bleprph.h"
|
||||
#include "host/ble_cs.h"
|
||||
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
static uint8_t ext_adv_pattern_1[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x03, 0x03, 0xab, 0xcd,
|
||||
0x03, 0x03, 0x18, 0x11,
|
||||
0x11, 0X09, 'n', 'i', 'm', 'b', 'l', 'e', '-', 'b', 'l', 'e', 'p', 'r', 'p', 'h', '-', 'e',
|
||||
};
|
||||
#endif
|
||||
|
||||
static const char *tag = "NimBLE_BLE_PRPH";
|
||||
static int bleprph_gap_event(struct ble_gap_event *event, void *arg);
|
||||
#if CONFIG_EXAMPLE_RANDOM_ADDR
|
||||
static uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM;
|
||||
#else
|
||||
static uint8_t own_addr_type;
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0
|
||||
static uint16_t cids[MYNEWT_VAL(BLE_EATT_CHAN_NUM)];
|
||||
static uint16_t bearers;
|
||||
#endif
|
||||
|
||||
void ble_store_config_init(void);
|
||||
|
||||
|
||||
#define BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_COMPLETE 0x0
|
||||
#define BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_PARTIAL 0x1
|
||||
#define BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_ABORTED 0xF
|
||||
|
||||
#define LOCAL_PROCEDURE_MEM 1024 // Replace with an appropriate constant value
|
||||
|
||||
|
||||
static struct cs_steps_data local_cs_steps_data[LOCAL_PROCEDURE_MEM];
|
||||
static struct cs_steps_data peer_cs_steps_data[LOCAL_PROCEDURE_MEM];
|
||||
static uint16_t most_recent_local_ranging_counter;
|
||||
static uint16_t dropped_ranging_counter = -1;
|
||||
static uint8_t nap;
|
||||
|
||||
static int blecs_gap_event(struct ble_cs_event *event, void *arg){
|
||||
int rc=0;
|
||||
|
||||
extern void bt_hci_log_hci_data_show(void);
|
||||
bt_hci_log_hci_data_show();
|
||||
switch(event->type){
|
||||
case BLE_CS_EVENT_CS_PROCEDURE_COMPLETE:
|
||||
printf("LE CS Procedure Complete , procedure counter");
|
||||
break;
|
||||
case BLE_CS_EVENT_SUBEVET_RESULT:
|
||||
MODLOG_DFLT(INFO, "LE CS Subevent Result , procedure counter: %d\n", event->subev_result.procedure_counter);
|
||||
|
||||
if(event->subev_result.subevent_done_status == BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_ABORTED){
|
||||
MODLOG_DFLT(INFO, "LE CS Subevent Result , status: Aborted\n");
|
||||
dropped_ranging_counter=event->subev_result.procedure_counter;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(dropped_ranging_counter==event->subev_result.procedure_counter){
|
||||
MODLOG_DFLT(INFO, "Ranging procedure was aborted\n");
|
||||
return 0;
|
||||
}
|
||||
if(event->subev_result.num_steps_reported){
|
||||
memcpy(&local_cs_steps_data, event->subev_result.steps, sizeof local_cs_steps_data);
|
||||
|
||||
}
|
||||
nap=event->subev_result.num_antenna_paths;
|
||||
|
||||
if(event->subev_result.procedure_done_status == BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_COMPLETE){
|
||||
most_recent_local_ranging_counter=event->subev_result.procedure_counter;
|
||||
}
|
||||
else if(event->subev_result.procedure_done_status == BLE_HCI_LE_CS_SUBEVENT_DONE_STATUS_ABORTED){
|
||||
MODLOG_DFLT(INFO, "LE CS Procedure , status: Aborted\n");
|
||||
memset(&local_cs_steps_data,0,sizeof local_cs_steps_data);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BLE_CS_EVENT_SUBEVET_RESULT_CONTINUE:
|
||||
printf("LE CS Subevent Result Continue , procedure counter:");
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static void
|
||||
bleprph_print_conn_desc(struct ble_gap_conn_desc *desc)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=",
|
||||
desc->conn_handle, desc->our_ota_addr.type);
|
||||
print_addr(desc->our_ota_addr.val);
|
||||
MODLOG_DFLT(INFO, " our_id_addr_type=%d our_id_addr=",
|
||||
desc->our_id_addr.type);
|
||||
print_addr(desc->our_id_addr.val);
|
||||
MODLOG_DFLT(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
|
||||
desc->peer_ota_addr.type);
|
||||
print_addr(desc->peer_ota_addr.val);
|
||||
MODLOG_DFLT(INFO, " peer_id_addr_type=%d peer_id_addr=",
|
||||
desc->peer_id_addr.type);
|
||||
print_addr(desc->peer_id_addr.val);
|
||||
MODLOG_DFLT(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
|
||||
"encrypted=%d authenticated=%d bonded=%d\n",
|
||||
desc->conn_itvl, desc->conn_latency,
|
||||
desc->supervision_timeout,
|
||||
desc->sec_state.encrypted,
|
||||
desc->sec_state.authenticated,
|
||||
desc->sec_state.bonded);
|
||||
}
|
||||
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
/**
|
||||
* Enables advertising with the following parameters:
|
||||
* o General discoverable mode.
|
||||
* o Undirected connectable mode.
|
||||
*/
|
||||
static void
|
||||
ext_bleprph_advertise(void)
|
||||
{
|
||||
struct ble_gap_ext_adv_params params;
|
||||
struct os_mbuf *data;
|
||||
uint8_t instance = 0;
|
||||
int rc;
|
||||
|
||||
/* First check if any instance is already active */
|
||||
if(ble_gap_ext_adv_active(instance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* use defaults for non-set params */
|
||||
memset (¶ms, 0, sizeof(params));
|
||||
|
||||
/* enable connectable advertising */
|
||||
params.connectable = 1;
|
||||
|
||||
/* advertise using random addr */
|
||||
params.own_addr_type = BLE_OWN_ADDR_PUBLIC;
|
||||
|
||||
params.primary_phy = BLE_HCI_LE_PHY_1M;
|
||||
params.secondary_phy = BLE_HCI_LE_PHY_2M;
|
||||
//params.tx_power = 127;
|
||||
params.sid = 1;
|
||||
|
||||
params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
|
||||
params.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
|
||||
|
||||
/* configure instance 0 */
|
||||
rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL,
|
||||
bleprph_gap_event, NULL);
|
||||
assert (rc == 0);
|
||||
|
||||
/* in this case only scan response is allowed */
|
||||
|
||||
/* get mbuf for scan rsp data */
|
||||
data = os_msys_get_pkthdr(sizeof(ext_adv_pattern_1), 0);
|
||||
assert(data);
|
||||
|
||||
/* fill mbuf with scan rsp data */
|
||||
rc = os_mbuf_append(data, ext_adv_pattern_1, sizeof(ext_adv_pattern_1));
|
||||
assert(rc == 0);
|
||||
|
||||
rc = ble_gap_ext_adv_set_data(instance, data);
|
||||
assert (rc == 0);
|
||||
|
||||
/* start advertising */
|
||||
rc = ble_gap_ext_adv_start(instance, 0, 0);
|
||||
// assert (rc == 0);
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* Enables advertising with the following parameters:
|
||||
* o General discoverable mode.
|
||||
* o Undirected connectable mode.
|
||||
*/
|
||||
static void
|
||||
bleprph_advertise(void)
|
||||
{
|
||||
struct ble_gap_adv_params adv_params;
|
||||
struct ble_hs_adv_fields fields;
|
||||
const char *name;
|
||||
int rc;
|
||||
|
||||
/**
|
||||
* Set the advertisement data included in our advertisements:
|
||||
* o Flags (indicates advertisement type and other general info).
|
||||
* o Advertising tx power.
|
||||
* o Device name.
|
||||
* o 16-bit service UUIDs (alert notifications).
|
||||
*/
|
||||
|
||||
memset(&fields, 0, sizeof fields);
|
||||
|
||||
/* Advertise two flags:
|
||||
* o Discoverability in forthcoming advertisement (general)
|
||||
* o BLE-only (BR/EDR unsupported).
|
||||
*/
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN |
|
||||
BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
|
||||
/* Indicate that the TX power level field should be included; have the
|
||||
* stack fill this value automatically. This is done by assigning the
|
||||
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
|
||||
*/
|
||||
fields.tx_pwr_lvl_is_present = 1;
|
||||
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||
|
||||
name = ble_svc_gap_device_name();
|
||||
fields.name = (uint8_t *)name;
|
||||
fields.name_len = strlen(name);
|
||||
fields.name_is_complete = 1;
|
||||
|
||||
fields.uuids16 = (ble_uuid16_t[]) {
|
||||
BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)
|
||||
};
|
||||
fields.num_uuids16 = 1;
|
||||
fields.uuids16_is_complete = 1;
|
||||
|
||||
rc = ble_gap_adv_set_fields(&fields);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Begin advertising. */
|
||||
memset(&adv_params, 0, sizeof adv_params);
|
||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
|
||||
&adv_params, bleprph_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_POWER_CONTROL)
|
||||
static void bleprph_power_control(uint16_t conn_handle)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_gap_read_remote_transmit_power_level(conn_handle, 0x01 ); // Attempting on LE 1M phy
|
||||
assert (rc == 0);
|
||||
|
||||
rc = ble_gap_set_transmit_power_reporting_enable(conn_handle, 0x1, 0x1);
|
||||
assert (rc == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The nimble host executes this callback when a GAP event occurs. The
|
||||
* application associates a GAP event callback with each connection that forms.
|
||||
* bleprph uses the same callback for all connections.
|
||||
*
|
||||
* @param event The type of event being signalled.
|
||||
* @param ctxt Various information pertaining to the event.
|
||||
* @param arg Application-specified argument; unused by
|
||||
* bleprph.
|
||||
*
|
||||
* @return 0 if the application successfully handled the
|
||||
* event; nonzero on failure. The semantics
|
||||
* of the return code is specific to the
|
||||
* particular GAP event being signalled.
|
||||
*/
|
||||
static int
|
||||
bleprph_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
struct ble_gap_conn_desc desc;
|
||||
int rc;
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
/* A new connection was established or a connection attempt failed. */
|
||||
MODLOG_DFLT(INFO, "connection %s; status=%d ",
|
||||
event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
if (event->connect.status == 0) {
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
bleprph_print_conn_desc(&desc);
|
||||
}
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising. */
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
ext_bleprph_advertise();
|
||||
#else
|
||||
bleprph_advertise();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MYNEWT_VAL(BLE_POWER_CONTROL)
|
||||
bleprph_power_control(event->connect.conn_handle);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
|
||||
bleprph_print_conn_desc(&event->disconnect.conn);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
/* Connection terminated; resume advertising. */
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
ext_bleprph_advertise();
|
||||
#else
|
||||
bleprph_advertise();
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
/* The central has updated the connection parameters. */
|
||||
MODLOG_DFLT(INFO, "connection updated; status=%d ",
|
||||
event->conn_update.status);
|
||||
rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
bleprph_print_conn_desc(&desc);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
MODLOG_DFLT(INFO, "advertise complete; reason=%d",
|
||||
event->adv_complete.reason);
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
ext_bleprph_advertise();
|
||||
#else
|
||||
bleprph_advertise();
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_ENC_CHANGE:
|
||||
/* Encryption has been enabled or disabled for this connection. */
|
||||
MODLOG_DFLT(INFO, "encryption change event; status=%d ",
|
||||
event->enc_change.status);
|
||||
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
bleprph_print_conn_desc(&desc);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
struct ble_cs_initiator_procedure_start_params param;
|
||||
memset(¶m,0,sizeof param);
|
||||
param.conn_handle=event->enc_change.conn_handle;
|
||||
param.cb=blecs_gap_event;
|
||||
param.cb_arg=NULL;
|
||||
|
||||
ble_cs_initiator_procedure_start(¶m);
|
||||
vTaskDelay(2000);
|
||||
|
||||
extern void bt_hci_log_hci_data_show(void);
|
||||
bt_hci_log_hci_data_show();
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_NOTIFY_TX:
|
||||
MODLOG_DFLT(INFO, "notify_tx event; conn_handle=%d attr_handle=%d "
|
||||
"status=%d is_indication=%d",
|
||||
event->notify_tx.conn_handle,
|
||||
event->notify_tx.attr_handle,
|
||||
event->notify_tx.status,
|
||||
event->notify_tx.indication);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
MODLOG_DFLT(INFO, "subscribe event; conn_handle=%d attr_handle=%d "
|
||||
"reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
|
||||
event->subscribe.conn_handle,
|
||||
event->subscribe.attr_handle,
|
||||
event->subscribe.reason,
|
||||
event->subscribe.prev_notify,
|
||||
event->subscribe.cur_notify,
|
||||
event->subscribe.prev_indicate,
|
||||
event->subscribe.cur_indicate);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
MODLOG_DFLT(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);
|
||||
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;
|
||||
|
||||
case BLE_GAP_EVENT_PASSKEY_ACTION:
|
||||
ESP_LOGI(tag, "PASSKEY_ACTION_EVENT started");
|
||||
struct ble_sm_io pkey = {0};
|
||||
int key = 0;
|
||||
|
||||
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
|
||||
pkey.action = event->passkey.params.action;
|
||||
pkey.passkey = 123456; // This is the passkey to be entered on peer
|
||||
ESP_LOGI(tag, "Enter passkey %" PRIu32 "on the peer side", pkey.passkey);
|
||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||
ESP_LOGI(tag, "ble_sm_inject_io result: %d", rc);
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
|
||||
ESP_LOGI(tag, "Passkey on device's display: %" PRIu32 , event->passkey.params.numcmp);
|
||||
ESP_LOGI(tag, "Accept or reject the passkey through console in this format -> key Y or key N");
|
||||
pkey.action = event->passkey.params.action;
|
||||
if (scli_receive_key(&key)) {
|
||||
pkey.numcmp_accept = key;
|
||||
} else {
|
||||
pkey.numcmp_accept = 0;
|
||||
ESP_LOGE(tag, "Timeout! Rejecting the key");
|
||||
}
|
||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||
ESP_LOGI(tag, "ble_sm_inject_io result: %d", rc);
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
|
||||
static uint8_t tem_oob[16] = {0};
|
||||
pkey.action = event->passkey.params.action;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
pkey.oob[i] = tem_oob[i];
|
||||
}
|
||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||
ESP_LOGI(tag, "ble_sm_inject_io result: %d", rc);
|
||||
} else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
|
||||
ESP_LOGI(tag, "Enter the passkey through console in this format-> key 123456");
|
||||
pkey.action = event->passkey.params.action;
|
||||
if (scli_receive_key(&key)) {
|
||||
pkey.passkey = key;
|
||||
} else {
|
||||
pkey.passkey = 0;
|
||||
ESP_LOGE(tag, "Timeout! Passing 0 as the key");
|
||||
}
|
||||
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
||||
ESP_LOGI(tag, "ble_sm_inject_io result: %d", rc);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_AUTHORIZE:
|
||||
MODLOG_DFLT(INFO, "authorize event: conn_handle=%d attr_handle=%d is_read=%d",
|
||||
event->authorize.conn_handle,
|
||||
event->authorize.attr_handle,
|
||||
event->authorize.is_read);
|
||||
|
||||
/* The default behaviour for the event is to reject authorize request */
|
||||
event->authorize.out_response = BLE_GAP_AUTHORIZE_REJECT;
|
||||
return 0;
|
||||
|
||||
#if MYNEWT_VAL(BLE_POWER_CONTROL)
|
||||
case BLE_GAP_EVENT_TRANSMIT_POWER:
|
||||
MODLOG_DFLT(INFO, "Transmit power event : status=%d conn_handle=%d reason=%d "
|
||||
"phy=%d power_level=%x power_level_flag=%d delta=%d",
|
||||
event->transmit_power.status,
|
||||
event->transmit_power.conn_handle,
|
||||
event->transmit_power.reason,
|
||||
event->transmit_power.phy,
|
||||
event->transmit_power.transmit_power_level,
|
||||
event->transmit_power.transmit_power_level_flag,
|
||||
event->transmit_power.delta);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_PATHLOSS_THRESHOLD:
|
||||
MODLOG_DFLT(INFO, "Pathloss threshold event : conn_handle=%d current path loss=%d "
|
||||
"zone_entered =%d",
|
||||
event->pathloss_threshold.conn_handle,
|
||||
event->pathloss_threshold.current_path_loss,
|
||||
event->pathloss_threshold.zone_entered);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0
|
||||
case BLE_GAP_EVENT_EATT:
|
||||
MODLOG_DFLT(INFO, "EATT %s : conn_handle=%d cid=%d",
|
||||
event->eatt.status ? "disconnected" : "connected",
|
||||
event->eatt.conn_handle,
|
||||
event->eatt.cid);
|
||||
if (event->eatt.status) {
|
||||
/* Abort if disconnected */
|
||||
return 0;
|
||||
}
|
||||
cids[bearers] = event->eatt.cid;
|
||||
bearers += 1;
|
||||
if (bearers != MYNEWT_VAL(BLE_EATT_CHAN_NUM)) {
|
||||
/* Wait until all EATT bearers are connected before proceeding */
|
||||
return 0;
|
||||
}
|
||||
/* Set the default bearer to use for further procedures */
|
||||
rc = ble_att_set_default_bearer_using_cid(event->eatt.conn_handle, cids[0]);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(INFO, "Cannot set default EATT bearer, rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_CONN_SUBRATING)
|
||||
case BLE_GAP_EVENT_SUBRATE_CHANGE:
|
||||
MODLOG_DFLT(INFO, "Subrate change event : conn_handle=%d status=%d factor=%d",
|
||||
event->subrate_change.conn_handle,
|
||||
event->subrate_change.status,
|
||||
event->subrate_change.subrate_factor);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
bleprph_on_reset(int reason)
|
||||
{
|
||||
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
#if CONFIG_EXAMPLE_RANDOM_ADDR
|
||||
static void
|
||||
ble_app_set_addr(void)
|
||||
{
|
||||
ble_addr_t addr;
|
||||
int rc;
|
||||
|
||||
/* generate new non-resolvable private address */
|
||||
rc = ble_hs_id_gen_rnd(0, &addr);
|
||||
assert(rc == 0);
|
||||
|
||||
/* set generated address */
|
||||
rc = ble_hs_id_set_rnd(addr.val);
|
||||
|
||||
assert(rc == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
bleprph_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
rc = ble_gap_set_host_feat(47,0x01);
|
||||
|
||||
|
||||
/* Make sure we have proper identity address set (public preferred) */
|
||||
#if CONFIG_EXAMPLE_RANDOM_ADDR
|
||||
rc = ble_hs_util_ensure_addr(1);
|
||||
#else
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
#endif
|
||||
assert(rc == 0);
|
||||
|
||||
/* Figure out address to use while advertising (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Printing ADDR */
|
||||
uint8_t addr_val[6] = {0};
|
||||
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
|
||||
|
||||
MODLOG_DFLT(INFO, "Device Address: ");
|
||||
print_addr(addr_val);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
/* Begin advertising. */
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
ext_bleprph_advertise();
|
||||
#else
|
||||
bleprph_advertise();
|
||||
#endif
|
||||
}
|
||||
|
||||
void bleprph_host_task(void *param)
|
||||
{
|
||||
ESP_LOGI(tag, "BLE Host Task Started");
|
||||
/* This function will return only when nimble_port_stop() is executed */
|
||||
nimble_port_run();
|
||||
|
||||
nimble_port_freertos_deinit();
|
||||
}
|
||||
|
||||
void
|
||||
app_main(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Initialize NVS — it is used to store PHY calibration data */
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ret = nimble_port_init();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(tag, "Failed to init nimble %d ", ret);
|
||||
return;
|
||||
}
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = bleprph_on_reset;
|
||||
ble_hs_cfg.sync_cb = bleprph_on_sync;
|
||||
ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
ble_hs_cfg.sm_io_cap = CONFIG_EXAMPLE_IO_TYPE;
|
||||
#ifdef CONFIG_EXAMPLE_BONDING
|
||||
ble_hs_cfg.sm_bonding = 1;
|
||||
/* Enable the appropriate bit masks to make sure the keys
|
||||
* that are needed are exchanged
|
||||
*/
|
||||
ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC;
|
||||
ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC;
|
||||
#endif
|
||||
#ifdef CONFIG_EXAMPLE_MITM
|
||||
ble_hs_cfg.sm_mitm = 1;
|
||||
#endif
|
||||
#ifdef CONFIG_EXAMPLE_USE_SC
|
||||
ble_hs_cfg.sm_sc = 1;
|
||||
#else
|
||||
ble_hs_cfg.sm_sc = 0;
|
||||
#endif
|
||||
#ifdef CONFIG_EXAMPLE_RESOLVE_PEER_ADDR
|
||||
/* Stores the IRK */
|
||||
ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ID;
|
||||
ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ID;
|
||||
#endif
|
||||
|
||||
rc = gatt_svr_init();
|
||||
assert(rc == 0);
|
||||
|
||||
/* Set the default device name. */
|
||||
rc = ble_svc_gap_device_name_set("nimble-bleprph");
|
||||
assert(rc == 0);
|
||||
|
||||
/* XXX Need to have template for store */
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(bleprph_host_task);
|
||||
|
||||
/* Initialize command line interface to accept input from user */
|
||||
rc = scli_init();
|
||||
if (rc != ESP_OK) {
|
||||
ESP_LOGE(tag, "scli_init() failed");
|
||||
}
|
||||
|
||||
#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0
|
||||
bearers = 0;
|
||||
for (int i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_NUM); i++) {
|
||||
cids[i] = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
@@ -0,0 +1,8 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_IDF_TARGET="esp32c2"
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
@@ -0,0 +1,7 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
File diff suppressed because it is too large
Load Diff
@@ -39,6 +39,27 @@ struct ble_gatt_register_ctxt;
|
||||
#define GATT_SVR_CHR_UNR_ALERT_STAT_UUID 0x2A45
|
||||
#define GATT_SVR_CHR_ALERT_NOT_CTRL_PT 0x2A44
|
||||
|
||||
#define BLE_UUID_RANGING_SERVICE_VAL (0x185B)
|
||||
|
||||
/** @brief UUID of the RAS Features Characteristic. **/
|
||||
#define BLE_UUID_RAS_FEATURES_VAL (0x2C14)
|
||||
|
||||
/** @brief UUID of the Real-time Ranging Data Characteristic. **/
|
||||
#define BLE_UUID_RAS_REALTIME_RD_VAL (0x2C15)
|
||||
|
||||
/** @brief UUID of the On-demand Ranging Data Characteristic. **/
|
||||
#define BLE_UUID_RAS_ONDEMAND_RD_VAL (0x2C16)
|
||||
|
||||
/** @brief UUID of the RAS Control Point Characteristic. **/
|
||||
#define BLE_UUID_RAS_CP_VAL (0x2C17)
|
||||
|
||||
/** @brief UUID of the Ranging Data Ready Characteristic. **/
|
||||
#define BLE_UUID_RAS_RD_READY_VAL (0x2C18)
|
||||
|
||||
/** @brief UUID of the Ranging Data Overwritten Characteristic. **/
|
||||
#define BLE_UUID_RAS_RD_OVERWRITTEN_VAL (0x2C19)
|
||||
|
||||
|
||||
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
int gatt_svr_init(void);
|
||||
|
||||
|
||||
@@ -27,113 +27,300 @@
|
||||
#include "bleprph.h"
|
||||
#include "services/ans/ble_svc_ans.h"
|
||||
|
||||
/*** Maximum number of characteristics with the notify flag ***/
|
||||
#define MAX_NOTIFY 5
|
||||
// /*** Maximum number of characteristics with the notify flag ***/
|
||||
// #define MAX_NOTIFY 5
|
||||
|
||||
static const ble_uuid128_t gatt_svr_svc_uuid =
|
||||
BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
|
||||
0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59);
|
||||
// static const ble_uuid128_t gatt_svr_svc_uuid =
|
||||
// BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
|
||||
// 0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59);
|
||||
|
||||
/* A characteristic that can be subscribed to */
|
||||
static uint8_t gatt_svr_chr_val;
|
||||
static uint16_t gatt_svr_chr_val_handle;
|
||||
static const ble_uuid128_t gatt_svr_chr_uuid =
|
||||
BLE_UUID128_INIT(0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,
|
||||
0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33);
|
||||
// /* A characteristic that can be subscribed to */
|
||||
// static uint8_t gatt_svr_chr_val;
|
||||
// static uint16_t gatt_svr_chr_val_handle;
|
||||
// static const ble_uuid128_t gatt_svr_chr_uuid =
|
||||
// BLE_UUID128_INIT(0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,
|
||||
// 0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33);
|
||||
|
||||
/* A custom descriptor */
|
||||
static uint8_t gatt_svr_dsc_val;
|
||||
static const ble_uuid128_t gatt_svr_dsc_uuid =
|
||||
BLE_UUID128_INIT(0x01, 0x01, 0x01, 0x01, 0x12, 0x12, 0x12, 0x12,
|
||||
0x23, 0x23, 0x23, 0x23, 0x34, 0x34, 0x34, 0x34);
|
||||
// /* A custom descriptor */
|
||||
// static uint8_t gatt_svr_dsc_val;
|
||||
// static const ble_uuid128_t gatt_svr_dsc_uuid =
|
||||
// BLE_UUID128_INIT(0x01, 0x01, 0x01, 0x01, 0x12, 0x12, 0x12, 0x12,
|
||||
// 0x23, 0x23, 0x23, 0x23, 0x34, 0x34, 0x34, 0x34);
|
||||
|
||||
static int
|
||||
gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg);
|
||||
// static int
|
||||
// gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
// struct ble_gatt_access_ctxt *ctxt,
|
||||
// void *arg);
|
||||
|
||||
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
||||
{
|
||||
/*** Service ***/
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &gatt_svr_svc_uuid.u,
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{ {
|
||||
/*** This characteristic can be subscribed to by writing 0x00 and 0x01 to the CCCD ***/
|
||||
.uuid = &gatt_svr_chr_uuid.u,
|
||||
.access_cb = gatt_svc_access,
|
||||
#if CONFIG_EXAMPLE_ENCRYPTION
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE |
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE,
|
||||
#else
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE,
|
||||
#endif
|
||||
.val_handle = &gatt_svr_chr_val_handle,
|
||||
.descriptors = (struct ble_gatt_dsc_def[])
|
||||
{ {
|
||||
.uuid = &gatt_svr_dsc_uuid.u,
|
||||
#if CONFIG_EXAMPLE_ENCRYPTION
|
||||
.att_flags = BLE_ATT_F_READ | BLE_ATT_F_READ_ENC,
|
||||
#else
|
||||
.att_flags = BLE_ATT_F_READ,
|
||||
#endif
|
||||
.access_cb = gatt_svc_access,
|
||||
}, {
|
||||
0, /* No more descriptors in this characteristic */
|
||||
}
|
||||
},
|
||||
// static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
||||
// {
|
||||
// /*** Service ***/
|
||||
// .type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
// .uuid = &gatt_svr_svc_uuid.u,
|
||||
// .characteristics = (struct ble_gatt_chr_def[])
|
||||
// { {
|
||||
// /*** This characteristic can be subscribed to by writing 0x00 and 0x01 to the CCCD ***/
|
||||
// .uuid = &gatt_svr_chr_uuid.u,
|
||||
// .access_cb = gatt_svc_access,
|
||||
// #if CONFIG_EXAMPLE_ENCRYPTION
|
||||
// .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE |
|
||||
// BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
// BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE,
|
||||
// #else
|
||||
// .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE,
|
||||
// #endif
|
||||
// .val_handle = &gatt_svr_chr_val_handle,
|
||||
// .descriptors = (struct ble_gatt_dsc_def[])
|
||||
// { {
|
||||
// .uuid = &gatt_svr_dsc_uuid.u,
|
||||
// #if CONFIG_EXAMPLE_ENCRYPTION
|
||||
// .att_flags = BLE_ATT_F_READ | BLE_ATT_F_READ_ENC,
|
||||
// #else
|
||||
// .att_flags = BLE_ATT_F_READ,
|
||||
// #endif
|
||||
// .access_cb = gatt_svc_access,
|
||||
// }, {
|
||||
// 0, /* No more descriptors in this characteristic */
|
||||
// }
|
||||
// },
|
||||
// }, {
|
||||
// 0, /* No more characteristics in this service. */
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
|
||||
// {
|
||||
// 0, /* No more services. */
|
||||
// },
|
||||
// };
|
||||
|
||||
// static int
|
||||
// gatt_svr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
|
||||
// void *dst, uint16_t *len)
|
||||
// {
|
||||
// uint16_t om_len;
|
||||
// int rc;
|
||||
|
||||
// om_len = OS_MBUF_PKTLEN(om);
|
||||
// if (om_len < min_len || om_len > max_len) {
|
||||
// return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
// }
|
||||
|
||||
// rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
|
||||
// if (rc != 0) {
|
||||
// return BLE_ATT_ERR_UNLIKELY;
|
||||
// }
|
||||
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Access callback whenever a characteristic/descriptor is read or written to.
|
||||
// * Here reads and writes need to be handled.
|
||||
// * ctxt->op tells weather the operation is read or write and
|
||||
// * weather it is on a characteristic or descriptor,
|
||||
// * ctxt->dsc->uuid tells which characteristic/descriptor is accessed.
|
||||
// * attr_handle give the value handle of the attribute being accessed.
|
||||
// * Accordingly do:
|
||||
// * Append the value to ctxt->om if the operation is READ
|
||||
// * Write ctxt->om to the value if the operation is WRITE
|
||||
// **/
|
||||
// static int
|
||||
// gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
// struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
// {
|
||||
// const ble_uuid_t *uuid;
|
||||
// int rc;
|
||||
|
||||
// switch (ctxt->op) {
|
||||
// case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
// if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
// MODLOG_DFLT(INFO, "Characteristic read; conn_handle=%d attr_handle=%d\n",
|
||||
// conn_handle, attr_handle);
|
||||
// } else {
|
||||
// MODLOG_DFLT(INFO, "Characteristic read by NimBLE stack; attr_handle=%d\n",
|
||||
// attr_handle);
|
||||
// }
|
||||
// uuid = ctxt->chr->uuid;
|
||||
// if (attr_handle == gatt_svr_chr_val_handle) {
|
||||
// rc = os_mbuf_append(ctxt->om,
|
||||
// &gatt_svr_chr_val,
|
||||
// sizeof(gatt_svr_chr_val));
|
||||
// return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
// }
|
||||
// goto unknown;
|
||||
|
||||
// case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
// if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
// MODLOG_DFLT(INFO, "Characteristic write; conn_handle=%d attr_handle=%d",
|
||||
// conn_handle, attr_handle);
|
||||
// } else {
|
||||
// MODLOG_DFLT(INFO, "Characteristic write by NimBLE stack; attr_handle=%d",
|
||||
// attr_handle);
|
||||
// }
|
||||
// uuid = ctxt->chr->uuid;
|
||||
// if (attr_handle == gatt_svr_chr_val_handle) {
|
||||
// rc = gatt_svr_write(ctxt->om,
|
||||
// sizeof(gatt_svr_chr_val),
|
||||
// sizeof(gatt_svr_chr_val),
|
||||
// &gatt_svr_chr_val, NULL);
|
||||
// ble_gatts_chr_updated(attr_handle);
|
||||
// MODLOG_DFLT(INFO, "Notification/Indication scheduled for "
|
||||
// "all subscribed peers.\n");
|
||||
// return rc;
|
||||
// }
|
||||
// goto unknown;
|
||||
|
||||
// case BLE_GATT_ACCESS_OP_READ_DSC:
|
||||
// if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
// MODLOG_DFLT(INFO, "Descriptor read; conn_handle=%d attr_handle=%d\n",
|
||||
// conn_handle, attr_handle);
|
||||
// } else {
|
||||
// MODLOG_DFLT(INFO, "Descriptor read by NimBLE stack; attr_handle=%d\n",
|
||||
// attr_handle);
|
||||
// }
|
||||
// uuid = ctxt->dsc->uuid;
|
||||
// if (ble_uuid_cmp(uuid, &gatt_svr_dsc_uuid.u) == 0) {
|
||||
// rc = os_mbuf_append(ctxt->om,
|
||||
// &gatt_svr_dsc_val,
|
||||
// sizeof(gatt_svr_chr_val));
|
||||
// return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
// }
|
||||
// goto unknown;
|
||||
|
||||
// case BLE_GATT_ACCESS_OP_WRITE_DSC:
|
||||
// goto unknown;
|
||||
|
||||
// default:
|
||||
// goto unknown;
|
||||
// }
|
||||
|
||||
// unknown:
|
||||
// /* Unknown characteristic/descriptor;
|
||||
// * The NimBLE host should not have called this function;
|
||||
// */
|
||||
// assert(0);
|
||||
// return BLE_ATT_ERR_UNLIKELY;
|
||||
// }
|
||||
|
||||
// void
|
||||
// gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
||||
// {
|
||||
// char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
// switch (ctxt->op) {
|
||||
// case BLE_GATT_REGISTER_OP_SVC:
|
||||
// MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
|
||||
// ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
|
||||
// ctxt->svc.handle);
|
||||
// break;
|
||||
|
||||
// case BLE_GATT_REGISTER_OP_CHR:
|
||||
// MODLOG_DFLT(DEBUG, "registering characteristic %s with "
|
||||
// "def_handle=%d val_handle=%d\n",
|
||||
// ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||
// ctxt->chr.def_handle,
|
||||
// ctxt->chr.val_handle);
|
||||
// break;
|
||||
|
||||
// case BLE_GATT_REGISTER_OP_DSC:
|
||||
// MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
|
||||
// ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
|
||||
// ctxt->dsc.handle);
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// assert(0);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// int
|
||||
// gatt_svr_init(void)
|
||||
// {
|
||||
// int rc;
|
||||
|
||||
// ble_svc_gap_init();
|
||||
// ble_svc_gatt_init();
|
||||
// ble_svc_ans_init();
|
||||
|
||||
// rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
||||
// if (rc != 0) {
|
||||
// return rc;
|
||||
// }
|
||||
|
||||
// rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
||||
// if (rc != 0) {
|
||||
// return rc;
|
||||
// }
|
||||
|
||||
// /* Setting a value for the read-only descriptor */
|
||||
// gatt_svr_dsc_val = 0x99;
|
||||
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
|
||||
static uint8_t ras_feat_val;
|
||||
static uint16_t ras_feat_val_handle;
|
||||
|
||||
static int
|
||||
gatt_svr_chr_access_ras_val(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
||||
{
|
||||
/* Service: Ranging Data Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RANGING_SERVICE_VAL),
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{ {
|
||||
/* Characteristic: Feature Value */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_FEATURES_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.val_handle = &ras_feat_val_handle,
|
||||
.flags = BLE_GATT_CHR_F_READ|BLE_GATT_CHR_F_READ_ENC,
|
||||
}, {
|
||||
/* Characteristic: On demand ranging data */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_ONDEMAND_RD_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE |BLE_GATT_CHR_F_READ_ENC ,
|
||||
},{
|
||||
/* Characteristic: RAS Control Point */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_CP_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_INDICATE |BLE_GATT_CHR_F_READ_ENC ,
|
||||
},{
|
||||
/* Characteristic: RAS Data Ready */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_RD_READY_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_READ_ENC,
|
||||
},{
|
||||
/* Characteristic: RAS data overwritten */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_UUID_RAS_RD_OVERWRITTEN_VAL),
|
||||
.access_cb = gatt_svr_chr_access_ras_val,
|
||||
.flags = BLE_GATT_CHR_F_INDICATE | BLE_GATT_CHR_F_READ_ENC,
|
||||
}, {
|
||||
0, /* No more characteristics in this service. */
|
||||
}
|
||||
},
|
||||
},
|
||||
0, /* No more characteristics in this service */
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
0, /* No more services */
|
||||
},
|
||||
};
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
gatt_svr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
|
||||
void *dst, uint16_t *len)
|
||||
{
|
||||
uint16_t om_len;
|
||||
int rc;
|
||||
|
||||
om_len = OS_MBUF_PKTLEN(om);
|
||||
if (om_len < min_len || om_len > max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access callback whenever a characteristic/descriptor is read or written to.
|
||||
* Here reads and writes need to be handled.
|
||||
* ctxt->op tells weather the operation is read or write and
|
||||
* weather it is on a characteristic or descriptor,
|
||||
* ctxt->dsc->uuid tells which characteristic/descriptor is accessed.
|
||||
* attr_handle give the value handle of the attribute being accessed.
|
||||
* Accordingly do:
|
||||
* Append the value to ctxt->om if the operation is READ
|
||||
* Write ctxt->om to the value if the operation is WRITE
|
||||
**/
|
||||
static int
|
||||
gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
static int
|
||||
gatt_svr_chr_access_ras_val(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
const ble_uuid_t *uuid;
|
||||
int rc;
|
||||
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
printf("reading call back \n");
|
||||
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
MODLOG_DFLT(INFO, "Characteristic read; conn_handle=%d attr_handle=%d\n",
|
||||
conn_handle, attr_handle);
|
||||
@@ -141,13 +328,16 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
MODLOG_DFLT(INFO, "Characteristic read by NimBLE stack; attr_handle=%d\n",
|
||||
attr_handle);
|
||||
}
|
||||
uuid = ctxt->chr->uuid;
|
||||
if (attr_handle == gatt_svr_chr_val_handle) {
|
||||
rc = os_mbuf_append(ctxt->om,
|
||||
&gatt_svr_chr_val,
|
||||
sizeof(gatt_svr_chr_val));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
// uuid = ctxt->chr->uuid;
|
||||
// if(uuid == BLE_UUID_RAS_FEATURES_VAL){
|
||||
|
||||
// if (attr_handle == ras_feat_val_handle) {
|
||||
// rc = os_mbuf_append(ctxt->om,
|
||||
// &ras_feat_val,
|
||||
// sizeof(ras_feat_val));
|
||||
// return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
// }
|
||||
// }
|
||||
goto unknown;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
@@ -159,39 +349,18 @@ gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
attr_handle);
|
||||
}
|
||||
uuid = ctxt->chr->uuid;
|
||||
if (attr_handle == gatt_svr_chr_val_handle) {
|
||||
rc = gatt_svr_write(ctxt->om,
|
||||
sizeof(gatt_svr_chr_val),
|
||||
sizeof(gatt_svr_chr_val),
|
||||
&gatt_svr_chr_val, NULL);
|
||||
ble_gatts_chr_updated(attr_handle);
|
||||
MODLOG_DFLT(INFO, "Notification/Indication scheduled for "
|
||||
"all subscribed peers.\n");
|
||||
return rc;
|
||||
}
|
||||
// if (attr_handle == ras_feat_val_handle) {
|
||||
// rc = gatt_svr_write(ctxt->om,
|
||||
// sizeof(ras_feat_val),
|
||||
// sizeof(ras_feat_val),
|
||||
// &ras_feat_val, NULL);
|
||||
// ble_gatts_chr_updated(attr_handle);
|
||||
// MODLOG_DFLT(INFO, "Notification/Indication scheduled for "
|
||||
// "all subscribed peers.\n");
|
||||
// return rc;
|
||||
// }
|
||||
goto unknown;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_READ_DSC:
|
||||
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
MODLOG_DFLT(INFO, "Descriptor read; conn_handle=%d attr_handle=%d\n",
|
||||
conn_handle, attr_handle);
|
||||
} else {
|
||||
MODLOG_DFLT(INFO, "Descriptor read by NimBLE stack; attr_handle=%d\n",
|
||||
attr_handle);
|
||||
}
|
||||
uuid = ctxt->dsc->uuid;
|
||||
if (ble_uuid_cmp(uuid, &gatt_svr_dsc_uuid.u) == 0) {
|
||||
rc = os_mbuf_append(ctxt->om,
|
||||
&gatt_svr_dsc_val,
|
||||
sizeof(gatt_svr_chr_val));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
goto unknown;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_DSC:
|
||||
goto unknown;
|
||||
|
||||
default:
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
|
||||
@@ -201,61 +370,58 @@ unknown:
|
||||
*/
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
void
|
||||
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
}
|
||||
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_REGISTER_OP_SVC:
|
||||
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
|
||||
ctxt->svc.handle);
|
||||
break;
|
||||
void
|
||||
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
case BLE_GATT_REGISTER_OP_CHR:
|
||||
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
|
||||
"def_handle=%d val_handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||
ctxt->chr.def_handle,
|
||||
ctxt->chr.val_handle);
|
||||
break;
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_REGISTER_OP_SVC:
|
||||
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
|
||||
ctxt->svc.handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_DSC:
|
||||
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
|
||||
ctxt->dsc.handle);
|
||||
break;
|
||||
case BLE_GATT_REGISTER_OP_CHR:
|
||||
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
|
||||
"def_handle=%d val_handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||
ctxt->chr.def_handle,
|
||||
ctxt->chr.val_handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case BLE_GATT_REGISTER_OP_DSC:
|
||||
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
|
||||
ctxt->dsc.handle);
|
||||
break;
|
||||
|
||||
int
|
||||
gatt_svr_init(void)
|
||||
{
|
||||
int rc;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
ble_svc_ans_init();
|
||||
int
|
||||
gatt_svr_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Setting a value for the read-only descriptor */
|
||||
gatt_svr_dsc_val = 0x99;
|
||||
rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ ext_bleprph_advertise(void)
|
||||
|
||||
/* start advertising */
|
||||
rc = ble_gap_ext_adv_start(instance, 0, 0);
|
||||
assert (rc == 0);
|
||||
// assert (rc == 0);
|
||||
}
|
||||
#else
|
||||
/**
|
||||
@@ -507,7 +507,7 @@ static void
|
||||
bleprph_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_gap_set_host_feat(47,0x01);
|
||||
#if CONFIG_EXAMPLE_RANDOM_ADDR
|
||||
/* Generate a non-resolvable private address. */
|
||||
ble_app_set_addr();
|
||||
|
||||
Reference in New Issue
Block a user