diff --git a/components/openthread/src/port/esp_openthread_radio.c b/components/openthread/src/port/esp_openthread_radio.c index 3079d75e16..07041438b2 100644 --- a/components/openthread/src/port/esp_openthread_radio.c +++ b/components/openthread/src/port/esp_openthread_radio.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include "esp_openthread_radio.h" #include "error.h" @@ -51,7 +52,7 @@ typedef struct { typedef struct { uint8_t head; uint8_t tail; - uint8_t used; + atomic_uint_fast8_t used; } esp_openthread_circular_queue_info_t; static otRadioFrame s_transmit_frame; @@ -216,7 +217,7 @@ esp_err_t esp_openthread_radio_process(otInstance *aInstance, const esp_openthre otPlatRadioEnergyScanDone(aInstance, s_ed_power); } - while (s_recv_queue.used) { + while (atomic_load(&s_recv_queue.used)) { if (s_receive_frame[s_recv_queue.head].mPsdu != NULL) { #if OPENTHREAD_CONFIG_DIAG_ENABLE if (otPlatDiagModeGet()) { @@ -229,7 +230,7 @@ esp_err_t esp_openthread_radio_process(otInstance *aInstance, const esp_openthre esp_ieee802154_receive_handle_done(s_receive_frame[s_recv_queue.head].mPsdu - 1); s_receive_frame[s_recv_queue.head].mPsdu = NULL; s_recv_queue.head = (s_recv_queue.head + 1) % CONFIG_IEEE802154_RX_BUFFER_SIZE; - s_recv_queue.used--; + atomic_fetch_sub(&s_recv_queue.used, 1); } } @@ -681,7 +682,7 @@ void IRAM_ATTR esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_i otRadioFrame ot_frame; ot_frame.mPsdu = data + 1; - if (s_recv_queue.used == CONFIG_IEEE802154_RX_BUFFER_SIZE) { + if (atomic_load(&s_recv_queue.used) == CONFIG_IEEE802154_RX_BUFFER_SIZE) { ESP_EARLY_LOGE(OT_PLAT_LOG_TAG, "radio receive buffer full!"); return; } @@ -699,7 +700,7 @@ void IRAM_ATTR esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_i s_with_security_enh_ack = false; #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 s_recv_queue.tail = (s_recv_queue.tail + 1) % CONFIG_IEEE802154_RX_BUFFER_SIZE; - s_recv_queue.used++; + atomic_fetch_add(&s_recv_queue.used, 1); set_event(EVENT_RX_DONE); } diff --git a/components/vfs/test_apps/main/test_vfs_eventfd.c b/components/vfs/test_apps/main/test_vfs_eventfd.c index 906bdecd1c..11ea46997d 100644 --- a/components/vfs/test_apps/main/test_vfs_eventfd.c +++ b/components/vfs/test_apps/main/test_vfs_eventfd.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -349,3 +349,48 @@ TEST_CASE("eventfd multiple selects", "[vfs][eventfd]") TEST_ASSERT_EQUAL(0, close(fd)); TEST_ESP_OK(esp_vfs_eventfd_unregister()); } + +typedef struct { + int *value; + int fd; +} select_block_task_args_t; + +static void select_block_task(void *arg) +{ + int fd = ((select_block_task_args_t *)arg)->fd; + fd_set read_fds; + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + select(fd + 1, &read_fds, NULL, NULL, NULL); + *(((select_block_task_args_t *)arg)->value) = 1; + vTaskDelete(NULL); +} + +TEST_CASE("eventfd select block", "[vfs][eventfd]") +{ + esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT(); + TEST_ESP_OK(esp_vfs_eventfd_register(&config)); + + select_block_task_args_t args; + args.fd = eventfd(0, 0); + TEST_ASSERT_GREATER_OR_EQUAL(0, args.fd); + int a = 0; + args.value = &a; + + int fd_write = eventfd(0, 0); + TEST_ASSERT_GREATER_OR_EQUAL(0, fd_write); + + xTaskCreate(select_block_task, "select_block_task", 2048, &args, 5, NULL); + vTaskDelay(pdMS_TO_TICKS(2000)); + + uint64_t val = 1; + TEST_ASSERT_EQUAL(sizeof(val), write(fd_write, &val, sizeof(val))); + vTaskDelay(pdMS_TO_TICKS(2000)); + + TEST_ASSERT_EQUAL(0, *(args.value)); + TEST_ASSERT_EQUAL(0, close(args.fd)); + TEST_ASSERT_EQUAL(0, close(fd_write)); + TEST_ESP_OK(esp_vfs_eventfd_unregister()); +} diff --git a/components/vfs/vfs_eventfd.c b/components/vfs/vfs_eventfd.c index 11ff2fb7e7..a9a979cf9c 100644 --- a/components/vfs/vfs_eventfd.c +++ b/components/vfs/vfs_eventfd.c @@ -106,7 +106,7 @@ static esp_err_t event_start_select(int nfds, for (int i = 0; i < nfds; i++) { _lock_acquire_recursive(&s_events[i].lock); - if (s_events[i].fd == i) { + if (s_events[i].fd == i && (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds))) { if (s_events[i].support_isr) { portENTER_CRITICAL(&s_events[i].data_spin_lock); } diff --git a/examples/openthread/ot_br/main/esp_ot_br.c b/examples/openthread/ot_br/main/esp_ot_br.c index 4996935c2c..d29718c4ae 100644 --- a/examples/openthread/ot_br/main/esp_ot_br.c +++ b/examples/openthread/ot_br/main/esp_ot_br.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 * @@ -15,6 +15,7 @@ #include #include +#include "sdkconfig.h" #include "esp_check.h" #include "esp_err.h" #include "esp_event.h" @@ -35,7 +36,6 @@ #include "mdns.h" #include "nvs_flash.h" #include "protocol_examples_common.h" -#include "sdkconfig.h" #include "driver/uart.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -44,6 +44,10 @@ #include "openthread/logging.h" #include "openthread/tasklet.h" +#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE +#include "ot_led_strip.h" +#endif + #define TAG "esp_ot_br" #if CONFIG_EXTERNAL_COEX_ENABLE @@ -72,6 +76,9 @@ static void ot_task_worker(void *aContext) // Initialize border routing features 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 ESP_ERROR_CHECK(esp_netif_attach(openthread_netif, esp_openthread_netif_glue_init(&config))); (void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL); diff --git a/examples/openthread/ot_br/main/idf_component.yml b/examples/openthread/ot_br/main/idf_component.yml index 98376227fe..124501cc61 100644 --- a/examples/openthread/ot_br/main/idf_component.yml +++ b/examples/openthread/ot_br/main/idf_component.yml @@ -10,3 +10,5 @@ dependencies: path: ${IDF_PATH}/examples/common_components/protocol_examples_common iperf: path: ${IDF_PATH}/examples/common_components/iperf + ot_led: + path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led diff --git a/examples/openthread/ot_br/sdkconfig.defaults b/examples/openthread/ot_br/sdkconfig.defaults index c223da9ab8..6620bfa46b 100644 --- a/examples/openthread/ot_br/sdkconfig.defaults +++ b/examples/openthread/ot_br/sdkconfig.defaults @@ -24,6 +24,7 @@ CONFIG_MBEDTLS_ECJPAKE_C=y # CONFIG_OPENTHREAD_ENABLED=y CONFIG_OPENTHREAD_BORDER_ROUTER=y +CONFIG_OPENTHREAD_RADIO_SPINEL_UART=y # end of OpenThread # diff --git a/examples/openthread/ot_cli/main/esp_ot_cli.c b/examples/openthread/ot_cli/main/esp_ot_cli.c index 912881c362..96a8d1e22c 100644 --- a/examples/openthread/ot_cli/main/esp_ot_cli.c +++ b/examples/openthread/ot_cli/main/esp_ot_cli.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 * @@ -16,6 +16,7 @@ #include #include +#include "sdkconfig.h" #include "esp_err.h" #include "esp_event.h" #include "esp_log.h" @@ -38,6 +39,10 @@ #include "openthread/logging.h" #include "openthread/tasklet.h" +#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE +#include "ot_led_strip.h" +#endif + #if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION #include "esp_ot_cli_extension.h" #endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION @@ -65,6 +70,10 @@ static void ot_task_worker(void *aContext) // 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); diff --git a/examples/openthread/ot_cli/main/idf_component.yml b/examples/openthread/ot_cli/main/idf_component.yml index 6cb24e1008..2ed997286a 100644 --- a/examples/openthread/ot_cli/main/idf_component.yml +++ b/examples/openthread/ot_cli/main/idf_component.yml @@ -6,3 +6,5 @@ dependencies: version: ">=4.1.0" iperf: path: ${IDF_PATH}/examples/common_components/iperf + ot_led: + path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led diff --git a/examples/openthread/ot_common_components/ot_led/CMakeLists.txt b/examples/openthread/ot_common_components/ot_led/CMakeLists.txt new file mode 100644 index 0000000000..8aedc48686 --- /dev/null +++ b/examples/openthread/ot_common_components/ot_led/CMakeLists.txt @@ -0,0 +1,7 @@ +if(CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE) + set(srcs "ot_led_strip.c") +endif() + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "include" + PRIV_REQUIRES led_strip openthread) diff --git a/examples/openthread/ot_common_components/ot_led/Kconfig.projbuild b/examples/openthread/ot_common_components/ot_led/Kconfig.projbuild new file mode 100644 index 0000000000..20bb56cba9 --- /dev/null +++ b/examples/openthread/ot_common_components/ot_led/Kconfig.projbuild @@ -0,0 +1,128 @@ +menu "OpenThread Device Role Indicator" + + orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps" + + config OPENTHREAD_STATE_INDICATOR_ENABLE + depends on SOC_RMT_SUPPORTED + bool 'Enable the LED for openthread deivce' + default False + help + If enabled, the LED of ESP Openthread Device will display different colors based on the current role. + + config OPENTHREAD_STATE_INDICATOR_GPIO + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "Blink GPIO number" + range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX + default 5 if IDF_TARGET_ESP32 + default 18 if IDF_TARGET_ESP32S2 + default 48 if IDF_TARGET_ESP32S3 + default 8 + help + GPIO number (IOxx) to blink on and off the LED. + Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink. + + menu "Indicator of Leader Device" + config LEADER_INDICATOR_RED + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "red config" + range 0 255 + default 40 + help + Red config of LED for OpenThread leader device + + config LEADER_INDICATOR_GREEN + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "green config" + range 0 255 + default 0 + help + Red config of LED for OpenThread leader device + + config LEADER_INDICATOR_BLUE + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "blue config" + range 0 255 + default 0 + help + Blue config of LED for OpenThread leader device + endmenu + + menu "Indicator of Router Device" + config ROUTER_INDICATOR_RED + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "red config" + range 0 255 + default 0 + help + Red config of LED for OpenThread router device + + config ROUTER_INDICATOR_GREEN + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "green config" + range 0 255 + default 0 + help + Green config of LED for OpenThread router device + + config ROUTER_INDICATOR_BLUE + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "blue config" + range 0 255 + default 40 + help + Blue config of LED for OpenThread router device + endmenu + + menu "Indicator of Child Device" + config CHILD_INDICATOR_RED + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "red config" + range 0 255 + default 0 + help + Red config of LED for OpenThread child device + + config CHILD_INDICATOR_GREEN + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "green config" + range 0 255 + default 40 + help + Green config of LED for OpenThread child device + + config CHILD_INDICATOR_BLUE + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "blue config" + range 0 255 + default 0 + help + Blue config of LED for OpenThread child device + endmenu + + menu "Indicator of Detached Device" + config DETACHED_INDICATOR_RED + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "red config" + range 0 255 + default 20 + help + Red config of LED for OpenThread detached device + + config DETACHED_INDICATOR_GREEN + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "green config" + range 0 255 + default 20 + help + Green config of LED for OpenThread detached device + + config DETACHED_INDICATOR_BLUE + depends on OPENTHREAD_STATE_INDICATOR_ENABLE + int "blue config" + range 0 255 + default 20 + help + Blue config of LED for OpenThread detached device + endmenu + +endmenu diff --git a/examples/openthread/ot_common_components/ot_led/idf_component.yml b/examples/openthread/ot_common_components/ot_led/idf_component.yml new file mode 100644 index 0000000000..8723a2e11a --- /dev/null +++ b/examples/openthread/ot_common_components/ot_led/idf_component.yml @@ -0,0 +1,2 @@ +dependencies: + espressif/led_strip: "^2.4.1" diff --git a/examples/openthread/ot_common_components/ot_led/include/ot_led_strip.h b/examples/openthread/ot_common_components/ot_led/include/ot_led_strip.h new file mode 100644 index 0000000000..a65c80db24 --- /dev/null +++ b/examples/openthread/ot_common_components/ot_led/include/ot_led_strip.h @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2024 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 Initilize the LED of OpenThread device. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failure + * + */ +esp_err_t esp_openthread_state_indicator_init(otInstance *instance); + +/** + * @brief Set the LED color of OpenThread device. + * + * @param[in] index index of pixel to set + * @param[in] red red part of color + * @param[in] green green part of color + * @param[in] blue blue part of color + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG: Set LED color failed because of invalid parameters + * - ESP_FAIL on other failure + * + */ +esp_err_t esp_openthread_state_indicator_set(uint32_t index, uint32_t red, uint32_t green, uint32_t blue); + +/** + * @brief Clear the LED color of OpenThread device. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG: Clear LED color failed because of invalid parameters + * - ESP_FAIL on other failure + * + */ +esp_err_t esp_openthread_state_indicator_clear(void); diff --git a/examples/openthread/ot_common_components/ot_led/ot_led_strip.c b/examples/openthread/ot_common_components/ot_led/ot_led_strip.c new file mode 100644 index 0000000000..cc9de4a188 --- /dev/null +++ b/examples/openthread/ot_common_components/ot_led/ot_led_strip.c @@ -0,0 +1,77 @@ +/* + * SPDX-FileCopyrightText: 2024 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_led_strip.h" +#include "esp_check.h" +#include "led_strip.h" +#include "esp_err.h" +#include "esp_openthread.h" + +static led_strip_handle_t s_led_strip; + +#define TAG "OT_LED" + +static void configure_led(void) +{ + /* LED strip initialization with the GPIO and pixels number*/ + led_strip_config_t strip_config = { + .strip_gpio_num = CONFIG_OPENTHREAD_STATE_INDICATOR_GPIO, + .max_leds = 1, // at least one LED on board + }; + led_strip_rmt_config_t rmt_config = { + .resolution_hz = 10 * 1000 * 1000, // 10MHz + .flags.with_dma = false, + }; + ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &s_led_strip)); + /* Set all LED off to clear all pixels */ + ESP_ERROR_CHECK(led_strip_clear(s_led_strip)); +} + +static void ot_indicator_change_callback(otChangedFlags changed_flags, void* ctx) +{ + otInstance *instance = esp_openthread_get_instance(); + otDeviceRole role = otThreadGetDeviceRole(instance); + if (role == OT_DEVICE_ROLE_DISABLED) { + esp_openthread_state_indicator_clear(); + } else if (role == OT_DEVICE_ROLE_DETACHED) { + esp_openthread_state_indicator_set(0, CONFIG_DETACHED_INDICATOR_RED, CONFIG_DETACHED_INDICATOR_GREEN, CONFIG_DETACHED_INDICATOR_BLUE); + } else if (role == OT_DEVICE_ROLE_LEADER) { + esp_openthread_state_indicator_set(0, CONFIG_LEADER_INDICATOR_RED, CONFIG_LEADER_INDICATOR_GREEN, CONFIG_LEADER_INDICATOR_BLUE); + } else if (role == OT_DEVICE_ROLE_ROUTER) { + esp_openthread_state_indicator_set(0, CONFIG_ROUTER_INDICATOR_RED, CONFIG_ROUTER_INDICATOR_GREEN, CONFIG_ROUTER_INDICATOR_BLUE); + } else if (role == OT_DEVICE_ROLE_CHILD) { + esp_openthread_state_indicator_set(0, CONFIG_CHILD_INDICATOR_RED, CONFIG_CHILD_INDICATOR_GREEN, CONFIG_CHILD_INDICATOR_BLUE); + } +} + +esp_err_t esp_openthread_state_indicator_init(otInstance *instance) +{ + configure_led(); + ESP_RETURN_ON_FALSE(otSetStateChangedCallback(instance, ot_indicator_change_callback, NULL) == OT_ERROR_NONE, + ESP_FAIL, TAG, "Failed to install state change callback"); + return ESP_OK; +} + +esp_err_t esp_openthread_state_indicator_set(uint32_t index, uint32_t red, uint32_t green, uint32_t blue) +{ + ESP_RETURN_ON_ERROR(led_strip_set_pixel(s_led_strip, index, red, green, blue), TAG, "Failed to set color for openthread state"); + ESP_RETURN_ON_ERROR(led_strip_refresh(s_led_strip), TAG, "Failed to refresh color for openthread state"); + return ESP_OK; +} + +esp_err_t esp_openthread_state_indicator_clear(void) +{ + ESP_RETURN_ON_ERROR(led_strip_clear(s_led_strip), TAG, "Failed to clear color for openthread state"); + return ESP_OK; +}