diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index 573825c061..fa1cf9a918 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -44,6 +44,13 @@ menu "OpenThread" default y help Select this option to enable Command-Line Interface in OpenThread. + + config OPENTHREAD_CONSOLE_COMMAND_PREFIX + string "The prefix of the openthread CLI command registered on the esp console" + default "ot" + help + A prefix string used before a Thread CLI command, allowing the ESP console to identify + it and delegate the remaining command to the OpenThread callback for processing. endmenu menu "Thread Core Features" @@ -130,6 +137,14 @@ menu "OpenThread" default 12390 help Configure the port number of TREL service. + + config OPENTHREAD_TREL_BUFFER_SIZE + int "The receive buffer size of openthread trel" + depends on OPENTHREAD_RADIO_TREL + range 10 255 + default 50 + help + Configure the receive buffer size of TREL service. endmenu menu "Thread 15.4 Radio Link" diff --git a/components/openthread/include/esp_openthread_border_router.h b/components/openthread/include/esp_openthread_border_router.h index 6fe915bc53..e78c28bddd 100644 --- a/components/openthread/include/esp_openthread_border_router.h +++ b/components/openthread/include/esp_openthread_border_router.h @@ -76,6 +76,14 @@ esp_netif_t *esp_openthread_get_backbone_netif(void); */ esp_err_t esp_openthread_set_meshcop_instance_name(const char *instance_name); +/** + * @brief Gets the meshcop(e) instance name. + * + * @return The instance name. + * + */ +const char* esp_openthread_get_meshcop_instance_name(void); + #ifdef __cplusplus } #endif diff --git a/components/openthread/include/esp_openthread_cli.h b/components/openthread/include/esp_openthread_cli.h index 554d0c755c..0bc7741a9c 100644 --- a/components/openthread/include/esp_openthread_cli.h +++ b/components/openthread/include/esp_openthread_cli.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,14 @@ extern "C" { /** * @brief This function initializes the OpenThread command line interface(CLI). * + * @note There are two ways to initialize the OpenThread CLI: + * 1. By creating a dedicated task via `esp_openthread_cli_create_task` + * + * 2. By registering a console command with the ESP console via + * `esp_openthread_cli_console_command_register` + * If using this approach, the user must initialize the interface used + * by the console and also initialize esp_console manually. Additionally, + * the `host_connection_mode` should be set to `HOST_CONNECTION_MODE_NONE`. */ void esp_openthread_cli_init(void); @@ -34,11 +42,27 @@ esp_err_t esp_openthread_cli_input(const char *line); /** * @brief This function launches an exclusive loop for the OpenThread CLI. * - * @param[in] priority The priority of the created task. - * */ void esp_openthread_cli_create_task(void); +/** + * @brief This function registers an ESP Console command for the OpenThread CLI. + * + * @return + * - ESP_OK on success + * - ESP_ERR_NO_MEM if allocation has failed + */ +esp_err_t esp_openthread_cli_console_command_register(void); + +/** + * @brief This function deregisters the ESP Console command for the OpenThread CLI. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if command is not registered + */ +esp_err_t esp_openthread_cli_console_command_unregister(void); + #ifdef __cplusplus } #endif diff --git a/components/openthread/include/esp_openthread_meshcop_mdns.h b/components/openthread/include/esp_openthread_meshcop_mdns.h new file mode 100644 index 0000000000..4e2c5926fa --- /dev/null +++ b/components/openthread/include/esp_openthread_meshcop_mdns.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_openthread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Publishes the OpenThread meshcop service in mDNS + * + * @param[in] instance_name Instance name of meshcop mDNS service + * + * @return + * - ESP_OK success + * - ESP_ERR_NO_MEM memory error + * - ESP_FAIL failed to add service + * + */ +esp_err_t esp_openthread_publish_meshcop_mdns(const char *instance_name); + +/** + * @brief Removes the OpenThread meshcop service in mDNS + * + * @return + * - ESP_OK success + * - ESP_ERR_NO_MEM memory error + * - ESP_FAIL failed to remove service + * + */ +esp_err_t esp_openthread_remove_meshcop_mdns(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/openthread/lib b/components/openthread/lib index d4d4738d0d..24a1ecd851 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit d4d4738d0d757dbcead167179ecf829a8c1d477b +Subproject commit 24a1ecd851c188aa9bc23578a0a39d20c77fba7f diff --git a/components/openthread/openthread b/components/openthread/openthread index ec2b0d4873..b945928d72 160000 --- a/components/openthread/openthread +++ b/components/openthread/openthread @@ -1 +1 @@ -Subproject commit ec2b0d487356d2955346457a6515201039140037 +Subproject commit b945928d722177cd9caeab2e1025499628c101ef diff --git a/components/openthread/private_include/esp_openthread_common.h b/components/openthread/private_include/esp_openthread_common.h new file mode 100644 index 0000000000..321b3c8e07 --- /dev/null +++ b/components/openthread/private_include/esp_openthread_common.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +typedef struct { + uint8_t head; + uint8_t tail; + atomic_uint_fast8_t used; +} esp_openthread_circular_queue_info_t; diff --git a/components/openthread/private_include/esp_openthread_radio.h b/components/openthread/private_include/esp_openthread_radio.h index 4b9aa4555f..ae7550471b 100644 --- a/components/openthread/private_include/esp_openthread_radio.h +++ b/components/openthread/private_include/esp_openthread_radio.h @@ -84,6 +84,27 @@ void esp_openthread_set_coex_config(esp_ieee802154_coex_config_t config); * */ esp_ieee802154_coex_config_t esp_openthread_get_coex_config(void); + +/** + * @brief This function updates the TREL fds and timeouts to the main loop. + * + * @param[inout] mainloop The main loop context. + * + */ +void esp_openthread_trel_update(esp_openthread_mainloop_context_t *mainloop); + +/** + * @brief This function performs the OpenThread TREL process. + * + * @param[in] instance The OpenThread instance. + * @param[in] mainloop The main loop context. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failure + * + */ +esp_err_t esp_openthread_trel_process(otInstance *aInstance, const esp_openthread_mainloop_context_t *mainloop); #endif #ifdef __cplusplus diff --git a/components/openthread/private_include/esp_openthread_state.h b/components/openthread/private_include/esp_openthread_state.h index e2ee350805..91d69c4283 100644 --- a/components/openthread/private_include/esp_openthread_state.h +++ b/components/openthread/private_include/esp_openthread_state.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,11 @@ #include #include +#define ESP_OPENTHREAD_BORDER_ROUTER_FLAG_OF_INTEREST \ + (OT_CHANGED_THREAD_ROLE | OT_CHANGED_THREAD_EXT_PANID | OT_CHANGED_THREAD_NETWORK_NAME | \ + OT_CHANGED_ACTIVE_DATASET | OT_CHANGED_THREAD_PARTITION_ID | OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE | \ + OT_CHANGED_PSKC) + #ifdef __cplusplus extern "C" { #endif diff --git a/components/openthread/sbom_openthread.yml b/components/openthread/sbom_openthread.yml index 789349f827..51447eac61 100644 --- a/components/openthread/sbom_openthread.yml +++ b/components/openthread/sbom_openthread.yml @@ -5,4 +5,4 @@ supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' originator: 'Organization: Google LLC' description: OpenThread released by Google is an open-source implementation of the Thread networking url: https://github.com/espressif/openthread -hash: ec2b0d487356d2955346457a6515201039140037 +hash: b945928d722177cd9caeab2e1025499628c101ef diff --git a/components/openthread/src/esp_openthread_cli.c b/components/openthread/src/esp_openthread_cli.c index b2a76a4df0..b7e1b933f9 100644 --- a/components/openthread/src/esp_openthread_cli.c +++ b/components/openthread/src/esp_openthread_cli.c @@ -1,14 +1,13 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "esp_openthread_cli.h" #include #include - +#include "sdkconfig.h" #include "openthread/cli.h" #include "esp_check.h" @@ -16,6 +15,7 @@ #include "esp_log.h" #include "esp_openthread.h" #include "esp_openthread_common_macro.h" +#include "esp_openthread_cli.h" #include "esp_openthread_task_queue.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -63,6 +63,40 @@ esp_err_t esp_openthread_cli_input(const char *line) return esp_openthread_task_queue_post(line_handle_task, line_copy); } +static int ot_cli_console_callback(int argc, char **argv) +{ + char cli_cmd[OT_CLI_MAX_LINE_LENGTH] = {0}; + strncpy(cli_cmd, argv[1], sizeof(cli_cmd) - strlen(cli_cmd) - 1); + for (int i = 2; i < argc; i++) { + strncat(cli_cmd, " ", sizeof(cli_cmd) - strlen(cli_cmd) - 1); + strncat(cli_cmd, argv[i], sizeof(cli_cmd) - strlen(cli_cmd) - 1); + } + s_cli_task = xTaskGetCurrentTaskHandle(); + if (esp_openthread_cli_input(cli_cmd) == ESP_OK) { + xTaskNotifyWait(0, 0, NULL, portMAX_DELAY); + } else { + printf("Openthread task is busy, failed to run command: %s\n", cli_cmd); + } + s_cli_task = NULL; + return 0; +} + +esp_err_t esp_openthread_cli_console_command_register(void) +{ + esp_console_cmd_t cmd = { + .command = CONFIG_OPENTHREAD_CONSOLE_COMMAND_PREFIX, + .help = "Execute `"CONFIG_OPENTHREAD_CONSOLE_COMMAND_PREFIX" ...` to run openthread cli", + .hint = NULL, + .func = ot_cli_console_callback, + }; + return esp_console_cmd_register(&cmd); +} + +esp_err_t esp_openthread_cli_console_command_unregister(void) +{ + return esp_console_cmd_deregister(CONFIG_OPENTHREAD_CONSOLE_COMMAND_PREFIX); +} + static void ot_cli_loop(void *context) { int ret = 0; diff --git a/components/openthread/src/port/esp_openthread_radio.c b/components/openthread/src/port/esp_openthread_radio.c index 28062b4afd..cc9a4a280b 100644 --- a/components/openthread/src/port/esp_openthread_radio.c +++ b/components/openthread/src/port/esp_openthread_radio.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include "esp_openthread_radio.h" #include "esp_err.h" @@ -13,6 +12,7 @@ #include "esp_ieee802154.h" #include "esp_ieee802154_types.h" #include "esp_mac.h" +#include "esp_openthread_common.h" #include "esp_openthread_common_macro.h" #include "esp_openthread_platform.h" #include "esp_openthread_types.h" @@ -52,12 +52,6 @@ typedef struct { uint8_t psdu[OT_RADIO_FRAME_MAX_SIZE]; } esp_openthread_radio_tx_psdu; -typedef struct { - uint8_t head; - uint8_t tail; - atomic_uint_fast8_t used; -} esp_openthread_circular_queue_info_t; - static otRadioFrame s_transmit_frame; static esp_openthread_radio_tx_psdu s_transmit_psdu; diff --git a/components/openthread/src/port/esp_openthread_state.c b/components/openthread/src/port/esp_openthread_state.c index 153d343ea1..bc2641d905 100644 --- a/components/openthread/src/port/esp_openthread_state.c +++ b/components/openthread/src/port/esp_openthread_state.c @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -19,6 +21,19 @@ #define TAG "OT_STATE" +#if CONFIG_OPENTHREAD_BORDER_ROUTER +static void handle_ot_border_router_state_changed(otInstance* instance) +{ + otDeviceRole role = otThreadGetDeviceRole(esp_openthread_get_instance()); + + if (role == OT_DEVICE_ROLE_CHILD || role == OT_DEVICE_ROLE_ROUTER || role == OT_DEVICE_ROLE_LEADER) { + esp_openthread_publish_meshcop_mdns(esp_openthread_get_meshcop_instance_name()); + } else { + esp_openthread_remove_meshcop_mdns(); + } +} +#endif + static void handle_ot_netif_state_change(otInstance* instance) { if (otIp6IsEnabled(instance)) { @@ -123,6 +138,12 @@ static void ot_state_change_callback(otChangedFlags changed_flags, void* ctx) return; } +#if CONFIG_OPENTHREAD_BORDER_ROUTER + if (changed_flags & ESP_OPENTHREAD_BORDER_ROUTER_FLAG_OF_INTEREST) { + handle_ot_border_router_state_changed(instance); + } +#endif + if (changed_flags & OT_CHANGED_THREAD_ROLE) { handle_ot_role_change(instance); } diff --git a/components/openthread/src/port/esp_openthread_trel.c b/components/openthread/src/port/esp_openthread_trel.c index 3c56e7a1c1..eae1c04219 100644 --- a/components/openthread/src/port/esp_openthread_trel.c +++ b/components/openthread/src/port/esp_openthread_trel.c @@ -18,10 +18,12 @@ #include "esp_netif_ip_addr.h" #include "esp_openthread.h" #include "esp_openthread_border_router.h" +#include "esp_openthread_common.h" #include "esp_openthread_common_macro.h" #include "esp_openthread_lock.h" +#include "esp_openthread_platform.h" #include "esp_openthread_radio.h" -#include "esp_openthread_task_queue.h" +#include "esp_vfs_eventfd.h" #include "lwip/pbuf.h" #include "lwip/tcpip.h" #include "lwip/udp.h" @@ -54,6 +56,10 @@ typedef struct { static ot_trel_t s_ot_trel = {CONFIG_OPENTHREAD_TREL_PORT, NULL}; static bool s_is_service_registered = false; +static ot_trel_recv_task_t s_trel_receive_buffer[CONFIG_OPENTHREAD_TREL_BUFFER_SIZE]; +static esp_openthread_circular_queue_info_t s_recv_queue = {.head = 0, .tail = 0, .used = 0}; +static const char *s_trel_workflow = "trel"; +static int s_trel_event_fd = -1; static void trel_browse_notifier(mdns_result_t *result) { @@ -89,55 +95,27 @@ static void trel_browse_notifier(mdns_result_t *result) } } -static void trel_recv_task(void *ctx) -{ - esp_err_t ret = ESP_OK; - OT_UNUSED_VARIABLE(ret); - ot_trel_recv_task_t *task_ctx = (ot_trel_recv_task_t *)ctx; - struct pbuf *recv_buf = task_ctx->p; - uint8_t *data_buf = (uint8_t *)recv_buf->payload; - uint8_t *data_buf_to_free = NULL; - uint16_t length = recv_buf->len; - - if (recv_buf->next != NULL) { - data_buf = (uint8_t *)malloc(recv_buf->tot_len); - ESP_GOTO_ON_FALSE(data_buf, ESP_ERR_NO_MEM, exit, OT_PLAT_LOG_TAG, "Failed to allocate data buf when receiving Thread TREL message"); - length = recv_buf->tot_len; - data_buf_to_free = data_buf; - pbuf_copy_partial(recv_buf, data_buf, recv_buf->tot_len, 0); - } - otPlatTrelHandleReceived(esp_openthread_get_instance(), data_buf, length, task_ctx->source_addr); - -exit: - if (recv_buf) { - pbuf_free(recv_buf); - } - free(data_buf_to_free); - free(task_ctx->source_addr); - free(task_ctx); -} - -// TZ-1704 static void handle_trel_udp_recv(void *ctx, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, uint16_t port) { esp_err_t ret = ESP_OK; + otSockAddr *source_addr = NULL; + uint64_t event_trel_rx = 1; ESP_LOGD(OT_PLAT_LOG_TAG, "Receive from %s:%d", ip6addr_ntoa(&(addr->u_addr.ip6)), port); + ESP_GOTO_ON_FALSE(atomic_load(&s_recv_queue.used) < CONFIG_OPENTHREAD_TREL_BUFFER_SIZE, ESP_ERR_NO_MEM, exit, OT_PLAT_LOG_TAG, "trel receive buffer full!"); + source_addr = (otSockAddr *)malloc(sizeof(otSockAddr)); + ESP_GOTO_ON_FALSE(source_addr, ESP_ERR_NO_MEM, exit, OT_PLAT_LOG_TAG, "Failed to allocate buf for Thread TREL"); - ot_trel_recv_task_t *task_ctx = (ot_trel_recv_task_t *)malloc(sizeof(ot_trel_recv_task_t)); - ESP_GOTO_ON_FALSE(task_ctx, ESP_ERR_NO_MEM, exit, OT_PLAT_LOG_TAG, "Failed to allocate buf for Thread TREL"); - task_ctx->p = p; - task_ctx->source_addr = (otSockAddr *)malloc(sizeof(otSockAddr)); - ESP_GOTO_ON_FALSE(task_ctx->source_addr, ESP_ERR_NO_MEM, exit, OT_PLAT_LOG_TAG, "Failed to allocate buf for Thread TREL"); - memset(task_ctx->source_addr, 0, sizeof(otSockAddr)); - task_ctx->source_addr->mPort = port; - memcpy(&task_ctx->source_addr->mAddress.mFields.m32, addr->u_addr.ip6.addr, sizeof(addr->u_addr.ip6.addr)); - - ESP_GOTO_ON_ERROR(esp_openthread_task_queue_post(trel_recv_task, task_ctx), exit, OT_PLAT_LOG_TAG, "Failed to receive OpenThread TREL message"); + memset(source_addr, 0, sizeof(otSockAddr)); + source_addr->mPort = port; + memcpy(&source_addr->mAddress.mFields.m32, addr->u_addr.ip6.addr, sizeof(addr->u_addr.ip6.addr)); + s_trel_receive_buffer[s_recv_queue.tail].source_addr = source_addr; + s_trel_receive_buffer[s_recv_queue.tail].p = p; + s_recv_queue.tail = (s_recv_queue.tail + 1) % CONFIG_OPENTHREAD_TREL_BUFFER_SIZE; + atomic_fetch_add(&s_recv_queue.used, 1); + assert(write(s_trel_event_fd, &event_trel_rx, sizeof(event_trel_rx)) == sizeof(event_trel_rx)); exit: if (ret != ESP_OK) { - free(task_ctx->source_addr); - free(task_ctx); if (p) { pbuf_free(p); } @@ -146,25 +124,76 @@ exit: static esp_err_t ot_new_trel(void *ctx) { - ot_trel_t *task = (ot_trel_t *)ctx; + s_ot_trel.trel_pcb = udp_new(); + ESP_RETURN_ON_FALSE(s_ot_trel.trel_pcb != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "Failed to create a new UDP pcb"); + udp_bind(s_ot_trel.trel_pcb, IP6_ADDR_ANY, s_ot_trel.port); + udp_recv(s_ot_trel.trel_pcb, handle_trel_udp_recv, NULL); + return ESP_OK; +} + +void esp_openthread_trel_update(esp_openthread_mainloop_context_t *mainloop) +{ + FD_SET(s_trel_event_fd, &mainloop->read_fds); + if (s_trel_event_fd > mainloop->max_fd) { + mainloop->max_fd = s_trel_event_fd; + } +} + +esp_err_t esp_openthread_trel_process(otInstance *aInstance, const esp_openthread_mainloop_context_t *mainloop) +{ + uint64_t event_read = 0; + assert(read(s_trel_event_fd, &event_read, sizeof(event_read)) == sizeof(event_read)); + struct pbuf *recv_buf = NULL; + uint8_t *data_buf = NULL; + uint16_t length = 0; + otSockAddr *source_addr = NULL; + + while (atomic_load(&s_recv_queue.used)) { + if (s_trel_receive_buffer[s_recv_queue.head].p != NULL) { + + uint8_t *data_buf_to_free = NULL; + bool should_handle = true; + recv_buf = s_trel_receive_buffer[s_recv_queue.head].p; + data_buf = (uint8_t *)recv_buf->payload; + length = recv_buf->len; + source_addr = s_trel_receive_buffer[s_recv_queue.head].source_addr; + + if (recv_buf->next != NULL) { + data_buf = (uint8_t *)malloc(recv_buf->tot_len); + if (data_buf) { + pbuf_copy_partial(recv_buf, data_buf, recv_buf->tot_len, 0); + } else { + should_handle = false; + } + length = recv_buf->tot_len; + data_buf_to_free = data_buf; + } + if (should_handle) { + otPlatTrelHandleReceived(aInstance, data_buf, length, source_addr); + } + pbuf_free(recv_buf); + free(data_buf_to_free); + free(source_addr); + + s_recv_queue.head = (s_recv_queue.head + 1) % CONFIG_OPENTHREAD_TREL_BUFFER_SIZE; + atomic_fetch_sub(&s_recv_queue.used, 1); + } + } - task->trel_pcb = udp_new(); - ESP_RETURN_ON_FALSE(task->trel_pcb != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "Failed to create a new UDP pcb"); - udp_bind(task->trel_pcb, IP6_ADDR_ANY, task->port); - udp_recv(task->trel_pcb, handle_trel_udp_recv, NULL); return ESP_OK; } void otPlatTrelEnable(otInstance *aInstance, uint16_t *aUdpPort) { + ESP_RETURN_ON_FALSE(s_trel_event_fd == -1, , OT_PLAT_LOG_TAG, "ot trel has been initialized."); + s_trel_event_fd = eventfd(0, 0); + assert(s_trel_event_fd >= 0); *aUdpPort = s_ot_trel.port; esp_openthread_task_switching_lock_release(); - esp_err_t err = esp_netif_tcpip_exec(ot_new_trel, &s_ot_trel); - if (err != ESP_OK) { - ESP_LOGE(OT_PLAT_LOG_TAG, "Fail to create trel udp"); - } + ESP_ERROR_CHECK(esp_netif_tcpip_exec(ot_new_trel, NULL)); mdns_browse_new(TREL_MDNS_TYPE, TREL_MDNS_PROTO, trel_browse_notifier); esp_openthread_task_switching_lock_acquire(portMAX_DELAY); + ESP_ERROR_CHECK(esp_openthread_platform_workflow_register(&esp_openthread_trel_update, &esp_openthread_trel_process, s_trel_workflow)); } static esp_err_t trel_send_task(void *ctx) @@ -263,23 +292,41 @@ void otPlatTrelResetCounters(otInstance *aInstance) memset(&s_trel_counters, 0, sizeof(otPlatTrelCounters)); } -static void trel_disable_task(void *ctx) +static esp_err_t trel_disable_task(void *ctx) { - struct udp_pcb *pcb = (struct udp_pcb *)ctx; - udp_remove(pcb); + if (ctx) { + struct udp_pcb *pcb = (struct udp_pcb *)ctx; + udp_remove(pcb); + } + return ESP_OK; +} + +static void free_all_buffer(void) +{ + while (atomic_load(&s_recv_queue.used)) { + if (s_trel_receive_buffer[s_recv_queue.head].p != NULL) { + pbuf_free(s_trel_receive_buffer[s_recv_queue.head].p); + free(s_trel_receive_buffer[s_recv_queue.head].source_addr); + s_recv_queue.head = (s_recv_queue.head + 1) % CONFIG_OPENTHREAD_TREL_BUFFER_SIZE; + atomic_fetch_sub(&s_recv_queue.used, 1); + } + } } void otPlatTrelDisable(otInstance *aInstance) { + ESP_RETURN_ON_FALSE(s_trel_event_fd >= 0, , OT_PLAT_LOG_TAG, "ot trel is not initialized."); esp_openthread_task_switching_lock_release(); - if (s_ot_trel.trel_pcb) { - tcpip_callback(trel_disable_task, s_ot_trel.trel_pcb); - } + esp_netif_tcpip_exec(trel_disable_task, s_ot_trel.trel_pcb); + s_ot_trel.trel_pcb = NULL; mdns_service_remove(TREL_MDNS_TYPE, TREL_MDNS_PROTO); s_is_service_registered = false; mdns_browse_delete(TREL_MDNS_TYPE, TREL_MDNS_PROTO); esp_openthread_task_switching_lock_acquire(portMAX_DELAY); - s_ot_trel.trel_pcb = NULL; + esp_openthread_platform_workflow_unregister(s_trel_workflow); + free_all_buffer(); + close(s_trel_event_fd); + s_trel_event_fd = -1; } const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *aInstance) diff --git a/examples/openthread/ot_br/main/esp_ot_br.c b/examples/openthread/ot_br/main/esp_ot_br.c index bbd5ae3f0a..ffcfd39157 100644 --- a/examples/openthread/ot_br/main/esp_ot_br.c +++ b/examples/openthread/ot_br/main/esp_ot_br.c @@ -199,15 +199,20 @@ void app_main(void) // * netif // * task queue // * border router - esp_vfs_eventfd_config_t eventfd_config = { + size_t max_eventfd = 3; + #if CONFIG_OPENTHREAD_RADIO_NATIVE || CONFIG_OPENTHREAD_RADIO_SPINEL_SPI - // * radio driver (A native radio device needs a eventfd for radio driver.) - // * SpiSpinelInterface (The Spi Spinel Interface needs a eventfd.) - // The above will not exist at the same time. - .max_fds = 4, -#else - .max_fds = 3, + // * radio driver (A native radio device needs a eventfd for radio driver.) + // * SpiSpinelInterface (The Spi Spinel Interface needs a eventfd.) + // The above will not exist at the same time. + max_eventfd++; #endif +#if CONFIG_OPENTHREAD_RADIO_TREL + // * TREL reception (The Thread Radio Encapsulation Link needs a eventfd for reception.) + max_eventfd++; +#endif + esp_vfs_eventfd_config_t eventfd_config = { + .max_fds = max_eventfd, }; ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); ESP_ERROR_CHECK(nvs_flash_init()); diff --git a/examples/openthread/ot_trel/main/esp_ot_trel.c b/examples/openthread/ot_trel/main/esp_ot_trel.c index 05b7251da4..a333eface5 100644 --- a/examples/openthread/ot_trel/main/esp_ot_trel.c +++ b/examples/openthread/ot_trel/main/esp_ot_trel.c @@ -125,8 +125,9 @@ void app_main(void) // Used eventfds: // * netif // * ot task queue + // * ot trel esp_vfs_eventfd_config_t eventfd_config = { - .max_fds = 2, + .max_fds = 3, }; ESP_ERROR_CHECK(nvs_flash_init());