Skip to content

Commit ffc0854

Browse files
committed
refactor(settings): swap worker to freertos
1 parent 1fc10d5 commit ffc0854

1 file changed

Lines changed: 212 additions & 9 deletions

File tree

custom/integration/settings_controller.cpp

Lines changed: 212 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,26 @@
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"
@@ -35,6 +40,10 @@
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

Comments
 (0)