NimbLE: Added multi advertising example

This commit is contained in:
isha.pardikar@espressif.com 2023-03-10 18:33:51 +05:30
parent e4cf722248
commit ec92e96406
10 changed files with 827 additions and 0 deletions

View File

@ -180,6 +180,16 @@ examples/bluetooth/nimble/ble_l2cap_coc:
temporary: true temporary: true
reason: The runner doesn't support yet 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: examples/bluetooth/nimble/ble_periodic_adv:
enable: enable:
- if: IDF_TARGET in ["esp32c2", "esp32c3", "esp32c6" , "esp32s3", "esp32h2", "esp32h4" ] - if: IDF_TARGET in ["esp32c2", "esp32c3", "esp32c6" , "esp32s3", "esp32h2", "esp32h4" ]

View 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)

View 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.

View File

@ -0,0 +1,5 @@
set(srcs "main.c"
"gatt_svr.c")
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS ".")

View 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;
}

View 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, &params, 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, &params, 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, &params, 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, &params, 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);
}

View 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

View 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

View File

@ -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

View File

@ -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