mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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:
commit
54ad993fe9
@ -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.
|
||||||
|
@ -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
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -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 os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -567,17 +565,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')
|
||||||
|
Loading…
Reference in New Issue
Block a user