Merge branch 'feat/add_openthread_start_stop_api' into 'master'

feat(openthread): add openthread start stop APIs

See merge request espressif/esp-idf!40349
This commit is contained in:
Xu Si Yu
2025-09-26 15:35:20 +08:00
54 changed files with 813 additions and 818 deletions

View File

@@ -6,6 +6,28 @@ menu "OpenThread"
help help
Select this option to enable OpenThread and show the submenu with OpenThread configuration choices. Select this option to enable OpenThread and show the submenu with OpenThread configuration choices.
menu "Thread Task Parameters"
depends on OPENTHREAD_ENABLED
config OPENTHREAD_TASK_NAME
string "OpenThread task name"
default "ot_main"
help
The OpenThread task name.
config OPENTHREAD_TASK_SIZE
int "Size of OpenThread task"
default 8192
help
The size in bytes of OpenThread task.
config OPENTHREAD_TASK_PRIORITY
int "Priority of OpenThread task"
default 5
help
The priority of OpenThread task.
endmenu
menu "Thread Version Message" menu "Thread Version Message"
depends on OPENTHREAD_ENABLED depends on OPENTHREAD_ENABLED
@@ -23,10 +45,18 @@ menu "OpenThread"
endmenu endmenu
menu "Thread Console" menu "Thread Console"
depends on OPENTHREAD_ENABLED config OPENTHREAD_CONSOLE_ENABLE
bool "Enable OpenThread console"
depends on OPENTHREAD_ENABLED
default y
help
Enable the OpenThread-specific console provided by the SDK. This only controls whether
the SDK sets up a dedicated console for OpenThread. Even if disabled, the default
ESP-IDF console (if initialized elsewhere) can still be used independently.
choice OPENTHREAD_CONSOLE_TYPE choice OPENTHREAD_CONSOLE_TYPE
prompt "OpenThread console type" prompt "OpenThread console type"
depends on OPENTHREAD_CONSOLE_ENABLE
default OPENTHREAD_CONSOLE_TYPE_UART default OPENTHREAD_CONSOLE_TYPE_UART
help help
Select OpenThread console type Select OpenThread console type

View File

@@ -7,6 +7,7 @@
#pragma once #pragma once
#include "esp_err.h" #include "esp_err.h"
#include "esp_netif.h"
#include "esp_openthread_types.h" #include "esp_openthread_types.h"
#include "openthread/dataset.h" #include "openthread/dataset.h"
#include "openthread/error.h" #include "openthread/error.h"
@@ -89,6 +90,29 @@ otInstance *esp_openthread_get_instance(void);
*/ */
esp_err_t esp_openthread_mainloop_exit(void); esp_err_t esp_openthread_mainloop_exit(void);
/**
* @brief Starts the full OpenThread stack and create a handle task.
*
* @note The OpenThread instance will also be initialized in this function.
*
* @param[in] config The OpenThread platform configuration.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if already initialized
*
*/
esp_err_t esp_openthread_start(esp_openthread_platform_config_t *config);
/**
* @brief This function performs OpenThread stack and platform driver deinitialization and delete the handle task.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if Thread is already active
*
*/
esp_err_t esp_openthread_stop(void);
#ifdef __cplusplus #ifdef __cplusplus
} // end of extern "C" } // end of extern "C"
#endif #endif

View File

@@ -1,10 +1,11 @@
/* /*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <spinel.h> #include <spinel.h>
#include <esp_openthread.h>
#if CONFIG_OPENTHREAD_NCP_VENDOR_HOOK #if CONFIG_OPENTHREAD_NCP_VENDOR_HOOK
@@ -15,3 +16,13 @@
#define SPINEL_PROP_VENDOR_ESP_COEX_EVENT (SPINEL_PROP_VENDOR_ESP__BEGIN + 3) #define SPINEL_PROP_VENDOR_ESP_COEX_EVENT (SPINEL_PROP_VENDOR_ESP__BEGIN + 3)
#endif #endif
#ifdef __cplusplus
extern "C" {
#endif
void otAppNcpInit(otInstance *aInstance);
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */

View File

@@ -4,12 +4,17 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include "sdkconfig.h"
#include "esp_openthread.h" #include "esp_openthread.h"
#include "esp_check.h" #include "esp_check.h"
#include "esp_heap_caps.h"
#include "esp_openthread_border_router.h" #include "esp_openthread_border_router.h"
#include "esp_openthread_common_macro.h" #include "esp_openthread_common_macro.h"
#include "esp_openthread_cli.h"
#include "esp_openthread_dns64.h" #include "esp_openthread_dns64.h"
#include "esp_openthread_lock.h" #include "esp_openthread_lock.h"
#include "esp_openthread_ncp.h"
#include "esp_openthread_netif_glue.h"
#include "esp_openthread_platform.h" #include "esp_openthread_platform.h"
#include "esp_openthread_sleep.h" #include "esp_openthread_sleep.h"
#include "esp_openthread_state.h" #include "esp_openthread_state.h"
@@ -18,15 +23,19 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "lwip/dns.h" #include "lwip/dns.h"
#include "openthread/instance.h" #include "openthread/instance.h"
#include "openthread/logging.h"
#include "openthread/netdata.h" #include "openthread/netdata.h"
#include "openthread/tasklet.h" #include "openthread/tasklet.h"
#include "openthread/thread.h" #include "openthread/thread.h"
#include <cstddef>
#if CONFIG_OPENTHREAD_FTD #if CONFIG_OPENTHREAD_FTD
#include "openthread/dataset_ftd.h" #include "openthread/dataset_ftd.h"
#endif #endif
static bool s_ot_mainloop_running = false; static bool s_ot_mainloop_running = false;
static SemaphoreHandle_t s_ot_syn_semaphore = NULL;
static TaskHandle_t s_ot_task_handle = NULL;
static int hex_digit_to_int(char hex) static int hex_digit_to_int(char hex)
{ {
@@ -223,3 +232,81 @@ esp_err_t esp_openthread_deinit(void)
otInstanceFinalize(esp_openthread_get_instance()); otInstanceFinalize(esp_openthread_get_instance());
return esp_openthread_platform_deinit(); return esp_openthread_platform_deinit();
} }
static void ot_task_worker(void *aContext)
{
esp_openthread_platform_config_t* config = (esp_openthread_platform_config_t *)aContext;
// Initialize the OpenThread stack
ESP_ERROR_CHECK(esp_openthread_init(config));
#if CONFIG_OPENTHREAD_FTD || CONFIG_OPENTHREAD_MTD
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD();
esp_netif_t *openthread_netif = esp_netif_new(&cfg);
assert(openthread_netif != NULL);
ESP_ERROR_CHECK(esp_netif_attach(openthread_netif, esp_openthread_netif_glue_init(config)));
#endif
#if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC
// The OpenThread log level directly matches ESP log level
(void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL);
#endif // CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_init();
esp_openthread_cli_console_command_register();
#endif // CONFIG_OPENTHREAD_CLI
xSemaphoreGive(s_ot_syn_semaphore);
#if CONFIG_OPENTHREAD_RADIO
otAppNcpInit(esp_openthread_get_instance());
#endif
// Run the main loop
esp_openthread_launch_mainloop();
#if CONFIG_OPENTHREAD_RADIO
ESP_LOGE(OT_PLAT_LOG_TAG, "RCP deinitialization is not supported for now");
assert(false);
#endif
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_console_command_unregister();
#endif // CONFIG_OPENTHREAD_CLI
#if CONFIG_OPENTHREAD_FTD || CONFIG_OPENTHREAD_MTD
// Clean up
esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
#endif
ESP_ERROR_CHECK(esp_openthread_deinit());
xSemaphoreGive(s_ot_syn_semaphore);
vTaskDelay(portMAX_DELAY);
}
esp_err_t esp_openthread_start(esp_openthread_platform_config_t *config)
{
ESP_RETURN_ON_FALSE(s_ot_syn_semaphore == NULL, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "OpenThread has been initialized");
s_ot_syn_semaphore = xSemaphoreCreateBinary();
ESP_RETURN_ON_FALSE(s_ot_syn_semaphore != NULL, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "Failed to create s_ot_syn_semaphore");
assert(xTaskCreate(ot_task_worker, CONFIG_OPENTHREAD_TASK_NAME, CONFIG_OPENTHREAD_TASK_SIZE, config, CONFIG_OPENTHREAD_TASK_PRIORITY, &s_ot_task_handle) == pdPASS);
xSemaphoreTake(s_ot_syn_semaphore, portMAX_DELAY);
return ESP_OK;
}
esp_err_t esp_openthread_stop(void)
{
ESP_RETURN_ON_FALSE(s_ot_syn_semaphore != NULL, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "OpenThread is not initialized");
esp_openthread_lock_acquire(portMAX_DELAY);
otInstance *instance = esp_openthread_get_instance();
bool is_thread_not_active = (otThreadGetDeviceRole(instance) == OT_DEVICE_ROLE_DISABLED && otIp6IsEnabled(instance) == false);
esp_openthread_lock_release();
ESP_RETURN_ON_FALSE(is_thread_not_active, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "Thread interface is still active");
esp_openthread_mainloop_exit();
xSemaphoreTake(s_ot_syn_semaphore, portMAX_DELAY);
vTaskDelete(s_ot_task_handle);
vSemaphoreDelete(s_ot_syn_semaphore);
s_ot_task_handle = NULL;
s_ot_syn_semaphore = NULL;
return ESP_OK;
}

View File

