9 #include "crsf_protocol.h"
10 #include "POWERMGNT.h"
12 static uint8_t pixelCount
;
13 static uint8_t *statusLEDs
;
14 static uint8_t statusLEDcount
;
15 static uint8_t *vtxStatusLEDs
;
16 static uint8_t vtxLEDcount
;
17 static uint8_t *bootLEDs
;
18 static uint8_t bootLEDcount
;
20 #if defined(PLATFORM_ESP32)
22 static ESP32S3LedDriverGRB
*stripgrb
;
23 static ESP32S3LedDriverRGB
*striprgb
;
25 #include <NeoPixelBus.h>
26 #define METHOD NeoEsp8266Uart1800KbpsMethod
27 static NeoPixelBus
<NeoGrbFeature
, METHOD
> *stripgrb
;
28 static NeoPixelBus
<NeoRgbFeature
, METHOD
> *striprgb
;
33 if (OPT_WS2812_IS_GRB
)
35 #if defined(PLATFORM_ESP32)
36 stripgrb
= new ESP32S3LedDriverGRB(pixelCount
, GPIO_PIN_LED_WS2812
);
38 stripgrb
= new NeoPixelBus
<NeoGrbFeature
, METHOD
>(pixelCount
, GPIO_PIN_LED_WS2812
);
41 stripgrb
->ClearTo(RgbColor(0), 0, pixelCount
-1);
46 #if defined(PLATFORM_ESP32)
47 striprgb
= new ESP32S3LedDriverRGB(pixelCount
, GPIO_PIN_LED_WS2812
);
49 striprgb
= new NeoPixelBus
<NeoRgbFeature
, METHOD
> (pixelCount
, GPIO_PIN_LED_WS2812
);
52 striprgb
->ClearTo(RgbColor(0), 0, pixelCount
-1);
57 void WS281BsetLED(int index
, uint32_t color
)
59 if (OPT_WS2812_IS_GRB
)
61 stripgrb
->SetPixelColor(index
, RgbColor(color
>> 16, color
>> 8, color
));
65 striprgb
->SetPixelColor(index
, RgbColor(color
>> 16, color
>> 8, color
));
69 void WS281BsetLED(uint32_t color
)
71 for (int i
=0 ; i
<statusLEDcount
; i
++)
73 if (OPT_WS2812_IS_GRB
)
75 stripgrb
->SetPixelColor(statusLEDs
[i
], RgbColor(color
>> 16, color
>> 8, color
));
79 striprgb
->SetPixelColor(statusLEDs
[i
], RgbColor(color
>> 16, color
>> 8, color
));
82 if (OPT_WS2812_IS_GRB
)
96 uint32_t HsvToRgb(const blinkyColor_t
&blinkyColor
)
98 uint8_t region
, remainder
, p
, q
, t
;
100 if (blinkyColor
.s
== 0)
102 return blinkyColor
.v
<< 16 | blinkyColor
.v
<< 8 | blinkyColor
.v
;
105 region
= blinkyColor
.h
/ 43;
106 remainder
= (blinkyColor
.h
- (region
* 43)) * 6;
108 p
= (blinkyColor
.v
* (255 - blinkyColor
.s
)) >> 8;
109 q
= (blinkyColor
.v
* (255 - ((blinkyColor
.s
* remainder
) >> 8))) >> 8;
110 t
= (blinkyColor
.v
* (255 - ((blinkyColor
.s
* (255 - remainder
)) >> 8))) >> 8;
115 return blinkyColor
.v
<< 16 | t
<< 8 | p
;
117 return q
<< 16 | blinkyColor
.v
<< 8 | p
;
119 return p
<< 16 | blinkyColor
.v
<< 8 | t
;
121 return p
<< 16 | q
<< 8 | blinkyColor
.v
;
123 return t
<< 16 | p
<< 8 | blinkyColor
.v
;
125 return blinkyColor
.v
<< 16 | p
<< 8 | q
;
129 void brightnessFadeLED(blinkyColor_t
&blinkyColor
, uint8_t start
, uint8_t end
)
131 static uint8_t lightness
= 0;
132 static int8_t dir
= 1;
134 if (lightness
<= start
)
139 else if (lightness
>= end
)
147 blinkyColor
.v
= lightness
;
148 WS281BsetLED(HsvToRgb(blinkyColor
));
151 void hueFadeLED(blinkyColor_t
&blinkyColor
, uint16_t start
, uint16_t end
, uint8_t lightness
, uint8_t count
)
153 static bool hueMode
= true;
158 if (blinkyColor
.v
== 0)
162 WS281BsetLED(HsvToRgb(blinkyColor
));
166 static uint16_t hue
= 0;
167 static int8_t dir
= 1;
195 blinkyColor
.h
= hue
% 256;
196 blinkyColor
.v
= lightness
;
197 WS281BsetLED(HsvToRgb(blinkyColor
));
199 if (count
!= 0 && hue
== start
)
201 static uint8_t counter
= 0;
203 if (counter
>= count
)
212 uint16_t flashLED(blinkyColor_t
&blinkyColor
, uint8_t onLightness
, uint8_t offLightness
, const uint8_t durations
[], uint8_t durationCounts
)
214 static int counter
= 0;
216 blinkyColor
.v
= counter
% 2 == 0 ? onLightness
: offLightness
;
217 WS281BsetLED(HsvToRgb(blinkyColor
));
218 if (counter
>= durationCounts
)
222 return durations
[counter
++] * 10;
225 uint32_t toRGB(uint8_t c
)
227 uint32_t r
= c
& 0xE0 ;
228 r
= ((r
<< 16) + (r
<< 13) + (r
<< 10)) & 0xFF0000;
229 uint32_t g
= c
& 0x1C;
230 g
= ((g
<< 11) + (g
<< 8) + (g
<< 5)) & 0xFF00;
231 uint32_t b
= ((c
& 0x3) << 1) + ((c
& 0x3) >> 1);
232 b
= (b
<< 5) + (b
<< 2) + (b
>> 1);
236 void setButtonColors(uint8_t b1
, uint8_t b2
)
238 #if defined(PLATFORM_ESP32) && defined(TARGET_TX)
239 if (USER_BUTTON_LED
!= -1)
241 WS281BsetLED(USER_BUTTON_LED
, toRGB(b1
));
243 if (USER_BUTTON2_LED
!= -1)
245 WS281BsetLED(USER_BUTTON2_LED
, toRGB(b2
));
255 constexpr uint8_t LEDSEQ_RADIO_FAILED
[] = { 10, 10 }; // 100ms on, 100ms off (fast blink)
256 constexpr uint8_t LEDSEQ_DISCONNECTED
[] = { 50, 50 }; // 500ms on, 500ms off
257 constexpr uint8_t LEDSEQ_NO_CROSSFIRE
[] = { 10, 100 }; // 1 blink, 1s pause (one blink/s)
258 constexpr uint8_t LEDSEQ_BINDING
[] = { 10, 10, 10, 100 }; // 2x 100ms blink, 1s pause
259 constexpr uint8_t LEDSEQ_MODEL_MISMATCH
[] = { 10, 10, 10, 10, 10, 100 }; // 3x 100ms blink, 1s pause
260 constexpr uint8_t LEDSEQ_UPDATE
[] = { 20, 5, 5, 5, 5, 40 }; // 200ms on, 2x 50ms off/on, 400ms off
262 #define NORMAL_UPDATE_INTERVAL 50
264 static blinkyColor_t blinkyColor
;
266 static int blinkyUpdate() {
267 static constexpr uint8_t hueStepValue
= 1;
268 static constexpr uint8_t lightnessStep
= 5;
272 WS281BsetLED(HsvToRgb(blinkyColor
));
276 blinkyColor_t c
= blinkyColor
;
277 for (int i
=0 ; i
<bootLEDcount
; i
++)
280 auto color
= HsvToRgb(c
);
281 if (OPT_WS2812_IS_GRB
)
283 stripgrb
->SetPixelColor(bootLEDs
[i
], RgbColor(color
>> 16, color
>> 8, color
));
287 striprgb
->SetPixelColor(bootLEDs
[i
], RgbColor(color
>> 16, color
>> 8, color
));
290 if (OPT_WS2812_IS_GRB
)
299 if ((int)blinkyColor
.h
+ hueStepValue
> 255) {
300 if ((int)blinkyColor
.v
- lightnessStep
< 0) {
301 blinkyState
= NORMAL
;
302 #if defined(PLATFORM_ESP32) || defined(PLATFORM_ESP8266)
305 if (OPT_WS2812_IS_GRB
)
307 stripgrb
->ClearTo(RgbColor(0), 0, pixelCount
-1);
311 striprgb
->ClearTo(RgbColor(0), 0, pixelCount
-1);
314 #if defined(TARGET_TX)
315 setButtonColors(config
.GetButtonActions(0)->val
.color
, config
.GetButtonActions(1)->val
.color
);
317 if (OPT_WS2812_IS_GRB
)
326 return NORMAL_UPDATE_INTERVAL
;
328 blinkyColor
.v
-= lightnessStep
;
330 blinkyColor
.h
+= hueStepValue
;
332 return 3000/(256/hueStepValue
);
335 static void initialize()
337 if (GPIO_PIN_LED_WS2812
!= UNDEF_PIN
)
340 statusLEDcount
= WS2812_STATUS_LEDS_COUNT
;
341 if (statusLEDcount
== 0)
343 statusLEDs
= new uint8_t[1];
349 statusLEDs
= new uint8_t[statusLEDcount
];
350 for (int i
=0 ; i
<statusLEDcount
; i
++)
352 statusLEDs
[i
] = WS2812_STATUS_LEDS
[i
];
353 pixelCount
= max((int)pixelCount
, statusLEDs
[i
]+1);
357 vtxLEDcount
= WS2812_VTX_STATUS_LEDS_COUNT
;
358 vtxStatusLEDs
= new uint8_t[vtxLEDcount
];
359 for (int i
=0 ; i
<vtxLEDcount
; i
++)
361 vtxStatusLEDs
[i
] = WS2812_VTX_STATUS_LEDS
[i
];
362 pixelCount
= max((int)pixelCount
, vtxStatusLEDs
[i
]+1);
365 bootLEDcount
= WS2812_BOOT_LEDS_COUNT
;
366 if (bootLEDcount
== 0)
368 bootLEDs
= statusLEDs
;
369 bootLEDcount
= statusLEDcount
;
373 bootLEDs
= new uint8_t[bootLEDcount
];
374 for (int i
=0 ; i
<bootLEDcount
; i
++)
376 bootLEDs
[i
] = WS2812_BOOT_LEDS
[i
];
377 pixelCount
= max((int)pixelCount
, bootLEDs
[i
]+1);
389 if (GPIO_PIN_LED_WS2812
== UNDEF_PIN
)
391 return DURATION_NEVER
;
393 blinkyState
= STARTUP
;
394 #if defined(PLATFORM_ESP32)
395 // Only do the blinkies if it was NOT a software reboot
396 if (esp_reset_reason() == ESP_RST_SW
) {
397 blinkyState
= NORMAL
;
398 #if defined(TARGET_TX)
399 setButtonColors(config
.GetButtonActions(0)->val
.color
, config
.GetButtonActions(1)->val
.color
);
401 return NORMAL_UPDATE_INTERVAL
;
404 return DURATION_IMMEDIATELY
;
409 if (GPIO_PIN_LED_WS2812
== UNDEF_PIN
)
411 return DURATION_NEVER
;
413 if (blinkyState
== STARTUP
&& connectionState
< FAILURE_STATES
)
415 return blinkyUpdate();
417 #if defined(TARGET_RX)
421 return flashLED(blinkyColor
, 192, 0, LEDSEQ_BINDING
, sizeof(LEDSEQ_BINDING
));
424 switch (connectionState
)
427 #if defined(TARGET_RX)
428 if (!connectionHasModelMatch
|| !teamraceHasModelMatch
)
431 return flashLED(blinkyColor
, 192, 0, LEDSEQ_MODEL_MISMATCH
, sizeof(LEDSEQ_MODEL_MISMATCH
));
434 // Set the color and we're done!
435 blinkyColor
.h
= ExpressLRS_currAirRate_Modparams
->index
* 256 / RATE_MAX
;
436 blinkyColor
.v
= fmap(POWERMGNT::currPower(), 0, PWR_COUNT
-1, 10, 128);
437 WS281BsetLED(HsvToRgb(blinkyColor
));
438 return DURATION_NEVER
;
440 // Set the color and we're done!
441 blinkyColor
.h
= ExpressLRS_currAirRate_Modparams
->index
* 256 / RATE_MAX
;
442 blinkyColor
.v
= fmap(POWERMGNT::currPower(), 0, PWR_COUNT
-1, 10, 50);
443 WS281BsetLED(HsvToRgb(blinkyColor
));
444 return DURATION_NEVER
;
446 #if defined(TARGET_RX)
448 return flashLED(blinkyColor
, 192, 0, LEDSEQ_DISCONNECTED
, sizeof(LEDSEQ_DISCONNECTED
));
450 blinkyColor
.h
= ExpressLRS_currAirRate_Modparams
->index
* 256 / RATE_MAX
;
451 brightnessFadeLED(blinkyColor
, 0, 64);
452 return NORMAL_UPDATE_INTERVAL
;
455 hueFadeLED(blinkyColor
, 85, 85-30, 128, 2); // Yellow->Green cross-fade
459 return flashLED(blinkyColor
, 192, 0, LEDSEQ_UPDATE
, sizeof(LEDSEQ_UPDATE
));
461 hueFadeLED(blinkyColor
, 170, 170+30, 128, 2); // Blue cross-fade
465 return flashLED(blinkyColor
, 192, 0, LEDSEQ_RADIO_FAILED
, sizeof(LEDSEQ_RADIO_FAILED
));
468 return flashLED(blinkyColor
, 192, 0, LEDSEQ_NO_CROSSFIRE
, sizeof(LEDSEQ_NO_CROSSFIRE
));
470 return DURATION_NEVER
;
474 device_t RGB_device
= {
475 .initialize
= initialize
,