#include #ifdef HAS_RGB_LED #define FASTLED_INTERNAL #include #endif #include "leds.h" #include "settings.h" #include "tag_db.h" #include "serialap.h" QueueHandle_t ledQueue; int maxledbrightness = 255; #ifdef HAS_RGB_LED QueueHandle_t rgbLedQueue; CRGB rgbIdleColor = CRGB::Green; uint16_t rgbIdlePeriod = 511; struct ledInstructionRGB { CRGB ledColor; uint16_t fadeTime; uint16_t length; bool reQueue = false; }; CRGB leds[1]; volatile bool rgbQueueFlush = false; #endif struct ledInstruction { uint16_t value; uint16_t fadeTime; uint16_t length; bool reQueue = false; }; #ifdef HAS_RGB_LED void addToRGBQueue(struct ledInstructionRGB* rgb, bool requeue) { rgb->reQueue = requeue; if (!rgbLedQueue) { delete rgb; return; } BaseType_t queuestatus = xQueueSend(rgbLedQueue, &rgb, 0); if (queuestatus == pdFALSE) { delete rgb; } } void addFadeColor(CRGB cname) { struct ledInstructionRGB* rgb = new struct ledInstructionRGB; rgb->ledColor = cname; rgb->fadeTime = 750; rgb->length = 0; addToRGBQueue(rgb, false); } void shortBlink(CRGB cname) { struct ledInstructionRGB* rgb = new struct ledInstructionRGB; rgb->ledColor = CRGB::Black; rgb->fadeTime = 0; rgb->length = 3; addToRGBQueue(rgb, false); rgb = new struct ledInstructionRGB; rgb->ledColor = cname; rgb->ledColor.maximizeBrightness(0x80); rgb->fadeTime = 0; rgb->length = 10; addToRGBQueue(rgb, false); rgb = new struct ledInstructionRGB; rgb->ledColor = CRGB::Black; rgb->fadeTime = 0; rgb->length = 3; addToRGBQueue(rgb, false); } void flushRGBQueue() { rgbQueueFlush = true; } void rgbIdle() { flushRGBQueue(); } void showColorPattern(CRGB colorone, CRGB colortwo, CRGB colorthree) { struct ledInstructionRGB* rgb; const int patternLengths[] = {600, 120, 200, 120, 200, 120}; const CRGB patternColors[] = {CRGB::Black, colorone, CRGB::Black, colortwo, CRGB::Black, colorthree}; while (xQueueReceive(rgbLedQueue, &rgb, 0) == pdPASS) { } for (int i = 0; i < sizeof(patternLengths) / sizeof(patternLengths[0]); i++) { rgb = new struct ledInstructionRGB; rgb->ledColor = patternColors[i]; rgb->fadeTime = 0; rgb->length = patternLengths[i]; addToRGBQueue(rgb, true); } } void showRGB() { FastLED.show(); } void rgbIdleStep() { static bool dirUp = true; static uint16_t step = 0; if (dirUp) { // up step++; if (step >= rgbIdlePeriod) { dirUp = false; } } else { // down step--; if (step == 0) { dirUp = true; } } CRGB newvalue = blend(CRGB::Black, (const CRGB&)rgbIdleColor, map(step, 0, rgbIdlePeriod, 0, 255)); if (newvalue != leds[0]) { leds[0] = newvalue; showRGB(); } } #endif void setBrightness(int brightness) { maxledbrightness = brightness; #ifdef HAS_LILYGO_TPANEL ledcWrite(1, config.tft); #else #ifdef HAS_TFT ledcWrite(6, config.tft); #endif #endif #ifdef HAS_RGB_LED FastLED.setBrightness(maxledbrightness); #endif } void updateBrightnessFromConfig() { int newbrightness = config.led; if (newbrightness != maxledbrightness) { setBrightness(newbrightness); } #ifdef HAS_LILYGO_TPANEL ledcWrite(1, config.tft); #else #ifdef HAS_TFT ledcWrite(6, config.tft); #endif #endif if (apInfo.state == AP_STATE_NORADIO) addFadeMono(config.led); } void addToMonoQueue(struct ledInstruction* mono) { BaseType_t queuestatus = xQueueSend(ledQueue, &mono, 0); if (queuestatus == pdFALSE) { delete mono; } } void addFadeMono(uint8_t value) { struct ledInstruction* mono = new struct ledInstruction; mono->value = value; mono->fadeTime = 750; mono->length = 0; addToMonoQueue(mono); } void showMono(uint8_t brightness) { #ifdef CONFIG_IDF_TARGET_ESP32 ledcWrite(7, 255 - gamma8[brightness]); #else ledcWrite(7, gamma8[brightness]); #endif } void quickBlink(uint8_t repeat) { for (int i = 0; i < repeat; i++) { struct ledInstruction* mono = new struct ledInstruction; #ifdef HAS_TFT mono->value = 255; #else mono->value = maxledbrightness; #endif mono->fadeTime = 120 / repeat; mono->length = 0; addToMonoQueue(mono); mono = new struct ledInstruction; mono->value = 0; mono->fadeTime = 120 / repeat; mono->length = 0; addToMonoQueue(mono); } } volatile uint16_t monoIdlePeriod = 900; void ledTask(void* parameter) { #ifdef HAS_RGB_LED FastLED.addLeds(leds, 1); // GRB ordering is typical leds[0] = CRGB::Blue; showRGB(); rgbLedQueue = xQueueCreate(30, sizeof(struct ledInstructionRGB*)); struct ledInstructionRGB* rgb = nullptr; // open with a nice RGB crossfade addFadeColor(CRGB::Red); addFadeColor(CRGB::Green); addFadeColor(CRGB::Blue); CRGB oldColor = CRGB::Black; uint16_t rgbInstructionFadeTime = 0; #endif ledQueue = xQueueCreate(30, sizeof(struct ledInstruction*)); ledcSetup(7, 5000, 8); if (FLASHER_LED != -1) { digitalWrite(FLASHER_LED, HIGH); pinMode(FLASHER_LED, OUTPUT); ledcAttachPin(FLASHER_LED, 7); } struct ledInstruction* monoled = nullptr; addFadeMono(0); #ifdef HAS_TFT addFadeMono(255); #else addFadeMono(maxledbrightness); #endif addFadeMono(0); uint8_t oldBrightness = 0; uint16_t monoInstructionFadeTime = 0; while (1) { #ifdef HAS_RGB_LED // handle RGB led instructions if (rgb == nullptr) { // fetch a led instruction BaseType_t q = xQueueReceive(rgbLedQueue, &rgb, 1); if (q == pdTRUE) { if (rgb->reQueue && !rgbQueueFlush) { // requeue this instruction at the end of the queue, caveman style. struct ledInstructionRGB* requeue = new ledInstructionRGB; requeue->fadeTime = rgb->fadeTime; requeue->ledColor = rgb->ledColor; requeue->length = rgb->length; addToRGBQueue(requeue, true); } if (rgbQueueFlush) { delete rgb; rgb = nullptr; } else { rgbInstructionFadeTime = rgb->fadeTime; if (rgb->fadeTime <= 1) { leds[0] = rgb->ledColor; showRGB(); } } } else { rgbQueueFlush = false; // no commands, run idle led task rgbIdleStep(); } } else { // process instruction if (rgb->fadeTime) { rgb->fadeTime--; leds[0] = blend(rgb->ledColor, oldColor, map(rgb->fadeTime, 0, rgbInstructionFadeTime, 0, 255)); showRGB(); } else if (rgb->length) { rgb->length--; } else { oldColor = rgb->ledColor; delete rgb; rgb = nullptr; } } #endif // handle flasher LED (single color) if (monoled == nullptr) { BaseType_t q = xQueueReceive(ledQueue, &monoled, 1); if (q == pdTRUE) { monoInstructionFadeTime = monoled->fadeTime; if (monoled->fadeTime <= 1) { showMono(monoled->value); } } } else { if (monoled->fadeTime) { monoled->fadeTime--; showMono(map(monoled->fadeTime, 0, monoInstructionFadeTime, monoled->value, oldBrightness)); } else if (monoled->length) { monoled->length--; } else { oldBrightness = monoled->value; delete monoled; monoled = nullptr; } } vTaskDelay(1 / portTICK_PERIOD_MS); } }