@@ -56,11 +56,11 @@ In order to run the example on single SoC which supports both Wi-Fi and Thread,
Two ways are provided to setup the Thread Border Router in this example: Two ways are provided to setup the Thread Border Router in this example:
- Auto Start - Auto Start
Enable `OPENTHREAD_BR_AUTO_START`, configure the `CONFIG_EXAMPLE_WIFI_SSID` and `CONFIG_EXAMPLE_WIFI_PASSWORD` with your access point's ssid and psk. Enable `OPENTHREAD_NETWORK_AUTO_START`, configure the `CONFIG_EXAMPLE_WIFI_SSID` and `CONFIG_EXAMPLE_WIFI_PASSWORD` with your access point's ssid and psk.
The device will connect to Wi-Fi and form a Thread network automatically after boot up. The device will connect to Wi-Fi and form a Thread network automatically after boot up.
- Manual mode - Manual mode
Disable `OPENTHREAD_BR_AUTO_START` and enable `OPENTHREAD_CLI_ESP_EXTENSION`. `wifi` command will be added for connecting the device to the Wi-Fi network. Disable `OPENTHREAD_NETWORK_AUTO_START` and enable `OPENTHREAD_CLI_ESP_EXTENSION`. `wifi` command will be added for connecting the device to the Wi-Fi network.
If the `CONFIG_EXAMPLE_CONNECT_ETHERNET` option is enabled, the device will connect to `Ethernet`, form a Thread network and act as a Ethernet based Thread Border Router. If the `CONFIG_EXAMPLE_CONNECT_ETHERNET` option is enabled, the device will connect to `Ethernet`, form a Thread network and act as a Ethernet based Thread Border Router.
@@ -71,14 +71,14 @@ Build the project and flash it to the board, then run monitor tool to view seria
``` ```
idf.py -p PORT build flash monitor idf.py -p PORT build flash monitor
``` ```
If the `OPENTHREAD_BR_AUTO_START` option is enabled, The device will be connected to the configured Wi-Fi and Thread network automatically then act as the border router. If the `OPENTHREAD_NETWORK_AUTO_START` option is enabled, The device will be connected to the configured Wi-Fi and Thread network automatically then act as the border router.
Otherwise, you need to manually configure the networks with CLI commands. Otherwise, you need to manually configure the networks with CLI commands.
`wifi` command can be used to configure the Wi-Fi network. `wifi` command can be used to configure the Wi-Fi network.
```bash ```bash
> wifi esp32s3> ot wifi
--wifi parameter--- --wifi parameter---
connect connect
-s : wifi ssid -s : wifi ssid
@@ -96,7 +96,7 @@ Done
To join a Wi-Fi network, please use the `wifi connect` command: To join a Wi-Fi network, please use the `wifi connect` command:
```bash ```bash
> wifi connect -s threadcertAP -p threadcertAP esp32s3> ot wifi connect -s threadcertAP -p threadcertAP
ssid: threadcertAP ssid: threadcertAP
psk: threadcertAP psk: threadcertAP
I (11331) wifi:wifi driver task: 3ffd06e4, prio:23, stack:6656, core=0 I (11331) wifi:wifi driver task: 3ffd06e4, prio:23, stack:6656, core=0
@@ -117,7 +117,7 @@ Done
To get the state of the Wi-Fi network: To get the state of the Wi-Fi network:
```bash ```bash
> wifi state esp32s3> ot wifi state
connected connected
Done Done
``` ```
@@ -165,7 +165,7 @@ For mobile devices, the route table rules will be automatically configured after
Now in the Thread end device, check the IP addresses: Now in the Thread end device, check the IP addresses:
``` ```
> ipaddr esp32h2> ot ipaddr
fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5 fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5
fdde:ad00:beef:0:0:ff:fe00:c402 fdde:ad00:beef:0:0:ff:fe00:c402
fdde:ad00:beef:0:ad4a:9a9a:3cd6:e423 fdde:ad00:beef:0:ad4a:9a9a:3cd6:e423
@@ -192,13 +192,13 @@ The newly introduced service registration protocol([SRP](https://datatracker.iet
Now we'll publish the service `my-service._test._udp` with hostname `test0` and port 12345 Now we'll publish the service `my-service._test._udp` with hostname `test0` and port 12345
``` ```
> srp client host name test0 esp32h2> ot srp client host name test0
Done Done
> srp client host address fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5 esp32h2> ot srp client host address fde6:75ff:def4:3bc3:9e9e:3ef:4245:28b5
Done Done
> srp client service add my-service _test._udp 12345 esp32h2> ot srp client service add my-service _test._udp 12345
Done Done
> srp client autostart enable esp32h2> ot srp client autostart enable
Done Done
``` ```
@@ -233,7 +233,7 @@ Then get the border router's OMR prefix global unicast address(or ML-EID), and c
On the border router: On the border router:
``` ```
> ipaddr esp32s3> ot ipaddr
fdde:ad00:beef:0:0:ff:fe00:fc10 fdde:ad00:beef:0:0:ff:fe00:fc10
fd9b:347f:93f7:1:1003:8f00:bcc1:3038 fd9b:347f:93f7:1:1003:8f00:bcc1:3038
fdde:ad00:beef:0:0:ff:fe00:fc00 fdde:ad00:beef:0:0:ff:fe00:fc00
@@ -245,19 +245,19 @@ Done
On the Thread end device: On the Thread end device:
``` ```
> dns config fd9b:347f:93f7:1:1003:8f00:bcc1:3038 esp32h2> ot dns config fd9b:347f:93f7:1:1003:8f00:bcc1:3038
(or (or
> dns config fdde:ad00:beef:0:f891:287:866:776) esp32h2> ot dns config fdde:ad00:beef:0:f891:287:866:776)
Done Done
``` ```
Now the service published on the Host can be discovered on the Thread end device. Now the service published on the Host can be discovered on the Thread end device.
``` ```
> dns resolve FA001208.default.service.arpa. esp32h2> ot dns resolve FA001208.default.service.arpa.
DNS response for FA001208.default.service.arpa. - fdde:ad00:beef:cafe:b939:26be:7516:b87e TTL:120 DNS response for FA001208.default.service.arpa. - fdde:ad00:beef:cafe:b939:26be:7516:b87e TTL:120
Done Done
> dns browse _test._udp.default.service.arpa. esp32h2> ot dns browse _test._udp.default.service.arpa.
DNS browse response for _test._udp.default.service.arpa. DNS browse response for _test._udp.default.service.arpa.
testhost testhost
Port:5683, Priority:0, Weight:0, TTL:120 Port:5683, Priority:0, Weight:0, TTL:120
@@ -266,7 +266,7 @@ testhost
TXT:[test=31, dn=616162626262] TTL:120 TXT:[test=31, dn=616162626262] TTL:120
Done Done
> dns service testhost _test._udp.default.service.arpa. esp32h2> ot dns service testhost _test._udp.default.service.arpa.
DNS service resolution response for testhost for service _test._udp.default.service.arpa. DNS service resolution response for testhost for service _test._udp.default.service.arpa.
Port:5683, Priority:0, Weight:0, TTL:120 Port:5683, Priority:0, Weight:0, TTL:120
Host:FA001208.default.service.arpa. Host:FA001208.default.service.arpa.

View File

@@ -1,13 +1,5 @@
menu "OpenThread Border Router Example" menu "OpenThread Border Router Example"
config OPENTHREAD_BR_AUTO_START
bool 'Enable the automatic start mode in Thread Border Router.'
default n
help
If enabled, The Thread Border Router will connect to Wi-Fi with pre-configured
SSID and PSK, and then form a Thread network automatically. Otherwise, user need
to configure Wi-Fi and Thread manually.
config OPENTHREAD_SUPPORT_HW_RESET_RCP config OPENTHREAD_SUPPORT_HW_RESET_RCP
bool 'Enable hardware RCP resetting' bool 'Enable hardware RCP resetting'
default n default n
@@ -20,33 +12,4 @@ menu "OpenThread Border Router Example"
depends on OPENTHREAD_SUPPORT_HW_RESET_RCP depends on OPENTHREAD_SUPPORT_HW_RESET_RCP
default 7 default 7
menu "External coexist wire type and pin config"
config EXTERNAL_COEX_WIRE_TYPE
int "The wire_type of external coexist"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE
default 3
range 0 3
help
Select wire_type for external coexist, the wire_type define in external_coex_wire_t.
config EXTERNAL_COEX_REQUEST_PIN
int "The number of external coexist request pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE >= 0)
default 0
config EXTERNAL_COEX_GRANT_PIN
int "The number of external coexist grant pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE >= 1)
default 1
config EXTERNAL_COEX_PRIORITY_PIN
int "The number of external coexist priority pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE >= 2)
default 2
config EXTERNAL_COEX_TX_LINE_PIN
int "The number of external coexist tx_line pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE = 3)
default 3
endmenu # External coexist wire type and pin config
endmenu endmenu

View File

@@ -17,50 +17,31 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_check.h" #include "esp_check.h"
#include "esp_coexist.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_event.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_openthread.h" #include "esp_openthread.h"
#include "esp_openthread_border_router.h"
#include "esp_openthread_cli.h"
#include "esp_openthread_lock.h" #include "esp_openthread_lock.h"
#include "esp_openthread_netif_glue.h" #include "esp_openthread_netif_glue.h"
#include "esp_openthread_spinel.h"
#include "esp_openthread_types.h" #include "esp_openthread_types.h"
#if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION #if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
#include "esp_ot_cli_extension.h" #include "esp_ot_cli_extension.h"
#endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION #endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
#include "esp_ot_config.h" #include "esp_ot_config.h"
#include "esp_ot_wifi_cmd.h"
#include "esp_vfs_dev.h" #include "esp_vfs_dev.h"
#include "esp_vfs_eventfd.h" #include "esp_vfs_eventfd.h"
#include "esp_wifi.h"
#include "mdns.h" #include "mdns.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "protocol_examples_common.h" #include "ot_examples_br.h"
#include "driver/gpio.h" #include "ot_examples_common.h"
#include "driver/uart.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "hal/uart_types.h"
#include "openthread/error.h"
#include "openthread/logging.h"
#include "openthread/tasklet.h"
#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE #if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE
#include "ot_led_strip.h" #include "ot_led_strip.h"
#endif #endif
#if CONFIG_OPENTHREAD_BR_AUTO_START
#include "example_common_private.h"
#include "protocol_examples_common.h"
#endif
#if !CONFIG_OPENTHREAD_BR_AUTO_START && CONFIG_EXAMPLE_CONNECT_ETHERNET
// TZ-1109: Add a menchanism for connecting ETH manually.
#error Currently we do not support a manual way to connect ETH, if you want to use ETH, please enable OPENTHREAD_BR_AUTO_START.
#endif
#define TAG "esp_ot_br" #define TAG "esp_ot_br"
#if CONFIG_OPENTHREAD_SUPPORT_HW_RESET_RCP #if CONFIG_OPENTHREAD_SUPPORT_HW_RESET_RCP
@@ -83,116 +64,6 @@ static void rcp_failure_hardware_reset_handler(void)
} }
#endif #endif
#if CONFIG_EXTERNAL_COEX_ENABLE
static void ot_br_external_coexist_init(void)
{
esp_external_coex_gpio_set_t gpio_pin = ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG();
esp_external_coex_set_work_mode(EXTERNAL_COEX_LEADER_ROLE);
ESP_ERROR_CHECK(esp_enable_extern_coex_gpio_pin(CONFIG_EXTERNAL_COEX_WIRE_TYPE, gpio_pin));
}
#endif /* CONFIG_EXTERNAL_COEX_ENABLE */
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(),
};
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD();
esp_netif_t *openthread_netif = esp_netif_new(&cfg);
assert(openthread_netif != NULL);
// Initialize the OpenThread stack
ESP_ERROR_CHECK(esp_openthread_init(&config));
ESP_ERROR_CHECK(esp_netif_attach(openthread_netif, esp_openthread_netif_glue_init(&config)));
esp_openthread_lock_acquire(portMAX_DELAY);
#if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC
// The OpenThread log level directly matches ESP log level
(void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL);
#endif // CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_init();
#if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
esp_cli_custom_command_init();
#endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
esp_openthread_cli_create_task();
#endif // CONFIG_OPENTHREAD_CLI
esp_openthread_lock_release();
// Run the main loop
esp_openthread_launch_mainloop();
// Clean up
esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
esp_vfs_eventfd_unregister();
vTaskDelete(NULL);
}
void ot_br_init(void *ctx)
{
#if CONFIG_OPENTHREAD_CLI_WIFI
ESP_ERROR_CHECK(esp_ot_wifi_config_init());
#endif
#if CONFIG_OPENTHREAD_BR_AUTO_START
#if CONFIG_EXAMPLE_CONNECT_WIFI || CONFIG_EXAMPLE_CONNECT_ETHERNET
bool wifi_or_ethernet_connected = false;
#else
#error No backbone netif!
#endif
#if CONFIG_EXAMPLE_CONNECT_WIFI
char wifi_ssid[32] = "";
char wifi_password[64] = "";
if (esp_ot_wifi_config_get_ssid(wifi_ssid) == ESP_OK) {
ESP_LOGI(TAG, "use the Wi-Fi config from NVS");
esp_ot_wifi_config_get_password(wifi_password);
} else {
ESP_LOGI(TAG, "use the Wi-Fi config from Kconfig");
strcpy(wifi_ssid, CONFIG_EXAMPLE_WIFI_SSID);
strcpy(wifi_password, CONFIG_EXAMPLE_WIFI_PASSWORD);
}
if (esp_ot_wifi_connect(wifi_ssid, wifi_password) == ESP_OK) {
wifi_or_ethernet_connected = true;
} else {
ESP_LOGE(TAG, "Fail to connect to Wi-Fi, please try again manually");
}
#endif
#if CONFIG_EXAMPLE_CONNECT_ETHERNET
ESP_ERROR_CHECK(example_ethernet_connect());
wifi_or_ethernet_connected = true;
#endif
#endif // CONFIG_OPENTHREAD_BR_AUTO_START
#if CONFIG_EXTERNAL_COEX_ENABLE
ot_br_external_coexist_init();
#endif // CONFIG_EXTERNAL_COEX_ENABLE
ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set("esp-ot-br"));
esp_openthread_lock_acquire(portMAX_DELAY);
#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE
ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance()));
#endif
#if CONFIG_OPENTHREAD_BR_AUTO_START
if (wifi_or_ethernet_connected) {
esp_openthread_set_backbone_netif(get_example_netif());
ESP_ERROR_CHECK(esp_openthread_border_router_init());
#if CONFIG_EXAMPLE_CONNECT_WIFI
esp_ot_wifi_border_router_init_flag_set(true);
#endif
otOperationalDatasetTlvs dataset;
otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset);
ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL));
} else {
ESP_LOGE(TAG, "Auto-start mode failed, please try to start manually");
}
#endif // CONFIG_OPENTHREAD_BR_AUTO_START
esp_openthread_lock_release();
vTaskDelete(NULL);
}
void app_main(void) void app_main(void)
{ {
// Used eventfds: // Used eventfds:
@@ -218,9 +89,38 @@ void app_main(void)
ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set("esp-ot-br"));
#if CONFIG_OPENTHREAD_SUPPORT_HW_RESET_RCP #if CONFIG_OPENTHREAD_SUPPORT_HW_RESET_RCP
esp_openthread_register_rcp_failure_handler(rcp_failure_hardware_reset_handler); esp_openthread_register_rcp_failure_handler(rcp_failure_hardware_reset_handler);
#endif #endif
xTaskCreate(ot_task_worker, "ot_br_main", 8192, xTaskGetCurrentTaskHandle(), 5, NULL);
xTaskCreate(ot_br_init, "ot_br_init", 6144, NULL, 4, NULL); #if CONFIG_OPENTHREAD_CLI
ot_console_start();
#endif
#if CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE
ot_external_coexist_init();
#endif
static 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(),
};
ESP_ERROR_CHECK(esp_openthread_start(&config));
esp_netif_set_default_netif(esp_openthread_get_netif());
#if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
esp_cli_custom_command_init();
#endif
#if CONFIG_OPENTHREAD_BORDER_ROUTER_AUTO_START
ESP_ERROR_CHECK(esp_openthread_border_router_start());
#if CONFIG_ESP_COEX_SW_COEXIST_ENABLE && CONFIG_SOC_IEEE802154_SUPPORTED
ESP_ERROR_CHECK(esp_coex_wifi_i154_enable());
#endif
#endif
#if CONFIG_OPENTHREAD_NETWORK_AUTO_START
ot_network_auto_start();
#endif
} }

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: CC0-1.0 * SPDX-License-Identifier: CC0-1.0
* *
@@ -68,39 +68,10 @@
} }
#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART OR CONFIG_OPENTHREAD_RADIO_SPINEL_SPI #endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART OR CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
#if CONFIG_IDF_TARGET_ESP32C2 && CONFIG_XTAL_FREQ_26
#define HOST_BAUD_RATE 74880
#else
#define HOST_BAUD_RATE 115200
#endif
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_UART
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_UART, \
.host_uart_config = { \
.port = 0, \
.uart_config = \
{ \
.baud_rate = HOST_BAUD_RATE, \
.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, \
}, \
}
#elif CONFIG_OPENTHREAD_CONSOLE_TYPE_USB_SERIAL_JTAG
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \ { \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_USB, \ .host_connection_mode = HOST_CONNECTION_MODE_NONE, \
.host_usb_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(), \
} }
#endif
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
{ \ { \
@@ -108,33 +79,3 @@
.netif_queue_size = 10, \ .netif_queue_size = 10, \
.task_queue_size = 10, \ .task_queue_size = 10, \
} }
#if CONFIG_EXTERNAL_COEX_ENABLE
#if CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_1
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
}
#elif CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_2
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
.grant = CONFIG_EXTERNAL_COEX_GRANT_PIN, \
}
#elif CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_3
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
.priority = CONFIG_EXTERNAL_COEX_PRIORITY_PIN, \
.grant = CONFIG_EXTERNAL_COEX_GRANT_PIN, \
}
#elif CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_4
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
.priority = CONFIG_EXTERNAL_COEX_PRIORITY_PIN, \
.grant = CONFIG_EXTERNAL_COEX_GRANT_PIN, \
.tx_line = CONFIG_EXTERNAL_COEX_TX_LINE_PIN, \
}
#endif
#endif // CONFIG_EXTERNAL_COEX_ENABLE

