66#include " integration/settings_controller.h"
77
88#include < algorithm>
9+ #include < atomic>
910#include < chrono>
10- #include < condition_variable>
1111#include < cstdint>
1212#include < cstdio>
1313#include < cstring>
1414#include < ctime>
1515#include < fstream>
1616#include < functional>
17- #include < mutex>
18- #include < queue>
17+ #include < new>
1918#include < sstream>
2019#include < string>
21- #include < thread>
2220#include < vector>
2321
22+ #if !defined(ESP_PLATFORM)
23+ # include < condition_variable>
24+ # include < mutex>
25+ # include < queue>
26+ # include < thread>
27+ #endif
28+
2429#include " ../app_trace.h"
2530#include " hal/hal.h"
2631#include " settings_core/app_cfg.h"
3540# include " diag/diag.h"
3641# include " esp_err.h"
3742# include " esp_wifi.h"
43+ # include " freertos/FreeRTOS.h"
44+ # include " freertos/queue.h"
45+ # include " freertos/semphr.h"
46+ # include " freertos/task.h"
3847# include " net_sntp/net_sntp.h"
3948# include " ota_update/ota_update.h"
4049#endif
@@ -54,6 +63,12 @@ namespace custom::integration
5463
5564 constexpr const char * kDefaultUpdateBaseUrl = " https://updates.m5stack.com/tab5" ;
5665
66+ #if defined(ESP_PLATFORM)
67+ constexpr UBaseType_t kTaskQueueLength = 8U ;
68+ constexpr uint32_t kWorkerTaskStackSize = 4096U ;
69+ constexpr UBaseType_t kWorkerTaskPriority = 5U ;
70+ #endif
71+
5772 std::string timestamp_string ()
5873 {
5974 std::time_t now = std::time (nullptr );
@@ -115,7 +130,11 @@ namespace custom::integration
115130 std::string current_variant_id () const ;
116131
117132 void enqueue_task (std::function<void ()> task);
133+ #if defined(ESP_PLATFORM)
134+ static void WorkerTaskEntry (void * arg);
135+ #else
118136 void worker_loop ();
137+ #endif
119138 void refresh_all_connections ();
120139 void perform_connection_test (const std::string& tester_id);
121140 void test_wifi_connection ();
@@ -148,12 +167,19 @@ namespace custom::integration
148167 bool diag_running_ = false ;
149168#endif
150169
170+ std::atomic<bool > running_{false };
171+ #if defined(ESP_PLATFORM)
172+ TaskHandle_t worker_task_ = nullptr ;
173+ QueueHandle_t task_queue_ = nullptr ;
174+ SemaphoreHandle_t refresh_semaphore_ = nullptr ;
175+ std::atomic<bool > worker_active_{false };
176+ #else
151177 std::thread worker_thread_;
152178 std::mutex mutex_;
153179 std::condition_variable cv_;
154- bool running_ = false ;
155180 std::queue<std::function<void ()>> tasks_;
156181 std::chrono::steady_clock::time_point next_refresh_;
182+ #endif
157183
158184 std::string backup_path_;
159185 std::string logs_path_;
@@ -171,22 +197,107 @@ namespace custom::integration
171197 logs_path_ = " m5tab5_logs.txt" ;
172198#endif
173199
174- running_ = true ;
200+ #if defined(ESP_PLATFORM)
201+ running_.store (true );
202+ refresh_semaphore_ = xSemaphoreCreateBinary ();
203+ if (refresh_semaphore_ == nullptr )
204+ {
205+ APP_LOG_ERROR (kTag , " Failed to create refresh semaphore" );
206+ running_.store (false );
207+ }
208+
209+ if (running_.load ())
210+ {
211+ task_queue_ = xQueueCreate (kTaskQueueLength , sizeof (std::function<void ()>*));
212+ if (task_queue_ == nullptr )
213+ {
214+ APP_LOG_ERROR (kTag , " Failed to create task queue" );
215+ running_.store (false );
216+ }
217+ }
218+
219+ if (running_.load ())
220+ {
221+ if (xTaskCreate (&SettingsController::Impl::WorkerTaskEntry,
222+ " settings_ctrl" ,
223+ kWorkerTaskStackSize ,
224+ this ,
225+ kWorkerTaskPriority ,
226+ &worker_task_)
227+ == pdPASS)
228+ {
229+ worker_active_.store (true );
230+ }
231+ else
232+ {
233+ APP_LOG_ERROR (kTag , " Failed to start worker task" );
234+ worker_task_ = nullptr ;
235+ running_.store (false );
236+ }
237+ }
238+
239+ if (!running_.load ())
240+ {
241+ if (task_queue_ != nullptr )
242+ {
243+ vQueueDelete (task_queue_);
244+ task_queue_ = nullptr ;
245+ }
246+ if (refresh_semaphore_ != nullptr )
247+ {
248+ vSemaphoreDelete (refresh_semaphore_);
249+ refresh_semaphore_ = nullptr ;
250+ }
251+ worker_active_.store (false );
252+ }
253+ #else
254+ running_.store (true );
175255 next_refresh_ = std::chrono::steady_clock::now () + kRefreshInterval ;
176256 worker_thread_ = std::thread (&SettingsController::Impl::worker_loop, this );
257+ #endif
177258 }
178259
179260 SettingsController::Impl::~Impl ()
180261 {
262+ #if defined(ESP_PLATFORM)
263+ running_.store (false );
264+ if (refresh_semaphore_ != nullptr )
265+ {
266+ xSemaphoreGive (refresh_semaphore_);
267+ }
268+
269+ while (worker_active_.load ())
270+ {
271+ vTaskDelay (pdMS_TO_TICKS (10 ));
272+ }
273+
274+ if (task_queue_ != nullptr )
275+ {
276+ std::function<void ()>* pending = nullptr ;
277+ while (xQueueReceive (task_queue_, &pending, 0 ) == pdTRUE)
278+ {
279+ delete pending;
280+ }
281+ vQueueDelete (task_queue_);
282+ task_queue_ = nullptr ;
283+ }
284+
285+ if (refresh_semaphore_ != nullptr )
286+ {
287+ vSemaphoreDelete (refresh_semaphore_);
288+ refresh_semaphore_ = nullptr ;
289+ }
290+ #else
181291 {
182292 std::lock_guard<std::mutex> lock (mutex_);
183- running_ = false ;
293+ running_. store ( false ) ;
184294 }
185295 cv_.notify_all ();
186296 if (worker_thread_.joinable ())
187297 {
188298 worker_thread_.join ();
189299 }
300+ #endif
190301
191302#if defined(ESP_PLATFORM)
192303 if (diag_running_)
@@ -637,17 +748,44 @@ namespace custom::integration
637748
638749 void SettingsController::Impl::enqueue_task (std::function<void ()> task)
639750 {
751+ #if defined(ESP_PLATFORM)
752+ if (!running_.load () || task_queue_ == nullptr )
753+ {
754+ return ;
755+ }
756+
757+ auto * heap_task = new (std::nothrow) std::function<void ()>(std::move (task));
758+ if (heap_task == nullptr )
759+ {
760+ APP_LOG_WARN (kTag , " Failed to allocate task" );
761+ return ;
762+ }
763+
764+ if (xQueueSend (task_queue_, &heap_task, 0 ) != pdPASS)
765+ {
766+ APP_LOG_WARN (kTag , " Task queue full" );
767+ delete heap_task;
768+ return ;
769+ }
770+
771+ if (refresh_semaphore_ != nullptr )
772+ {
773+ xSemaphoreGive (refresh_semaphore_);
774+ }
775+ #else
640776 {
641777 std::lock_guard<std::mutex> lock (mutex_);
642778 tasks_.push (std::move (task));
643779 }
644780 cv_.notify_all ();
781+ #endif
645782 }
646783
784+ #if !defined(ESP_PLATFORM)
647785 void SettingsController::Impl::worker_loop ()
648786 {
649787 std::unique_lock<std::mutex> lock (mutex_);
650- while (running_)
788+ while (running_. load () )
651789 {
652790 if (!tasks_.empty ())
653791 {
@@ -670,9 +808,74 @@ namespace custom::integration
670808 continue ;
671809 }
672810
673- cv_.wait_until (lock, next_refresh_, [this ]() { return !running_ || !tasks_.empty (); });
811+ cv_.wait_until (
812+ lock, next_refresh_, [this ]() { return !running_.load () || !tasks_.empty (); });
813+ }
814+ }
815+ #else
816+ void SettingsController::Impl::WorkerTaskEntry (void * arg)
817+ {
818+ auto * self = static_cast <SettingsController::Impl*>(arg);
819+ if (self == nullptr )
820+ {
821+ vTaskDelete (nullptr );
822+ return ;
823+ }
824+
825+ if (self->task_queue_ == nullptr || self->refresh_semaphore_ == nullptr )
826+ {
827+ self->running_ .store (false );
828+ self->worker_active_ .store (false );
829+ self->worker_task_ = nullptr ;
830+ vTaskDelete (nullptr );
831+ return ;
832+ }
833+
834+ self->worker_active_ .store (true );
835+
836+ const uint32_t refresh_ms = static_cast <uint32_t >(
837+ std::chrono::duration_cast<std::chrono::milliseconds>(kRefreshInterval ).count ());
838+ const TickType_t refresh_ticks = std::max<TickType_t>(1 , pdMS_TO_TICKS (refresh_ms));
839+
840+ while (self->running_ .load ())
841+ {
842+ std::function<void ()>* task_ptr = nullptr ;
843+ while (self->running_ .load ()
844+ && xQueueReceive (self->task_queue_ , &task_ptr, 0 ) == pdTRUE)
845+ {
846+ if (task_ptr == nullptr )
847+ {
848+ self->running_ .store (false );
849+ break ;
850+ }
851+
852+ (*task_ptr)();
853+ delete task_ptr;
854+ task_ptr = nullptr ;
855+ }
856+
857+ if (!self->running_ .load ())
858+ {
859+ break ;
860+ }
861+
862+ if (xSemaphoreTake (self->refresh_semaphore_ , refresh_ticks) == pdFALSE)
863+ {
864+ self->refresh_all_connections ();
865+ }
866+ }
867+
868+ std::function<void ()>* leftover = nullptr ;
869+ while (xQueueReceive (self->task_queue_ , &leftover, 0 ) == pdTRUE)
870+ {
871+ delete leftover;
674872 }
873+
874+ self->worker_active_ .store (false );
875+ self->worker_task_ = nullptr ;
876+ vTaskDelete (nullptr );
675877 }
878+ #endif
676879
677880 void SettingsController::Impl::refresh_all_connections ()
678881 {
0 commit comments