diff --git a/components/bt/controller/esp32c3/Kconfig.in b/components/bt/controller/esp32c3/Kconfig.in index 1ebd78ea7a..fb9920251f 100644 --- a/components/bt/controller/esp32c3/Kconfig.in +++ b/components/bt/controller/esp32c3/Kconfig.in @@ -390,7 +390,7 @@ menu "MODEM SLEEP Options" than other bluetooth low power clock sources. config BT_CTRL_LPCLK_SEL_EXT_32K_XTAL bool "External 32kHz crystal" - depends on ESP32C3_RTC_CLK_SRC_EXT_CRYS + depends on (ESP32C3_RTC_CLK_SRC_EXT_CRYS || ESP32S3_RTC_CLK_SRC_EXT_CRYS) help External 32kHz crystal has a nominal frequency of 32.768kHz and provides good frequency stability. If used as Bluetooth low power clock, External 32kHz can support Bluetooth @@ -398,7 +398,7 @@ menu "MODEM SLEEP Options" config BT_CTRL_LPCLK_SEL_RTC_SLOW bool "Internal 150kHz RC oscillator" - depends on ESP32C3_RTC_CLK_SRC_INT_RC + depends on (ESP32C3_RTC_CLK_SRC_INT_RC || ESP32S3_RTC_CLK_SRC_INT_RC) help Internal 150kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state. diff --git a/examples/bluetooth/nimble/power_save/CMakeLists.txt b/examples/bluetooth/nimble/power_save/CMakeLists.txt new file mode 100644 index 0000000000..cfe527e3c2 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/CMakeLists.txt @@ -0,0 +1,6 @@ +# 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.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(power_save) diff --git a/examples/bluetooth/nimble/power_save/Makefile b/examples/bluetooth/nimble/power_save/Makefile new file mode 100644 index 0000000000..62a7d0f5cf --- /dev/null +++ b/examples/bluetooth/nimble/power_save/Makefile @@ -0,0 +1,8 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := power_save + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/nimble/power_save/README.md b/examples/bluetooth/nimble/power_save/README.md new file mode 100644 index 0000000000..ff7c77ba87 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/README.md @@ -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.defaults.esp32c3`: ESP32C3 uses 32kHz XTAL as low power clock in light sleep enabled. +- `sdkconfig.40m.esp32c3`: 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. \ No newline at end of file diff --git a/examples/bluetooth/nimble/power_save/main/CMakeLists.txt b/examples/bluetooth/nimble/power_save/main/CMakeLists.txt new file mode 100644 index 0000000000..e634d91537 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/main/CMakeLists.txt @@ -0,0 +1,7 @@ +set(srcs "main.c" + "gatt_svr.c" + "misc.c" + "scli.c") + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ".") diff --git a/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild b/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild new file mode 100644 index 0000000000..8f011b1260 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild @@ -0,0 +1,127 @@ +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 + + config EXAMPLE_ADVERTISE_INTERVAL + int "BLE Advertise interval" + range 0 5000 + default 100 + help + Wake up interval for BLE advertising. Unit: 1 microsecond. + + 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_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 diff --git a/examples/bluetooth/nimble/power_save/main/bleprph.h b/examples/bluetooth/nimble/power_save/main/bleprph.h new file mode 100644 index 0000000000..cf90b9fb6a --- /dev/null +++ b/examples/bluetooth/nimble/power_save/main/bleprph.h @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLEPRPH_ +#define H_BLEPRPH_ + +#include +#include "nimble/ble.h" +#include "modlog/modlog.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); + +/* Console */ +int scli_init(void); +int scli_receive_key(int *key); + +/** Misc. */ +void print_bytes(const uint8_t *bytes, int len); +void print_addr(const void *addr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/bluetooth/nimble/power_save/main/component.mk b/examples/bluetooth/nimble/power_save/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/bluetooth/nimble/power_save/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/bluetooth/nimble/power_save/main/gatt_svr.c b/examples/bluetooth/nimble/power_save/main/gatt_svr.c new file mode 100644 index 0000000000..d48a35f0ab --- /dev/null +++ b/examples/bluetooth/nimble/power_save/main/gatt_svr.c @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#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; +} diff --git a/examples/bluetooth/nimble/power_save/main/main.c b/examples/bluetooth/nimble/power_save/main/main.c new file mode 100644 index 0000000000..1df20a3738 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/main/main.c @@ -0,0 +1,436 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "esp_log.h" +#include "nvs_flash.h" +/* power management */ +#include "esp_pm.h" +/* BLE */ +#include "esp_nimble_hci.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#include "host/util/util.h" +#include "console/console.h" +#include "services/gap/ble_svc_gap.h" +#include "bleprph.h" +#include "driver/gpio.h" + +static const char *tag = "NimBLE_BLE_PRPH"; +static int bleprph_gap_event(struct ble_gap_event *event, void *arg); +static uint8_t own_addr_type; + +void ble_store_config_init(void); + +/** + * 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); +} + +/** + * 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; + adv_params.itvl_min = (CONFIG_EXAMPLE_ADVERTISE_INTERVAL*1000/625); + adv_params.itvl_max = (CONFIG_EXAMPLE_ADVERTISE_INTERVAL*1000/625); + + 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; + } +} + +/** + * 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. */ + bleprph_advertise(); + } + 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. */ + bleprph_advertise(); + 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); + bleprph_advertise(); + 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 %d 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: %d", 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); +} + +static void +bleprph_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; + } + + /* 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. */ + bleprph_advertise(); +} + +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. +#if CONFIG_IDF_TARGET_ESP32 + esp_pm_config_esp32_t pm_config = { +#elif CONFIG_IDF_TARGET_ESP32C3 + esp_pm_config_esp32c3_t pm_config = { +#elif CONFIG_IDF_TARGET_ESP32S3 + esp_pm_config_esp32s3_t pm_config = { +#endif + .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 + + ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init()); + + nimble_port_init(); + /* 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); + + #if CONFIG_IDF_TARGET_ESP32C3 + gpio_sleep_set_direction(20, GPIO_MODE_INPUT); + gpio_sleep_set_pull_mode(20, GPIO_PULLUP_ONLY); + #elif CONFIG_IDF_TARGET_ESP32S3 + gpio_sleep_set_direction(44, GPIO_MODE_INPUT); + gpio_sleep_set_pull_mode(44, GPIO_PULLUP_ONLY); + #endif + + /* Initialize command line interface to accept input from user */ + rc = scli_init(); + if (rc != ESP_OK) { + ESP_LOGE(tag, "scli_init() failed"); + } +} diff --git a/examples/bluetooth/nimble/power_save/main/misc.c b/examples/bluetooth/nimble/power_save/main/misc.c new file mode 100644 index 0000000000..640b7ff8b6 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/main/misc.c @@ -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. + */ + +#include "bleprph.h" + +/** + * Utility function to log an array of bytes. + */ +void +print_bytes(const uint8_t *bytes, int len) +{ + int i; + + for (i = 0; i < len; i++) { + MODLOG_DFLT(INFO, "%s0x%02x", i != 0 ? ":" : "", bytes[i]); + } +} + +void +print_addr(const void *addr) +{ + const uint8_t *u8p; + + u8p = addr; + MODLOG_DFLT(INFO, "%02x:%02x:%02x:%02x:%02x:%02x", + u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); +} diff --git a/examples/bluetooth/nimble/power_save/main/scli.c b/examples/bluetooth/nimble/power_save/main/scli.c new file mode 100644 index 0000000000..ec47a104c1 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/main/scli.c @@ -0,0 +1,161 @@ +/* + * Copyright 2019 Espressif Systems (Shanghai) PTE LTD + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "esp_log.h" +#include +#include +#include +#include +#include +#include +#include +#include "bleprph.h" + +#define BLE_RX_TIMEOUT (30000 / portTICK_PERIOD_MS) + +static TaskHandle_t cli_task; +static QueueHandle_t cli_handle; +static int stop; + +static int enter_passkey_handler(int argc, char *argv[]) +{ + int key; + char pkey[8]; + int num; + + if (argc != 2) { + return -1; + } + + sscanf(argv[1], "%s", pkey); + ESP_LOGI("You entered", "%s %s", argv[0], argv[1]); + num = pkey[0]; + + if (isalpha(num)) { + if ((strcasecmp(pkey, "Y") == 0) || (strcasecmp(pkey, "Yes") == 0)) { + key = 1; + xQueueSend(cli_handle, &key, 0); + } else { + key = 0; + xQueueSend(cli_handle, &key, 0); + } + } else { + sscanf(pkey, "%d", &key); + xQueueSend(cli_handle, &key, 0); + } + + return 0; +} + +int scli_receive_key(int *console_key) +{ + return xQueueReceive(cli_handle, console_key, BLE_RX_TIMEOUT); +} + +static esp_console_cmd_t cmds[] = { + { + .command = "key", + .help = "", + .func = enter_passkey_handler, + }, +}; + +static int ble_register_cli(void) +{ + int cmds_num = sizeof(cmds) / sizeof(esp_console_cmd_t); + int i; + for (i = 0; i < cmds_num; i++) { + esp_console_cmd_register(&cmds[i]); + } + return 0; +} + +static void scli_task(void *arg) +{ + int uart_num = (int) arg; + uint8_t linebuf[256]; + int i, cmd_ret; + esp_err_t ret; + QueueHandle_t uart_queue; + uart_event_t event; + + uart_driver_install(uart_num, 256, 0, 8, &uart_queue, 0); + /* Initialize the console */ + esp_console_config_t console_config = { + .max_cmdline_args = 8, + .max_cmdline_length = 256, + }; + + esp_console_init(&console_config); + + while (!stop) { + i = 0; + memset(linebuf, 0, sizeof(linebuf)); + do { + ret = xQueueReceive(uart_queue, (void * )&event, (portTickType)portMAX_DELAY); + if (ret != pdPASS) { + if (stop == 1) { + break; + } else { + continue; + } + } + if (event.type == UART_DATA) { + while (uart_read_bytes(uart_num, (uint8_t *) &linebuf[i], 1, 0)) { + if (linebuf[i] == '\r') { + uart_write_bytes(uart_num, "\r\n", 2); + } else { + uart_write_bytes(uart_num, (char *) &linebuf[i], 1); + } + i++; + } + } + } while ((i < 255) && linebuf[i - 1] != '\r'); + if (stop) { + break; + } + /* Remove the truncating \r\n */ + linebuf[strlen((char *)linebuf) - 1] = '\0'; + ret = esp_console_run((char *) linebuf, &cmd_ret); + if (ret < 0) { + break; + } + } + vTaskDelete(NULL); +} + +int scli_init(void) +{ + /* Register CLI "key " to accept input from user during pairing */ + ble_register_cli(); + + xTaskCreate(scli_task, "scli_cli", 4096, (void *) 0, 3, &cli_task); + if (cli_task == NULL) { + return ESP_FAIL; + } + cli_handle = xQueueCreate( 1, sizeof(int) ); + if (cli_handle == NULL) { + return ESP_FAIL; + } + return ESP_OK; +} diff --git a/examples/bluetooth/nimble/power_save/sdkconfig.40m.esp32c3 b/examples/bluetooth/nimble/power_save/sdkconfig.40m.esp32c3 new file mode 100644 index 0000000000..5350dc1304 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/sdkconfig.40m.esp32c3 @@ -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 diff --git a/examples/bluetooth/nimble/power_save/sdkconfig.40m.esp32s3 b/examples/bluetooth/nimble/power_save/sdkconfig.40m.esp32s3 new file mode 100644 index 0000000000..bc3e7033cd --- /dev/null +++ b/examples/bluetooth/nimble/power_save/sdkconfig.40m.esp32s3 @@ -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 diff --git a/examples/bluetooth/nimble/power_save/sdkconfig.defaults b/examples/bluetooth/nimble/power_save/sdkconfig.defaults new file mode 100644 index 0000000000..8b57fab433 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/sdkconfig.defaults @@ -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 diff --git a/examples/bluetooth/nimble/power_save/sdkconfig.defaults.esp32 b/examples/bluetooth/nimble/power_save/sdkconfig.defaults.esp32 new file mode 100644 index 0000000000..fabbd14967 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/sdkconfig.defaults.esp32 @@ -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_ESP32_RTC_CLK_SRC_EXT_CRYS=y + +# Run FreeRTOS only on first core +CONFIG_FREERTOS_UNICORE=y diff --git a/examples/bluetooth/nimble/power_save/sdkconfig.defaults.esp32c3 b/examples/bluetooth/nimble/power_save/sdkconfig.defaults.esp32c3 new file mode 100644 index 0000000000..2fe565449a --- /dev/null +++ b/examples/bluetooth/nimble/power_save/sdkconfig.defaults.esp32c3 @@ -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_ESP32C3_RTC_CLK_SRC_EXT_CRYS=y + +# Enable power down of MAC and baseband in light sleep mode +CONFIG_ESP_PHY_MAC_BB_PD=y diff --git a/examples/bluetooth/nimble/power_save/sdkconfig.defaults.esp32s3 b/examples/bluetooth/nimble/power_save/sdkconfig.defaults.esp32s3 new file mode 100644 index 0000000000..b47060083d --- /dev/null +++ b/examples/bluetooth/nimble/power_save/sdkconfig.defaults.esp32s3 @@ -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_ESP32S3_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