From 06b10bfd906e3ea60167e1ff0c771893083e907e Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Mon, 30 Sep 2024 22:18:51 -0400 Subject: [PATCH] openthread: move esp-idf specific logic into openthread_esp --- esphome/components/openthread/openthread.cpp | 400 +++++++----------- esphome/components/openthread/openthread.h | 66 +-- .../components/openthread/openthread_esp.cpp | 172 ++++++++ .../components/openthread/openthread_esp.h | 45 -- 4 files changed, 355 insertions(+), 328 deletions(-) diff --git a/esphome/components/openthread/openthread.cpp b/esphome/components/openthread/openthread.cpp index d3dadcacc5..1fe3b63826 100644 --- a/esphome/components/openthread/openthread.cpp +++ b/esphome/components/openthread/openthread.cpp @@ -18,6 +18,9 @@ #include +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + #define TAG "openthread" namespace esphome { @@ -25,298 +28,181 @@ namespace openthread { OpenThreadComponent *global_openthread_component = nullptr; -OpenThreadComponent::OpenThreadComponent() { - global_openthread_component = this; -} +OpenThreadComponent::OpenThreadComponent() { global_openthread_component = this; } OpenThreadComponent::~OpenThreadComponent() { - auto lock = EspOpenThreadLockGuard::TryAcquire(100); - if (!lock) { - ESP_LOGW(TAG, "Failed to acquire OpenThread lock in destructor, leaking memory"); - return; - } - otInstance *instance = esp_openthread_get_instance(); - otSrpClientClearHostAndServices(instance); - otSrpClientBuffersFreeAllServices(instance); + auto lock = OpenThreadLockGuard::TryAcquire(100); + if (!lock) { + ESP_LOGW(TAG, "Failed to acquire OpenThread lock in destructor, leaking memory"); + return; + } + otInstance *instance = lock->get_instance(); + otSrpClientClearHostAndServices(instance); + otSrpClientBuffersFreeAllServices(instance); - global_openthread_component = nullptr; -} - -void OpenThreadComponent::setup() { - ESP_LOGI("openthread", "Setting up OpenThread..."); - // Used eventfds: - // * netif - // * ot task queue - // * radio driver - // TODO: Does anything else in esphome set this up? - esp_vfs_eventfd_config_t eventfd_config = { - .max_fds = 3, - }; - ESP_ERROR_CHECK(nvs_flash_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); - - xTaskCreate([](void* arg) { - static_cast(arg)->ot_main(); - vTaskDelete(NULL); - }, "ot_main", 10240, this, 5, nullptr); - - xTaskCreate([](void* arg) { - static_cast(arg)->srp_setup(); - vTaskDelete(NULL); - }, "ot_srp_setup", 10240, this, 5, nullptr); - ESP_LOGI("openthread", "OpenThread started"); -} - -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; -} - -void OpenThreadComponent::ot_main() { - - esp_openthread_platform_config_t config = { - .radio_config = { - .radio_mode = RADIO_MODE_NATIVE, - .radio_uart_config = {}, - }, - .host_config = { - // There is a conflict between esphome's logger which also - // claims the usb serial jtag device. - // .host_connection_mode = HOST_CONNECTION_MODE_CLI_USB, - // .host_usb_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(), - }, - .port_config = { - .storage_partition_name = "nvs", - .netif_queue_size = 10, - .task_queue_size = 10, - }, - }; - - // 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 - ESP_LOGI(TAG, "Activating dataset..."); - otOperationalDatasetTlvs dataset; - otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset); - ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL)); - - esp_openthread_launch_mainloop(); - - // Clean up - esp_openthread_netif_glue_deinit(); - esp_netif_destroy(openthread_netif); - - esp_vfs_eventfd_unregister(); + global_openthread_component = nullptr; } bool OpenThreadComponent::is_connected() { - otInstance *instance = esp_openthread_get_instance(); - if (instance == nullptr) { - return false; - } - - otDeviceRole role = otThreadGetDeviceRole(instance); - - // TODO: If we're a leader, check that there is at least 1 known peer - return role >= OT_DEVICE_ROLE_CHILD; -} - -// TODO: This gets used by mqtt in order to register the device's IP. Likely it doesn't -// make sense to return thread-local addresses, since they can't be reached from outside the thread network. -// It could make more sense to return the off-mesh-routable address instead. -network::IPAddresses OpenThreadComponent::get_ip_addresses() { - network::IPAddresses addresses; - struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES]; - uint8_t count = 0; - esp_netif_t *netif = esp_netif_get_default_netif(); - count = esp_netif_get_all_ip6(netif, if_ip6s); - assert(count <= CONFIG_LWIP_IPV6_NUM_ADDRESSES); - for (int i = 0; i < count; i++) { - addresses[i + 1] = network::IPAddress(&if_ip6s[i]); + auto lock = OpenThreadLockGuard::TryAcquire(100); + if (!lock) { + ESP_LOGW(TAG, "Failed to acquire OpenThread lock in is_connected"); + return false; } - return addresses; + + otInstance *instance = lock->get_instance(); + if (instance == nullptr) { + return false; + } + + otDeviceRole role = otThreadGetDeviceRole(instance); + + // TODO: If we're a leader, check that there is at least 1 known peer + return role >= OT_DEVICE_ROLE_CHILD; } // Gets the off-mesh routable address std::optional OpenThreadComponent::get_omr_address() { - auto lock = EspOpenThreadLockGuard::Acquire(); - return this->get_omr_address(lock); + auto lock = OpenThreadLockGuard::Acquire(); + return this->get_omr_address(lock); } -std::optional OpenThreadComponent::get_omr_address(std::optional &lock) { - otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; - otInstance *instance = nullptr; +std::optional OpenThreadComponent::get_omr_address(std::optional &lock) { + otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; + otInstance *instance = nullptr; - instance = esp_openthread_get_instance(); + instance = lock->get_instance(); - otBorderRouterConfig aConfig; - while (otNetDataGetNextOnMeshPrefix(instance, &iterator, &aConfig) != OT_ERROR_NONE) { - lock.reset(); - vTaskDelay(100); - lock = EspOpenThreadLockGuard::TryAcquire(portMAX_DELAY); - if (!lock) { - ESP_LOGW("OT SRP", "Could not re-acquire lock"); - return {}; - } - }; - const otIp6Prefix * omrPrefix = &aConfig.mPrefix; - - char addressAsString[40]; - otIp6PrefixToString(omrPrefix, addressAsString, 40); - ESP_LOGW("OT SRP", "USING omr prefix %s", addressAsString); - - const otNetifAddress *unicastAddrs = otIp6GetUnicastAddresses(instance); - for (const otNetifAddress *addr = unicastAddrs; addr; addr = addr->mNext){ - const otIp6Address *localIp = &addr->mAddress; - if (otIp6PrefixMatch(&omrPrefix->mPrefix, localIp)) { - otIp6AddressToString(localIp, addressAsString, 40); - ESP_LOGW("OT SRP", "USING %s for SRP address", addressAsString); - return *localIp; - } + otBorderRouterConfig aConfig; + while (otNetDataGetNextOnMeshPrefix(instance, &iterator, &aConfig) != OT_ERROR_NONE) { + lock.reset(); + vTaskDelay(100); + lock = OpenThreadLockGuard::TryAcquire(portMAX_DELAY); + if (!lock) { + ESP_LOGW("OT SRP", "Could not re-acquire lock"); + return {}; } - ESP_LOGW("OT SRP", "Could not find the OMR address"); - return {}; + }; + const otIp6Prefix *omrPrefix = &aConfig.mPrefix; + + char addressAsString[40]; + otIp6PrefixToString(omrPrefix, addressAsString, 40); + ESP_LOGW("OT SRP", "USING omr prefix %s", addressAsString); + + const otNetifAddress *unicastAddrs = otIp6GetUnicastAddresses(instance); + for (const otNetifAddress *addr = unicastAddrs; addr; addr = addr->mNext) { + const otIp6Address *localIp = &addr->mAddress; + if (otIp6PrefixMatch(&omrPrefix->mPrefix, localIp)) { + otIp6AddressToString(localIp, addressAsString, 40); + ESP_LOGW("OT SRP", "USING %s for SRP address", addressAsString); + return *localIp; + } + } + ESP_LOGW("OT SRP", "Could not find the OMR address"); + return {}; } -void OpenThreadComponent::srp_setup(){ - otError error; - otInstance *instance = nullptr; - auto lock = EspOpenThreadLockGuard::Acquire(); - instance = esp_openthread_get_instance(); +void OpenThreadComponent::srp_setup() { + otError error; + auto lock = OpenThreadLockGuard::Acquire(); + otInstance *instance = lock->get_instance(); - // set the host name - uint16_t size; - char *existing_host_name = otSrpClientBuffersGetHostNameString(instance, &size); - uint16_t len = host_name.size(); - if (len > size) { - ESP_LOGW("OT SRP", "Hostname is too long, choose a shorter project name"); - return; - } - memcpy(existing_host_name, host_name.c_str(), len + 1); + // set the host name + uint16_t size; + char *existing_host_name = otSrpClientBuffersGetHostNameString(instance, &size); + uint16_t len = host_name.size(); + if (len > size) { + ESP_LOGW("OT SRP", "Hostname is too long, choose a shorter project name"); + return; + } + memcpy(existing_host_name, host_name.c_str(), len + 1); - error = otSrpClientSetHostName(instance, existing_host_name); - if (error != 0) { - ESP_LOGW("OT SRP", "Could not set host name with srp server"); - return; + error = otSrpClientSetHostName(instance, existing_host_name); + if (error != 0) { + ESP_LOGW("OT SRP", "Could not set host name with srp server"); + return; + } + + uint8_t arrayLength; + otIp6Address *hostAddressArray = otSrpClientBuffersGetHostAddressesArray(instance, &arrayLength); + + const std::optional localIp = this->get_omr_address(lock); + if (!localIp) { + ESP_LOGW("OT SRP", "Could not get local IP address"); + return; + } + memcpy(hostAddressArray, &*localIp, sizeof(localIp)); + + error = otSrpClientSetHostAddresses(instance, hostAddressArray, 1); + if (error != 0) { + ESP_LOGW("OT SRP", "Could not set ip address with srp server"); + return; + } + + // Copy the mdns services to our local instance so that the c_str pointers remain valid for the lifetime of this + // component + this->mdns_services_ = this->mdns_->get_services(); + for (const auto &service : this->mdns_services_) { + otSrpClientBuffersServiceEntry *entry = otSrpClientBuffersAllocateService(instance); + if (!entry) { + ESP_LOGW("OT SRP", "Failed to allocate service entry"); + continue; } - uint8_t arrayLength; - otIp6Address *hostAddressArray = otSrpClientBuffersGetHostAddressesArray(instance, &arrayLength); - - const std::optional localIp = this->get_omr_address(lock); - if (!localIp) { - ESP_LOGW("OT SRP", "Could not get local IP address"); - return; + // Set service name + char *string = otSrpClientBuffersGetServiceEntryServiceNameString(entry, &size); + std::string full_service = service.service_type + "." + service.proto; + if (full_service.size() > size) { + ESP_LOGW("OT SRP", "Service name too long: %s", full_service.c_str()); + continue; } - memcpy(hostAddressArray, &*localIp, sizeof(localIp)); + memcpy(string, full_service.c_str(), full_service.size() + 1); - error = otSrpClientSetHostAddresses(instance, hostAddressArray, 1); - if (error != 0){ - ESP_LOGW("OT SRP", "Could not set ip address with srp server"); - return; + // Set instance name (using host_name) + string = otSrpClientBuffersGetServiceEntryInstanceNameString(entry, &size); + if (this->host_name.size() > size) { + ESP_LOGW("OT SRP", "Instance name too long: %s", this->host_name.c_str()); + continue; } + memcpy(string, this->host_name.c_str(), this->host_name.size() + 1); - // Copy the mdns services to our local instance so that the c_str pointers remain valid for the lifetime of this component - this->mdns_services_ = this->mdns_->get_services(); - for (const auto& service : this->mdns_services_) { - otSrpClientBuffersServiceEntry *entry = otSrpClientBuffersAllocateService(instance); - if (!entry) { - ESP_LOGW("OT SRP", "Failed to allocate service entry"); - continue; - } + // Set port + entry->mService.mPort = service.port; - // Set service name - char *string = otSrpClientBuffersGetServiceEntryServiceNameString(entry, &size); - std::string full_service = service.service_type + "." + service.proto; - if (full_service.size() > size) { - ESP_LOGW("OT SRP", "Service name too long: %s", full_service.c_str()); - continue; - } - memcpy(string, full_service.c_str(), full_service.size() + 1); - - // Set instance name (using host_name) - string = otSrpClientBuffersGetServiceEntryInstanceNameString(entry, &size); - if (this->host_name.size() > size) { - ESP_LOGW("OT SRP", "Instance name too long: %s", this->host_name.c_str()); - continue; - } - memcpy(string, this->host_name.c_str(), this->host_name.size() + 1); - - // Set port - entry->mService.mPort = service.port; - - otDnsTxtEntry *mTxtEntries = reinterpret_cast(this->pool_alloc(sizeof(otDnsTxtEntry) * service.txt_records.size())); - // Set TXT records - entry->mService.mNumTxtEntries = service.txt_records.size(); - for (size_t i = 0; i < service.txt_records.size(); i++) { - const auto& txt = service.txt_records[i]; - mTxtEntries[i].mKey = txt.key.c_str(); - mTxtEntries[i].mValue = reinterpret_cast(txt.value.c_str()); - mTxtEntries[i].mValueLength = txt.value.size(); - } - entry->mService.mTxtEntries = mTxtEntries; - entry->mService.mNumTxtEntries = service.txt_records.size(); - - // Add service - error = otSrpClientAddService(instance, &entry->mService); - if (error != OT_ERROR_NONE) { - ESP_LOGW("OT SRP", "Failed to add service: %s", otThreadErrorToString(error)); - } + otDnsTxtEntry *mTxtEntries = + reinterpret_cast(this->pool_alloc(sizeof(otDnsTxtEntry) * service.txt_records.size())); + // Set TXT records + entry->mService.mNumTxtEntries = service.txt_records.size(); + for (size_t i = 0; i < service.txt_records.size(); i++) { + const auto &txt = service.txt_records[i]; + mTxtEntries[i].mKey = txt.key.c_str(); + mTxtEntries[i].mValue = reinterpret_cast(txt.value.c_str()); + mTxtEntries[i].mValueLength = txt.value.size(); } + entry->mService.mTxtEntries = mTxtEntries; + entry->mService.mNumTxtEntries = service.txt_records.size(); - otSrpClientEnableAutoStartMode(instance, nullptr, nullptr); + // Add service + error = otSrpClientAddService(instance, &entry->mService); + if (error != OT_ERROR_NONE) { + ESP_LOGW("OT SRP", "Failed to add service: %s", otThreadErrorToString(error)); + } + } + + otSrpClientEnableAutoStartMode(instance, nullptr, nullptr); } void *OpenThreadComponent::pool_alloc(size_t size) { - uint8_t* ptr = new uint8_t[size]; - if (ptr) { - this->_memory_pool.emplace_back(std::unique_ptr(ptr)); - } - return ptr; -} - -void OpenThreadComponent::set_host_name(std::string host_name){ - this->host_name = host_name; -} - -void OpenThreadComponent::set_mdns(esphome::mdns::MDNSComponent *mdns) { - this->mdns_ = mdns; + uint8_t *ptr = new uint8_t[size]; + if (ptr) { + this->_memory_pool.emplace_back(std::unique_ptr(ptr)); + } + return ptr; } +void OpenThreadComponent::set_host_name(std::string host_name) { this->host_name = host_name; } +void OpenThreadComponent::set_mdns(esphome::mdns::MDNSComponent *mdns) { this->mdns_ = mdns; } } // namespace openthread } // namespace esphome diff --git a/esphome/components/openthread/openthread.h b/esphome/components/openthread/openthread.h index e16348b234..c529a7dbc8 100644 --- a/esphome/components/openthread/openthread.h +++ b/esphome/components/openthread/openthread.h @@ -6,44 +6,58 @@ #include -#ifdef USE_ESP_IDF -#include "openthread_esp.h" -#endif - #include +#include namespace esphome { namespace openthread { +class OpenThreadLockGuard; + class OpenThreadComponent : public Component { - public: - OpenThreadComponent(); - ~OpenThreadComponent(); - void setup() override; - float get_setup_priority() const override { - return setup_priority::WIFI; - } + public: + OpenThreadComponent(); + ~OpenThreadComponent(); + void setup() override; + float get_setup_priority() const override { return setup_priority::WIFI; } - void set_host_name(std::string host_name); - void set_mdns(esphome::mdns::MDNSComponent *mdns); - bool is_connected(); - network::IPAddresses get_ip_addresses(); - std::optional get_omr_address(); - void ot_main(); - protected: - void srp_setup(); - std::optional get_omr_address(std::optional &lock); - std::string host_name; - void *pool_alloc(size_t size); + void set_host_name(std::string host_name); + void set_mdns(esphome::mdns::MDNSComponent *mdns); + bool is_connected(); + network::IPAddresses get_ip_addresses(); + std::optional get_omr_address(); + void ot_main(); - private: - esphome::mdns::MDNSComponent *mdns_{nullptr}; - std::vector mdns_services_; - std::vector> _memory_pool; + protected: + void srp_setup(); + std::optional get_omr_address(std::optional &lock); + std::string host_name; + void *pool_alloc(size_t size); + private: + // void platform_init(); + + esphome::mdns::MDNSComponent *mdns_{nullptr}; + std::vector mdns_services_; + std::vector> _memory_pool; }; extern OpenThreadComponent *global_openthread_component; +class OpenThreadLockGuard { + public: + static std::optional TryAcquire(int delay); + static std::optional Acquire(); + ~OpenThreadLockGuard(); + + // Returns the global openthread instance guarded by this lock + otInstance *get_instance(); + + private: + // Use a private constructor in order to force thehandling + // of acquisition failure + OpenThreadLockGuard() {} +}; + } // namespace openthread } // namespace esphome diff --git a/esphome/components/openthread/openthread_esp.cpp b/esphome/components/openthread/openthread_esp.cpp index e69de29bb2..abc10330e8 100644 --- a/esphome/components/openthread/openthread_esp.cpp +++ b/esphome/components/openthread/openthread_esp.cpp @@ -0,0 +1,172 @@ +// #ifdef USE_ESP_IDF +#include "openthread_esp.h" +#include "openthread.h" +#include + +#include "esp_openthread.h" +#include "esp_openthread_lock.h" +#include "esp_log.h" + +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" +#include "esp_task_wdt.h" + +#include "esp_openthread_cli.h" +#include "esp_openthread_netif_glue.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_vfs_eventfd.h" +#include "esp_netif.h" +#include "esp_netif_types.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#define TAG "openthread" + +namespace esphome { +namespace openthread { + +void OpenThreadComponent::setup() { + ESP_LOGI("openthread", "Setting up OpenThread..."); + // Used eventfds: + // * netif + // * ot task queue + // * radio driver + // TODO: Does anything else in esphome set this up? + esp_vfs_eventfd_config_t eventfd_config = { + .max_fds = 3, + }; + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); + + xTaskCreate( + [](void *arg) { + static_cast(arg)->ot_main(); + vTaskDelete(NULL); + }, + "ot_main", 10240, this, 5, nullptr); + + xTaskCreate( + [](void *arg) { + static_cast(arg)->srp_setup(); + vTaskDelete(NULL); + }, + "ot_srp_setup", 10240, this, 5, nullptr); + + ESP_LOGI("openthread", "OpenThread started"); +} + +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; +} + +void OpenThreadComponent::ot_main() { + esp_openthread_platform_config_t config = { + .radio_config = + { + .radio_mode = RADIO_MODE_NATIVE, + .radio_uart_config = {}, + }, + .host_config = + { + // There is a conflict between esphome's logger which also + // claims the usb serial jtag device. + // .host_connection_mode = HOST_CONNECTION_MODE_CLI_USB, + // .host_usb_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(), + }, + .port_config = + { + .storage_partition_name = "nvs", + .netif_queue_size = 10, + .task_queue_size = 10, + }, + }; + + // 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 + ESP_LOGI(TAG, "Activating dataset..."); + otOperationalDatasetTlvs dataset; + otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset); + ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL)); + + esp_openthread_launch_mainloop(); + + // Clean up + esp_openthread_netif_glue_deinit(); + esp_netif_destroy(openthread_netif); + + esp_vfs_eventfd_unregister(); +} + +// TODO: This gets used by mqtt in order to register the device's IP. Likely it doesn't +// make sense to return thread-local addresses, since they can't be reached from outside the thread network. +// It could make more sense to return the off-mesh-routable address instead. +network::IPAddresses OpenThreadComponent::get_ip_addresses() { + network::IPAddresses addresses; + struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES]; + uint8_t count = 0; + esp_netif_t *netif = esp_netif_get_default_netif(); + count = esp_netif_get_all_ip6(netif, if_ip6s); + assert(count <= CONFIG_LWIP_IPV6_NUM_ADDRESSES); + for (int i = 0; i < count; i++) { + addresses[i + 1] = network::IPAddress(&if_ip6s[i]); + } + return addresses; +} + +std::optional OpenThreadLockGuard::TryAcquire(int delay) { + if (esp_openthread_lock_acquire(delay)) { + return OpenThreadLockGuard(); + } + return {}; +} + +std::optional OpenThreadLockGuard::Acquire() { + while (!esp_openthread_lock_acquire(100)) { + esp_task_wdt_reset(); + } + return OpenThreadLockGuard(); +} + +otInstance *OpenThreadLockGuard::get_instance() { return esp_openthread_get_instance(); } + +OpenThreadLockGuard::~OpenThreadLockGuard() { esp_openthread_lock_release(); } + +} // namespace openthread +} // namespace esphome +// #endif diff --git a/esphome/components/openthread/openthread_esp.h b/esphome/components/openthread/openthread_esp.h index 42dde5cdab..6f70f09bee 100644 --- a/esphome/components/openthread/openthread_esp.h +++ b/esphome/components/openthread/openthread_esp.h @@ -1,46 +1 @@ #pragma once - -#include -#include "esp_openthread.h" -#include "esp_openthread_lock.h" -#include "esp_log.h" - -#include "esphome/core/helpers.h" -#include "esphome/core/log.h" -#include "esp_task_wdt.h" - -#include "esp_openthread_cli.h" -#include "esp_openthread_netif_glue.h" -#include "esp_event.h" -#include "nvs_flash.h" -#include "esp_vfs_eventfd.h" -#include "esp_netif.h" -#include "esp_netif_types.h" -#include "esp_err.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -namespace esphome { -namespace openthread { - -class EspOpenThreadLockGuard { - public: - static std::optional TryAcquire(TickType_t delay) { - if (esp_openthread_lock_acquire(delay)) { - return EspOpenThreadLockGuard(); - } - return {}; - } - static std::optional Acquire() { - while (!esp_openthread_lock_acquire(100)) { - esp_task_wdt_reset(); - } - return EspOpenThreadLockGuard(); - } - ~EspOpenThreadLockGuard() { esp_openthread_lock_release(); } - private: - // Use a private constructor in order to force thehandling - // of acquisition failure - EspOpenThreadLockGuard() {} -}; -} -}