ieee802154: add sleep state

This commit is contained in:
xiaqilin 2023-06-01 14:31:03 +08:00
parent 4f537d3b98
commit b4d951fa6a
19 changed files with 64 additions and 167 deletions

View File

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

View File

@ -205,6 +205,10 @@ IEEE802154_STATIC bool stop_current_operation(void)
ieee802154_ll_set_cmd(IEEE802154_CMD_STOP); ieee802154_ll_set_cmd(IEEE802154_CMD_STOP);
break; break;
case IEEE802154_STATE_SLEEP:
// Do nothing
break;
case IEEE802154_STATE_RX: case IEEE802154_STATE_RX:
stop_rx(); stop_rx();
break; break;
@ -771,7 +775,7 @@ static esp_err_t ieee802154_sleep_init(void)
return err; return err;
} }
IRAM_ATTR void ieee802154_sleep_cb(void) IRAM_ATTR void ieee802154_enter_sleep(void)
{ {
#if CONFIG_IEEE802154_SLEEP_ENABLE #if CONFIG_IEEE802154_SLEEP_ENABLE
esp_phy_disable(); esp_phy_disable();
@ -782,7 +786,7 @@ IRAM_ATTR void ieee802154_sleep_cb(void)
#endif // CONFIG_IEEE802154_SLEEP_ENABLE #endif // CONFIG_IEEE802154_SLEEP_ENABLE
} }
IRAM_ATTR void ieee802154_wakeup_cb(void) IRAM_ATTR void ieee802154_wakeup(void)
{ {
#if CONFIG_IEEE802154_SLEEP_ENABLE #if CONFIG_IEEE802154_SLEEP_ENABLE
ieee802154_enable(); // IEEE802154 CLOCK Enable ieee802154_enable(); // IEEE802154 CLOCK Enable
@ -798,7 +802,7 @@ esp_err_t ieee802154_sleep(void)
ieee802154_enter_critical(); ieee802154_enter_critical();
stop_current_operation(); stop_current_operation();
s_ieee802154_state = IEEE802154_STATE_IDLE; s_ieee802154_state = IEEE802154_STATE_SLEEP;
ieee802154_exit_critical(); ieee802154_exit_critical();
return ESP_OK; return ESP_OK;

View File

@ -280,6 +280,9 @@ esp_ieee802154_state_t esp_ieee802154_get_state(void)
return ESP_IEEE802154_RADIO_DISABLE; return ESP_IEEE802154_RADIO_DISABLE;
case IEEE802154_STATE_IDLE: case IEEE802154_STATE_IDLE:
return ESP_IEEE802154_RADIO_IDLE;
case IEEE802154_STATE_SLEEP:
return ESP_IEEE802154_RADIO_SLEEP; return ESP_IEEE802154_RADIO_SLEEP;
case IEEE802154_STATE_RX: case IEEE802154_STATE_RX:
@ -331,14 +334,14 @@ uint8_t esp_ieee802154_get_recent_lqi(void)
return ieee802154_get_recent_lqi(); return ieee802154_get_recent_lqi();
} }
void esp_ieee802154_sleep_cb(void) void esp_ieee802154_enter_sleep(void)
{ {
ieee802154_sleep_cb(); ieee802154_enter_sleep();
} }
void esp_ieee802154_wakeup_cb(void) void esp_ieee802154_wakeup(void)
{ {
ieee802154_wakeup_cb(); ieee802154_wakeup();
} }
__attribute__((weak)) void esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info) __attribute__((weak)) void esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info)

View File

