mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/add_bluetooth_nimble_lightsleep_example' into 'master'
bt: Added an example of Bluetooth using light sleep Closes BCI-299 and BT-1879 See merge request espressif/esp-idf!19698
This commit is contained in:
commit
9b3dfe2caf
@ -267,3 +267,9 @@ examples/bluetooth/nimble/hci:
|
||||
- if: IDF_TARGET in ["esp32c2", "esp32c3", "esp32s3", "esp32c6"]
|
||||
temporary: true
|
||||
reason: The runner doesn't support yet
|
||||
|
||||
examples/bluetooth/nimble/power_save:
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32", "esp32c3", "esp32s3"]
|
||||
temporary: true
|
||||
reason: the other targets are not tested yet
|
||||
|
8
examples/bluetooth/nimble/power_save/CMakeLists.txt
Normal file
8
examples/bluetooth/nimble/power_save/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(power_save)
|
113
examples/bluetooth/nimble/power_save/README.md
Normal file
113
examples/bluetooth/nimble/power_save/README.md
Normal file
@ -0,0 +1,113 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- |
|
||||
|
||||
Bluetooth Power Save Example
|
||||
=================================
|
||||
|
||||
This example is based on the [bleprph](../bleprph) example to show how to use the bluetooth power save mode.
|
||||
|
||||
If the modem sleep mode is enabled, bluetooth will switch periodically between active and sleep.
|
||||
In sleep state, RF, PHY and BB are turned off in order to reduce power consumption.
|
||||
|
||||
This example contains five build configurations. For each configuration, a few configuration options are set:
|
||||
- `sdkconfig.defaults.esp32`: ESP32 uses 32kHz XTAL as low power clock in light sleep enabled.
|
||||
- `sdkconfig.40m.esp32c3`: ESP32C3 uses 32kHz XTAL as low power clock in light sleep enabled.
|
||||
- `sdkconfig.esp32c3_40m`: ESP32C3 uses main XTAL as low power clock in light sleep enabled.
|
||||
- `sdkconfig.defaults.esp32s3`: ESP32S3 uses 32kHz XTAL as low power clock in light sleep enabled.
|
||||
- `sdkconfig.40m.esp32s3`: ESP32S3 uses main XTAL as low power clock in light sleep enabled.
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example should be able to run on any commonly available ESP32/ESP32-C3/ESP32-S3 development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
1. Configure RTC clock source:
|
||||
- `Component config > Hardware Settings > RTC Clock Config > RTC clock source`
|
||||
2. Enable power management:
|
||||
- `Component config > Power Management > [*] Support for power management`
|
||||
3. Configure FreeRTOS:
|
||||
- `Component config > FreeRTOS > Kernel`
|
||||
- `(1000) configTICK_RATE_HZ`
|
||||
- `[*] configUSE_TICKLESS_IDLE`
|
||||
- `(3) configEXPECTED_IDLE_TIME_BEFORE_SLEEP`
|
||||
4. Enable power down MAC and baseband:
|
||||
- `Component config > PHY > [*] Power down MAC and baseband of Wi-Fi and Bluetooth when PHY is disabled`
|
||||
5. Enable bluetooth modem sleep:
|
||||
- `Component config > Bluetooth > Controller Options > MODEM SLEEP Options`
|
||||
- `[*] Bluetooth modem sleep`
|
||||
- `[*] Bluetooth Modem sleep Mode 1`
|
||||
6. Configure bluetooth low power clock:
|
||||
- `Component config > Bluetooth > Controller Options > MODEM SLEEP Options > Bluetooth modem sleep > Bluetooth Modem sleep Mode 1 > Bluetooth low power clock`
|
||||
7. Enable power up main XTAL during light sleep:
|
||||
- `Component config > Bluetooth > Controller Options > MODEM SLEEP Options > [*] power up main XTAL during light sleep`
|
||||
|
||||
### Build and Flash
|
||||
|
||||
```
|
||||
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.40m.esp32c3" set-target ESP32C3 build
|
||||
```
|
||||
|
||||
* `-D SDKCONFIG_DEFAULTS` select configuration file to be used for creating app sdkconfig.
|
||||
* `set-target ` Set the chip target to build.
|
||||
|
||||
|
||||
To flash the project and see the output, run:
|
||||
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
When you run this example, the prints the following at the very begining:
|
||||
|
||||
```
|
||||
I (333) cpu_start: Starting scheduler.
|
||||
I (347) pm: Frequency switching config: CPU_MAX: 160, APB_MAX: 80, APB_MIN: 40, Light sleep: ENABLED
|
||||
I (351) sleep: Enable automatic switching of GPIO sleep configuration
|
||||
I (358) BTDM_INIT: BT controller compile version [f2e5d81]
|
||||
I (365) BTDM_INIT: Bluetooth will use main XTAL as Bluetooth sleep clock.
|
||||
I (372) phy_init: phy_version 912,d001756,Jun 2 2022,16:28:07
|
||||
I (411) system_api: Base MAC address is not set
|
||||
I (412) system_api: read default base MAC address from EFUSE
|
||||
I (412) BTDM_INIT: Bluetooth MAC: 7c:df:a1:61:b6:f6
|
||||
|
||||
I (419) NimBLE_BLE_PRPH: BLE Host Task Started
|
||||
I (424) uart: queue free spaces: 8
|
||||
I (432) NimBLE: GAP procedure initiated: stop advertising.
|
||||
|
||||
I (435) NimBLE: Device Address:
|
||||
I (437) NimBLE: 7c:df:a1:61:b6:f6
|
||||
I (441) NimBLE:
|
||||
|
||||
I (446) NimBLE: GAP procedure initiated: advertise;
|
||||
I (450) NimBLE: disc_mode=2
|
||||
I (453) NimBLE: adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0
|
||||
I (463) NimBLE:
|
||||
```
|
||||
|
||||
## Typical current consumption with management enabled
|
||||
|
||||
| | max current | modem sleep | light sleep (main XTAL)| light sleep (32KHz XTAL)|
|
||||
|-------- | ----------- | ------------ | ---------------------- |------------------------ |
|
||||
| ESP32 | 231 mA | 14.1 mA | X | 1.9 mA |
|
||||
| ESP32C3 | 262 mA | 12 mA | 2.3 mA | 140 uA |
|
||||
| ESP32S3 | 240 mA | 17.9 mA | 3.3 mA | 230 uA |
|
||||
X: This feature is currently not supported.
|
||||
|
||||
## Example Breakdown
|
||||
|
||||
- ESP32 does not support the use of main XTAL in light sleep mode, so an external 32kHz crystal is required.
|
5
examples/bluetooth/nimble/power_save/main/CMakeLists.txt
Normal file
5
examples/bluetooth/nimble/power_save/main/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(srcs "main.c"
|
||||
"gatt_svr.c")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS ".")
|
135
examples/bluetooth/nimble/power_save/main/Kconfig.projbuild
Normal file
135
examples/bluetooth/nimble/power_save/main/Kconfig.projbuild
Normal file
@ -0,0 +1,135 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_MAX_CPU_FREQ
|
||||
prompt "Maximum CPU frequency"
|
||||
default EXAMPLE_MAX_CPU_FREQ_160
|
||||
depends on PM_ENABLE
|
||||
help
|
||||
Maximum CPU frequency to use for dynamic frequency scaling.
|
||||
|
||||
config EXAMPLE_MAX_CPU_FREQ_80
|
||||
bool "80 MHz"
|
||||
config EXAMPLE_MAX_CPU_FREQ_160
|
||||
bool "160 MHz"
|
||||
config EXAMPLE_MAX_CPU_FREQ_240
|
||||
bool "240 MHz"
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_MAX_CPU_FREQ_MHZ
|
||||
int
|
||||
default 80 if EXAMPLE_MAX_CPU_FREQ_80
|
||||
default 160 if EXAMPLE_MAX_CPU_FREQ_160
|
||||
default 240 if EXAMPLE_MAX_CPU_FREQ_240
|
||||
|
||||
choice EXAMPLE_MIN_CPU_FREQ
|
||||
prompt "Minimum CPU frequency"
|
||||
default EXAMPLE_MIN_CPU_FREQ_40M
|
||||
depends on PM_ENABLE
|
||||
help
|
||||
Minimum CPU frequency to use for dynamic frequency scaling.
|
||||
Should be set to XTAL frequency or XTAL frequency divided by integer.
|
||||
|
||||
config EXAMPLE_MIN_CPU_FREQ_80M
|
||||
bool "80 MHz"
|
||||
depends on !(IDF_TARGET_ESP32 && EXAMPLE_MAX_CPU_FREQ_240)
|
||||
help
|
||||
ESP32 does not support switching between 240M and 80M.The root cause
|
||||
is that when switching between 240M and 80M, we need to disable
|
||||
BBPLL and then re-enable it with a different frequency.Since the
|
||||
Bluetooth baseband works from PLL frequency, it will temporarily
|
||||
lose its 80 MHz clock, while the BBPLL is disabled.
|
||||
config EXAMPLE_MIN_CPU_FREQ_40M
|
||||
bool "40 MHz (use with 40MHz XTAL)"
|
||||
depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO
|
||||
config EXAMPLE_MIN_CPU_FREQ_20M
|
||||
bool "20 MHz (use with 40MHz XTAL)"
|
||||
depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO
|
||||
config EXAMPLE_MIN_CPU_FREQ_10M
|
||||
bool "10 MHz (use with 40MHz XTAL)"
|
||||
depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_MIN_CPU_FREQ_MHZ
|
||||
int
|
||||
default 80 if EXAMPLE_MIN_CPU_FREQ_80M
|
||||
default 40 if EXAMPLE_MIN_CPU_FREQ_40M
|
||||
default 20 if EXAMPLE_MIN_CPU_FREQ_20M
|
||||
default 10 if EXAMPLE_MIN_CPU_FREQ_10M
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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
|
36
examples/bluetooth/nimble/power_save/main/bleprph.h
Normal file
36
examples/bluetooth/nimble/power_save/main/bleprph.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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 GATT_SVR_SVC_ALERT_UUID 0x1811
|
||||
#define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47
|
||||
#define GATT_SVR_CHR_NEW_ALERT 0x2A46
|
||||
#define GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID 0x2A48
|
||||
#define GATT_SVR_CHR_UNR_ALERT_STAT_UUID 0x2A45
|
||||
#define GATT_SVR_CHR_ALERT_NOT_CTRL_PT 0x2A44
|
||||
|
||||
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
int gatt_svr_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
248
examples/bluetooth/nimble/power_save/main/gatt_svr.c
Normal file
248
examples/bluetooth/nimble/power_save/main/gatt_svr.c
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-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 "bleprph.h"
|
||||
#include "services/ans/ble_svc_ans.h"
|
||||
|
||||
/*** 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
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 */
|
||||
}
|
||||
},
|
||||
}, {
|
||||
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;
|
||||
}
|
582
examples/bluetooth/nimble/power_save/main/main.c
Normal file
582
examples/bluetooth/nimble/power_save/main/main.c
Normal file
@ -0,0 +1,582 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
/* power management */
|
||||
#include "esp_pm.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"
|
||||
|
||||
#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
|
||||
|
||||
void ble_store_config_init(void);
|
||||
|
||||
#if MYNEWT_VAL(BLE_POWER_CONTROL)
|
||||
static struct ble_gap_event_listener power_control_event_listener;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Logs information about a connection to the console.
|
||||
*/
|
||||
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
|
||||
|
||||
|
||||
#if MYNEWT_VAL(BLE_POWER_CONTROL)
|
||||
static int
|
||||
bleprph_gap_power_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
|
||||
switch(event->type) {
|
||||
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;
|
||||
|
||||
default:
|
||||
return 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);
|
||||
|
||||
ble_gap_event_listener_register(&power_control_event_listener,
|
||||
bleprph_gap_power_event, NULL);
|
||||
#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");
|
||||
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 \n");
|
||||
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\n", 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\n", 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\n", 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\n", rc);
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#if CONFIG_EXAMPLE_RANDOM_ADDR
|
||||
/* Generate a non-resolvable private address. */
|
||||
ble_app_set_addr();
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
// Configure dynamic frequency scaling:
|
||||
// maximum and minimum frequencies are set in sdkconfig,
|
||||
// automatic light sleep is enabled if tickless idle support is enabled.
|
||||
esp_pm_config_t pm_config = {
|
||||
.max_freq_mhz = CONFIG_EXAMPLE_MAX_CPU_FREQ_MHZ,
|
||||
.min_freq_mhz = CONFIG_EXAMPLE_MIN_CPU_FREQ_MHZ,
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
.light_sleep_enable = true
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_pm_configure(&pm_config) );
|
||||
#endif // CONFIG_PM_ENABLE
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
12
examples/bluetooth/nimble/power_save/sdkconfig.40m.esp32c3
Normal file
12
examples/bluetooth/nimble/power_save/sdkconfig.40m.esp32c3
Normal file
@ -0,0 +1,12 @@
|
||||
CONFIG_IDF_TARGET="esp32c3"
|
||||
|
||||
# MODEM SLEEP Options
|
||||
CONFIG_BT_CTRL_MODEM_SLEEP=y
|
||||
CONFIG_BT_CTRL_MODEM_SLEEP_MODE_1=y
|
||||
# Bluetooth low power clock
|
||||
CONFIG_BT_CTRL_LPCLK_SEL_MAIN_XTAL=y
|
||||
# Power up main XTAL during light sleep
|
||||
CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP=y
|
||||
|
||||
# Enable power down of MAC and baseband in light sleep mode
|
||||
CONFIG_ESP_PHY_MAC_BB_PD=y
|
14
examples/bluetooth/nimble/power_save/sdkconfig.40m.esp32s3
Normal file
14
examples/bluetooth/nimble/power_save/sdkconfig.40m.esp32s3
Normal file
@ -0,0 +1,14 @@
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
# MODEM SLEEP Options
|
||||
CONFIG_BT_CTRL_MODEM_SLEEP=y
|
||||
CONFIG_BT_CTRL_MODEM_SLEEP_MODE_1=y
|
||||
# Bluetooth low power clock
|
||||
CONFIG_BT_CTRL_LPCLK_SEL_MAIN_XTAL=y
|
||||
# Power up main XTAL during light sleep
|
||||
CONFIG_BT_CTRL_MAIN_XTAL_PU_DURING_LIGHT_SLEEP=y
|
||||
|
||||
# Run FreeRTOS only on first core
|
||||
CONFIG_FREERTOS_UNICORE=y
|
||||
# Enable power down of MAC and baseband in light sleep mode
|
||||
CONFIG_ESP_PHY_MAC_BB_PD=y
|
21
examples/bluetooth/nimble/power_save/sdkconfig.defaults
Normal file
21
examples/bluetooth/nimble/power_save/sdkconfig.defaults
Normal file
@ -0,0 +1,21 @@
|
||||
# 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
|
||||
|
||||
# Enable support for power management
|
||||
CONFIG_PM_ENABLE=y
|
||||
# Enable tickless idle mode
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
# Set the tick rate at which FreeRTOS does pre-emptive context switching.
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
# Minimum number of ticks to enter sleep mode for
|
||||
CONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP=3
|
@ -0,0 +1,13 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
# MODEM SLEEP Options
|
||||
CONFIG_BTDM_CTRL_MODEM_SLEEP=y
|
||||
CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG=y
|
||||
# Bluetooth low power clock
|
||||
CONFIG_BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL=y
|
||||
|
||||
# RTC clock source
|
||||
CONFIG_RTC_CLK_SRC_EXT_CRYS=y
|
||||
|
||||
# Run FreeRTOS only on first core
|
||||
CONFIG_FREERTOS_UNICORE=y
|
@ -0,0 +1,13 @@
|
||||
CONFIG_IDF_TARGET="esp32c3"
|
||||
|
||||
# MODEM SLEEP Options
|
||||
CONFIG_BT_CTRL_MODEM_SLEEP=y
|
||||
CONFIG_BT_CTRL_MODEM_SLEEP_MODE_1=y
|
||||
# Bluetooth low power clock
|
||||
CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL=y
|
||||
|
||||
# RTC clock source
|
||||
CONFIG_RTC_CLK_SRC_EXT_CRYS=y
|
||||
|
||||
# Enable power down of MAC and baseband in light sleep mode
|
||||
CONFIG_ESP_PHY_MAC_BB_PD=y
|
@ -0,0 +1,15 @@
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
|
||||
# MODEM SLEEP Options
|
||||
CONFIG_BT_CTRL_MODEM_SLEEP=y
|
||||
CONFIG_BT_CTRL_MODEM_SLEEP_MODE_1=y
|
||||
# Bluetooth low power clock
|
||||
CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL=y
|
||||
|
||||
# RTC clock source
|
||||
CONFIG_RTC_CLK_SRC_EXT_CRYS=y
|
||||
|
||||
# Run FreeRTOS only on first core
|
||||
CONFIG_FREERTOS_UNICORE=y
|
||||
# Enable power down of MAC and baseband in light sleep mode
|
||||
CONFIG_ESP_PHY_MAC_BB_PD=y
|
Loading…
x
Reference in New Issue
Block a user