Merge branch 'feature/add_cli_in_openthread_sleep_example_v5.1' into 'release/v5.1'

feat(openthread): add cli in openthread sleep example (backport v5.1)

See merge request espressif/esp-idf!29596
This commit is contained in:
Jiang Jiang Jian 2024-04-03 19:02:32 +08:00
commit 54ad993fe9
5 changed files with 157 additions and 33 deletions

View File

@ -6,34 +6,100 @@ The example demonstrates the Thread Sleepy End Device (SED), the device will ent
## How to use example
### Hardware Required
* One 802.15.4 SoC (for example ESP32-H2) runs [ot_cli](../../ot_cli/) example, and forms a Thread network.
* A second 802.15.4 SoC runs this example.
* Prepare an 802.15.4 SoC development board as an OpenThread Sleepy End Device (SED).
* Connect the board using a USB cable for power supply and programming.
* Choose another 802.15.4 SoC as the OpenThread Leader.
### Configure the project
## Configure the Openthread Dataset
Set the chip target: `idf.py set-target <chip_name>`, then configure the project via `idf.py menuconfig`.
* Run [ot_cli](../../ot_cli/) on another 802.15.4 SoC device to create openthread dataset configuration and start an openthread network as the leader.
* Configure the Openthread dataset using `idf.py menuconfig` in `Component config ---> Openthread ---> Thread Operation Dataset`, ensuring that the openthread sleepy device's dataset matches the dataset of the leader.
There are two options to configure Openthread Dataset:
* Auto start mode: Enable `OPENTHREAD_AUTO_START` under `OpenThread Sleepy Example---> Enable the automatic start mode`, and configure the dataset under `Component config ---> Openthread ---> Thread Operation Dataset`.
* Manual mode: Disable `OPENTHREAD_AUTO_START`, use the CLI command to configure the dataset and start network.
### Build and Flash
Build the project and flash it to the board. Use the following command: `idf.py -p <PORT> erase-flash flash monitor`.
### Configure the Openthread sleepy device
```
> mode -
> pollperiod 3000
> dataset set active <the same as dataset of the leader>
> ifconfig up
> thread start
```
### 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
I (486) app_init: ESP-IDF: v5.3-dev-2053-g4d7e86eeb6-dirty
I (493) app_init: Min chip rev: v0.0
I (497) app_init: Max chip rev: v0.99
I (502) app_init: Chip rev: v0.1
I (507) sleep: Enable automatic switching of GPIO sleep configuration
I (514) sleep_clock: System Power, Clock and Reset sleep retention initialization
I (522) sleep_clock: Modem Power, Clock and Reset sleep retention initialization
I (530) sleep_sys_periph: Interrupt Matrix sleep retention initialization
I (538) sleep_sys_periph: HP System sleep retention initialization
I (545) sleep_sys_periph: TEE/APM sleep retention initialization
I (551) sleep_sys_periph: UART sleep retention initialization
I (558) sleep_sys_periph: Timer Group sleep retention initialization
I (565) sleep_sys_periph: IO Matrix sleep retention initialization
I (572) sleep_sys_periph: SPI Mem sleep retention initialization
I (579) sleep_sys_periph: SysTimer sleep retention initialization
I (597) main_task: Started on CPU0
I (597) main_task: Calling app_main()
I (608) pm: Frequency switching config: CPU_MAX: 96, APB_MAX: 96, APB_MIN: 96, Light sleep: ENABLED
I (609) ot_esp_power_save: Create ot cI (631) phy: phy_version: 230,2, 9aae6ea, Jan 15 2024, 11:17:12
I (633) phy: libbtbb version: 944f18e, Jan 15 2024, 11:17:25
I (634) btbb_init: btbb sleep retention initialization
I (646) ieee802154: ieee802154 mac sleep retention initialization
I (652) gdma: GDMA pair (0, 0) retention initialization
I(660) OPENTHREAD:[I] ChildSupervsn-: Timeout: 0 -> 190
> I (664) OPENTHREAD: OpenThread attached to netif
I (635) main_task: Returned from app_main()
> mode -
I(2250683) OPENTHREAD:[N] Mle-----------: Mode 0x0f -> 0x04 [rx-on:no ftd:no full-net:no]
Done
> pollperiod 3000
Done
> dataset set active 0e080000000000010000000300001a35060004001fffe00208dead00beef00cafe0708fd000db800a00000051000112233445566778899aabbccdd0000030e4f70656e5468726561642d455350010212340410104810e2315100afd6bc9215a6bfac530c0402a0f7f8
Done
> ifconfig up
Done
I (2274801) OT_STATE: netif up
> thread start
I(2279917) OPENTHREAD:[N] Mle-----------: Role disabled -> detached
Done
> I(2280368) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition reattaching with Active Dataset
I(2281262) OPENTHREAD:[N] Mle-----------: RLOC16 fffe -> 5019
I(2281264) OPENTHREAD:[N] Mle-----------: Role detached -> child
```
When the device is running in auto start mode, the running log is as follows:
```
I(662) OPENTHREAD:[I] ChildSupervsn-: Timeout: 0 -> 190
> I (666) OPENTHREAD: OpenThread attached to netif
I(668) OPENTHREAD:[N] Mle-----------: Mode 0x0f -> 0x04 [rx-on:no ftd:no full-net:no]
I (637) main_task: Returned from app_main()
I(693) OPENTHREAD:[N] Mle-----------: Role disabled -> detached
I (705) OT_STATE: netif up
I(867) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition reattaching with Active Dataset
I(1819) OPENTHREAD:[N] Mle-----------: RLOC16 fffe -> 500b
I(1821) OPENTHREAD:[N] Mle-----------: Role detached -> child
```
### Note
Currently, UART wakeup is not enabled. Once the device joins the network as a child and enters sleep mode, the OT CLI will become inaccessible.

View File

@ -0,0 +1,9 @@
menu "OpenThread Sleepy Example"
config OPENTHREAD_AUTO_START
bool 'Enable the automatic start mode.'
default False
help
If enabled, the Openthread Device will create or connect to thread network with pre-configured
network parameters automatically. Otherwise, user need to configure Thread via CLI command manually.
endmenu

View File

@ -20,6 +20,8 @@
#include "esp_event.h"
#include "esp_log.h"
#include "esp_openthread.h"
#include "esp_openthread_cli.h"
#include "esp_openthread_lock.h"
#include "esp_openthread_netif_glue.h"
#include "esp_ot_sleepy_device_config.h"
#include "esp_vfs_eventfd.h"
@ -27,7 +29,6 @@
#include "nvs_flash.h"
#include "openthread/logging.h"
#include "openthread/thread.h"
#if CONFIG_ESP_SLEEP_DEBUG
#include "esp_timer.h"
#include "esp_sleep.h"
@ -45,6 +46,9 @@
#define TAG "ot_esp_power_save"
static esp_pm_lock_handle_t s_cli_pm_lock = NULL;
#if CONFIG_OPENTHREAD_AUTO_START
static void create_config_network(otInstance *instance)
{
otLinkModeConfig linkMode = { 0 };
@ -62,7 +66,41 @@ static void create_config_network(otInstance *instance)
ESP_LOGE(TAG, "Failed to set OpenThread linkmode.");
abort();
}
ESP_ERROR_CHECK(esp_openthread_auto_start(NULL));
otOperationalDatasetTlvs dataset;
otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset);
ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL));
}
#endif // CONFIG_OPENTHREAD_AUTO_START
static esp_err_t esp_openthread_sleep_device_init(void)
{
esp_err_t ret = ESP_OK;
ret = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "otcli", &s_cli_pm_lock);
if (ret == ESP_OK) {
esp_pm_lock_acquire(s_cli_pm_lock);
ESP_LOGI(TAG, "Successfully created CLI pm lock");
} else {
if (s_cli_pm_lock != NULL) {
esp_pm_lock_delete(s_cli_pm_lock);
s_cli_pm_lock = NULL;
}
ESP_LOGI(TAG, " Failed to create CLI pm lock");
}
return ret;
}
static void process_state_change(otChangedFlags flags, void* context)
{
otDeviceRole ot_device_role = otThreadGetDeviceRole(esp_openthread_get_instance());
if(ot_device_role == OT_DEVICE_ROLE_CHILD) {
if (s_cli_pm_lock != NULL) {
esp_pm_lock_release(s_cli_pm_lock);
esp_pm_lock_delete(s_cli_pm_lock);
s_cli_pm_lock = NULL;
}
}
}
static esp_netif_t *init_openthread_netif(const esp_openthread_platform_config_t *config)
@ -88,6 +126,7 @@ static void print_sleep_flag(void *arg)
static void ot_task_worker(void *aContext)
{
otError ret;
esp_openthread_platform_config_t config = {
.radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(),
.host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
@ -97,17 +136,31 @@ static void ot_task_worker(void *aContext)
// Initialize the OpenThread stack
ESP_ERROR_CHECK(esp_openthread_init(&config));
esp_openthread_lock_acquire(portMAX_DELAY);
ret = otSetStateChangedCallback(esp_openthread_get_instance(), process_state_change, esp_openthread_get_instance());
esp_openthread_lock_release();
if(ret != OT_ERROR_NONE) {
ESP_LOGE(TAG, "Failed to set state changed callback");
}
#if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC
// The OpenThread log level directly matches ESP log level
(void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL);
#endif
// Initialize the OpenThread cli
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_init();
#endif
esp_netif_t *openthread_netif;
// Initialize the esp_netif bindings
openthread_netif = init_openthread_netif(&config);
esp_netif_set_default_netif(openthread_netif);
#if CONFIG_OPENTHREAD_AUTO_START
create_config_network(esp_openthread_get_instance());
#endif // CONFIG_OPENTHREAD_AUTO_START
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_create_task();
#endif
#if CONFIG_ESP_SLEEP_DEBUG
esp_sleep_set_sleep_context(&s_sleep_ctx);
esp_log_level_set(TAG, ESP_LOG_DEBUG);
@ -170,6 +223,6 @@ void app_main(void)
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
ESP_ERROR_CHECK(ot_power_save_init());
ESP_ERROR_CHECK(esp_openthread_sleep_device_init());
xTaskCreate(ot_task_worker, "ot_power_save_main", 4096, NULL, 5, NULL);
}

View File

@ -21,6 +21,7 @@ CONFIG_MBEDTLS_ECJPAKE_C=y
CONFIG_OPENTHREAD_ENABLED=y
CONFIG_OPENTHREAD_BORDER_ROUTER=n
CONFIG_OPENTHREAD_DNS64_CLIENT=y
CONFIG_OPENTHREAD_CLI=y
# end of OpenThread
#

View File

@ -1,8 +1,6 @@
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
# !/usr/bin/env python3
import os.path
import re
import subprocess
@ -567,17 +565,14 @@ def test_ot_sleepy_device(dut: Tuple[IdfDut, IdfDut]) -> None:
ocf.init_thread(leader)
time.sleep(3)
leader_para = ocf.thread_parameter('leader', '', '12', '7766554433221100', False)
leader_para.setnetworkname('OpenThread-ESP')
leader_para.setpanid('0x1234')
leader_para.setextpanid('dead00beef00cafe')
leader_para.setnetworkkey('aabbccddeeff00112233445566778899')
leader_para.setpskc('104810e2315100afd6bc9215a6bfac53')
ocf.joinThreadNetwork(leader, leader_para)
ocf.wait(leader, 5)
output = sleepy_device.expect(pexpect.TIMEOUT, timeout=5)
assert not bool(fail_info.search(str(output)))
ocf.clean_buffer(sleepy_device)
sleepy_device.serial.hard_reset()
dataset = ocf.getDataset(leader)
ocf.execute_command(sleepy_device, 'mode -')
ocf.execute_command(sleepy_device, 'pollperiod 3000')
ocf.execute_command(sleepy_device, 'dataset set active ' + dataset)
ocf.execute_command(sleepy_device, 'ifconfig up')
ocf.execute_command(sleepy_device, 'thread start')
info = sleepy_device.expect(r'(.+)detached -> child', timeout=20)[1].decode(errors='replace')
assert not bool(fail_info.search(str(info)))
info = sleepy_device.expect(r'(.+)PMU_SLEEP_PD_TOP: True', timeout=10)[1].decode(errors='replace')