mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
NimbLE: Added multi advertising example
This commit is contained in:
parent
e4cf722248
commit
ec92e96406
@ -180,6 +180,16 @@ examples/bluetooth/nimble/ble_l2cap_coc:
|
||||
temporary: true
|
||||
reason: The runner doesn't support yet
|
||||
|
||||
examples/bluetooth/nimble/ble_multi_adv:
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32h4", "esp32s3"]
|
||||
temporary: true
|
||||
reason: the other targets are not tested yet
|
||||
disable_test:
|
||||
- if: IDF_TARGET in ["esp32"]
|
||||
temporary: true
|
||||
reason: The runner doesn't support yet
|
||||
|
||||
examples/bluetooth/nimble/ble_periodic_adv:
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32c2", "esp32c3", "esp32c6" , "esp32s3", "esp32h2", "esp32h4" ]
|
||||
|
8
examples/bluetooth/nimble/ble_multi_adv/CMakeLists.txt
Normal file
8
examples/bluetooth/nimble/ble_multi_adv/CMakeLists.txt
Normal file
@ -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)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ble_multi_adv)
|
74
examples/bluetooth/nimble/ble_multi_adv/README.md
Normal file
74
examples/bluetooth/nimble/ble_multi_adv/README.md
Normal file
@ -0,0 +1,74 @@
|
||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-H4 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# BLE Multi Adv Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example support legacy as well as extended advertisement for all phy. For multi advertising, random addresses are generated for each instance.
|
||||
|
||||
It starts 4 types of advertising:
|
||||
* Non connectable extended
|
||||
* Connectable extended
|
||||
* Scannable legacy
|
||||
* Legacy withe specified duration(5 sec)
|
||||
|
||||
## 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:
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
To configure number of advertising instances:
|
||||
|
||||
* Component config → Bluetooth → NimBLE Options → Enable BLE 5 feature → Maximum number of extended advertising instances
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with ESP32-C3 SoC,ESP32-S3/ESP32-H4/ESP32-C2 SoC and BLE5.0 supported chips (e.g., ESP32-C3-DevKitC, etc.)
|
||||
* A USB cable for Power supply and programming
|
||||
|
||||
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
|
||||
|
||||
### 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
|
||||
|
||||
```
|
||||
I (404) NimBLE_MULTI_ADV: BLE Host Task Started
|
||||
|
||||
I (414) NimBLE_MULTI_ADV: Instance 0 started
|
||||
I (414) NimBLE_MULTI_ADV: Instance 1 started
|
||||
I (434) NimBLE_MULTI_ADV: Instance 2 started
|
||||
I (444) NimBLE_MULTI_ADV: Instance 3 started
|
||||
|
||||
I (454) main_task: Returned from app_main()
|
||||
I (5404) NimBLE: advertise complete; reason=13
|
||||
I (5404) NimBLE_MULTI_ADV: In ble_legacy_duration_cb, instance = 3
|
||||
|
||||
I (5404) NimBLE_MULTI_ADV: Instance 3 started
|
||||
I (10384) NimBLE: advertise complete; reason=13
|
||||
I (10384) NimBLE_MULTI_ADV: In ble_legacy_duration_cb, instance = 3
|
||||
|
||||
I (10394) NimBLE_MULTI_ADV: Instance 3 started
|
||||
|
||||
```
|
||||
## 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 ".")
|
169
examples/bluetooth/nimble/ble_multi_adv/main/gatt_svr.c
Normal file
169
examples/bluetooth/nimble/ble_multi_adv/main/gatt_svr.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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 "multi_adv.h"
|
||||
|
||||
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 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);
|
||||
|
||||
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,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE,
|
||||
.val_handle = &gatt_svr_chr_val_handle,
|
||||
.descriptors = (struct ble_gatt_dsc_def[]) {
|
||||
{
|
||||
.uuid = &gatt_svr_dsc_uuid.u,
|
||||
.att_flags = BLE_ATT_F_READ,
|
||||
.access_cb = gatt_svc_access,
|
||||
}, {
|
||||
0, /* No more descriptors in this characteristic */
|
||||
}
|
||||
},
|
||||
}, {
|
||||
0, /* No more characteristics in this service. */
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
MODLOG_DFLT(INFO, "Characteristic read; conn_handle=%d attr_handle=%d\n",
|
||||
conn_handle, attr_handle);
|
||||
return 0;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
MODLOG_DFLT(INFO, "Characteristic write; conn_handle=%d attr_handle=%d",
|
||||
conn_handle, attr_handle);
|
||||
return 0;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_READ_DSC:
|
||||
MODLOG_DFLT(INFO, "Descriptor read; conn_handle=%d attr_handle=%d\n",
|
||||
conn_handle, attr_handle);
|
||||
return 0;
|
||||
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
499
examples/bluetooth/nimble/ble_multi_adv/main/main.c
Normal file
499
examples/bluetooth/nimble/ble_multi_adv/main/main.c
Normal file
@ -0,0 +1,499 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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 "multi_adv.h"
|
||||
|
||||
static const char *tag = "NimBLE_MULTI_ADV";
|
||||
static int ble_multi_adv_gap_event(struct ble_gap_event *event, void *arg);
|
||||
static uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM;
|
||||
struct ble_instance_cb_register ble_instance_cb[BLE_ADV_INSTANCES];
|
||||
|
||||
void ble_store_config_init(void);
|
||||
static int ble_connectable_ext_cb(uint16_t instance);
|
||||
static int ble_scannable_legacy_ext_cb(uint16_t instance);
|
||||
static int ble_legacy_duration_cb(uint16_t instance);
|
||||
static int ble_non_conn_ext_cb(uint16_t instance);
|
||||
static void ble_multi_advertise(ble_addr_t addr);
|
||||
|
||||
/* Advertising patterns */
|
||||
static uint8_t legacy_dur_adv_pattern[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x03, 0x03, 0xab, 0xcd,
|
||||
0x03, 0x03, 0x18, 0x11,
|
||||
0x12, 0X09, 'n', 'i', 'm', 'b', 'l', 'e', '-', 'l', 'e', 'g', 'a', 'c', 'y', '-', 'd', 'u',
|
||||
'r'
|
||||
};
|
||||
|
||||
static uint8_t scannable_legacy_adv_pattern[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x03, 0x03, 0xab, 0xcd,
|
||||
0x03, 0x03, 0x18, 0x11,
|
||||
0x13, 0X09, 'n', 'i', 'm', 'b', 'l', 'e', '-', 's', 'c', 'a', 'n', '-', 'l', 'e', 'g', 'a',
|
||||
'c', 'y'
|
||||
};
|
||||
|
||||
static uint8_t connectable_adv_pattern[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x03, 0x03, 0xab, 0xcd,
|
||||
0x03, 0x03, 0x18, 0x11,
|
||||
0x12, 0X09, 'n', 'i', 'm', 'b', 'l', 'e', '-', 'c', 'o', 'n', 'n', 'e', 't', 'a', 'b', 'l', 'e'
|
||||
};
|
||||
|
||||
static uint8_t non_conn_adv_pattern[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x03, 0x03, 0xab, 0xcd,
|
||||
0x03, 0x03, 0x18, 0x11,
|
||||
0x10, 0X09, 'n', 'i', 'm', 'b', 'l', 'e', '-', 'n', 'o', 'n', '-', 'c', 'o', 'n', 'n'
|
||||
};
|
||||
|
||||
/**
|
||||
* Logs information about a connection to the console.
|
||||
*/
|
||||
static void
|
||||
ble_multi_adv_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);
|
||||
}
|
||||
|
||||
/* Generates and sets random address */
|
||||
static int
|
||||
ble_multi_adv_set_addr(uint16_t instance)
|
||||
{
|
||||
ble_addr_t addr;
|
||||
int rc;
|
||||
|
||||
/* generate new non-resolvable private address */
|
||||
rc = ble_hs_id_gen_rnd(1, &addr);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Set generated address */
|
||||
rc = ble_gap_ext_adv_set_addr(instance, &addr);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
memcpy(&ble_instance_cb[instance].addr, &addr, sizeof(addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Configures extended advertsing params*/
|
||||
static void
|
||||
ble_multi_adv_conf_set_addr(uint16_t instance, struct ble_gap_ext_adv_params *params,
|
||||
uint8_t *pattern, int size_pattern, int duration)
|
||||
{
|
||||
int rc;
|
||||
struct os_mbuf *data;
|
||||
|
||||
if (ble_gap_ext_adv_active(instance)) {
|
||||
ESP_LOGI(tag, "Instance already advertising");
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ble_gap_ext_adv_configure(instance, params, NULL,
|
||||
ble_multi_adv_gap_event, NULL);
|
||||
assert (rc == 0);
|
||||
|
||||
rc = ble_multi_adv_set_addr(instance);
|
||||
assert (rc == 0);
|
||||
|
||||
/* get mbuf for adv data */
|
||||
data = os_msys_get_pkthdr(size_pattern, 0);
|
||||
assert(data);
|
||||
|
||||
/* fill mbuf with adv data */
|
||||
rc = os_mbuf_append(data, pattern, size_pattern);
|
||||
assert(rc == 0);
|
||||
|
||||
rc = ble_gap_ext_adv_set_data(instance, data);
|
||||
assert (rc == 0);
|
||||
|
||||
/* start advertising */
|
||||
rc = ble_gap_ext_adv_start(instance, duration, 0);
|
||||
assert (rc == 0);
|
||||
|
||||
ESP_LOGI(tag, "Instance %d started", instance);
|
||||
}
|
||||
|
||||
/* Starts advertising instance with 5sec timeout */
|
||||
static void
|
||||
start_legacy_duration(void)
|
||||
{
|
||||
uint8_t instance = 3;
|
||||
int duration = 500; /* 5seconds, 10ms units */
|
||||
struct ble_gap_ext_adv_params params;
|
||||
int size_pattern = sizeof(legacy_dur_adv_pattern) / sizeof(legacy_dur_adv_pattern[0]);
|
||||
|
||||
params.legacy_pdu = 1;
|
||||
params.own_addr_type = BLE_OWN_ADDR_RANDOM;
|
||||
params.sid = 3;
|
||||
params.primary_phy = BLE_HCI_LE_PHY_1M;
|
||||
params.secondary_phy = BLE_HCI_LE_PHY_1M;
|
||||
params.tx_power = 127;
|
||||
|
||||
ble_multi_adv_conf_set_addr(instance, ¶ms, legacy_dur_adv_pattern,
|
||||
size_pattern, duration);
|
||||
|
||||
ble_instance_cb[instance].cb = &ble_legacy_duration_cb;
|
||||
}
|
||||
|
||||
/* Starts simple non-connectable scannable instance using legacy PUDs that
|
||||
* runs forever
|
||||
*/
|
||||
static void
|
||||
start_scannable_legacy_ext(void)
|
||||
{
|
||||
uint8_t instance = 2;
|
||||
struct ble_gap_ext_adv_params params;
|
||||
int size_pattern = sizeof(scannable_legacy_adv_pattern)/sizeof(scannable_legacy_adv_pattern[0]);
|
||||
|
||||
params.legacy_pdu = 1;
|
||||
params.scannable = 1;
|
||||
params.own_addr_type = BLE_OWN_ADDR_RANDOM;
|
||||
params.sid = 2;
|
||||
params.primary_phy = BLE_HCI_LE_PHY_1M;
|
||||
params.secondary_phy = BLE_HCI_LE_PHY_1M;
|
||||
params.tx_power = 127;
|
||||
|
||||
ble_multi_adv_conf_set_addr(instance, ¶ms, scannable_legacy_adv_pattern
|
||||
, size_pattern, 0);
|
||||
|
||||
ble_instance_cb[instance].cb = &ble_scannable_legacy_ext_cb;
|
||||
}
|
||||
|
||||
/* this is simple scannable instance that runs forever
|
||||
* TODO Get scan request notifications.
|
||||
*/
|
||||
static void
|
||||
start_connectable_ext(void)
|
||||
{
|
||||
uint8_t instance = 1;
|
||||
struct ble_gap_ext_adv_params params;
|
||||
int size_pattern = sizeof(connectable_adv_pattern) / sizeof(connectable_adv_pattern[0]);
|
||||
|
||||
params.connectable = 1;
|
||||
params.own_addr_type = BLE_OWN_ADDR_RANDOM;
|
||||
params.sid = 1;
|
||||
params.primary_phy = BLE_HCI_LE_PHY_1M;
|
||||
params.secondary_phy = BLE_HCI_LE_PHY_1M;
|
||||
params.tx_power = 127;
|
||||
|
||||
ble_multi_adv_conf_set_addr(instance, ¶ms, connectable_adv_pattern,
|
||||
size_pattern, 0);
|
||||
|
||||
ble_instance_cb[instance].cb = &ble_connectable_ext_cb;
|
||||
}
|
||||
|
||||
/* Starts a connectable instance */
|
||||
static void
|
||||
start_non_connectable_ext(void)
|
||||
{
|
||||
uint8_t instance = 0;
|
||||
struct ble_gap_ext_adv_params params;
|
||||
int size_pattern = sizeof(non_conn_adv_pattern) / sizeof(non_conn_adv_pattern[0]);
|
||||
|
||||
params.own_addr_type = BLE_OWN_ADDR_RANDOM;
|
||||
params.sid = 0;
|
||||
params.primary_phy = BLE_HCI_LE_PHY_1M;
|
||||
params.secondary_phy = BLE_HCI_LE_PHY_2M;
|
||||
params.tx_power = 127;
|
||||
|
||||
ble_multi_adv_conf_set_addr(instance, ¶ms, non_conn_adv_pattern,
|
||||
size_pattern, 0);
|
||||
|
||||
ble_instance_cb[instance].cb = &ble_non_conn_ext_cb;
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
static int
|
||||
ble_connectable_ext_cb(uint16_t instance)
|
||||
{
|
||||
ESP_LOGI(tag, "In %s, instance = %d", __func__, instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ble_scannable_legacy_ext_cb(uint16_t instance)
|
||||
{
|
||||
ESP_LOGI(tag, "In %s, instance = %d", __func__, instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ble_legacy_duration_cb(uint16_t instance)
|
||||
{
|
||||
ESP_LOGI(tag, "In %s, instance = %d", __func__, instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ble_non_conn_ext_cb(uint16_t instance)
|
||||
{
|
||||
ESP_LOGI(tag, "In %s, instance = %d", __func__, instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Finds instance associated with the random address passed and calls its callback function */
|
||||
static void
|
||||
ble_multi_advertise(ble_addr_t addr)
|
||||
{
|
||||
for (int i = 0; i < BLE_ADV_INSTANCES; i++) {
|
||||
if (memcmp(&addr, &ble_instance_cb[i].addr, sizeof(addr)) == 0) {
|
||||
switch(i) {
|
||||
case 0:
|
||||
start_non_connectable_ext();
|
||||
break;
|
||||
case 1:
|
||||
start_connectable_ext();
|
||||
break;
|
||||
case 2:
|
||||
start_scannable_legacy_ext();
|
||||
break;
|
||||
case 3:
|
||||
start_legacy_duration();
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(tag, "Instance not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ble_multi_perform_gatt_proc(ble_addr_t addr)
|
||||
{
|
||||
/* GATT procedures like notify, indicate can be perfomed now */
|
||||
for (int i = 0; i < BLE_ADV_INSTANCES; i++) {
|
||||
if (memcmp(&addr, &ble_instance_cb[i].addr, sizeof(addr)) == 0) {
|
||||
if (ble_instance_cb[i].cb) {
|
||||
ble_instance_cb[i].cb(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
ble_multi_adv_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);
|
||||
ble_multi_adv_print_conn_desc(&desc);
|
||||
|
||||
ble_multi_perform_gatt_proc(desc.our_id_addr);
|
||||
}
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
|
||||
ble_multi_adv_print_conn_desc(&event->disconnect.conn);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
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);
|
||||
ble_multi_adv_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);
|
||||
ble_multi_advertise(ble_instance_cb[event->adv_complete.instance].addr);
|
||||
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);
|
||||
ble_multi_adv_print_conn_desc(&desc);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ble_multi_adv_on_reset(int reason)
|
||||
{
|
||||
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static void
|
||||
ble_multi_adv_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
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;
|
||||
}
|
||||
|
||||
start_non_connectable_ext();
|
||||
|
||||
start_connectable_ext();
|
||||
|
||||
start_scannable_legacy_ext();
|
||||
|
||||
start_legacy_duration();
|
||||
}
|
||||
|
||||
void ble_multi_adv_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 = ble_multi_adv_on_reset;
|
||||
ble_hs_cfg.sync_cb = ble_multi_adv_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_bonding = 1;
|
||||
ble_hs_cfg.sm_mitm = 1;
|
||||
ble_hs_cfg.sm_sc = 1;
|
||||
ble_hs_cfg.sm_sc = 0;
|
||||
/* 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;
|
||||
|
||||
/* Initialize callbacks to NULL */
|
||||
for (int i = 0; i < BLE_ADV_INSTANCES; i++) {
|
||||
ble_instance_cb[i].cb = NULL;
|
||||
}
|
||||
|
||||
rc = gatt_svr_init();
|
||||
assert(rc == 0);
|
||||
|
||||
/* Set the default device name. */
|
||||
rc = ble_svc_gap_device_name_set("nimble-multi-adv");
|
||||
assert(rc == 0);
|
||||
|
||||
/* XXX Need to have template for store */
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(ble_multi_adv_host_task);
|
||||
}
|
35
examples/bluetooth/nimble/ble_multi_adv/main/multi_adv.h
Normal file
35
examples/bluetooth/nimble/ble_multi_adv/main/multi_adv.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_MULTI_ADV_
|
||||
#define H_BLE_MULTI_ADV_
|
||||
|
||||
#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;
|
||||
|
||||
typedef int ble_instance_cb_fn(uint16_t instance);
|
||||
|
||||
struct ble_instance_cb_register {
|
||||
ble_addr_t addr;
|
||||
ble_instance_cb_fn *cb;
|
||||
};
|
||||
|
||||
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
int gatt_svr_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
14
examples/bluetooth/nimble/ble_multi_adv/sdkconfig.defaults
Normal file
14
examples/bluetooth/nimble/ble_multi_adv/sdkconfig.defaults
Normal file
@ -0,0 +1,14 @@
|
||||
# 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_EXT_ADV=y
|
||||
CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=4
|
@ -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_IDF_TARGET="esp32c2"
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70
|
@ -0,0 +1,6 @@
|
||||
# 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
|
Loading…
Reference in New Issue
Block a user