Merge branch 'feat/gattc_gatts_coex' into 'master'

feat(nimble): Add new gattc + gatts coex example for nimble

Closes IDFGH-11642

See merge request espressif/esp-idf!37139
This commit is contained in:
Rahul Tank
2025-05-20 19:49:02 +05:30
8 changed files with 783 additions and 0 deletions

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

View File

@@ -0,0 +1,147 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- |
# BLE GATTC GATTS Coex Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This is a simple demo example to showcase a single code which exhibits functionality of both GATT client and GATT server. This example creates a GATT client and performs passive scan to connect to a peripheral device if the device advertises connectability and the device advertises support for the Alert Notification service (0x1811) as primary service UUID. This example also creates a GATT server and advertises, so a remote device can connect to it. If the device is not found within 120 seconds, the example will stop scanning. Upon disconnection in any role, the example ONLY advertises and accepts incoming connections.
It uses ESP32's Bluetooth controller and NimBLE stack based BLE host.
To test this demo, you can run a bleprph example first where gatt client connects to bleprph. Once a disconnect happens, you can use any third party phone and initiate a BLE connection. The same ble_gattc_gatts_coex example will accept incoming connection request. The client is free to perform GATT operations on this connection.
The test demo example is only to show how to use the API. The actual ble coex stability is not the criteria for this demo example.
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 series 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:
```
### 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 (439) NimBLE: GAP procedure initiated: advertise;
I (439) NimBLE: disc_mode=2
I (449) NimBLE: adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0
I (459) NimBLE:
I (459) NimBLE: GAP procedure initiated: discovery;
I (459) NimBLE: own_addr_type=0 filter_policy=0 passive=1 limited=0 filter_duplicates=1
I (469) NimBLE: duration=120000ms
I (469) NimBLE:
I (479) main_task: Returned from app_main()
I (489) NimBLE: GAP procedure initiated: connect;
I (489) NimBLE: peer_addr_type=0 peer_addr=
I (489) NimBLE: 84:f7:03:05:a5:f6
I (489) NimBLE: scan_itvl=16 scan_window=16 itvl_min=24 itvl_max=40 latency=0 supervision_timeout=256 min_ce_len=0 max_ce_len=0 own_addr_type=0
I (509) NimBLE:
I (629) NimBLE: Client connection established; status=0
I (629) NimBLE:
I (629) NimBLE: peer_ota_addr_type=0 peer_ota_addr=
I (629) NimBLE: 84:f7:03:05:a5:f6
I (639) NimBLE: peer_id_addr_type=0 peer_id_addr=
I (639) NimBLE: 84:f7:03:05:a5:f6
I (639) NimBLE: GATT procedure initiated: discover all services
I (829) NimBLE: GATT procedure initiated: discover all characteristics;
I (829) NimBLE: start_handle=1 end_handle=5
I (1029) NimBLE: GATT procedure initiated: discover all characteristics;
I (1029) NimBLE: start_handle=6 end_handle=13
I (1229) NimBLE: GATT procedure initiated: discover all characteristics;
I (1229) NimBLE: start_handle=14 end_handle=26
I (1529) NimBLE: GATT procedure initiated: discover all characteristics;
I (1529) NimBLE: start_handle=27 end_handle=65535
I (1729) NimBLE: GATT procedure initiated: discover all descriptors;
I (1729) NimBLE: chr_val_handle=8 end_handle=9
I (1829) NimBLE: GATT procedure initiated: discover all descriptors;
I (1829) NimBLE: chr_val_handle=18 end_handle=19
I (1929) NimBLE: GATT procedure initiated: discover all descriptors;
I (1929) NimBLE: chr_val_handle=23 end_handle=24
I (2029) NimBLE: GATT procedure initiated: discover all descriptors;
I (2029) NimBLE: chr_val_handle=29 end_handle=65535
I (2329) NimBLE: Service discovery complete; status=0 conn_handle=3
I (2329) NimBLE: GATT procedure initiated: read;
I (2329) NimBLE: att_handle=16
I (2429) NimBLE: Read complete; status=0 conn_handle=3
I (2429) NimBLE: attr_handle=16 value=
I (2429) NimBLE: 0x00
I (2429) NimBLE:
I (2429) NimBLE: GATT procedure initiated: write;
I (2439) NimBLE: att_handle=26 len=2
I (2529) NimBLE: Write complete; status=270 conn_handle=3 attr_handle=26
I (2529) NimBLE: GATT procedure initiated: write;
I (2529) NimBLE: att_handle=24 len=2
I (2629) NimBLE: Subscribe complete; status=0 conn_handle=3 attr_handle=24
I (2629) NimBLE: GAP procedure initiated: terminate connection; conn_handle=3 hci_reason=19
I (2679) NimBLE: Disconnect
I (2679) NimBLE: GAP procedure initiated: stop advertising.
I (2679) NimBLE: GAP procedure initiated: advertise;
I (2679) NimBLE: disc_mode=2
I (2689) NimBLE: adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0
I (2699) NimBLE:
I (5329) NimBLE: Server connection established; status=0
I (5329) NimBLE:
I (5329) NimBLE: peer_ota_addr_type=1 peer_ota_addr=
I (5329) NimBLE: 4c:4a:07:8d:4a:15
I (5329) NimBLE: peer_id_addr_type=1 peer_id_addr=
I (5339) NimBLE: 4c:4a:07:8d:4a:15
I (17429) NimBLE: subscribe event; conn_handle=1 attr_handle=29 reason=1 prevn=0 curn=1 previ=0 curi=0
```
## 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,4 @@
set(srcs "main.c")
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS ".")