View File

@@ -1,7 +1,7 @@
## IDF Component Manager Manifest File ## IDF Component Manager Manifest File
dependencies: dependencies:
espressif/esp_ot_cli_extension: espressif/esp_ot_cli_extension:
version: "~1.3.0" version: "~1.4.0"
espressif/mdns: "^1.0.3" espressif/mdns: "^1.0.3"
## Required IDF version ## Required IDF version
idf: idf:
@@ -10,3 +10,7 @@ dependencies:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common path: ${IDF_PATH}/examples/common_components/protocol_examples_common
ot_led: ot_led:
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led
ot_examples_br:
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_examples_br
ot_examples_common:
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_examples_common

View File

@@ -1,2 +1,2 @@
CONFIG_EXTERNAL_COEX_ENABLE=y CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE=y
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=n CONFIG_ESP_COEX_SW_COEXIST_ENABLE=n

View File

@@ -1,2 +1,2 @@
CONFIG_OPENTHREAD_RADIO_TREL=y CONFIG_OPENTHREAD_RADIO_TREL=y
CONFIG_EXTERNAL_COEX_ENABLE=y CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE=y

View File

@@ -25,6 +25,8 @@ CONFIG_MBEDTLS_ECJPAKE_C=y
CONFIG_OPENTHREAD_ENABLED=y CONFIG_OPENTHREAD_ENABLED=y
CONFIG_OPENTHREAD_BORDER_ROUTER=y CONFIG_OPENTHREAD_BORDER_ROUTER=y
CONFIG_OPENTHREAD_RADIO_SPINEL_UART=y CONFIG_OPENTHREAD_RADIO_SPINEL_UART=y
CONFIG_OPENTHREAD_TASK_SIZE=8192
CONFIG_OPENTHREAD_CONSOLE_ENABLE=n
# end of OpenThread # end of OpenThread
# #
@@ -54,4 +56,5 @@ CONFIG_EXAMPLE_CONNECT_THREAD=n
# ESP System Settings # ESP System Settings
# #
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3584 CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3584
CONFIG_ESP_MAIN_TASK_STACK_SIZE=6144
# end of ESP System Settings # end of ESP System Settings

View File

@@ -1,5 +1,6 @@
# Enable BR auto start for Ethernet builds # Enable BR auto start for Ethernet builds
CONFIG_OPENTHREAD_BR_AUTO_START=y CONFIG_OPENTHREAD_NETWORK_AUTO_START=y
CONFIG_OPENTHREAD_BORDER_ROUTER_AUTO_START=y
# Enable PPP support as a workaround to ensure LWIP thread-lib compatibility for Ethernet builds # Enable PPP support as a workaround to ensure LWIP thread-lib compatibility for Ethernet builds
CONFIG_LWIP_PPP_SUPPORT=y CONFIG_LWIP_PPP_SUPPORT=y