@ -112,15 +112,15 @@ esp_ieee802154_state_t esp_ieee802154_get_state(void);
esp_err_t esp_ieee802154_sleep(void); esp_err_t esp_ieee802154_sleep(void);
/** /**
* @brief The IEEE 802.15.4 sleep callback. * @brief The IEEE 802.15.4 enter sleep.
*/ */
void esp_ieee802154_sleep_cb(void); void esp_ieee802154_enter_sleep(void);
/** /**
* @brief The IEEE 802.15.4 wakeup callback. * @brief The IEEE 802.15.4 wakeup.
*/ */
void esp_ieee802154_wakeup_cb(void); void esp_ieee802154_wakeup(void);
/** /**
* @brief Set the IEEE 802.15.4 Radio to receive state. * @brief Set the IEEE 802.15.4 Radio to receive state.

View File

@ -18,6 +18,7 @@ extern "C" {
*/ */
typedef enum { typedef enum {
ESP_IEEE802154_RADIO_DISABLE, /*!< Radio not up */ ESP_IEEE802154_RADIO_DISABLE, /*!< Radio not up */
ESP_IEEE802154_RADIO_IDLE, /*!< Radio in the idle state */
ESP_IEEE802154_RADIO_SLEEP, /*!< Radio in the sleep state */ ESP_IEEE802154_RADIO_SLEEP, /*!< Radio in the sleep state */
ESP_IEEE802154_RADIO_RECEIVE, /*!< Radio in the receive state */ ESP_IEEE802154_RADIO_RECEIVE, /*!< Radio in the receive state */
ESP_IEEE802154_RADIO_TRANSMIT, /*!< Radio in the transmit state */ ESP_IEEE802154_RADIO_TRANSMIT, /*!< Radio in the transmit state */

View File

@ -31,6 +31,7 @@ extern "C" {
typedef enum { typedef enum {
IEEE802154_STATE_DISABLE, /*!< IEEE802154 radio state disable */ IEEE802154_STATE_DISABLE, /*!< IEEE802154 radio state disable */
IEEE802154_STATE_IDLE, /*!< IEEE802154 radio state idle */ IEEE802154_STATE_IDLE, /*!< IEEE802154 radio state idle */
IEEE802154_STATE_SLEEP, /*!< IEEE802154 radio state sleep */
IEEE802154_STATE_RX, /*!< IEEE802154 radio state rx */ IEEE802154_STATE_RX, /*!< IEEE802154 radio state rx */
IEEE802154_STATE_TX_ACK, /*!< IEEE802154 radio state tx ack */ IEEE802154_STATE_TX_ACK, /*!< IEEE802154 radio state tx ack */
IEEE802154_STATE_TX_ENH_ACK, /*!< IEEE802154 radio state tx enh-ack */ IEEE802154_STATE_TX_ENH_ACK, /*!< IEEE802154 radio state tx enh-ack */
@ -178,16 +179,16 @@ uint8_t ieee802154_get_recent_lqi(void);
ieee802154_state_t ieee802154_get_state(void); ieee802154_state_t ieee802154_get_state(void);
/** /**
* @brief The callback of IEEE 802.15.4 sleep. * @brief The IEEE 802.15.4 enter sleep.
* *
*/ */
void ieee802154_sleep_cb(void); void ieee802154_enter_sleep(void);
/** /**
* @brief The callback of IEEE 802.15.4 wakeup. * @brief The IEEE 802.15.4 wakeup.
* *
*/ */
void ieee802154_wakeup_cb(void); void ieee802154_wakeup(void);
/** The following three functions are only used for internal test. **/ /** The following three functions are only used for internal test. **/
/** /**

View File

@ -1,107 +0,0 @@
/*
* 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

@ -12,6 +12,7 @@
#include "esp_openthread_lock.h" #include "esp_openthread_lock.h"
#include "esp_openthread_platform.h" #include "esp_openthread_platform.h"
#include "esp_openthread_state.h" #include "esp_openthread_state.h"
#include "esp_openthread_sleep.h"
#include "esp_openthread_task_queue.h" #include "esp_openthread_task_queue.h"
#include "esp_openthread_types.h" #include "esp_openthread_types.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
@ -21,6 +22,7 @@
#include "openthread/tasklet.h" #include "openthread/tasklet.h"
#include "openthread/thread.h" #include "openthread/thread.h"
static int hex_digit_to_int(char hex) static int hex_digit_to_int(char hex)
{ {
if ('A' <= hex && hex <= 'F') { if ('A' <= hex && hex <= 'F') {
@ -59,6 +61,10 @@ esp_err_t esp_openthread_init(const esp_openthread_platform_config_t *config)
{ {
ESP_RETURN_ON_ERROR(esp_openthread_platform_init(config), OT_PLAT_LOG_TAG, ESP_RETURN_ON_ERROR(esp_openthread_platform_init(config), OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread platform driver"); "Failed to initialize OpenThread platform driver");
#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_openthread_lock_acquire(portMAX_DELAY); esp_openthread_lock_acquire(portMAX_DELAY);
ESP_RETURN_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, OT_PLAT_LOG_TAG, ESP_RETURN_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread instance"); "Failed to initialize OpenThread instance");
@ -159,11 +165,17 @@ esp_err_t esp_openthread_launch_mainloop(void)
mainloop.timeout.tv_sec = 0; mainloop.timeout.tv_sec = 0;
mainloop.timeout.tv_usec = 0; mainloop.timeout.tv_usec = 0;
} }
#if CONFIG_IEEE802154_SLEEP_ENABLE
esp_openthread_sleep_process();
#endif
esp_openthread_lock_release(); esp_openthread_lock_release();
if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds, if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds,
&mainloop.timeout) >= 0) { &mainloop.timeout) >= 0) {
esp_openthread_lock_acquire(portMAX_DELAY); esp_openthread_lock_acquire(portMAX_DELAY);
#if CONFIG_IEEE802154_SLEEP_ENABLE
esp_openthread_wakeup_process();
#endif
error = esp_openthread_platform_process(instance, &mainloop); error = esp_openthread_platform_process(instance, &mainloop);
while (otTaskletsArePending(instance)) { while (otTaskletsArePending(instance)) {
otTaskletsProcess(instance); otTaskletsProcess(instance);

View File

@ -6,9 +6,6 @@
#include "esp_log.h" #include "esp_log.h"
#include "esp_check.h" #include "esp_check.h"
#include "openthread/instance.h"
#include "openthread/thread.h"
#include "esp_openthread.h"
#include "esp_ieee802154.h" #include "esp_ieee802154.h"
#if CONFIG_IEEE802154_SLEEP_ENABLE #if CONFIG_IEEE802154_SLEEP_ENABLE
@ -22,36 +19,22 @@ esp_err_t esp_openthread_sleep_init(void)
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
err = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "ieee802154", &s_pm_lock); err = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "ieee802154", &s_pm_lock);
if (err != ESP_OK) { 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");
esp_pm_lock_acquire(s_pm_lock); } else {
if (s_pm_lock != NULL) {
ESP_LOGI(TAG, "Enable ieee802154 light sleep, the wake up source is ESP timer"); esp_pm_lock_delete(s_pm_lock);
s_pm_lock = NULL;
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; return err;
} }
void esp_openthread_sleep_process(void) void esp_openthread_sleep_process(void)
{ {
otInstance *instance = esp_openthread_get_instance(); if (esp_ieee802154_get_state() == ESP_IEEE802154_RADIO_SLEEP) {
otLinkModeConfig linkMode = otThreadGetLinkMode(instance); esp_ieee802154_enter_sleep();
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); esp_pm_lock_release(s_pm_lock);
s_ot_sleep = true; s_ot_sleep = true;
} }
@ -61,7 +44,7 @@ void esp_openthread_wakeup_process(void)
{ {
if (s_ot_sleep) { if (s_ot_sleep) {
esp_pm_lock_acquire(s_pm_lock); esp_pm_lock_acquire(s_pm_lock);
esp_ieee802154_wakeup_cb(); esp_ieee802154_wakeup();
s_ot_sleep = false; s_ot_sleep = false;
} }
} }

View File

@ -18,14 +18,6 @@ examples/openthread/ot_cli:
temporary: true temporary: true
reason: only test on esp32h2 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: examples/openthread/ot_rcp:
enable: enable:
- if: IDF_TARGET in ["esp32h2", "esp32c6"] - if: IDF_TARGET in ["esp32h2", "esp32c6"]
@ -33,3 +25,11 @@ examples/openthread/ot_rcp:
- if: IDF_TARGET == "esp32h2" - if: IDF_TARGET == "esp32h2"
temporary: true temporary: true
reason: only test on esp32c6 reason: only test on esp32c6
examples/openthread/ot_sleepy_device:
enable:
- if: IDF_TARGET == "esp32c6"
disable_test:
- if: IDF_TARGET in ["esp32h2", "esp32c6"]
temporary: true
reason: No support # TO-DO: TZ-134

View File

@ -12,4 +12,4 @@ In this folder, it contains following OpenThread examples:
* [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_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. * [ot_sleepy_device](ot_sleepy_device) is an OpenThread sleepy device example, it supports 802.15.4 radio light sleep. It runs on an 802.15.4 SoC like ESP32-C6.

View File

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

View File

@ -3,4 +3,4 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ot_power_save) project(ot_sleepy_device)

View File

@ -1,9 +1,9 @@
| Supported Targets | ESP32-C6 | | Supported Targets | ESP32-C6 |
| ----------------- | -------- | | ----------------- | -------- |
# OpenThread Power Save Example # OpenThread Sleepy Device 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. The example demonstrates the Thread Sleepy End Device (SED), the device will enter [Light Sleep mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32h2/api-reference/system/sleep_modes.html#sleep-modes) during idle state.
## How to use example ## How to use example
### Hardware Required ### Hardware Required

View File

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

View File

@ -22,7 +22,7 @@
#include "esp_log.h" #include "esp_log.h"
#include "esp_openthread.h" #include "esp_openthread.h"
#include "esp_openthread_netif_glue.h" #include "esp_openthread_netif_glue.h"
#include "esp_ot_power_save_config.h" #include "esp_ot_sleepy_device_config.h"
#include "esp_vfs_eventfd.h" #include "esp_vfs_eventfd.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "nvs_flash.h" #include "nvs_flash.h"
@ -34,7 +34,7 @@
#endif #endif
#if !SOC_IEEE802154_SUPPORTED #if !SOC_IEEE802154_SUPPORTED
#error "Power save is only supported for the SoCs which have IEEE 802.15.4 module" #error "Openthread sleepy device is only supported for the SoCs which have IEEE 802.15.4 module"
#endif #endif
#define TAG "ot_esp_power_save" #define TAG "ot_esp_power_save"