ieee802154: support light sleep

This commit is contained in:
xiaqilin 2023-05-25 18:18:03 +08:00
parent 65bf500d29
commit 4f537d3b98
22 changed files with 699 additions and 11 deletions

View File

@ -40,8 +40,8 @@ extern "C" {
#define REGDMA_IOMUX_LINK(_pri) ((0x12 << 8) | _pri)
#define REGDMA_SPIMEM_LINK(_pri) ((0x13 << 8) | _pri)
#define REGDMA_SYSTIMER_LINK(_pri) ((0x14 << 8) | _pri)
#define REGDMA_BLE_MAC_LINK(_pri) ((0x15 << 8) | _pri)
#define REGDMA_MODEM_BT_BB_LINK(_pri) ((0x16 << 8) | _pri)
#define REGDMA_MODEM_BTBB_LINK(_pri) ((0x15 << 8) | _pri)
#define REGDMA_MODEM_IEEE802154_LINK(_pri) ((0x16 << 8) | _pri)
#define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri)
typedef enum {

View File

@ -32,9 +32,8 @@ typedef enum sleep_retention_module_bitmap {
SLEEP_RETENTION_MODULE_WIFI_MAC = BIT(10),
SLEEP_RETENTION_MODULE_WIFI_BB = BIT(11),
SLEEP_RETENTION_MODULE_BLE_MAC = BIT(12),
SLEEP_RETENTION_MODULE_BLE_BB = BIT(13),
SLEEP_RETENTION_MODULE_BT_BB = BIT(13),
SLEEP_RETENTION_MODULE_802154_MAC = BIT(14),
SLEEP_RETENTION_MODULE_802154_BB = BIT(15),
/* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM,
* TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */

View File

@ -81,21 +81,21 @@ bool IRAM_ATTR clock_domain_pd_allowed(void)
const uint32_t modules = sleep_retention_get_modules();
const uint32_t mask = (const uint32_t) (
SLEEP_RETENTION_MODULE_CLOCK_SYSTEM
#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE
#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE
| SLEEP_RETENTION_MODULE_CLOCK_MODEM
#endif
);
return ((modules & mask) == mask);
}
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP || CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP || CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE
ESP_SYSTEM_INIT_FN(sleep_clock_startup_init, BIT(0), 106)
{
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
sleep_clock_system_retention_init();
#endif
#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE
#if CONFIG_MAC_BB_PD || CONFIG_BT_LE_SLEEP_ENABLE || CONFIG_IEEE802154_SLEEP_ENABLE
sleep_clock_modem_retention_init();
#endif
return ESP_OK;

View File

@ -21,7 +21,6 @@
#include "sdkconfig.h"
#include "esp_pmu.h"
static __attribute__((unused)) const char *TAG = "sleep";
/**

View File

@ -74,4 +74,12 @@ menu "IEEE 802.15.4"
Enabling this option increases throughput by ~5% at the expense of ~2.1k
IRAM code size increase.
config IEEE802154_SLEEP_ENABLE
bool "Enable IEEE802154 light sleep"
depends on PM_ENABLE && PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
default n
help
Enabling this option allows the IEEE802.15.4 module to be powered down during automatic light sleep,
which reduces current consumption.
endmenu # IEEE 802.15.4

View File

@ -24,6 +24,13 @@
#include "esp_ieee802154_timer.h"
#include "hal/ieee802154_ll.h"
#include "esp_attr.h"
#include "esp_phy_init.h"
#if CONFIG_IEEE802154_SLEEP_ENABLE
#include "esp_pm.h"
#include "esp_private/esp_clk.h"
#include "esp_private/sleep_retention.h"
#endif
#define CCA_DETECTION_TIME 8
@ -38,6 +45,8 @@ static uint8_t s_enh_ack_frame[128];
static uint8_t s_recent_rx_frame_info_index;
static portMUX_TYPE s_ieee802154_spinlock = portMUX_INITIALIZER_UNLOCKED;
static esp_err_t ieee802154_sleep_init(void);
static IRAM_ATTR void event_end_process(void)
{
ieee802154_etm_channel_clear(IEEE802154_ETM_CHANNEL0);
@ -193,7 +202,7 @@ IEEE802154_STATIC bool stop_current_operation(void)
break;
case IEEE802154_STATE_IDLE:
// do nothing
ieee802154_ll_set_cmd(IEEE802154_CMD_STOP);
break;
case IEEE802154_STATE_RX:
@ -580,10 +589,12 @@ IEEE802154_STATIC IRAM_ATTR void ieee802154_exit_critical(void)
void ieee802154_enable(void)
{
modem_clock_module_enable(ieee802154_periph.module);
s_ieee802154_state = IEEE802154_STATE_IDLE;
}
void ieee802154_disable(void)
{
modem_clock_module_disable(ieee802154_periph.module);
s_ieee802154_state = IEEE802154_STATE_DISABLE;
}
@ -616,12 +627,13 @@ esp_err_t ieee802154_mac_init(void)
#endif
memset(s_rx_frame, 0, sizeof(s_rx_frame));
s_ieee802154_state = IEEE802154_STATE_IDLE;
// TODO: Add flags for IEEE802154 ISR allocating. TZ-102
ret = esp_intr_alloc(ieee802154_periph.irq_id, 0, ieee802154_isr, NULL, NULL);
ESP_RETURN_ON_FALSE(ret == ESP_OK, ESP_FAIL, IEEE802154_TAG, "IEEE802154 MAC init failed");
ret = ieee802154_sleep_init();
return ret;
}
@ -743,6 +755,44 @@ esp_err_t ieee802154_receive_at(uint32_t time)
return ESP_OK;
}
static esp_err_t ieee802154_sleep_init(void)
{
esp_err_t err = ESP_OK;
#if CONFIG_IEEE802154_SLEEP_ENABLE
#define N_REGS_IEEE802154() (((IEEE802154_MAC_DATE_REG - IEEE802154_REG_BASE) / 4) + 1)
const static sleep_retention_entries_config_t ieee802154_mac_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_IEEE802154_LINK(0x00), IEEE802154_REG_BASE, IEEE802154_REG_BASE, N_REGS_IEEE802154(), 0, 0), .owner = ENTRY(3) },
};
err = sleep_retention_entries_create(ieee802154_mac_regs_retention, ARRAY_SIZE(ieee802154_mac_regs_retention), REGDMA_LINK_PRI_7, SLEEP_RETENTION_MODULE_802154_MAC);
ESP_RETURN_ON_ERROR(err, IEEE802154_TAG, "failed to allocate memory for ieee802154 mac retention");
ESP_LOGI(IEEE802154_TAG, "ieee802154 mac sleep retention initialization");
#endif
return err;
}
IRAM_ATTR void ieee802154_sleep_cb(void)
{
#if CONFIG_IEEE802154_SLEEP_ENABLE
esp_phy_disable();
#if SOC_PM_RETENTION_HAS_CLOCK_BUG
sleep_retention_do_extra_retention(true);// backup
#endif
ieee802154_disable(); // IEEE802154 CLOCK Disable
#endif // CONFIG_IEEE802154_SLEEP_ENABLE
}
IRAM_ATTR void ieee802154_wakeup_cb(void)
{
#if CONFIG_IEEE802154_SLEEP_ENABLE
ieee802154_enable(); // IEEE802154 CLOCK Enable
#if SOC_PM_RETENTION_HAS_CLOCK_BUG
sleep_retention_do_extra_retention(false);// restore
#endif
esp_phy_enable();
#endif //CONFIG_IEEE802154_SLEEP_ENABLE
}
esp_err_t ieee802154_sleep(void)
{
ieee802154_enter_critical();

View File

@ -331,6 +331,16 @@ uint8_t esp_ieee802154_get_recent_lqi(void)
return ieee802154_get_recent_lqi();
}
void esp_ieee802154_sleep_cb(void)
{
ieee802154_sleep_cb();
}
void esp_ieee802154_wakeup_cb(void)
{
ieee802154_wakeup_cb();
}
__attribute__((weak)) void esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info)
{

View File

@ -111,6 +111,17 @@ esp_ieee802154_state_t esp_ieee802154_get_state(void);
*/
esp_err_t esp_ieee802154_sleep(void);
/**
* @brief The IEEE 802.15.4 sleep callback.
*/
void esp_ieee802154_sleep_cb(void);
/**
* @brief The IEEE 802.15.4 wakeup callback.
*/
void esp_ieee802154_wakeup_cb(void);
/**
* @brief Set the IEEE 802.15.4 Radio to receive state.
*

View File

@ -177,6 +177,18 @@ uint8_t ieee802154_get_recent_lqi(void);
*/
ieee802154_state_t ieee802154_get_state(void);
/**
* @brief The callback of IEEE 802.15.4 sleep.
*
*/
void ieee802154_sleep_cb(void);
/**
* @brief The callback of IEEE 802.15.4 wakeup.
*
*/
void ieee802154_wakeup_cb(void);
/** The following three functions are only used for internal test. **/
/**
* @brief The clear channel assessment done.

View File

@ -0,0 +1,107 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_openthread.h"
#include "esp_check.h"
#include "esp_openthread_border_router.h"
#include "esp_openthread_common_macro.h"
#include "esp_openthread_dns64.h"
#include "esp_openthread_lock.h"
#include "esp_openthread_platform.h"
#include "esp_openthread_task_queue.h"
#include "esp_openthread_types.h"
#include "freertos/FreeRTOS.h"
#include "lwip/dns.h"
#include "openthread/instance.h"
#include "openthread/netdata.h"
#include "openthread/tasklet.h"
#include "esp_openthread_sleep.h"
esp_err_t esp_openthread_init(const esp_openthread_platform_config_t *config)
{
#if CONFIG_IEEE802154_SLEEP_ENABLE
ESP_RETURN_ON_ERROR(esp_openthread_sleep_init(), OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread esp pm_lock");
#endif
ESP_RETURN_ON_ERROR(esp_openthread_platform_init(config), OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread platform driver");
esp_openthread_lock_acquire(portMAX_DELAY);
ESP_RETURN_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread instance");
#if CONFIG_OPENTHREAD_DNS64_CLIENT
ESP_RETURN_ON_ERROR(esp_openthread_dns64_client_init(), OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread dns64 client");
#endif
esp_openthread_lock_release();
return ESP_OK;
}
esp_err_t esp_openthread_launch_mainloop(void)
{
esp_openthread_mainloop_context_t mainloop;
otInstance *instance = esp_openthread_get_instance();
esp_err_t error = ESP_OK;
while (true) {
FD_ZERO(&mainloop.read_fds);
FD_ZERO(&mainloop.write_fds);
FD_ZERO(&mainloop.error_fds);
mainloop.max_fd = -1;
mainloop.timeout.tv_sec = 10;
mainloop.timeout.tv_usec = 0;
esp_openthread_lock_acquire(portMAX_DELAY);
esp_openthread_platform_update(&mainloop);
if (otTaskletsArePending(instance)) {
mainloop.timeout.tv_sec = 0;
mainloop.timeout.tv_usec = 0;
}
#if CONFIG_IEEE802154_SLEEP_ENABLE
esp_openthread_sleep_process();
#endif
esp_openthread_lock_release();
if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds,
&mainloop.timeout) >= 0) {
esp_openthread_lock_acquire(portMAX_DELAY);
#if CONFIG_IEEE802154_SLEEP_ENABLE
esp_openthread_wakeup_process();
#endif
error = esp_openthread_platform_process(instance, &mainloop);
while (otTaskletsArePending(instance)) {
otTaskletsProcess(instance);
}
esp_openthread_lock_release();
if (error != ESP_OK) {
ESP_LOGE(OT_PLAT_LOG_TAG, "esp_openthread_platform_process failed");
break;
}
} else {
error = ESP_FAIL;
ESP_LOGE(OT_PLAT_LOG_TAG, "OpenThread system polling failed");
break;
}
}
return error;
}
esp_err_t esp_openthread_deinit(void)
{
otInstanceFinalize(esp_openthread_get_instance());
return esp_openthread_platform_deinit();
}
static void stub_task(void *context)
{
// this is a empty function used for ot-task signal pending
}
void otTaskletsSignalPending(otInstance *aInstance)
{
esp_openthread_task_queue_post(stub_task, NULL);
}

View File

@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_check.h"
#include "openthread/instance.h"
#include "openthread/thread.h"
#include "esp_openthread.h"
#include "esp_ieee802154.h"
#if CONFIG_IEEE802154_SLEEP_ENABLE
#include "esp_pm.h"
static esp_pm_lock_handle_t s_pm_lock = NULL;
static const char* TAG = "esp openthread sleep";
static bool s_ot_sleep = false;
esp_err_t esp_openthread_sleep_init(void)
{
esp_err_t err = ESP_OK;
err = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "ieee802154", &s_pm_lock);
if (err != ESP_OK) {
goto error;
}
esp_pm_lock_acquire(s_pm_lock);
ESP_LOGI(TAG, "Enable ieee802154 light sleep, the wake up source is ESP timer");
return err;
error:
/*lock should release first and then delete*/
if (s_pm_lock != NULL) {
esp_pm_lock_release(s_pm_lock);
esp_pm_lock_delete(s_pm_lock);
s_pm_lock = NULL;
}
return err;
}
void esp_openthread_sleep_process(void)
{
otInstance *instance = esp_openthread_get_instance();
otLinkModeConfig linkMode = otThreadGetLinkMode(instance);
bool s_ot_sed_ssed = false;
if (linkMode.mRxOnWhenIdle == false && linkMode.mDeviceType == false && linkMode.mNetworkData == false) {
s_ot_sed_ssed = true;
}
if (esp_ieee802154_get_state() == ESP_IEEE802154_RADIO_SLEEP && s_ot_sed_ssed) {
esp_ieee802154_sleep_cb();
esp_pm_lock_release(s_pm_lock);
s_ot_sleep = true;
}
}
void esp_openthread_wakeup_process(void)
{
if (s_ot_sleep) {
esp_pm_lock_acquire(s_pm_lock);
esp_ieee802154_wakeup_cb();
s_ot_sleep = false;
}
}
#endif // CONFIG_IEEE802154_SLEEP_ENABLE

View File

@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_IEEE802154_SLEEP_ENABLE
/**
* @brief This function initializes the OpenThread sleep.
*
* @return
* - ESP_OK on success
* - ESP_FAIL on failure
*
*/
esp_err_t esp_openthread_sleep_init(void);
/**
* @brief This function performs the OpenThread sleep process.
*
*/
void esp_openthread_sleep_process(void);
/**
* @brief This function performs the OpenThread wakeup process.
*
*/
void esp_openthread_wakeup_process(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -273,7 +273,7 @@ otError otPlatRadioEnable(otInstance *aInstance)
otError otPlatRadioDisable(otInstance *aInstance)
{
esp_ieee802154_disable();
// radio will be disabled in esp_openthread_radio_deinit()
return OT_ERROR_NONE;
}

View File

@ -18,6 +18,14 @@ examples/openthread/ot_cli:
temporary: true
reason: only test on esp32h2
examples/openthread/ot_power_save:
enable:
- if: IDF_TARGET == "esp32c6"
disable_test:
- if: IDF_TARGET in ["esp32h2", "esp32c6"]
temporary: true
reason: No support # TO-DO: TZ-134
examples/openthread/ot_rcp:
enable:
- if: IDF_TARGET in ["esp32h2", "esp32c6"]

View File

@ -11,3 +11,5 @@ In this folder, it contains following OpenThread examples:
* [ot_rcp](ot_rcp) is an [OpenThread RCP](https://openthread.io/platforms/co-processor) example. It runs on an 802.15.4 SoC like ESP32-H2, to extend 802.15.4 radio.
* [ot_br](ot_br) is an [OpenThread Border Router](https://openthread.io/guides/border-router) example. It runs on a Wi-Fi SoC such as ESP32, ESP32-C3 and ESP32-S3. It needs an 802.15.4 SoC like ESP32-H2 running [ot_rcp](ot_rcp) example to provide 802.15.4 radio.
* [ot_power_save](ot_power_save) is an OpenThread Power save example, it supports 802.15.4 radio light sleep. It runs on an 802.15.4 SoC like ESP32-C6.

View File

@ -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.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ot_power_save)

View File

@ -0,0 +1,46 @@
| Supported Targets | ESP32-C6 |
| ----------------- | -------- |
# OpenThread Power Save Example
The example demonstrates the OpenThread Power Save based on light sleep, which reduces power consumption by turning off RF, PHY, BB, and IEEE802154 MAC during the sleep state.
## How to use example
### Hardware Required
* Prepare an ESP32-C6 development board as an OpenThread Sleepy End Device (SED).
* Connect the board using a USB cable for power supply and programming.
* Choose another ESP32-C6 as the OpenThread Leader.
## Configure the Openthread Dataset
* Run [ot_cli](../ot_cli/) on another ESP32-C6 device to create openthread dataset configuration and start an openthread network as the leader.
* Configure the Openthread dataset (`CONFIG_OPENTHREAD_NETWORK_DATASET`) in [ot_power_save](../ot_power_save/main/esp_ot_power_save_config.h), ensuring that the device's dataset matches the dataset of the leader.
## Erase the ot_storage
If desired, erase the ot_storage by running `idf.py -p <PORT> erase-flash` before flashing the board to remove previous examples or other project data.
### Build and Flash
Build the project and flash it to the board. Use the following command: `idf.py -p <PORT> build flash monitor`.
### Example Output
As the example runs, you will see the log output indicating the initialization and operation of OpenThread, including the device joining the OpenThread network as a Sleepy End Device (SED) and periodic polling of the leader.
```
I (769) btbb_init: btbb sleep retention initialization
I (769) ieee802154: ieee802154 mac sleep retention initialization
I(769) OPENTHREAD:[I] ChildSupervsn-: Timeout: 0 -> 190
I (699) main_task: Returned from app_main()
I (799) OPENTHREAD: OpenThread attached to netif
I(799) OPENTHREAD:[N] Mle-----------: Mode 0x0f -> 0x04 [rx-on:no ftd:no full-net:no]
I(809) OPENTHREAD:[N] Mle-----------: Role disabled -> detached
I (819) OPENTHREAD: netif up
I(1519) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition reattaching with Active Dataset
I(2479) OPENTHREAD:[N] Mle-----------: RLOC16 fffe -> 5023
I(2529) OPENTHREAD:[N] Mle-----------: Role detached -> child
```

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "esp_ot_power_save.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,206 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* OpenThread Command Line Example
*
* This example code is in the Public Domain (or CC0 licensed, at your option.)
*
* Unless required by applicable law or agreed to in writing, this
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "esp_err.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_openthread.h"
#include "esp_openthread_netif_glue.h"
#include "esp_ot_power_save_config.h"
#include "esp_vfs_eventfd.h"
#include "driver/uart.h"
#include "nvs_flash.h"
#include "openthread/logging.h"
#include "openthread/thread.h"
#ifdef CONFIG_PM_ENABLE
#include "esp_pm.h"
#endif
#if !SOC_IEEE802154_SUPPORTED
#error "Power save is only supported for the SoCs which have IEEE 802.15.4 module"
#endif
#define TAG "ot_esp_power_save"
static int hex_digit_to_int(char hex)
{
if ('A' <= hex && hex <= 'F') {
return 10 + hex - 'A';
}
if ('a' <= hex && hex <= 'f') {
return 10 + hex - 'a';
}
if ('0' <= hex && hex <= '9') {
return hex - '0';
}
return -1;
}
static size_t hex_string_to_binary(const char *hex_string, uint8_t *buf)
{
int num_char = strlen(hex_string);
if (num_char % 2 == true) {
return 0;
}
for (size_t i = 0; i < num_char; i += 2) {
int digit0 = hex_digit_to_int(hex_string[i]);
int digit1 = hex_digit_to_int(hex_string[i + 1]);
if (digit0 < 0 || digit1 < 0) {
return 0;
}
buf[i / 2] = (digit0 << 4) + digit1;
}
return num_char/2;
}
static void create_config_network(otInstance *instance)
{
otLinkModeConfig linkMode;
uint16_t dataset_str_len = strlen(CONFIG_OPENTHREAD_NETWORK_DATASET);
otOperationalDatasetTlvs datasetTlvs;
memset(&linkMode, 0, sizeof(otLinkModeConfig));
linkMode.mRxOnWhenIdle = false;
linkMode.mDeviceType = false;
linkMode.mNetworkData = false;
if (otLinkSetPollPeriod(instance, CONFIG_OPENTHREAD_NETWORK_POLLPERIOD_TIME) != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to set OpenThread pollperiod.");
abort();
}
if (otThreadSetLinkMode(instance, linkMode) != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to set OpenThread linkmode.");
abort();
}
if (dataset_str_len > (OT_OPERATIONAL_DATASET_MAX_LENGTH * 2)) {
ESP_LOGE(TAG, "dataset length error.");
abort();
}
datasetTlvs.mLength = hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_DATASET, datasetTlvs.mTlvs);
if (!datasetTlvs.mLength) {
ESP_LOGE(TAG, "Failed convert configured dataset");
abort();
}
if (otDatasetSetActiveTlvs(instance, &datasetTlvs) != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to set OpenThread otDatasetSetActiveTlvs.");
abort();
}
if(otIp6SetEnabled(instance, true) != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to enable OpenThread IP6 link");
abort();
}
if(otThreadSetEnabled(instance, true) != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to enable OpenThread");
abort();
}
}
static esp_netif_t *init_openthread_netif(const esp_openthread_platform_config_t *config)
{
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD();
esp_netif_t *netif = esp_netif_new(&cfg);
assert(netif != NULL);
ESP_ERROR_CHECK(esp_netif_attach(netif, esp_openthread_netif_glue_init(config)));
return netif;
}
static void ot_task_worker(void *aContext)
{
esp_openthread_platform_config_t config = {
.radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(),
.host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
.port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),
};
// Initialize the OpenThread stack
ESP_ERROR_CHECK(esp_openthread_init(&config));
#if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC
// The OpenThread log level directly matches ESP log level
(void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL);
#endif
esp_netif_t *openthread_netif;
// Initialize the esp_netif bindings
openthread_netif = init_openthread_netif(&config);
esp_netif_set_default_netif(openthread_netif);
create_config_network(esp_openthread_get_instance());
// Run the main loop
esp_openthread_launch_mainloop();
// Clean up
esp_netif_destroy(openthread_netif);
esp_openthread_netif_glue_deinit();
esp_vfs_eventfd_unregister();
vTaskDelete(NULL);
}
static esp_err_t ot_power_save_init(void)
{
esp_err_t rc = ESP_OK;
#ifdef CONFIG_PM_ENABLE
int cur_cpu_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
esp_pm_config_t pm_config = {
.max_freq_mhz = cur_cpu_freq_mhz,
.min_freq_mhz = cur_cpu_freq_mhz,
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
.light_sleep_enable = true
#endif
};
rc = esp_pm_configure(&pm_config);
#endif
return rc;
}
void app_main(void)
{
// Used eventfds:
// * netif
// * ot task queue
// * radio driver
esp_vfs_eventfd_config_t eventfd_config = {
.max_fds = 3,
};
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
ESP_ERROR_CHECK(ot_power_save_init());
xTaskCreate(ot_task_worker, "ot_power_save_main", 4096, NULL, 5, NULL);
}

View File

@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* OpenThread Command Line Example
*
* This example code is in the Public Domain (or CC0 licensed, at your option.)
*
* Unless required by applicable law or agreed to in writing, this
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "esp_openthread_types.h"
# define CONFIG_OPENTHREAD_NETWORK_DATASET "0e080000000000010000000300000b35060004001fffe002084c14b4d26855fcd00708fdf7e918eb62e2a905107ca0e75a6ead4b960cfe073386943605030f4f70656e5468726561642d616631360102af1604102b9084b26c9a7d10a1a729bfc2e84ea00c0402a0f7f8"
# define CONFIG_OPENTHREAD_NETWORK_POLLPERIOD_TIME 3000
#if SOC_IEEE802154_SUPPORTED
#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \
{ \
.radio_mode = RADIO_MODE_NATIVE, \
}
#endif
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_UART, \
.host_uart_config = { \
.port = 0, \
.uart_config = \
{ \
.baud_rate = 115200, \
.data_bits = UART_DATA_8_BITS, \
.parity = UART_PARITY_DISABLE, \
.stop_bits = UART_STOP_BITS_1, \
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, \
.rx_flow_ctrl_thresh = 0, \
.source_clk = UART_SCLK_DEFAULT, \
}, \
.rx_pin = UART_PIN_NO_CHANGE, \
.tx_pin = UART_PIN_NO_CHANGE, \
}, \
}
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
{ \
.storage_partition_name = "ot_storage", \
.netif_queue_size = 10, \
.task_queue_size = 10, \
}

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 0x120000,
ot_storage, data, 0x3a, , 0x2000,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 0x120000,
6 ot_storage, data, 0x3a, , 0x2000,

View File

@ -0,0 +1,53 @@
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=2048
#
# Partition Table
#
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
# end of Partition Table
#
# mbedTLS
#
# ESP32H2-TODO: JIRA TZ-127, enable HW acceleration.
CONFIG_MBEDTLS_HARDWARE_AES=n
CONFIG_MBEDTLS_HARDWARE_MPI=n
CONFIG_MBEDTLS_HARDWARE_SHA=n
CONFIG_MBEDTLS_CMAC_C=y
CONFIG_MBEDTLS_SSL_PROTO_DTLS=y
CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y
CONFIG_MBEDTLS_ECJPAKE_C=y
# end of mbedTLS
#
# OpenThread
#
CONFIG_OPENTHREAD_ENABLED=y
CONFIG_OPENTHREAD_BORDER_ROUTER=n
CONFIG_OPENTHREAD_DNS64_CLIENT=y
# end of OpenThread
#
# lwIP
#
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
CONFIG_LWIP_IPV6_NUM_ADDRESSES=8
CONFIG_LWIP_MULTICAST_PING=y
# end of lwIP
#
# IEEE 802.15.4
#
CONFIG_IEEE802154_ENABLED=y
# end of IEEE 802.15.4
#
# light sleep
#
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
CONFIG_IEEE802154_SLEEP_ENABLE=y
# end of light sleep