View File

@@ -8,9 +8,8 @@ import socket
import struct import struct
import subprocess import subprocess
import time import time
from collections.abc import Callable
from functools import wraps from functools import wraps
from typing import Callable
from typing import Tuple
import netifaces import netifaces
import pexpect import pexpect
@@ -133,7 +132,7 @@ def wait_for_join(dut: IdfDut, role: str) -> bool:
return False return False
def joinWiFiNetwork(dut: IdfDut, wifi: wifi_parameter) -> Tuple[str, int]: def joinWiFiNetwork(dut: IdfDut, wifi: wifi_parameter) -> tuple[str, int]:
clean_buffer(dut) clean_buffer(dut)
ip_address = '' ip_address = ''
for order in range(1, wifi.retry_times): for order in range(1, wifi.retry_times):
@@ -168,7 +167,7 @@ def getDataset(dut: IdfDut) -> str:
def init_thread(dut: IdfDut) -> None: def init_thread(dut: IdfDut) -> None:
dut.expect('>', timeout=10) dut.expect('OpenThread attached to netif', timeout=10)
wait(dut, 3) wait(dut, 3)
reset_thread(dut) reset_thread(dut)
@@ -176,7 +175,6 @@ def init_thread(dut: IdfDut) -> None:
def reset_thread(dut: IdfDut) -> None: def reset_thread(dut: IdfDut) -> None:
execute_command(dut, 'factoryreset') execute_command(dut, 'factoryreset')
dut.expect('OpenThread attached to netif', timeout=20) dut.expect('OpenThread attached to netif', timeout=20)
dut.expect('>', timeout=10)
wait(dut, 3) wait(dut, 3)
clean_buffer(dut) clean_buffer(dut)
@@ -186,7 +184,7 @@ def get_mleid_addr(dut: IdfDut) -> str:
dut_adress = '' dut_adress = ''
execute_command(dut, 'ipaddr mleid') execute_command(dut, 'ipaddr mleid')
dut_adress = dut.expect(r'\n((?:\w+:){7}\w+)\r', timeout=5)[1].decode() dut_adress = dut.expect(r'\n((?:\w+:){7}\w+)\r', timeout=5)[1].decode()
return dut_adress return str(dut_adress)
# get the rloc address of the thread # get the rloc address of the thread
@@ -194,7 +192,7 @@ def get_rloc_addr(dut: IdfDut) -> str:
dut_adress = '' dut_adress = ''
execute_command(dut, 'ipaddr rloc') execute_command(dut, 'ipaddr rloc')
dut_adress = dut.expect(r'\n((?:\w+:){7}\w+)\r', timeout=5)[1].decode() dut_adress = dut.expect(r'\n((?:\w+:){7}\w+)\r', timeout=5)[1].decode()
return dut_adress return str(dut_adress)
# get the linklocal address of the thread # get the linklocal address of the thread
@@ -202,7 +200,7 @@ def get_linklocal_addr(dut: IdfDut) -> str:
dut_adress = '' dut_adress = ''
execute_command(dut, 'ipaddr linklocal') execute_command(dut, 'ipaddr linklocal')
dut_adress = dut.expect(r'\n((?:\w+:){7}\w+)\r', timeout=5)[1].decode() dut_adress = dut.expect(r'\n((?:\w+:){7}\w+)\r', timeout=5)[1].decode()
return dut_adress return str(dut_adress)
# get the global unicast address of the thread: # get the global unicast address of the thread:
@@ -211,8 +209,8 @@ def get_global_unicast_addr(dut: IdfDut, br: IdfDut) -> str:
clean_buffer(br) clean_buffer(br)
omrprefix = get_omrprefix(br) omrprefix = get_omrprefix(br)
execute_command(dut, 'ipaddr') execute_command(dut, 'ipaddr')
dut_adress = dut.expect(r'(%s(?:\w+:){3}\w+)\r' % str(omrprefix), timeout=5)[1].decode() dut_adress = dut.expect(rf'({omrprefix}(?:\w+:){{3}}\w+)\r', timeout=5)[1].decode()
return dut_adress return str(dut_adress)
@extract_address('rloc16', r'(\w{4})') @extract_address('rloc16', r'(\w{4})')
@@ -223,7 +221,7 @@ def get_rloc16_addr(rloc16: str) -> str:
# ping of thread # ping of thread
def ot_ping( def ot_ping(
dut: IdfDut, target: str, timeout: int = 5, count: int = 1, size: int = 56, interval: int = 1, hoplimit: int = 64 dut: IdfDut, target: str, timeout: int = 5, count: int = 1, size: int = 56, interval: int = 1, hoplimit: int = 64
) -> Tuple[int, int]: ) -> tuple[int, int]:
command = f'ping {str(target)} {size} {count} {interval} {hoplimit} {str(timeout)}' command = f'ping {str(target)} {size} {count} {interval} {hoplimit} {str(timeout)}'
execute_command(dut, command) execute_command(dut, command)
transmitted = dut.expect(r'(\d+) packets transmitted', timeout=60)[1].decode() transmitted = dut.expect(r'(\d+) packets transmitted', timeout=60)[1].decode()
@@ -307,7 +305,7 @@ def get_host_interface_name() -> str:
config_path = os.path.join(home_dir, 'config', 'env_config.yml') config_path = os.path.join(home_dir, 'config', 'env_config.yml')
try: try:
if os.path.exists(config_path): if os.path.exists(config_path):
with open(config_path, 'r') as file: with open(config_path) as file:
config = yaml.safe_load(file) config = yaml.safe_load(file)
interface_name = config.get('interface_name') interface_name = config.get('interface_name')
if interface_name: if interface_name:
@@ -331,7 +329,7 @@ def get_host_interface_name() -> str:
def clean_buffer(dut: IdfDut) -> None: def clean_buffer(dut: IdfDut) -> None:
str_length = str(len(dut.expect(pexpect.TIMEOUT, timeout=0.1))) str_length = str(len(dut.expect(pexpect.TIMEOUT, timeout=0.1)))
dut.expect(r'[\s\S]{%s}' % str(str_length), timeout=10) dut.expect(rf'[\s\S]{{{str_length}}}', timeout=10)
def check_if_host_receive_ra(br: IdfDut) -> bool: def check_if_host_receive_ra(br: IdfDut) -> bool:
@@ -422,7 +420,7 @@ def create_host_udp_server(myudp: udp_parameter) -> None:
print('The host start to receive message!') print('The host start to receive message!')
myudp.udp_bytes = (sock.recvfrom(1024))[0] myudp.udp_bytes = (sock.recvfrom(1024))[0]
print('The host has received message: ', myudp.udp_bytes) print('The host has received message: ', myudp.udp_bytes)
except socket.error: except OSError:
print('The host did not receive message!') print('The host did not receive message!')
finally: finally:
print('Close the socket.') print('Close the socket.')
@@ -442,7 +440,7 @@ def host_udp_send_message(udp_target: udp_parameter) -> None:
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, 32) sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, 32)
print('Host is sending message') print('Host is sending message')
sock.sendto(udp_target.udp_bytes, (udp_target.addr, udp_target.port)) sock.sendto(udp_target.udp_bytes, (udp_target.addr, udp_target.port))
except socket.error: except OSError:
print('Host cannot send message') print('Host cannot send message')
finally: finally:
sock.close() sock.close()
@@ -459,7 +457,7 @@ def get_host_ipv4_address() -> str:
out_str = out_bytes.decode('utf-8') out_str = out_bytes.decode('utf-8')
host_ipv4_address = '' host_ipv4_address = ''
host_ipv4_address = re.findall(r'((?:\d+.){3}\d+)', str(out_str))[0] host_ipv4_address = re.findall(r'((?:\d+.){3}\d+)', str(out_str))[0]
return host_ipv4_address return str(host_ipv4_address)
def restart_avahi() -> None: def restart_avahi() -> None:
@@ -592,7 +590,7 @@ def create_host_tcp_server(mytcp: tcp_parameter) -> None:
mytcp.tcp_bytes = connfd.recv(1024) mytcp.tcp_bytes = connfd.recv(1024)
print('The tcp server has received message: ', mytcp.tcp_bytes) print('The tcp server has received message: ', mytcp.tcp_bytes)
except socket.error: except OSError:
if mytcp.recv_flag: if mytcp.recv_flag:
print('The tcp server did not receive message!') print('The tcp server did not receive message!')
else: else:
@@ -636,9 +634,9 @@ def get_nat64prefix(br: IdfDut) -> str:
return str(nat64prefix) return str(nat64prefix)
def execute_command(dut: IdfDut, command: str) -> None: def execute_command(dut: IdfDut, command: str, prefix: str = 'ot ') -> None:
clean_buffer(dut) clean_buffer(dut)
dut.write(command) dut.write(prefix + command)
def get_ouput_string(dut: IdfDut, command: str, wait_time: int) -> str: def get_ouput_string(dut: IdfDut, command: str, wait_time: int) -> str:

View File