View File

@@ -0,0 +1,43 @@
/*
* 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_BLECOEX_
#define H_BLECOEX_
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_central.h"
#define SERVICE_UUID 0x181A
#define CHAR_UUID 0x2A6E
/** GATT server. */
#define BLECOEX_SVC_ALERT_UUID 0x1811
#define BLECOEX_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47
#define BLECOEX_CHR_UNR_ALERT_STAT_UUID 0x2A45
#define BLECOEX_CHR_ALERT_NOT_CTRL_PT 0x2A44
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,5 @@
dependencies:
nimble_central_utils:
path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils
nimble_peripheral_utils:
path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils

View File

@@ -0,0 +1,563 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "nvs_flash.h"
#include "blecoex.h"
#include "services/ans/ble_svc_ans.h"
static uint8_t own_addr_type;
static int blecoex_gap_event(struct ble_gap_event *event, void *arg);
void ble_coex_advertise(void);
void ble_coex_scan(void);
static bool client_connect = 0;
static int gatt_svr_access_cb(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg) {
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
static uint8_t data[1] = {42}; // Example value
os_mbuf_append(ctxt->om, data, sizeof(data));
}
return 0;
}
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 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 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_svr_access_cb,
.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_svr_access_cb,
}, {
0, /* No more descriptors in this characteristic */
}
},
}, {
0, /* No more characteristics in this service. */
}
},
},
{
0, /* No more services. */
},
};
static int
blecoex_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;
}
/* 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) == BLECOEX_SVC_ALERT_UUID) {
return 1;
}
}
return 0;
}
static void
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 (!blecoex_should_connect((struct ble_gap_disc_desc *)disc)) {
return;
}
/* 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.
*/
addr = &((struct ble_gap_disc_desc *)disc)->addr;
rc = ble_gap_connect(own_addr_type, addr, 30000, NULL,
blecoex_gap_event, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Failed to connect to device \n");
return;
}
client_connect = 1;
}
static int
blecent_on_subscribe(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
MODLOG_DFLT(INFO, "Subscribe complete; status=%d conn_handle=%d "
"attr_handle=%d\n",
error->status, conn_handle, attr->handle);
/* Terminate connection */
ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
return 0;
}
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(BLECOEX_SVC_ALERT_UUID),
BLE_UUID16_DECLARE(BLECOEX_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);
}
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(BLECOEX_SVC_ALERT_UUID),
BLE_UUID16_DECLARE(BLECOEX_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);
}
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(BLECOEX_SVC_ALERT_UUID),
BLE_UUID16_DECLARE(BLECOEX_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);
}
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);
}
static void restart_coex(void)
{
client_connect = 0;
ble_gap_adv_stop();
ble_coex_advertise();
//TODO: Current example only restarts advertising.
#if 0
ble_gap_disc_cancel();
ble_coex_scan();
#endif
}
static int
blecoex_gap_event(struct ble_gap_event *event, void *arg)
{
struct ble_gap_conn_desc desc;
int rc;
switch (event->type) {
case BLE_GAP_EVENT_DISC:
connect_if_interesting(&event->disc);
return 0;
case BLE_GAP_EVENT_CONNECT:
MODLOG_DFLT(INFO, "%s connection %s; status=%d ",
client_connect == 1 ? "Client" : "Server",
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);
MODLOG_DFLT(INFO, "\n");
const uint8_t *u8p;
MODLOG_DFLT(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
desc.peer_ota_addr.type);
u8p = desc.peer_ota_addr.val;
MODLOG_DFLT(INFO, "%02x:%02x:%02x:%02x:%02x:%02x",
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
MODLOG_DFLT(INFO, " peer_id_addr_type=%d peer_id_addr=",
desc.peer_id_addr.type);
u8p = desc.peer_id_addr.val;
MODLOG_DFLT(INFO, "%02x:%02x:%02x:%02x:%02x:%02x",
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
}
if (client_connect == 1 ) {
client_connect = 2;
/* Remember peer. */
rc = peer_add(event->connect.conn_handle);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Failed to add peer; rc=%d\n", rc);
restart_coex();
}
/* 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);
restart_coex();
}
}
return 0;
case BLE_GAP_EVENT_DISCONNECT:
MODLOG_DFLT(INFO, "Disconnect \n");
restart_coex();
return 0;
case BLE_GAP_EVENT_DISC_COMPLETE:
MODLOG_DFLT(INFO, "Discovery completed \n");
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;
default:
return 0;
}
}
void
ble_coex_scan(void)
{
uint8_t own_addr_type;
struct ble_gap_disc_params disc_params = {0};
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;
/* Start discovery for 120 seconds */
rc = ble_gap_disc(own_addr_type, (120*1000) , &disc_params,
blecoex_gap_event, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Error initiating GAP discovery procedure; rc=%d\n",
rc);
}
}
void
ble_coex_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(BLECOEX_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, blecoex_gap_event, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
return;
}
}
static void on_sync(void)
{
int rc;
ble_hs_util_ensure_addr(0);
ble_hs_id_infer_auto(0, &own_addr_type);
ble_svc_gap_device_name_set("NimBLE Coex");
ble_coex_advertise();
// Start scanning as a client
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
ble_coex_scan();
}
void ble_hs_task(void *param)
{
MODLOG_DFLT(INFO, "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)
{
/* 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);
nimble_port_init();
ble_hs_cfg.sync_cb = on_sync;
peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
ble_svc_gap_init();
ble_svc_gatt_init();
ble_svc_ans_init();
ble_gatts_count_cfg(gatt_svr_svcs);
ble_gatts_add_svcs(gatt_svr_svcs);
nimble_port_freertos_init(ble_hs_task);
}

View File

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

View File

@@ -792,6 +792,7 @@ examples/bluetooth/esp_ble_mesh/aligenie_demo/components/vendor_model/include/ge
examples/bluetooth/esp_ble_mesh/aligenie_demo/components/vendor_model/include/genie_slist.h
examples/bluetooth/esp_ble_mesh/aligenie_demo/components/vendor_model/include/genie_timer.h
examples/bluetooth/esp_ble_mesh/aligenie_demo/components/vendor_model/include/genie_util.h
examples/bluetooth/nimble/ble_gattc_gatts_coex/main/blecoex.h
examples/bluetooth/nimble/blecent/main/blecent.h
examples/bluetooth/nimble/blecent/main/main.c
examples/bluetooth/nimble/blecsc/main/blecsc_sens.h