Files
OpenIris-ESPIDF/components/LEDManager/LEDManager/LEDManager.cpp
PhosphorosVR 2346d0ec6c -Add configurable PWM frequency and duty cycle for external LED control
-Reworked Kconfig menu structure for better organization
2025-08-08 21:26:06 +02:00

175 lines
4.9 KiB
C++

#include "LEDManager.hpp"
const char *LED_MANAGER_TAG = "[LED_MANAGER]";
ledStateMap_t LEDManager::ledStateMap = {
{
LEDStates_e::LedStateNone,
{
false,
false,
{{LED_OFF, 1000}},
},
},
{
LEDStates_e::LedStateStreaming,
{
false,
true,
{{LED_ON, 1000}},
},
},
{
LEDStates_e::LedStateStoppedStreaming,
{
false,
true,
{{LED_OFF, 1000}},
},
},
{
LEDStates_e::CameraError,
{
true,
true,
{{{LED_ON, 300}, {LED_OFF, 300}, {LED_ON, 300}, {LED_OFF, 300}}},
},
},
{
LEDStates_e::WiFiStateConnecting,
{
false,
true,
{{LED_ON, 400}, {LED_OFF, 400}},
},
},
{
LEDStates_e::WiFiStateConnected,
{
false,
false,
{
{LED_ON, 200}, {LED_OFF, 200}, {LED_ON, 200}, {LED_OFF, 200}, {LED_ON, 200}, {LED_OFF, 200},
{LED_ON, 200}, {LED_OFF, 200}, {LED_ON, 200}, {LED_OFF, 200}
},
},
},
{
LEDStates_e::WiFiStateError,
{
true,
true,
{{LED_ON, 200}, {LED_OFF, 100}, {LED_ON, 500}, {LED_OFF, 100}, {LED_ON, 200}},
},
},
};
LEDManager::LEDManager(gpio_num_t pin, gpio_num_t illumninator_led_pin,
QueueHandle_t ledStateQueue) : blink_led_pin(pin),
illumninator_led_pin(illumninator_led_pin),
ledStateQueue(ledStateQueue),
currentState(LEDStates_e::LedStateNone) {
}
void LEDManager::setup() {
ESP_LOGD(LED_MANAGER_TAG, "Setting up status led.");
gpio_reset_pin(blink_led_pin);
/* Set the GPIO as a push/pull output */
gpio_set_direction(blink_led_pin, GPIO_MODE_OUTPUT);
this->toggleLED(LED_OFF);
#ifdef CONFIG_LED_EXTERNAL_CONTROL
ESP_LOGD(LED_MANAGER_TAG, "Setting up illuminator led.");
const int freq = CONFIG_LED_EXTERNAL_PWM_FREQ;
const auto resolution = LEDC_TIMER_8_BIT;
const int dutyCycle = (CONFIG_LED_EXTERNAL_PWM_DUTY_CYCLE * 255) / 100;
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = resolution,
.timer_num = LEDC_TIMER_0,
.freq_hz = freq,
.clk_cfg = LEDC_AUTO_CLK
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
ledc_channel_config_t ledc_channel = {
.gpio_num = this->illumninator_led_pin,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LEDC_CHANNEL_0,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER_0,
.duty = dutyCycle,
.hpoint = 0
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
#endif
ESP_LOGD(LED_MANAGER_TAG, "Done.");
}
void LEDManager::handleLED() {
if (!this->finishedPattern) {
displayCurrentPattern();
return;
}
if (xQueueReceive(this->ledStateQueue, &buffer, 10)) {
this->updateState(buffer);
} else {
// we've finished displaying the pattern, so let's check if it's repeatable and if so - reset it
if (ledStateMap[this->currentState].isRepeatable || ledStateMap[this->currentState].isError) {
this->currentPatternIndex = 0;
this->finishedPattern = false;
}
}
}
void LEDManager::displayCurrentPattern() {
auto [state, delayTime] = ledStateMap[this->currentState].patterns[this->currentPatternIndex];
this->toggleLED(state);
this->timeToDelayFor = delayTime;
if (this->currentPatternIndex < ledStateMap[this->currentState].patterns.size() - 1)
this->currentPatternIndex++;
else {
this->finishedPattern = true;
this->toggleLED(LED_OFF);
}
}
void LEDManager::updateState(const LEDStates_e newState) {
// we should change the displayed state
// only if we finished displaying the current one - which is handled by the task
// if the new state is not the same as the current one
// and if can actually display the state
// if we've got an error state - that's it, we'll just keep repeating it indefinitely
if (ledStateMap[this->currentState].isError)
return;
if (newState == this->currentState)
return;
if (ledStateMap.contains(newState)) {
this->currentState = newState;
this->currentPatternIndex = 0;
this->finishedPattern = false;
}
}
void LEDManager::toggleLED(const bool state) const {
gpio_set_level(blink_led_pin, state);
}
void HandleLEDDisplayTask(void *pvParameter) {
auto *ledManager = static_cast<LEDManager *>(pvParameter);
while (true) {
ledManager->handleLED();
vTaskDelay(ledManager->getTimeToDelayFor());
}
}