@@ -37,7 +37,7 @@ Now you'll get an OpenThread command line shell.
The `help` command will print all of the supported commands. The `help` command will print all of the supported commands.
```bash ```bash
> help esp32h2> ot help
I(7058) OPENTHREAD:[INFO]-CLI-----: execute command: help I(7058) OPENTHREAD:[INFO]-CLI-----: execute command: help
bbr bbr
bufferinfo bufferinfo
@@ -71,51 +71,51 @@ To run this example, at least two ESP32-H2 boards flashed with this ot_cli examp
On the first device, run the following commands: On the first device, run the following commands:
```bash ```bash
> factoryreset esp32h2> ot factoryreset
... # the device will reboot ... # the device will reboot
> dataset init new esp32h2> ot dataset init new
Done Done
> dataset commit active esp32h2> ot dataset commit active
Done Done
> ifconfig up esp32h2> ot ifconfig up
Done Done
> thread start esp32h2> ot thread start
Done Done
# After some seconds # After some seconds
> state esp32h2> ot state
leader leader
Done Done
``` ```
Now the first device has formed a Thread network as a leader. Get some information which will be used in next steps: Now the first device has formed a Thread network as a leader. Get some information which will be used in next steps:
```bash ```bash
> ipaddr esp32h2> ot ipaddr
fdde:ad00:beef:0:0:ff:fe00:fc00 fdde:ad00:beef:0:0:ff:fe00:fc00
fdde:ad00:beef:0:0:ff:fe00:8000 fdde:ad00:beef:0:0:ff:fe00:8000
fdde:ad00:beef:0:a7c6:6311:9c8c:271b fdde:ad00:beef:0:a7c6:6311:9c8c:271b
fe80:0:0:0:5c27:a723:7115:c8f8 fe80:0:0:0:5c27:a723:7115:c8f8
# Get the Active Dataset # Get the Active Dataset
> dataset active -x esp32h2> ot dataset active -x
0e080000000000010000000300001835060004001fffe00208fe7bb701f5f1125d0708fd75cbde7c6647bd0510b3914792d44f45b6c7d76eb9306eec94030f4f70656e5468726561642d35383332010258320410e35c581af5029b054fc904a24c2b27700c0402a0fff8 0e080000000000010000000300001835060004001fffe00208fe7bb701f5f1125d0708fd75cbde7c6647bd0510b3914792d44f45b6c7d76eb9306eec94030f4f70656e5468726561642d35383332010258320410e35c581af5029b054fc904a24c2b27700c0402a0fff8
``` ```
On the second device, set the active dataset from leader, and start Thread interface: On the second device, set the active dataset from leader, and start Thread interface:
```bash ```bash
> factoryreset esp32h2> ot factoryreset
... # the device will reboot ... # the device will reboot
> dataset set active 0e080000000000010000000300001835060004001fffe00208fe7bb701f5f1125d0708fd75cbde7c6647bd0510b3914792d44f45b6c7d76eb9306eec94030f4f70656e5468726561642d35383332010258320410e35c581af5029b054fc904a24c2b27700c0402a0fff8 esp32h2> ot dataset set active 0e080000000000010000000300001835060004001fffe00208fe7bb701f5f1125d0708fd75cbde7c6647bd0510b3914792d44f45b6c7d76eb9306eec94030f4f70656e5468726561642d35383332010258320410e35c581af5029b054fc904a24c2b27700c0402a0fff8
> ifconfig up esp32h2> ot ifconfig up
Done Done
> thread start esp32h2> ot thread start
Done Done
# After some seconds # After some seconds
> state esp32h2> ot state
router # child is also a valid state router # child is also a valid state
Done Done
``` ```

View File

@@ -1,9 +0,0 @@
menu "OpenThread CLI Example"
config OPENTHREAD_AUTO_START
bool 'Enable the automatic start mode.'
default n
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

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: CC0-1.0 * SPDX-License-Identifier: CC0-1.0
* *
@@ -23,21 +23,12 @@
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_netif_types.h" #include "esp_netif_types.h"
#include "esp_openthread.h" #include "esp_openthread.h"
#include "esp_openthread_cli.h"
#include "esp_openthread_lock.h" #include "esp_openthread_lock.h"
#include "esp_openthread_netif_glue.h"
#include "esp_openthread_types.h" #include "esp_openthread_types.h"
#include "esp_ot_config.h" #include "esp_ot_config.h"
#include "esp_vfs_eventfd.h" #include "esp_vfs_eventfd.h"
#include "driver/uart.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "hal/uart_types.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "openthread/cli.h" #include "ot_examples_common.h"
#include "openthread/instance.h"
#include "openthread/logging.h"
#include "openthread/tasklet.h"
#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE #if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE
#include "ot_led_strip.h" #include "ot_led_strip.h"
@@ -49,68 +40,6 @@
#define TAG "ot_esp_cli" #define TAG "ot_esp_cli"
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_STATE_INDICATOR_ENABLE
ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance()));
#endif
#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_CLI_ESP_EXTENSION
esp_cli_custom_command_init();
#endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
// Run the main loop
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_create_task();
#endif
#if CONFIG_OPENTHREAD_AUTO_START
otOperationalDatasetTlvs dataset;
otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset);
ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL));
#endif
esp_openthread_launch_mainloop();
// Clean up
esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
esp_vfs_eventfd_unregister();
vTaskDelete(NULL);
}
void app_main(void) void app_main(void)
{ {
// Used eventfds: // Used eventfds:
@@ -125,5 +54,22 @@ void app_main(void)
ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_loop_create_default());
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));
xTaskCreate(ot_task_worker, "ot_cli_main", 10240, xTaskGetCurrentTaskHandle(), 5, NULL);
#if CONFIG_OPENTHREAD_CLI
ot_console_start();
#endif
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(),
};
ESP_ERROR_CHECK(esp_openthread_start(&config));
#if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
esp_cli_custom_command_init();
#endif
#if CONFIG_OPENTHREAD_NETWORK_AUTO_START
ot_network_auto_start();
#endif
} }

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: CC0-1.0 * SPDX-License-Identifier: CC0-1.0
* *
@@ -44,33 +44,10 @@
} }
#endif #endif
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_UART
#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, \
}, \
}
#elif CONFIG_OPENTHREAD_CONSOLE_TYPE_USB_SERIAL_JTAG
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \ { \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_USB, \ .host_connection_mode = HOST_CONNECTION_MODE_NONE, \
.host_usb_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(), \
} }
#endif
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
{ \ { \

View File

@@ -1,8 +1,10 @@
## IDF Component Manager Manifest File ## IDF Component Manager Manifest File
dependencies: dependencies:
espressif/esp_ot_cli_extension: espressif/esp_ot_cli_extension:
version: "~1.2.0" version: "~1.4.0"
idf: idf:
version: ">=4.1.0" version: ">=4.1.0"
ot_led: ot_led:
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led
ot_examples_common:
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_examples_common

View File

@@ -1 +1 @@
CONFIG_EXTERNAL_COEX_ENABLE=y CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE=y

View File

@@ -23,6 +23,8 @@ 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_TASK_SIZE=10240
CONFIG_OPENTHREAD_CONSOLE_ENABLE=n
# end of OpenThread # end of OpenThread
# #
@@ -33,3 +35,9 @@ CONFIG_LWIP_IPV6_NUM_ADDRESSES=8
CONFIG_LWIP_MULTICAST_PING=y CONFIG_LWIP_MULTICAST_PING=y
CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM=y CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM=y
# end of lwIP # end of lwIP
#
# ESP System Settings
#
CONFIG_ESP_MAIN_TASK_STACK_SIZE=6144
# end of ESP System Settings

View File

@@ -0,0 +1,9 @@
set(srcs "")
if(CONFIG_OPENTHREAD_BORDER_ROUTER_AUTO_START)
list(APPEND srcs "ot_examples_br.c")
endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
PRIV_REQUIRES openthread protocol_examples_common)

View File

@@ -0,0 +1,12 @@
menu "OpenThread Border Router Config"
depends on OPENTHREAD_BORDER_ROUTER
config OPENTHREAD_BORDER_ROUTER_AUTO_START
depends on OPENTHREAD_BORDER_ROUTER
bool 'Enable the border router auto start'
default n
help
If enabled, the program will automatically connect to the backbone network and
initialize the border router at startup.
endmenu

View File

@@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2025 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 "esp_err.h"
#include "esp_openthread.h"
/**
* @brief Start the border router features of OpenThread.
*
* @note Calling this function will make the device connect to the Wi-Fi or Ethernet,
* and initialize the border router feature.
*
* @return
* - ESP_OK on success.
* - ESP_FAIL on failure.
*
*/
esp_err_t esp_openthread_border_router_start(void);
/**
* @brief Stop the border router features of OpenThread.
*
* @note Calling this function will make the device deinitialize the border router feature.
*
*/
void esp_openthread_border_router_stop(void);

View File

@@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2025 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 "ot_examples_br.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_openthread.h"
#include "esp_openthread_lock.h"
#include "esp_openthread_border_router.h"
#include "protocol_examples_common.h"
#define TAG "ot_examples_br"
#if CONFIG_OPENTHREAD_CLI_WIFI
#error "CONFIG_OPENTHREAD_CLI_WIFI conflicts with the border router auto-initialization feature"
#endif
static bool s_border_router_started = false;
static void ot_br_init(void *ctx)
{
ESP_ERROR_CHECK(example_connect());
esp_openthread_lock_acquire(portMAX_DELAY);
esp_openthread_set_backbone_netif(get_example_netif());
ESP_ERROR_CHECK(esp_openthread_border_router_init());
esp_openthread_lock_release();
s_border_router_started = true;
vTaskDelete(NULL);
}
esp_err_t esp_openthread_border_router_start(void)
{
return (xTaskCreate(ot_br_init, "ot_br_init", 6144, NULL, 4, NULL) == pdPASS) ? ESP_OK : ESP_FAIL;
}
void esp_openthread_border_router_stop(void)
{
if (s_border_router_started) {
esp_openthread_lock_acquire(portMAX_DELAY);
ESP_ERROR_CHECK(esp_openthread_border_router_deinit());
esp_openthread_lock_release();
s_border_router_started =false;
}
}

View File

@@ -0,0 +1,19 @@
set(srcs "")
if(CONFIG_OPENTHREAD_FTD OR CONFIG_OPENTHREAD_MTD)
list(APPEND srcs "ot_network.c")
endif()
if(CONFIG_OPENTHREAD_CLI)
list(APPEND srcs "ot_console.c")
endif()
if(CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE)
list(APPEND srcs "ot_external_coexist.c")
endif()
idf_component_register(
SRCS "${srcs}"
INCLUDE_DIRS "include"
PRIV_REQUIRES console cmd_system esp_coex openthread
)

View File

@@ -0,0 +1,67 @@
menu "Config for OpenThread Examples"
depends on OPENTHREAD_ENABLED
config OPENTHREAD_NETWORK_AUTO_START
bool 'Enable the automatic start mode of Thread network.'
depends on OPENTHREAD_FTD || OPENTHREAD_MTD
default n
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.
menu "External coexist wire type and pin config"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE
choice EXTERNAL_COEX_WORK_MODE
prompt "The work mode of external coexist"
default EXTERNAL_COEX_WORK_MODE_FOLLOWER if SOC_IEEE802154_SUPPORTED
default EXTERNAL_COEX_WORK_MODE_LEADER if !SOC_IEEE802154_SUPPORTED && SOC_WIFI_SUPPORTED
help
Select work mode for external coexist, the work mode defined in esp_extern_coex_work_mode_t.
config EXTERNAL_COEX_WORK_MODE_LEADER
bool "Leader mode"
help
Select this to set the external coexistence work mode to leader mode.
config EXTERNAL_COEX_WORK_MODE_FOLLOWER
bool "Follower mode"
help
Select this to set the external coexistence work mode to follower mode.
config EXTERNAL_COEX_WORK_MODE_UNKNOWN
bool "Unknown mode"
help
Select this to set the external coexistence work mode to unknown mode.
endchoice
config EXTERNAL_COEX_WIRE_TYPE
int "The wire_type of external coexist"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE
default 3
range 0 3
help
Select wire_type for external coexist, the wire_type define in external_coex_wire_t.
config EXTERNAL_COEX_REQUEST_PIN
int "The number of external coexist request pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE >= 0)
default 0
config EXTERNAL_COEX_GRANT_PIN
int "The number of external coexist grant pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE >= 1)
default 1
config EXTERNAL_COEX_PRIORITY_PIN
int "The number of external coexist priority pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE >= 2)
default 2
config EXTERNAL_COEX_TX_LINE_PIN
int "The number of external coexist tx_line pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE = 3)
default 3
endmenu # External coexist wire type and pin config
endmenu

View File

@@ -0,0 +1,4 @@
## IDF Component Manager Manifest File
dependencies:
cmd_system:
path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system

View File

@@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2025 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 "sdkconfig.h"
#if CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE
#if CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_1
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
}
#elif CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_2
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
.grant = CONFIG_EXTERNAL_COEX_GRANT_PIN, \
}
#elif CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_3
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
.priority = CONFIG_EXTERNAL_COEX_PRIORITY_PIN, \
.grant = CONFIG_EXTERNAL_COEX_GRANT_PIN, \
}
#elif CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_4
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
.priority = CONFIG_EXTERNAL_COEX_PRIORITY_PIN, \
.grant = CONFIG_EXTERNAL_COEX_GRANT_PIN, \
.tx_line = CONFIG_EXTERNAL_COEX_TX_LINE_PIN, \
}
#endif
#endif // CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE
/**
* @brief Initializes the external coexistence.
*
*/
void ot_external_coexist_init(void);
/**
* @brief Initializes the console.
*
*/
void ot_console_start(void);
/**
* @brief Form or join the Thread network automatically.
*
*/
void ot_network_auto_start(void);

