feat(openthread): add cli in openthread sleep example

This commit is contained in:
xiaqilin 2024-03-04 14:07:25 +08:00
parent 0c47128627
commit 57189ec1a7
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 ## How to use example
### Hardware Required ### 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). ### Configure the project
* Connect the board using a USB cable for power supply and programming.
* Choose another 802.15.4 SoC as the OpenThread Leader.
## 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. There are two options to configure Openthread Dataset:
* 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.
* 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 and Flash
Build the project and flash it to the board. Use the following command: `idf.py -p <PORT> erase-flash flash monitor`. 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 ### 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. 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 (486) app_init: ESP-IDF: v5.3-dev-2053-g4d7e86eeb6-dirty
I (769) ieee802154: ieee802154 mac sleep retention initialization I (493) app_init: Min chip rev: v0.0
I(769) OPENTHREAD:[I] ChildSupervsn-: Timeout: 0 -> 190 I (497) app_init: Max chip rev: v0.99
I (699) main_task: Returned from app_main() I (502) app_init: Chip rev: v0.1
I (799) OPENTHREAD: OpenThread attached to netif I (507) sleep: Enable automatic switching of GPIO sleep configuration
I(799) OPENTHREAD:[N] Mle-----------: Mode 0x0f -> 0x04 [rx-on:no ftd:no full-net:no] I (514) sleep_clock: System Power, Clock and Reset sleep retention initialization
I(809) OPENTHREAD:[N] Mle-----------: Role disabled -> detached I (522) sleep_clock: Modem Power, Clock and Reset sleep retention initialization
I (819) OPENTHREAD: netif up I (530) sleep_sys_periph: Interrupt Matrix sleep retention initialization
I(1519) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition reattaching with Active Dataset I (538) sleep_sys_periph: HP System sleep retention initialization
I(2479) OPENTHREAD:[N] Mle-----------: RLOC16 fffe -> 5023 I (545) sleep_sys_periph: TEE/APM sleep retention initialization
I(2529) OPENTHREAD:[N] Mle-----------: Role detached -> child 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_event.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_openthread.h" #include "esp_openthread.h"
#include "esp_openthread_cli.h"
#include "esp_openthread_lock.h"
#include "esp_openthread_netif_glue.h" #include "esp_openthread_netif_glue.h"
#include "esp_ot_sleepy_device_config.h" #include "esp_ot_sleepy_device_config.h"
#include "esp_vfs_eventfd.h" #include "esp_vfs_eventfd.h"
@ -27,7 +29,6 @@
#include "nvs_flash.h" #include "nvs_flash.h"
#include "openthread/logging.h" #include "openthread/logging.h"
#include "openthread/thread.h" #include "openthread/thread.h"
#if CONFIG_ESP_SLEEP_DEBUG #if CONFIG_ESP_SLEEP_DEBUG
#include "esp_timer.h" #include "esp_timer.h"
#include "esp_sleep.h" #include "esp_sleep.h"
@ -45,6 +46,9 @@
#define TAG "ot_esp_power_save" #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) static void create_config_network(otInstance *instance)
{ {
otLinkModeConfig linkMode = { 0 }; otLinkModeConfig linkMode = { 0 };
@ -62,7 +66,41 @@ static void create_config_network(otInstance *instance)
ESP_LOGE(TAG, "Failed to set OpenThread linkmode."); ESP_LOGE(TAG, "Failed to set OpenThread linkmode.");
abort(); 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) 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) static void ot_task_worker(void *aContext)
{ {
otError ret;
esp_openthread_platform_config_t config = { esp_openthread_platform_config_t config = {
.radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(), .radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(),
.host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(), .host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
@ -97,17 +136,31 @@ static void ot_task_worker(void *aContext)
// Initialize the OpenThread stack // Initialize the OpenThread stack
ESP_ERROR_CHECK(esp_openthread_init(&config)); 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 #if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC
// The OpenThread log level directly matches ESP log level // The OpenThread log level directly matches ESP log level
(void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL); (void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL);
#endif
// Initialize the OpenThread cli
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_init();
#endif #endif
esp_netif_t *openthread_netif; esp_netif_t *openthread_netif;
// Initialize the esp_netif bindings // Initialize the esp_netif bindings
openthread_netif = init_openthread_netif(&config); openthread_netif = init_openthread_netif(&config);
esp_netif_set_default_netif(openthread_netif); esp_netif_set_default_netif(openthread_netif);
#if CONFIG_OPENTHREAD_AUTO_START
create_config_network(esp_openthread_get_instance()); 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 #if CONFIG_ESP_SLEEP_DEBUG
esp_sleep_set_sleep_context(&s_sleep_ctx); esp_sleep_set_sleep_context(&s_sleep_ctx);
esp_log_level_set(TAG, ESP_LOG_DEBUG); 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_netif_init());
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
ESP_ERROR_CHECK(ot_power_save_init()); 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); 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_ENABLED=y
CONFIG_OPENTHREAD_BORDER_ROUTER=n CONFIG_OPENTHREAD_BORDER_ROUTER=n
CONFIG_OPENTHREAD_DNS64_CLIENT=y CONFIG_OPENTHREAD_DNS64_CLIENT=y
CONFIG_OPENTHREAD_CLI=y
# end of OpenThread # end of OpenThread
# #

View File

@ -1,8 +1,6 @@
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0 # SPDX-License-Identifier: Unlicense OR CC0-1.0
# !/usr/bin/env python3 # !/usr/bin/env python3
import copy import copy
import os.path import os.path
import re import re
@ -581,17 +579,14 @@ def test_ot_sleepy_device(dut: Tuple[IdfDut, IdfDut]) -> None:
ocf.init_thread(leader) ocf.init_thread(leader)
time.sleep(3) time.sleep(3)
leader_para = ocf.thread_parameter('leader', '', '12', '7766554433221100', False) 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.joinThreadNetwork(leader, leader_para)
ocf.wait(leader, 5) ocf.wait(leader, 5)
output = sleepy_device.expect(pexpect.TIMEOUT, timeout=5) dataset = ocf.getDataset(leader)
assert not bool(fail_info.search(str(output))) ocf.execute_command(sleepy_device, 'mode -')
ocf.clean_buffer(sleepy_device) ocf.execute_command(sleepy_device, 'pollperiod 3000')
sleepy_device.serial.hard_reset() 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') info = sleepy_device.expect(r'(.+)detached -> child', timeout=20)[1].decode(errors='replace')
assert not bool(fail_info.search(str(info))) assert not bool(fail_info.search(str(info)))
info = sleepy_device.expect(r'(.+)PMU_SLEEP_PD_TOP: True', timeout=10)[1].decode(errors='replace') info = sleepy_device.expect(r'(.+)PMU_SLEEP_PD_TOP: True', timeout=10)[1].decode(errors='replace')