diff --git a/components/openthread/include/esp_openthread.h b/components/openthread/include/esp_openthread.h index 35a7d44383..a29b3efa36 100644 --- a/components/openthread/include/esp_openthread.h +++ b/components/openthread/include/esp_openthread.h @@ -24,11 +24,9 @@ extern "C" { #endif /** - * @brief Initializes the platform-specific support for the OpenThread stack. + * @brief Initializes the full OpenThread stack. * - * @note This function is not called by and will not call the OpenThread library. - * The user needs to call otInstanceInitSingle to intialize the OpenThread - * stack after calling this fucntion. + * @note The OpenThread instance will also be initialized in this function. * * @param[in] init_config The initialization configuration. * @@ -39,20 +37,30 @@ extern "C" { * - ESP_ERR_INVALID_STATE if already initialized * */ -esp_err_t esp_openthread_platform_init(const esp_openthread_platform_config_t *init_config); +esp_err_t esp_openthread_init(const esp_openthread_platform_config_t *init_config); /** - * This function performs all platform-specific deinitialization for OpenThread's drivers. + * @brief Launches the OpenThread main loop. * - * @note This function is not called by the OpenThread library. Instead, the user should - * call this function when deinitialization of OpenThread's drivers is most appropriate. + * @note Thie function will not return unless error happens when running the OpenThread stack. + * + * @return + * - ESP_OK on success + * - ESP_ERR_NO_MEM if allocation has failed + * - ESP_FAIL on other failures + * + */ +esp_err_t esp_openthread_launch_mainloop(void); + +/** + * @brief This function performs OpenThread stack and platform driver deinitialization. * * @return * - ESP_OK on success * - ESP_ERR_INVALID_STATE if not initialized * */ -esp_err_t esp_openthread_platform_deinit(void); +esp_err_t esp_openthread_deinit(void); /** * @brief This function acquires the underlying OpenThread instance. @@ -64,34 +72,6 @@ esp_err_t esp_openthread_platform_deinit(void); */ otInstance *esp_openthread_get_instance(void); -/** - * @brief This function updates the platform fds and timeouts - * - * @note This function will not update the OpenThread core stack pending events. - * The users need to call `otTaskletsArePending` to check whether there being - * pending OpenThread tasks. - * - * @param[inout] mainloop The main loop context. - * - */ -void esp_openthread_platform_update(esp_openthread_mainloop_context_t *mainloop); - -/** - * @brief This function performs the OpenThread related platform process (radio, uart, alarm etc.) - * - * @note This function will call the OpenThread core stack process functions. - * The users need to call `otTaskletsProcess` by self. - * - * @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_platform_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop); - #ifdef __cplusplus } // end of extern "C" #endif diff --git a/components/openthread/include/esp_openthread_defaults.h b/components/openthread/include/esp_openthread_defaults.h new file mode 100644 index 0000000000..cbbfc15ac5 --- /dev/null +++ b/components/openthread/include/esp_openthread_defaults.h @@ -0,0 +1,57 @@ +// Copyright 2021 Espressif Systems (Shanghai) CO LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#pragma once + +#include "esp_openthread_types.h" + +#define ESP_OPENTHREAD_DEFAULT_RADIO_UART_RCP_CONFIG(pin_rx, pin_tx) \ + { \ + .radio_mode = RADIO_MODE_UART_RCP, \ + .radio_uart_config = { \ + .port = 1, \ + .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_APB, \ + }, \ + .rx_pin = pin_rx, \ + .tx_pin = pin_tx, \ + }, \ + } + +#define ESP_OPENTHREAD_DEFAULT_UART_HOST_CONFIG() \ + { \ + .host_connection_mode = HOST_CONNECTION_MODE_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_APB, \ + }, \ + .rx_pin = UART_PIN_NO_CHANGE, \ + .tx_pin = UART_PIN_NO_CHANGE, \ + }, \ + } diff --git a/components/openthread/include/esp_openthread_netif_glue.h b/components/openthread/include/esp_openthread_netif_glue.h index 035f201fd4..319362a172 100644 --- a/components/openthread/include/esp_openthread_netif_glue.h +++ b/components/openthread/include/esp_openthread_netif_glue.h @@ -38,27 +38,6 @@ void *esp_openthread_netif_glue_init(void); */ void esp_openthread_netif_glue_deinit(void); -/** - * @brief This function updates the netif fds and timeouts to the main loop. - * - * @param[inout] mainloop The main loop context. - * - */ -void esp_openthread_netif_glue_update(esp_openthread_mainloop_context_t *mainloop); - -/** - * @brief This function performs the netif process. - * - * @param[in] instance The OpenThread instance. - * - * @return - * - ESP_OK on success - * - ESP_FAIL on OpenThread failure - * - ESP_ERR_NO_MEM on memory allocation failure - * - */ -esp_err_t esp_openthread_netif_glue_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop); - #ifdef __cplusplus } #endif diff --git a/components/openthread/port/esp_openthread.cpp b/components/openthread/port/esp_openthread.cpp index 69a859a0b2..f3b6d37acd 100644 --- a/components/openthread/port/esp_openthread.cpp +++ b/components/openthread/port/esp_openthread.cpp @@ -11,97 +11,84 @@ // See the License for the specific language governing permissions and // limitations under the License -#include "esp_openthread.h" - #include "esp_check.h" -#include "esp_err.h" -#include "esp_log.h" -#include "esp_openthread_alarm.h" +#include "esp_openthread.h" #include "esp_openthread_common_macro.h" #include "esp_openthread_lock.h" -#include "esp_openthread_netif_glue.h" -#include "esp_openthread_radio_uart.h" +#include "esp_openthread_netif_glue_priv.h" +#include "esp_openthread_platform.h" #include "esp_openthread_types.h" -#include "esp_openthread_uart.h" -#include "common/code_utils.hpp" -#include "common/logging.hpp" -#include "core/common/instance.hpp" #include "freertos/FreeRTOS.h" -#include "freertos/queue.h" -#include "openthread/cli.h" #include "openthread/instance.h" -#include "openthread/platform/alarm-milli.h" -#include "openthread/platform/time.h" #include "openthread/tasklet.h" -static esp_openthread_platform_config_t s_platform_config; -static bool s_openthread_platform_initialized = false; - -esp_err_t esp_openthread_platform_init(const esp_openthread_platform_config_t *config) +static void esp_openthread_state_callback(otChangedFlags changed_flags, void *ctx) { - if (config->radio_config.radio_mode != RADIO_MODE_UART_RCP) { - otLogCritPlat("Radio mode not supported"); - return ESP_ERR_INVALID_ARG; - } - if (config->host_config.host_connection_mode != HOST_CONNECTION_MODE_NONE && - config->host_config.host_connection_mode != HOST_CONNECTION_MODE_UART) { - otLogCritPlat("Host connection mode not supported"); - return ESP_ERR_INVALID_ARG; - } - if (s_openthread_platform_initialized) { - return ESP_ERR_INVALID_STATE; - } - - esp_err_t error = ESP_OK; - - s_platform_config = *config; - SuccessOrExit(error = esp_openthread_lock_init()); - if (config->host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) { - SuccessOrExit(error = esp_openthread_uart_init(config)); - } - SuccessOrExit(error = esp_openthread_radio_init(config)); -exit: - if (error != ESP_OK) { - esp_openthread_platform_deinit(); - } - - return error; + esp_openthread_netif_glue_state_callback(changed_flags); } -otInstance *esp_openthread_get_instance(void) +static esp_err_t register_esp_openthread_state_callbacks(void) { - return &ot::Instance::Get(); -} - -esp_err_t esp_openthread_platform_deinit(void) -{ - if (!s_openthread_platform_initialized) { - return ESP_ERR_INVALID_STATE; - } - esp_openthread_radio_deinit(); - if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) { - esp_openthread_uart_deinit(); - } - esp_openthread_lock_deinit(); + otInstance *instance = esp_openthread_get_instance(); + ESP_RETURN_ON_FALSE(otSetStateChangedCallback(instance, esp_openthread_state_callback, NULL) == OT_ERROR_NONE, + ESP_FAIL, OT_PLAT_LOG_TAG, "Failed to install OpenThread state callback"); return ESP_OK; } -void esp_openthread_platform_update(esp_openthread_mainloop_context_t *mainloop) +esp_err_t esp_openthread_init(const esp_openthread_platform_config_t *config) { - esp_openthread_alarm_update(mainloop); - if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) { - esp_openthread_uart_update(mainloop); - } - esp_openthread_radio_update(mainloop); - esp_openthread_netif_glue_update(mainloop); + ESP_RETURN_ON_ERROR(esp_openthread_platform_init(config), OT_PLAT_LOG_TAG, + "Failed to initialize OpenThread platform driver"); + ESP_RETURN_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, OT_PLAT_LOG_TAG, + "Failed to initialize OpenThread instance"); + + return register_esp_openthread_state_callbacks(); } -esp_err_t esp_openthread_platform_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop) +esp_err_t esp_openthread_launch_mainloop(void) { - if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) { - ESP_RETURN_ON_ERROR(esp_openthread_uart_process(), OT_PLAT_LOG_TAG, "esp_openthread_uart_process failed"); + esp_openthread_mainloop_context_t mainloop; + otInstance *instance = esp_openthread_get_instance(); + esp_err_t error = ESP_OK; + + while (true) { + FD_ZERO(&mainloop.read_fds); + FD_ZERO(&mainloop.write_fds); + FD_ZERO(&mainloop.error_fds); + + mainloop.max_fd = -1; + mainloop.timeout.tv_sec = 10; + mainloop.timeout.tv_usec = 0; + + esp_openthread_lock_acquire(portMAX_DELAY); + esp_openthread_platform_update(&mainloop); + if (otTaskletsArePending(instance)) { + mainloop.timeout.tv_sec = 0; + mainloop.timeout.tv_usec = 0; + } + esp_openthread_lock_release(); + + if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds, + &mainloop.timeout) >= 0) { + esp_openthread_lock_acquire(portMAX_DELAY); + otTaskletsProcess(instance); + error = esp_openthread_platform_process(instance, &mainloop); + esp_openthread_lock_release(); + if (error != ESP_OK) { + ESP_LOGE(OT_PLAT_LOG_TAG, "esp_openthread_platform_process failed"); + break; + } + } else { + error = ESP_FAIL; + ESP_LOGE(OT_PLAT_LOG_TAG, "OpenThread system polling failed"); + break; + } } - esp_openthread_radio_process(instance, mainloop); - esp_openthread_alarm_process(instance); - return esp_openthread_netif_glue_process(instance, mainloop); + return error; +} + +esp_err_t esp_openthread_deinit(void) +{ + otInstanceFinalize(esp_openthread_get_instance()); + return esp_openthread_platform_deinit(); } diff --git a/components/openthread/port/esp_openthread_netif_glue.c b/components/openthread/port/esp_openthread_netif_glue.c index 514453a629..f9d6bed7dd 100644 --- a/components/openthread/port/esp_openthread_netif_glue.c +++ b/components/openthread/port/esp_openthread_netif_glue.c @@ -24,6 +24,7 @@ #include "esp_openthread.h" #include "esp_openthread_common_macro.h" #include "esp_openthread_lock.h" +#include "esp_openthread_netif_glue_priv.h" #include "esp_vfs_eventfd.h" #include "sdkconfig.h" #include "common/code_utils.hpp" @@ -151,12 +152,12 @@ static esp_err_t process_thread_transmit(otInstance *instance) return error; } -static void process_thread_state(otChangedFlags changed_flags, void *context) +void esp_openthread_netif_glue_state_callback(otChangedFlags changed_flags) { - otInstance *instance = (otInstance *)context; + otInstance *instance = esp_openthread_get_instance(); esp_err_t err = ESP_OK; - if (OT_CHANGED_THREAD_NETIF_STATE & changed_flags) { + if (s_packet_queue != NULL && (OT_CHANGED_THREAD_NETIF_STATE & changed_flags)) { if (otLinkIsEnabled(instance)) { otLogInfoPlat("netif up"); if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_UP, NULL, 0, 0) != ESP_OK) { @@ -274,7 +275,6 @@ static esp_err_t openthread_netif_post_attach(esp_netif_t *esp_netif, void *args void *esp_openthread_netif_glue_init(void) { otInstance *instance = esp_openthread_get_instance(); - otError ot_err; esp_err_t error = ESP_OK; if (instance == NULL || s_packet_queue || s_openthread_netif_glue.event_fd >= 0) { @@ -289,11 +289,6 @@ void *esp_openthread_netif_glue_init(void) otIp6SetAddressCallback(instance, process_thread_address, instance); otIp6SetReceiveCallback(instance, process_thread_receive, instance); - ot_err = otSetStateChangedCallback(instance, process_thread_state, instance); - if (ot_err != OT_ERROR_NONE) { - otLogCritPlat("Failed to register callback for OpenThread lwip interface: %s", otThreadErrorToString(ot_err)); - ExitNow(error = ESP_FAIL); - } otIp6SetReceiveFilterEnabled(instance, true); otIcmp6SetEchoMode(instance, OT_ICMP6_ECHO_HANDLER_DISABLED); @@ -315,7 +310,6 @@ exit: void esp_openthread_netif_glue_deinit(void) { otInstance *instance = esp_openthread_get_instance(); - otRemoveStateChangeCallback(instance, process_thread_state, instance); otIp6SetAddressCallback(instance, NULL, NULL); otIp6SetReceiveCallback(instance, NULL, NULL); if (s_packet_queue) { diff --git a/components/openthread/port/esp_openthread_platform.cpp b/components/openthread/port/esp_openthread_platform.cpp new file mode 100644 index 0000000000..a5e736f8e5 --- /dev/null +++ b/components/openthread/port/esp_openthread_platform.cpp @@ -0,0 +1,103 @@ +// Copyright 2021 Espressif Systems (Shanghai) CO LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#include "esp_openthread_platform.h" + +#include "esp_check.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_openthread_alarm.h" +#include "esp_openthread_common_macro.h" +#include "esp_openthread_lock.h" +#include "esp_openthread_netif_glue.h" +#include "esp_openthread_netif_glue_priv.h" +#include "esp_openthread_radio_uart.h" +#include "esp_openthread_types.h" +#include "esp_openthread_uart.h" +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "core/common/instance.hpp" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "openthread/cli.h" +#include "openthread/instance.h" +#include "openthread/tasklet.h" + +static esp_openthread_platform_config_t s_platform_config; +static bool s_openthread_platform_initialized = false; + +esp_err_t esp_openthread_platform_init(const esp_openthread_platform_config_t *config) +{ + ESP_RETURN_ON_FALSE(config->radio_config.radio_mode == RADIO_MODE_UART_RCP, ESP_ERR_INVALID_ARG, OT_PLAT_LOG_TAG, + "Radio mode not supported"); + ESP_RETURN_ON_FALSE(config->host_config.host_connection_mode == HOST_CONNECTION_MODE_NONE || + config->host_config.host_connection_mode == HOST_CONNECTION_MODE_UART, + ESP_ERR_INVALID_ARG, OT_PLAT_LOG_TAG, "Host connection mode not supported"); + ESP_RETURN_ON_FALSE(!s_openthread_platform_initialized, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, + "OpenThread platform already initialized"); + + esp_err_t ret = ESP_OK; + + s_platform_config = *config; + ESP_GOTO_ON_ERROR(esp_openthread_lock_init(), exit, OT_PLAT_LOG_TAG, "esp_openthread_lock_init failed"); + if (config->host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) { + ESP_GOTO_ON_ERROR(esp_openthread_uart_init(config), exit, OT_PLAT_LOG_TAG, "esp_openthread_uart_init failed"); + } + ESP_GOTO_ON_ERROR(esp_openthread_radio_init(config), exit, OT_PLAT_LOG_TAG, "esp_openthread_radio_init failed"); + +exit: + if (ret != ESP_OK) { + esp_openthread_platform_deinit(); + } + + return ret; +} + +otInstance *esp_openthread_get_instance(void) +{ + return (otInstance *)&ot::Instance::Get(); +} + +esp_err_t esp_openthread_platform_deinit(void) +{ + ESP_RETURN_ON_FALSE(s_openthread_platform_initialized, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, + "OpenThread platform not initialized"); + + esp_openthread_radio_deinit(); + if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) { + esp_openthread_uart_deinit(); + } + esp_openthread_lock_deinit(); + + return ESP_OK; +} + +void esp_openthread_platform_update(esp_openthread_mainloop_context_t *mainloop) +{ + esp_openthread_alarm_update(mainloop); + if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) { + esp_openthread_uart_update(mainloop); + } + esp_openthread_radio_update(mainloop); + esp_openthread_netif_glue_update(mainloop); +} + +esp_err_t esp_openthread_platform_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop) +{ + if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) { + ESP_RETURN_ON_ERROR(esp_openthread_uart_process(), OT_PLAT_LOG_TAG, "esp_openthread_uart_process failed"); + } + esp_openthread_radio_process(instance, mainloop); + esp_openthread_alarm_process(instance); + return esp_openthread_netif_glue_process(instance, mainloop); +} diff --git a/components/openthread/private_include/esp_openthread_netif_glue_priv.h b/components/openthread/private_include/esp_openthread_netif_glue_priv.h new file mode 100644 index 0000000000..b9c06f5e45 --- /dev/null +++ b/components/openthread/private_include/esp_openthread_netif_glue_priv.h @@ -0,0 +1,55 @@ +// Copyright 2021 Espressif Systems (Shanghai) CO LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#pragma once + +#include "esp_openthread.h" +#include "openthread/instance.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The state handler to be called when OpenThread state changes + * + * @param[in] changed_flags The changed Openthread states + * + */ +void esp_openthread_netif_glue_state_callback(otChangedFlags changed_flags); + +/** + * @brief This function updates the netif fds and timeouts to the main loop. + * + * @param[inout] mainloop The main loop context. + * + */ +void esp_openthread_netif_glue_update(esp_openthread_mainloop_context_t *mainloop); + +/** + * @brief This function performs the netif process. + * + * @param[in] instance The OpenThread instance. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on OpenThread failure + * - ESP_ERR_NO_MEM on memory allocation failure + * + */ +esp_err_t esp_openthread_netif_glue_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop); + +#ifdef __cplusplus +} +#endif diff --git a/components/openthread/private_include/esp_openthread_platform.h b/components/openthread/private_include/esp_openthread_platform.h new file mode 100644 index 0000000000..05bcabb813 --- /dev/null +++ b/components/openthread/private_include/esp_openthread_platform.h @@ -0,0 +1,87 @@ +// Copyright 2021 Espressif Systems (Shanghai) CO LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#pragma once + +#include "esp_err.h" +#include "esp_openthread_types.h" +#include "openthread/error.h" +#include "openthread/instance.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initializes the platform-specific support for the OpenThread stack. + * + * @note This function is not called by and will not call the OpenThread library. + * The user needs to call otInstanceInitSingle to intialize the OpenThread + * stack after calling this function. + * + * @param[in] init_config The initialization configuration. + * + * @return + * - ESP_OK on success + * - ESP_ERR_NO_MEM if allocation has failed + * - ESP_ERR_INVALID_ARG if radio or host connection mode not supported + * - ESP_ERR_INVALID_STATE if already initialized + * + */ +esp_err_t esp_openthread_platform_init(const esp_openthread_platform_config_t *init_config); + +/** + * This function performs all platform-specific deinitialization for OpenThread's drivers. + * + * @note This function is not called by the OpenThread library. Instead, the user should + * call this function when deinitialization of OpenThread's drivers is most appropriate. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE if not initialized + * + */ +esp_err_t esp_openthread_platform_deinit(void); + +/** + * @brief This function updates the platform fds and timeouts + * + * @note This function will not update the OpenThread core stack pending events. + * The users need to call `otTaskletsArePending` to check whether there being + * pending OpenThread tasks. + * + * @param[inout] mainloop The main loop context. + * + */ +void esp_openthread_platform_update(esp_openthread_mainloop_context_t *mainloop); + +/** + * @brief This function performs the OpenThread related platform process (radio, uart, alarm etc.) + * + * @note This function will call the OpenThread core stack process functions. + * The users need to call `otTaskletsProcess` by self. + * + * @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_platform_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop); + +#ifdef __cplusplus +} // end of extern "C" +#endif diff --git a/examples/openthread/ot_cli/main/esp_ot_cli.c b/examples/openthread/ot_cli/main/esp_ot_cli.c index 8e904aca59..c1adb45e5d 100644 --- a/examples/openthread/ot_cli/main/esp_ot_cli.c +++ b/examples/openthread/ot_cli/main/esp_ot_cli.c @@ -19,7 +19,9 @@ #include "esp_event.h" #include "esp_log.h" #include "esp_netif.h" +#include "esp_netif_types.h" #include "esp_openthread.h" +#include "esp_openthread_defaults.h" #include "esp_openthread_lock.h" #include "esp_openthread_netif_glue.h" #include "esp_openthread_types.h" @@ -41,115 +43,58 @@ extern void otAppCliInit(otInstance *instance); -static void ot_task_worker(void *aContext) +static esp_netif_t *init_openthread_netif(void) { - esp_openthread_platform_config_t config = { - .radio_config = - { - .radio_mode = RADIO_MODE_UART_RCP, - .radio_uart_config = - { - .port = 1, - .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_APB, - }, - .rx_pin = 4, - .tx_pin = 5, - }, - }, - .host_config = - { - .host_connection_mode = HOST_CONNECTION_MODE_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_APB, - }, - .rx_pin = UART_PIN_NO_CHANGE, - .tx_pin = UART_PIN_NO_CHANGE, - }, - }, - }; - esp_vfs_eventfd_config_t eventfd_config = { - .max_fds = 2, - }; - esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD(); esp_netif_t *netif = esp_netif_new(&cfg); assert(netif != NULL); - - esp_openthread_mainloop_context_t mainloop; - - ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); - ESP_ERROR_CHECK(esp_openthread_platform_init(&config)); - otInstance *instance = otInstanceInitSingle(); ESP_ERROR_CHECK(esp_netif_attach(netif, esp_openthread_netif_glue_init())); - assert(instance != NULL); - esp_openthread_lock_acquire(portMAX_DELAY); - otAppCliInit(instance); - esp_openthread_lock_release(); + return netif; +} + +static void ot_task_worker(void *aContext) +{ + esp_openthread_platform_config_t config = { + .radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_UART_RCP_CONFIG(4, 5), + .host_config = ESP_OPENTHREAD_DEFAULT_UART_HOST_CONFIG(), + }; + esp_netif_t *openthread_netif; + + // Initialize the OpenThread stack + ESP_ERROR_CHECK(esp_openthread_init(&config)); + + // Initialize the OpenThread cli + otAppCliInit(esp_openthread_get_instance()); + + // Initialize the esp_netif bindings + openthread_netif = init_openthread_netif(); + #if CONFIG_OPENTHREAD_CUSTOM_COMMAND esp_cli_custom_command_init(); #endif // CONFIG_OPENTHREAD_CUSTOM_COMMAND - while (true) { - FD_ZERO(&mainloop.read_fds); - FD_ZERO(&mainloop.write_fds); - FD_ZERO(&mainloop.error_fds); + // Run the main loop + esp_openthread_launch_mainloop(); - mainloop.max_fd = -1; - mainloop.timeout.tv_sec = 10; - mainloop.timeout.tv_usec = 0; - - esp_openthread_lock_acquire(portMAX_DELAY); - esp_openthread_platform_update(&mainloop); - if (otTaskletsArePending(instance)) { - mainloop.timeout.tv_sec = 0; - mainloop.timeout.tv_usec = 0; - } - esp_openthread_lock_release(); - - if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds, - &mainloop.timeout) >= 0) { - esp_openthread_lock_acquire(portMAX_DELAY); - otTaskletsProcess(instance); - if (esp_openthread_platform_process(instance, &mainloop)) { - ESP_LOGE(TAG, "esp_openthread_platform_process failed"); - } - esp_openthread_lock_release(); - } else { - ESP_LOGE(TAG, "OpenThread system polling failed"); - break; - } - } - - esp_netif_destroy(netif); + // Clean up + esp_netif_destroy(openthread_netif); esp_openthread_netif_glue_deinit(); - otInstanceFinalize(instance); - esp_openthread_platform_deinit(); esp_vfs_eventfd_unregister(); vTaskDelete(NULL); } void app_main(void) { + // Used eventfds: + // * netif + // * radio driver + esp_vfs_eventfd_config_t eventfd_config = { + .max_fds = 2, + }; + ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); xTaskCreate(ot_task_worker, "ot_cli_main", 10240, xTaskGetCurrentTaskHandle(), 5, NULL); }