View File

@@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: 2025 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 "ot_examples_common.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_console.h"
#include "cmd_system.h"
void ot_console_start(void)
{
esp_console_repl_t *repl = NULL;
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
repl_config.prompt = CONFIG_IDF_TARGET ">";
repl_config.max_cmdline_length = 256;
repl_config.max_history_len = 10;
#if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) || defined(CONFIG_ESP_CONSOLE_UART_CUSTOM)
esp_console_dev_uart_config_t hw_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_console_new_repl_uart(&hw_config, &repl_config, &repl));
#elif defined(CONFIG_ESP_CONSOLE_USB_CDC)
esp_console_dev_usb_cdc_config_t hw_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&hw_config, &repl_config, &repl));
#elif defined(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG)
esp_console_dev_usb_serial_jtag_config_t hw_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&hw_config, &repl_config, &repl));
#else
#error Unsupported console type
#endif
ESP_ERROR_CHECK(esp_console_start_repl(repl));
register_system();
}

View File

@@ -0,0 +1,35 @@
/*
* SPDX-FileCopyrightText: 2025 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 "sdkconfig.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_coexist.h"
#include "ot_examples_common.h"
void ot_external_coexist_init(void)
{
esp_extern_coex_work_mode_t mode =
#if CONFIG_EXTERNAL_COEX_WORK_MODE_LEADER
EXTERNAL_COEX_LEADER_ROLE;
#elif CONFIG_EXTERNAL_COEX_WORK_MODE_FOLLOWER
EXTERNAL_COEX_FOLLOWER_ROLE;
#else
EXTERNAL_COEX_UNKNOWN_ROLE;
#endif
esp_external_coex_gpio_set_t gpio_pin = ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG();
ESP_ERROR_CHECK(esp_external_coex_set_work_mode(mode));
ESP_ERROR_CHECK(esp_enable_extern_coex_gpio_pin(CONFIG_EXTERNAL_COEX_WIRE_TYPE, gpio_pin));
}

View File

@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2025 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 "ot_examples_common.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_openthread.h"
#include "esp_openthread_lock.h"
void ot_network_auto_start(void)
{
otOperationalDatasetTlvs dataset;
esp_openthread_lock_acquire(portMAX_DELAY);
otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset);
ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL));
esp_openthread_lock_release();
}

View File

@@ -18,33 +18,4 @@ menu "OpenThread RCP Example"
default 5 default 5
range 0 25 range 0 25
menu "External coexist wire type and pin config"
config EXTERNAL_COEX_WIRE_TYPE
int "The wire_type of external coexist"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE
default 3
range 0 3
help
Select wire_type for external coexist, the wire_type define in external_coex_wire_t.
config EXTERNAL_COEX_REQUEST_PIN
int "The number of external coexist request pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE >= 0)
default 0
config EXTERNAL_COEX_GRANT_PIN
int "The number of external coexist grant pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE >= 1)
default 1
config EXTERNAL_COEX_PRIORITY_PIN
int "The number of external coexist priority pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE >= 2)
default 2
config EXTERNAL_COEX_TX_LINE_PIN
int "The number of external coexist tx_line pin"
depends on ESP_COEX_EXTERNAL_COEXIST_ENABLE && (EXTERNAL_COEX_WIRE_TYPE = 3)
default 3
endmenu # External coexist wire type and pin config
endmenu endmenu

View File

@@ -14,10 +14,6 @@
#pragma once #pragma once
#if CONFIG_EXTERNAL_COEX_ENABLE
#include "esp_coexist.h"
#endif
#include "esp_openthread_types.h" #include "esp_openthread_types.h"
#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \
{ \ { \
@@ -89,33 +85,3 @@
.netif_queue_size = 10, \ .netif_queue_size = 10, \
.task_queue_size = 10, \ .task_queue_size = 10, \
} }
#if CONFIG_EXTERNAL_COEX_ENABLE
#if CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_1
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
}
#elif CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_2
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
.grant = CONFIG_EXTERNAL_COEX_GRANT_PIN, \
}
#elif CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_3
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
.priority = CONFIG_EXTERNAL_COEX_PRIORITY_PIN, \
.grant = CONFIG_EXTERNAL_COEX_GRANT_PIN, \
}
#elif CONFIG_EXTERNAL_COEX_WIRE_TYPE == EXTERNAL_COEXIST_WIRE_4
#define ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG() \
{ \
.request = CONFIG_EXTERNAL_COEX_REQUEST_PIN, \
.priority = CONFIG_EXTERNAL_COEX_PRIORITY_PIN, \
.grant = CONFIG_EXTERNAL_COEX_GRANT_PIN, \
.tx_line = CONFIG_EXTERNAL_COEX_TX_LINE_PIN, \
}
#endif
#endif // CONFIG_EXTERNAL_COEX_ENABLE

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: CC0-1.0 * SPDX-License-Identifier: CC0-1.0
* *
@@ -20,10 +20,9 @@
#include "esp_openthread.h" #include "esp_openthread.h"
#include "esp_ot_config.h" #include "esp_ot_config.h"
#include "esp_vfs_eventfd.h" #include "esp_vfs_eventfd.h"
#include "driver/uart.h"
#if CONFIG_EXTERNAL_COEX_ENABLE #if CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE
#include "esp_coexist.h" #include "ot_examples_common.h"
#endif #endif
#if !SOC_IEEE802154_SUPPORTED #if !SOC_IEEE802154_SUPPORTED
@@ -34,43 +33,6 @@
extern void otAppNcpInit(otInstance *instance); extern void otAppNcpInit(otInstance *instance);
#if CONFIG_EXTERNAL_COEX_ENABLE
#if SOC_EXTERNAL_COEX_ADVANCE
static void ot_external_coexist_init(void)
{
esp_external_coex_gpio_set_t gpio_pin = ESP_OPENTHREAD_DEFAULT_EXTERNAL_COEX_CONFIG();
esp_external_coex_set_work_mode(EXTERNAL_COEX_FOLLOWER_ROLE);
ESP_ERROR_CHECK(esp_enable_extern_coex_gpio_pin(CONFIG_EXTERNAL_COEX_WIRE_TYPE, gpio_pin));
}
#endif // SOC_EXTERNAL_COEX_ADVANCE
#endif // CONFIG_EXTERNAL_COEX_ENABLE
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_EXTERNAL_COEX_ENABLE
ot_external_coexist_init();
#endif // CONFIG_EXTERNAL_COEX_ENABLE
// Initialize the OpenThread ncp
otAppNcpInit(esp_openthread_get_instance());
// Run the main loop
esp_openthread_launch_mainloop();
// Clean up
esp_vfs_eventfd_unregister();
vTaskDelete(NULL);
}
void app_main(void) void app_main(void)
{ {
// Used eventfds: // Used eventfds:
@@ -83,5 +45,16 @@ void app_main(void)
ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
xTaskCreate(ot_task_worker, "ot_rcp_main", 3072, xTaskGetCurrentTaskHandle(), 5, NULL);
#if CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE
ot_external_coexist_init();
#endif
static 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(),
};
ESP_ERROR_CHECK(esp_openthread_start(&config));
} }

View File

@@ -0,0 +1,4 @@
## IDF Component Manager Manifest File
dependencies:
ot_examples_common:
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_examples_common

View File

@@ -1,2 +1,3 @@
CONFIG_EXTERNAL_COEX_ENABLE=y CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE=y
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=n CONFIG_ESP_COEX_SW_COEXIST_ENABLE=n
CONFIG_EXTERNAL_COEX_WORK_MODE_FOLLOWER=y

View File

@@ -25,6 +25,8 @@ CONFIG_OPENTHREAD_BORDER_ROUTER=n
CONFIG_OPENTHREAD_CLI=n CONFIG_OPENTHREAD_CLI=n
CONFIG_OPENTHREAD_SRP_CLIENT=n CONFIG_OPENTHREAD_SRP_CLIENT=n
CONFIG_OPENTHREAD_DNS_CLIENT=n CONFIG_OPENTHREAD_DNS_CLIENT=n
CONFIG_OPENTHREAD_TASK_SIZE=3072
CONFIG_OPENTHREAD_CONSOLE_ENABLE=n
# end of OpenThread # end of OpenThread

View File

@@ -27,9 +27,6 @@
#include "esp_vfs_eventfd.h" #include "esp_vfs_eventfd.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "driver/rtc_io.h" #include "driver/rtc_io.h"
#include "driver/uart.h"
#include "openthread/logging.h"
#include "openthread/thread.h"
#if !SOC_IEEE802154_SUPPORTED #if !SOC_IEEE802154_SUPPORTED
#error "Openthread sleepy device 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"
@@ -60,16 +57,6 @@ static void create_config_network(otInstance *instance)
ESP_ERROR_CHECK(esp_openthread_auto_start(NULL)); ESP_ERROR_CHECK(esp_openthread_auto_start(NULL));
} }
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_state_change_callback(otChangedFlags changed_flags, void* ctx) static void ot_state_change_callback(otChangedFlags changed_flags, void* ctx)
{ {
OT_UNUSED_VARIABLE(ctx); OT_UNUSED_VARIABLE(ctx);
@@ -160,44 +147,6 @@ static void ot_deep_sleep_init(void)
ESP_ERROR_CHECK(gpio_pulldown_dis(gpio_wakeup_pin)); ESP_ERROR_CHECK(gpio_pulldown_dis(gpio_wakeup_pin));
} }
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));
ot_deep_sleep_init();
#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);
otSetStateChangedCallback(esp_openthread_get_instance(), ot_state_change_callback, NULL);
create_config_network(esp_openthread_get_instance());
// Run the main loop
esp_openthread_launch_mainloop();
// Clean up
esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
esp_vfs_eventfd_unregister();
vTaskDelete(NULL);
}
void app_main(void) void app_main(void)
{ {
// Used eventfds: // Used eventfds:
@@ -212,6 +161,16 @@ void app_main(void)
ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_loop_create_default());
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));
ot_deep_sleep_init();
xTaskCreate(ot_task_worker, "ot_power_save_main", 4096, NULL, 5, NULL); 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(),
};
ESP_ERROR_CHECK(esp_openthread_start(&config));
esp_netif_set_default_netif(esp_openthread_get_netif());
otSetStateChangedCallback(esp_openthread_get_instance(), ot_state_change_callback, NULL);
create_config_network(esp_openthread_get_instance());
} }

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: CC0-1.0 * SPDX-License-Identifier: CC0-1.0
* *
@@ -25,24 +25,9 @@
} }
#endif #endif
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \ { \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_UART, \ .host_connection_mode = HOST_CONNECTION_MODE_NONE, \
.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() \ #define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \

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_CONSOLE_ENABLE=n
# end of OpenThread # end of OpenThread
# #

View File

@@ -15,8 +15,8 @@ Set the chip target: `idf.py set-target <chip_name>`, then configure the project
There are two options to configure Openthread Dataset: 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`. * Auto start mode: Enable `OPENTHREAD_NETWORK_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. * Manual mode: Disable `OPENTHREAD_NETWORK_AUTO_START`, use the CLI command to configure the dataset and start network.
### Build and Flash ### Build and Flash
@@ -24,11 +24,11 @@ Build the project and flash it to the board. Use the following command: `idf.py
### Configure the Openthread sleepy device ### Configure the Openthread sleepy device
``` ```
> mode - esp32h2> ot mode -
> pollperiod 3000 esp32h2> ot pollperiod 3000
> dataset set active <the same as dataset of the leader> esp32h2> ot dataset set active <the same as dataset of the leader>
> ifconfig up esp32h2> ot ifconfig up
> thread start esp32h2> ot thread start
``` ```
### Example Output ### Example Output
@@ -62,23 +62,23 @@ I (652) gdma: GDMA pair (0, 0) retention initialization
I(660) OPENTHREAD:[I] ChildSupervsn-: Timeout: 0 -> 190 I(660) OPENTHREAD:[I] ChildSupervsn-: Timeout: 0 -> 190
> I (664) OPENTHREAD: OpenThread attached to netif > I (664) OPENTHREAD: OpenThread attached to netif
I (635) main_task: Returned from app_main() I (635) main_task: Returned from app_main()
> mode - esp32h2> ot mode -
I(2250683) OPENTHREAD:[N] Mle-----------: Mode 0x0f -> 0x04 [rx-on:no ftd:no full-net:no] I(2250683) OPENTHREAD:[N] Mle-----------: Mode 0x0f -> 0x04 [rx-on:no ftd:no full-net:no]
Done Done
> pollperiod 3000 esp32h2> ot pollperiod 3000
Done Done
> dataset set active 0e080000000000010000000300001a35060004001fffe00208dead00beef00cafe0708fd000db800a00000051000112233445566778899aabbccdd0000030e4f70656e5468726561642d455350010212340410104810e2315100afd6bc9215a6bfac530c0402a0f7f8 esp32h2> ot dataset set active 0e080000000000010000000300001a35060004001fffe00208dead00beef00cafe0708fd000db800a00000051000112233445566778899aabbccdd0000030e4f70656e5468726561642d455350010212340410104810e2315100afd6bc9215a6bfac530c0402a0f7f8
Done Done
> ifconfig up esp32h2> ot ifconfig up
Done Done
I (2274801) OT_STATE: netif up I (2274801) OT_STATE: netif up
> thread start esp32h2> ot thread start
I(2279917) OPENTHREAD:[N] Mle-----------: Role disabled -> detached I(2279917) OPENTHREAD:[N] Mle-----------: Role disabled -> detached
Done Done

View File

@@ -1,9 +0,0 @@
menu "OpenThread Sleepy Example"
config OPENTHREAD_AUTO_START
bool 'Enable the automatic start mode.'
default n
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

@@ -19,17 +19,15 @@
#include "esp_err.h" #include "esp_err.h"
#include "esp_event.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_netif.h"
#include "esp_openthread.h" #include "esp_openthread.h"
#include "esp_openthread_cli.h"
#include "esp_openthread_lock.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"
#include "esp_private/esp_clk.h" #include "esp_private/esp_clk.h"
#include "driver/uart.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "openthread/logging.h" #include "ot_examples_common.h"
#include "openthread/thread.h"
#if CONFIG_ESP_SLEEP_DEBUG #if CONFIG_ESP_SLEEP_DEBUG
#include "esp_private/esp_pmu.h" #include "esp_private/esp_pmu.h"
#include "esp_private/esp_sleep_internal.h" #include "esp_private/esp_sleep_internal.h"
@@ -50,7 +48,7 @@
static esp_pm_lock_handle_t s_cli_pm_lock = NULL; static esp_pm_lock_handle_t s_cli_pm_lock = NULL;
TimerHandle_t xTimer; TimerHandle_t xTimer;
#if CONFIG_OPENTHREAD_AUTO_START #if CONFIG_OPENTHREAD_NETWORK_AUTO_START
static void create_config_network(otInstance *instance) static void create_config_network(otInstance *instance)
{ {
otLinkModeConfig linkMode = { 0 }; otLinkModeConfig linkMode = { 0 };
@@ -73,7 +71,7 @@ static void create_config_network(otInstance *instance)
otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset); otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset);
ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL)); ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL));
} }
#endif // CONFIG_OPENTHREAD_AUTO_START #endif // CONFIG_OPENTHREAD_NETWORK_AUTO_START
static esp_err_t esp_openthread_sleep_device_init(void) static esp_err_t esp_openthread_sleep_device_init(void)
{ {
@@ -105,16 +103,6 @@ static void process_state_change(otChangedFlags flags, void* context)
} }
} }
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;
}
#if CONFIG_ESP_SLEEP_DEBUG #if CONFIG_ESP_SLEEP_DEBUG
static esp_sleep_context_t s_sleep_ctx; static esp_sleep_context_t s_sleep_ctx;
@@ -128,63 +116,6 @@ void vTimerCallback( TimerHandle_t xTimer )
} }
#endif #endif
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(),
.port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),
};
// 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);
// Use freeRTOS timer so that it is lower priority than OpenThread
xTimer = xTimerCreate("print_sleep_flag", pdMS_TO_TICKS(2000), pdTRUE, NULL, vTimerCallback);
xTimerStart( xTimer, 0 );
#endif
// Run the main loop
esp_openthread_launch_mainloop();
// Clean up
esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
esp_vfs_eventfd_unregister();
vTaskDelete(NULL);
}
static esp_err_t ot_power_save_init(void) static esp_err_t ot_power_save_init(void)
{ {
esp_err_t rc = ESP_OK; esp_err_t rc = ESP_OK;
@@ -227,5 +158,31 @@ void app_main(void)
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()); ESP_ERROR_CHECK(esp_openthread_sleep_device_init());
xTaskCreate(ot_task_worker, "ot_power_save_main", 4096, NULL, 5, NULL);
#if CONFIG_OPENTHREAD_CLI
ot_console_start();
#endif
static 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(),
};
ESP_ERROR_CHECK(esp_openthread_start(&config));
esp_netif_set_default_netif(esp_openthread_get_netif());
otSetStateChangedCallback(esp_openthread_get_instance(), process_state_change, esp_openthread_get_instance());
#if CONFIG_OPENTHREAD_NETWORK_AUTO_START
create_config_network(esp_openthread_get_instance());
#endif
#if CONFIG_ESP_SLEEP_DEBUG
esp_sleep_set_sleep_context(&s_sleep_ctx);
esp_log_level_set(TAG, ESP_LOG_DEBUG);
// Use freeRTOS timer so that it is lower priority than OpenThread
xTimer = xTimerCreate("print_sleep_flag", pdMS_TO_TICKS(2000), pdTRUE, NULL, vTimerCallback);
xTimerStart( xTimer, 0 );
#endif
} }

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: CC0-1.0 * SPDX-License-Identifier: CC0-1.0
* *
@@ -25,25 +25,9 @@
} }
#endif #endif
// When JIRA PM-3 is fixed, the UART clock will automatically switch. #define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \ { \
{ \ .host_connection_mode = HOST_CONNECTION_MODE_NONE, \
.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_XTAL, \
}, \
.rx_pin = UART_PIN_NO_CHANGE, \
.tx_pin = UART_PIN_NO_CHANGE, \
}, \
} }
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \

View File

@@ -0,0 +1,6 @@
## IDF Component Manager Manifest File
dependencies:
idf:
version: ">=4.1.0"
ot_examples_common:
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_examples_common

View File

@@ -23,6 +23,8 @@ CONFIG_OPENTHREAD_BORDER_ROUTER=n
CONFIG_OPENTHREAD_MTD=y CONFIG_OPENTHREAD_MTD=y
CONFIG_OPENTHREAD_DNS64_CLIENT=y CONFIG_OPENTHREAD_DNS64_CLIENT=y
CONFIG_OPENTHREAD_CLI=y CONFIG_OPENTHREAD_CLI=y
CONFIG_OPENTHREAD_TASK_SIZE=4096
CONFIG_OPENTHREAD_CONSOLE_ENABLE=n
# end of OpenThread # end of OpenThread
# #
@@ -51,3 +53,9 @@ CONFIG_IEEE802154_SLEEP_ENABLE=y
CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y
# end of light sleep # end of light sleep
#
# ESP System Settings
#
CONFIG_ESP_MAIN_TASK_STACK_SIZE=6144
# end of ESP System Settings

View File

@@ -44,7 +44,7 @@ Now you'll get an OpenThread command line shell.
The `help` command will print all of the supported commands. The `help` command will print all of the supported commands.
```bash ```bash
> help esp32s3> ot help
I(7058) OPENTHREAD:[INFO]-CLI-----: execute command: help I(7058) OPENTHREAD:[INFO]-CLI-----: execute command: help
bbr bbr
bufferinfo bufferinfo
@@ -78,51 +78,51 @@ To run this example, at least two ESP32-S3 boards flashed with this ot_trel exam
On the first device, run the following commands: On the first device, run the following commands:
```bash ```bash
> factoryreset esp32s3> ot factoryreset
... # the device will reboot ... # the device will reboot
> dataset init new esp32s3> ot dataset init new
Done Done
> dataset commit active esp32s3> ot dataset commit active
Done Done
> ifconfig up esp32s3> ot ifconfig up
Done Done
> thread start esp32s3> ot thread start
Done Done
# After some seconds # After some seconds
> state esp32s3> ot state
leader leader
Done Done
``` ```
Now the first device has formed a Thread network as a leader. Get some information which will be used in next steps: Now the first device has formed a Thread network as a leader. Get some information which will be used in next steps:
```bash ```bash
> ipaddr esp32s3> ot ipaddr
fdde:ad00:beef:0:0:ff:fe00:fc00 fdde:ad00:beef:0:0:ff:fe00:fc00
fdde:ad00:beef:0:0:ff:fe00:8000 fdde:ad00:beef:0:0:ff:fe00:8000
fdde:ad00:beef:0:a7c6:6311:9c8c:271b fdde:ad00:beef:0:a7c6:6311:9c8c:271b
fe80:0:0:0:5c27:a723:7115:c8f8 fe80:0:0:0:5c27:a723:7115:c8f8
# Get the Active Dataset # Get the Active Dataset
> dataset active -x esp32s3> ot dataset active -x
0e080000000000010000000300001835060004001fffe00208fe7bb701f5f1125d0708fd75cbde7c6647bd0510b3914792d44f45b6c7d76eb9306eec94030f4f70656e5468726561642d35383332010258320410e35c581af5029b054fc904a24c2b27700c0402a0fff8 0e080000000000010000000300001835060004001fffe00208fe7bb701f5f1125d0708fd75cbde7c6647bd0510b3914792d44f45b6c7d76eb9306eec94030f4f70656e5468726561642d35383332010258320410e35c581af5029b054fc904a24c2b27700c0402a0fff8
``` ```
On the second device, set the active dataset from leader, and start Thread interface: On the second device, set the active dataset from leader, and start Thread interface:
```bash ```bash
> factoryreset esp32s3> ot factoryreset
... # the device will reboot ... # the device will reboot
> dataset set active 0e080000000000010000000300001835060004001fffe00208fe7bb701f5f1125d0708fd75cbde7c6647bd0510b3914792d44f45b6c7d76eb9306eec94030f4f70656e5468726561642d35383332010258320410e35c581af5029b054fc904a24c2b27700c0402a0fff8 esp32s3> ot dataset set active 0e080000000000010000000300001835060004001fffe00208fe7bb701f5f1125d0708fd75cbde7c6647bd0510b3914792d44f45b6c7d76eb9306eec94030f4f70656e5468726561642d35383332010258320410e35c581af5029b054fc904a24c2b27700c0402a0fff8
> ifconfig up esp32s3> ot ifconfig up
Done Done
> thread start esp32s3> ot thread start
Done Done
# After some seconds # After some seconds
> state esp32s3> ot state
router # child is also a valid state router # child is also a valid state
Done Done
``` ```

View File

@@ -1,9 +0,0 @@
menu "OpenThread TREL Example"
config OPENTHREAD_AUTO_START
bool 'Enable the automatic start mode.'
default n
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

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: CC0-1.0 * SPDX-License-Identifier: CC0-1.0
* *
@@ -22,33 +22,10 @@
.radio_mode = RADIO_MODE_TREL, \ .radio_mode = RADIO_MODE_TREL, \
} }
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_UART
#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, \
}, \
}
#elif CONFIG_OPENTHREAD_CONSOLE_TYPE_USB_SERIAL_JTAG
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \ { \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_USB, \ .host_connection_mode = HOST_CONNECTION_MODE_NONE, \
.host_usb_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(), \
} }
#endif
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \ #define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
{ \ { \

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: CC0-1.0 * SPDX-License-Identifier: CC0-1.0
* *
@@ -23,23 +23,14 @@
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_netif_types.h" #include "esp_netif_types.h"
#include "esp_openthread.h" #include "esp_openthread.h"
#include "esp_openthread_cli.h"
#include "esp_openthread_lock.h" #include "esp_openthread_lock.h"
#include "esp_openthread_netif_glue.h" #include "esp_openthread_netif_glue.h"
#include "esp_openthread_types.h"
#include "esp_ot_config.h" #include "esp_ot_config.h"
#include "esp_vfs_eventfd.h" #include "esp_vfs_eventfd.h"
#include "driver/uart.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "hal/uart_types.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "openthread/cli.h"
#include "openthread/instance.h"
#include "openthread/logging.h"
#include "openthread/tasklet.h"
#include "protocol_examples_common.h" #include "protocol_examples_common.h"
#include "mdns.h" #include "mdns.h"
#include "ot_examples_common.h"
#if !CONFIG_EXAMPLE_CONNECT_WIFI && !CONFIG_EXAMPLE_CONNECT_ETHERNET #if !CONFIG_EXAMPLE_CONNECT_WIFI && !CONFIG_EXAMPLE_CONNECT_ETHERNET
#error No netif for TREL! #error No netif for TREL!
@@ -56,70 +47,6 @@
#define TAG "ot_esp_trel" #define TAG "ot_esp_trel"
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(),
};
ESP_ERROR_CHECK(example_connect());
// Initialize the OpenThread stack
ESP_ERROR_CHECK(esp_openthread_init(&config));
#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE
ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance()));
#endif
#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_CLI_ESP_EXTENSION
esp_cli_custom_command_init();
#endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
// Run the main loop
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_create_task();
#endif
#if CONFIG_OPENTHREAD_AUTO_START
otOperationalDatasetTlvs dataset;
otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset);
ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL));
#endif
esp_openthread_launch_mainloop();
// Clean up
esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
esp_vfs_eventfd_unregister();
vTaskDelete(NULL);
}
void app_main(void) void app_main(void)
{ {
// Used eventfds: // Used eventfds:
@@ -136,5 +63,24 @@ void app_main(void)
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
ESP_ERROR_CHECK(mdns_init()); ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set("esp-ot-trel")); ESP_ERROR_CHECK(mdns_hostname_set("esp-ot-trel"));
xTaskCreate(ot_task_worker, "ot_trel_main", 8192, xTaskGetCurrentTaskHandle(), 5, NULL);
ESP_ERROR_CHECK(example_connect());
#if CONFIG_OPENTHREAD_CLI
ot_console_start();
#endif
static 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(),
};
ESP_ERROR_CHECK(esp_openthread_start(&config));
esp_netif_set_default_netif(esp_openthread_get_netif());
#if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
esp_cli_custom_command_init();
#endif
#if CONFIG_OPENTHREAD_NETWORK_AUTO_START
ot_network_auto_start();
#endif
} }

View File

@@ -1,7 +1,7 @@
## IDF Component Manager Manifest File ## IDF Component Manager Manifest File
dependencies: dependencies:
espressif/esp_ot_cli_extension: espressif/esp_ot_cli_extension:
version: "~1.2.0" version: "~1.4.0"
espressif/mdns: "^1.0.3" espressif/mdns: "^1.0.3"
idf: idf:
version: ">=4.1.0" version: ">=4.1.0"
@@ -9,3 +9,5 @@ dependencies:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common path: ${IDF_PATH}/examples/common_components/protocol_examples_common
ot_led: ot_led:
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led
ot_examples_common:
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_examples_common

View File

@@ -25,6 +25,8 @@ CONFIG_OPENTHREAD_BORDER_ROUTER=n
CONFIG_OPENTHREAD_DNS64_CLIENT=y CONFIG_OPENTHREAD_DNS64_CLIENT=y
CONFIG_OPENTHREAD_RADIO_154_NONE=y CONFIG_OPENTHREAD_RADIO_154_NONE=y
CONFIG_OPENTHREAD_RADIO_TREL=y CONFIG_OPENTHREAD_RADIO_TREL=y
CONFIG_OPENTHREAD_TASK_SIZE=10240
CONFIG_OPENTHREAD_CONSOLE_ENABLE=n
# end of OpenThread # end of OpenThread
# #
@@ -49,4 +51,10 @@ CONFIG_EXAMPLE_CONNECT_THREAD=n
# Wireless Coexistence # Wireless Coexistence
# #
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=n CONFIG_ESP_COEX_SW_COEXIST_ENABLE=n
CONFIG_EXTERNAL_COEX_ENABLE=n CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE=n
#
# ESP System Settings
#
CONFIG_ESP_MAIN_TASK_STACK_SIZE=6144
# end of ESP System Settings