GCC Code Coverage Report


Directory: ./
File: components/parking_system/src/events/FreeRtosEventBus.cpp
Date: 2025-12-16 19:41:02
Exec Total Coverage
Lines: 0 98 0.0%
Functions: 0 12 0.0%
Branches: 0 80 0.0%

Line Branch Exec Source
1 #include "FreeRtosEventBus.h"
2 #include "esp_log.h"
3 #include "esp_timer.h"
4
5 static const char* TAG = "FreeRtosEventBus";
6
7 ✗ FreeRtosEventBus::FreeRtosEventBus(size_t queueSize) {
8 ✗ m_queue = xQueueCreate(queueSize, sizeof(Event));
9 ✗ if (!m_queue) {
10 ✗ ESP_LOGE(TAG, "Failed to create event queue");
11 }
12
13 ✗ m_mutex = xSemaphoreCreateMutex();
14 ✗ if (!m_mutex) {
15 ✗ ESP_LOGE(TAG, "Failed to create mutex");
16 }
17
18 ✗ ESP_LOGI(TAG, "EventBus created (queue size: %d)", queueSize);
19 ✗ }
20
21 ✗ FreeRtosEventBus::~FreeRtosEventBus() {
22 // Stop event loop first to prevent access to deleted resources
23 ✗ stopEventLoop();
24
25 ✗ if (m_queue) {
26 ✗ vQueueDelete(m_queue);
27 }
28 ✗ if (m_mutex) {
29 ✗ vSemaphoreDelete(m_mutex);
30 }
31 ✗ }
32
33 ✗ void FreeRtosEventBus::subscribe(EventType type, std::function<void(const Event&)> handler) {
34 ✗ if (xSemaphoreTake(m_mutex, portMAX_DELAY) == pdTRUE) {
35 ✗ m_subscribers[type].push_back(std::move(handler));
36 ✗ ESP_LOGI(TAG, "Subscriber added for event: %s", eventTypeToString(type));
37 ✗ xSemaphoreGive(m_mutex);
38 }
39 ✗ }
40
41 ✗ void FreeRtosEventBus::publish(const Event& event) {
42 ✗ if (!m_queue) {
43 ✗ ESP_LOGE(TAG, "Cannot publish: queue not initialized");
44 ✗ return;
45 }
46
47 // Add timestamp if not set
48 ✗ Event timestampedEvent = event;
49 ✗ if (timestampedEvent.timestamp == 0) {
50 ✗ timestampedEvent.timestamp = esp_timer_get_time();
51 }
52
53 ✗ if (xQueueSend(m_queue, &timestampedEvent, 0) != pdTRUE) {
54 ✗ ESP_LOGW(TAG, "Event queue full, dropping event: %s", eventTypeToString(event.type));
55 }
56 }
57
58 ✗ bool FreeRtosEventBus::publishFromISR(const Event& event) {
59 ✗ if (!m_queue) {
60 ✗ return false;
61 }
62
63 ✗ Event timestampedEvent = event;
64 ✗ if (timestampedEvent.timestamp == 0) {
65 ✗ timestampedEvent.timestamp = esp_timer_get_time();
66 }
67
68 ✗ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
69 ✗ BaseType_t result = xQueueSendFromISR(m_queue, &timestampedEvent, &xHigherPriorityTaskWoken);
70
71 ✗ if (xHigherPriorityTaskWoken == pdTRUE) {
72 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
73 }
74
75 ✗ return result == pdTRUE;
76 }
77
78 ✗ void FreeRtosEventBus::processAllPending() {
79 ✗ Event event;
80 ✗ while (xQueueReceive(m_queue, &event, 0) == pdTRUE) {
81 ✗ dispatchEvent(event);
82 }
83 ✗ }
84
85 ✗ bool FreeRtosEventBus::waitForEvent(Event& outEvent, uint32_t timeoutMs) {
86 ✗ if (!m_queue) {
87 ✗ return false;
88 }
89
90 ✗ TickType_t ticks = (timeoutMs == portMAX_DELAY) ? portMAX_DELAY : pdMS_TO_TICKS(timeoutMs);
91 ✗ if (xQueueReceive(m_queue, &outEvent, ticks) == pdTRUE) {
92 ✗ dispatchEvent(outEvent);
93 ✗ return true;
94 }
95
96 ✗ return false;
97 }
98
99 ✗ void FreeRtosEventBus::dispatchEvent(const Event& event) {
100 ✗ if (xSemaphoreTake(m_mutex, portMAX_DELAY) == pdTRUE) {
101 ✗ auto it = m_subscribers.find(event.type);
102 ✗ if (it != m_subscribers.end()) {
103 ✗ ESP_LOGD(TAG, "Dispatching event: %s to %d subscribers",
104 eventTypeToString(event.type), it->second.size());
105
106 ✗ for (const auto& handler : it->second) {
107 ✗ if (handler) {
108 ✗ handler(event);
109 }
110 }
111 }
112 ✗ xSemaphoreGive(m_mutex);
113 }
114 ✗ }
115
116 ✗ void FreeRtosEventBus::startEventLoop(uint32_t stackSize, UBaseType_t priority,
117 const char* taskName) {
118 ✗ if (m_eventLoopTask != nullptr) {
119 ✗ ESP_LOGW(TAG, "Event loop already running");
120 ✗ return;
121 }
122
123 ✗ m_stopRequested = false;
124
125 ✗ BaseType_t result = xTaskCreate(
126 eventLoopTask,
127 taskName,
128 stackSize,
129 this,
130 priority,
131 &m_eventLoopTask);
132
133 ✗ if (result == pdPASS) {
134 ✗ ESP_LOGI(TAG, "Event loop task started (stack: %lu, priority: %u)",
135 stackSize, priority);
136 } else {
137 ✗ ESP_LOGE(TAG, "Failed to create event loop task");
138 ✗ m_eventLoopTask = nullptr;
139 }
140 }
141
142 ✗ void FreeRtosEventBus::stopEventLoop() {
143 ✗ if (m_eventLoopTask == nullptr) {
144 ✗ ESP_LOGW(TAG, "Event loop not running");
145 ✗ return;
146 }
147
148 ✗ ESP_LOGI(TAG, "Stopping event loop...");
149 ✗ m_stopRequested = true;
150
151 // Give the task time to exit gracefully
152 ✗ vTaskDelay(pdMS_TO_TICKS(100));
153
154 // If still running, delete it
155 ✗ if (m_eventLoopTask != nullptr) {
156 ✗ vTaskDelete(m_eventLoopTask);
157 ✗ m_eventLoopTask = nullptr;
158 }
159
160 ✗ ESP_LOGI(TAG, "Event loop stopped");
161 }
162
163 ✗ bool FreeRtosEventBus::isEventLoopRunning() const {
164 ✗ return m_eventLoopTask != nullptr && !m_stopRequested;
165 }
166
167 ✗ void FreeRtosEventBus::eventLoopTask(void* pvParameters) {
168 ✗ auto* self = static_cast<FreeRtosEventBus*>(pvParameters);
169
170 ✗ ESP_LOGI(TAG, "Event loop task running");
171
172 ✗ Event event;
173 ✗ while (!self->m_stopRequested) {
174 // Wait for event with timeout to check stop flag periodically
175 ✗ if (self->waitForEvent(event, 100)) {
176 ✗ ESP_LOGD(TAG, "Event processed: %s", eventTypeToString(event.type));
177 }
178 }
179
180 ✗ ESP_LOGI(TAG, "Event loop task exiting");
181 ✗ self->m_eventLoopTask = nullptr;
182 ✗ vTaskDelete(nullptr);
183 ✗ }
184