refactoring files

Dieser Commit ist enthalten in:
tom committed 2026-10-17 19:38:30 +02:00
1 Ursprung 58dcdbdcb3
Commit ab51ed746a
15 Dateien geändert
+945 -292

Keine Dateien entsprechen Ihrer Suche

+70 -19
Datei anzeigen
@@ -1,57 +1,108 @@
/**
* @file led.cpp
* @brief Thread-safe hardware LED controller task implementation with profile selection
* @author OM Tom (OE3TKT)
*
* @license SPDX-License-Identifier: MIT
* @copyright Copyright (c) 2026 OM Tom (OE3TKT)
* For the full license terms, see the LICENSE file in the project root.
*/
#include "led.hpp"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "config.hpp"
#include <climits> // Enforces definitions of macro bounds like ULONG_MAX
// Initialize the static log tag
const char* LedController::TAG = "LED";
LedController::LedController(gpio_num_t gpioPin) : m_gpioPin(gpioPin) {
// Hardware initialization inside the constructor guarantees safe state upon creation
// Core default profile initialized using standard configurations
m_currentProfile.intervalMs = static_cast<uint32_t>(Config::BLINK_INTERVAL_MS);
m_currentProfile.pulseWidthMs = 30;
// Instantiate a lightweight mutex token to guarantee strict isolation
m_mutexHandle = xSemaphoreCreateMutex();
if (m_mutexHandle == nullptr) {
ESP_LOGE(TAG, "Fatal: Failed to allocate mutex tracking resources.");
}
gpio_reset_pin(m_gpioPin);
gpio_set_direction(m_gpioPin, GPIO_MODE_OUTPUT);
ESP_LOGI(TAG, "Hardware initialized on GPIO %d.", m_gpioPin);
}
LedController::~LedController() {
if (m_mutexHandle != nullptr) {
vSemaphoreDelete(m_mutexHandle);
}
}
void LedController::startTask(uint32_t priority, BaseType_t coreId) {
// Pass 'this' (the pointer to the current instance) as the task parameter
xTaskCreatePinnedToCore(
LedController::taskTrampoline,
"LEDTask",
3072,
this,
priority,
nullptr,
&m_taskHandle,
coreId
);
}
void LedController::updateProfile(const BlinkProfile& profile) {
if (profile.pulseWidthMs >= profile.intervalMs) {
ESP_LOGE(TAG, "Profile rejection: pulseWidthMs must be smaller than intervalMs!");
return;
}
// Safely block writing operations across separate core domains until token release
if (m_mutexHandle != nullptr && xSemaphoreTake(m_mutexHandle, portMAX_DELAY) == pdTRUE) {
m_currentProfile = profile;
xSemaphoreGive(m_mutexHandle);
}
// Interrupt the active blocking state of the worker thread instantly
if (m_taskHandle != nullptr) {
xTaskNotifyGive(m_taskHandle);
}
}
void LedController::taskTrampoline(void* pvParameters) {
// Cast the raw object pointer back to our class instance
auto* instance = static_cast<LedController*>(pvParameters);
if (instance != nullptr) {
instance->run();
}
// Safety fallback: FreeRTOS tasks must never return natively
vTaskDelete(nullptr);
}
void LedController::run() {
ESP_LOGI(TAG, "FreeRTOS instance task successfully started on Core %d.", xPortGetCoreID());
// Define the fixed ON-time as a local constant
constexpr uint32_t led_on_ms = 30;
// Compile-time assertion to ensure the interval is always larger than the flash duration
static_assert(Config::BLINK_INTERVAL_MS > led_on_ms, "Global blink interval must be greater than 30ms!");
while (true) {
gpio_set_level(m_gpioPin, 1); // LED on (High)
vTaskDelay(pdMS_TO_TICKS(led_on_ms)); // 30ms pulse width
BlinkProfile active = {};
gpio_set_level(m_gpioPin, 0); // LED off (Low)
vTaskDelay(pdMS_TO_TICKS(Config::BLINK_INTERVAL_MS - led_on_ms)); // typ. 1970ms period low time
// Extract a thread-safe snapshot configuration boundary under lock condition
if (m_mutexHandle != nullptr && xSemaphoreTake(m_mutexHandle, portMAX_DELAY) == pdTRUE) {
active = m_currentProfile;
xSemaphoreGive(m_mutexHandle);
} else {
// Safe hardware fallback calculation loops
active.intervalMs = 1000;
active.pulseWidthMs = 30;
}
if (active.pulseWidthMs == 0) active.pulseWidthMs = 1;
if (active.pulseWidthMs >= active.intervalMs) active.intervalMs = active.pulseWidthMs + 10;
// 1. High pulse execution phase
gpio_set_level(m_gpioPin, 1);
vTaskDelay(pdMS_TO_TICKS(active.pulseWidthMs));
gpio_set_level(m_gpioPin, 0);
// 2. Dynamic evaluation of low-state processing window
uint32_t remainingLowTimeMs = active.intervalMs - active.pulseWidthMs;
// Non-polling block sleep that awakes immediately upon configuration adjustments
xTaskNotifyWait(0x00, ULONG_MAX, nullptr, pdMS_TO_TICKS(remainingLowTimeMs));
}
}