mirror of
https://github.com/esphome/esphome.git
synced 2026-08-28 16:53:28 +00:00
[openthread] fix shutdown (#16332)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Jonathan Swoboda
Claude Sonnet 4.6
parent
a8c8827a5b
commit
c3c69c730c
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <openthread/cli.h>
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/logging.h>
|
||||
#include <openthread/netdata.h>
|
||||
#include <openthread/tasklet.h>
|
||||
@@ -229,26 +230,43 @@ void *OpenThreadSrpComponent::pool_alloc_(size_t size) {
|
||||
void OpenThreadSrpComponent::set_mdns(esphome::mdns::MDNSComponent *mdns) { this->mdns_ = mdns; }
|
||||
|
||||
bool OpenThreadComponent::teardown() {
|
||||
if (!this->teardown_started_) {
|
||||
this->teardown_started_ = true;
|
||||
ESP_LOGD(TAG, "Clear Srp");
|
||||
auto lock = InstanceLock::try_acquire(100);
|
||||
if (!lock) {
|
||||
ESP_LOGW(TAG, "Failed to acquire OpenThread lock during teardown, leaking memory");
|
||||
return true;
|
||||
}
|
||||
otInstance *instance = lock.get_instance();
|
||||
otSrpClientClearHostAndServices(instance);
|
||||
otSrpClientBuffersFreeAllServices(instance);
|
||||
global_openthread_component = nullptr;
|
||||
ESP_LOGD(TAG, "Exit main loop ");
|
||||
int error = this->openthread_stop_();
|
||||
if (error != 0) {
|
||||
ESP_LOGW(TAG, "Failed attempt to stop main loop %d", error);
|
||||
this->teardown_complete_ = true;
|
||||
}
|
||||
switch (this->teardown_stage_) {
|
||||
case TeardownStage::TEARDOWN_STAGE_NOT_STARTED: {
|
||||
auto lock = InstanceLock::try_acquire(100);
|
||||
if (!lock) {
|
||||
// Try again on next teardown loop
|
||||
ESP_LOGV(TAG, "Failed to acquire OpenThread lock during teardown");
|
||||
return false;
|
||||
}
|
||||
// Start tearing down
|
||||
this->teardown_stage_ = TeardownStage::TEARDOWN_STAGE_STOP_IN_PROCESS;
|
||||
ESP_LOGV(TAG, "Clear SRP");
|
||||
otInstance *instance = lock.get_instance();
|
||||
otSrpClientClearHostAndServices(instance);
|
||||
otSrpClientBuffersFreeAllServices(instance);
|
||||
if (otThreadSetEnabled(instance, false) != OT_ERROR_NONE) {
|
||||
ESP_LOGW(TAG, "Failed to disable Thread during teardown");
|
||||
}
|
||||
if (otIp6SetEnabled(instance, false) != OT_ERROR_NONE) {
|
||||
ESP_LOGW(TAG, "Failed to disable IPv6 during teardown");
|
||||
}
|
||||
// Stop OpenThread
|
||||
global_openthread_component = nullptr;
|
||||
ESP_LOGV(TAG, "Stop OpenThread");
|
||||
int error = this->openthread_stop_();
|
||||
if (error != 0) {
|
||||
ESP_LOGW(TAG, "Failed attempt to stop OpenThread %d", error);
|
||||
this->teardown_stage_ = TeardownStage::TEARDOWN_STAGE_COMPLETED;
|
||||
}
|
||||
} break;
|
||||
case TeardownStage::TEARDOWN_STAGE_STOP_IN_PROCESS:
|
||||
// Waiting on OpenThread stop
|
||||
break;
|
||||
case TeardownStage::TEARDOWN_STAGE_COMPLETED:
|
||||
ESP_LOGV(TAG, "OpenThreadComponent Teardown Complete");
|
||||
break;
|
||||
}
|
||||
return this->teardown_complete_;
|
||||
return this->teardown_stage_ == TeardownStage::TEARDOWN_STAGE_COMPLETED;
|
||||
}
|
||||
|
||||
void OpenThreadComponent::on_factory_reset(std::function<void()> callback) {
|
||||
|
||||
@@ -19,6 +19,12 @@ namespace esphome::openthread {
|
||||
|
||||
class InstanceLock;
|
||||
|
||||
enum class TeardownStage : uint8_t {
|
||||
TEARDOWN_STAGE_NOT_STARTED = 0,
|
||||
TEARDOWN_STAGE_STOP_IN_PROCESS,
|
||||
TEARDOWN_STAGE_COMPLETED,
|
||||
};
|
||||
|
||||
template<typename... Ts> class OpenThreadComponentPollPeriodAction;
|
||||
|
||||
class OpenThreadComponent final : public Component {
|
||||
@@ -71,9 +77,8 @@ class OpenThreadComponent final : public Component {
|
||||
#endif
|
||||
std::optional<int8_t> output_power_{};
|
||||
std::atomic<bool> lock_initialized_{false};
|
||||
bool teardown_started_{false};
|
||||
bool teardown_complete_{false};
|
||||
bool connected_{false};
|
||||
std::atomic<TeardownStage> teardown_stage_{TeardownStage::TEARDOWN_STAGE_NOT_STARTED};
|
||||
std::atomic<bool> connected_{false};
|
||||
|
||||
private:
|
||||
// Stores a pointer to a string literal (static storage duration).
|
||||
|
||||
@@ -168,7 +168,7 @@ void OpenThreadComponent::ot_main() {
|
||||
esp_netif_destroy(openthread_netif);
|
||||
|
||||
esp_vfs_eventfd_unregister();
|
||||
this->teardown_complete_ = true;
|
||||
this->teardown_stage_ = TeardownStage::TEARDOWN_STAGE_COMPLETED;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,10 +90,8 @@ void OpenThreadComponent::ot_main() {}
|
||||
otInstance *OpenThreadComponent::get_openthread_instance_() { return openthread_get_default_instance(); }
|
||||
|
||||
int OpenThreadComponent::openthread_stop_() {
|
||||
// OT stack is intentionally left running — no Zephyr stop API. The state callback stays
|
||||
// registered but is safe (null-checks global_openthread_component). nRF52840 never
|
||||
// re-enters setup() after teardown so this is functionally correct.
|
||||
this->teardown_complete_ = true;
|
||||
// Zephyr has no stack-stop API, so stop is synchronous here; mark complete immediately.
|
||||
this->teardown_stage_ = TeardownStage::TEARDOWN_STAGE_COMPLETED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user