2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
26 #include <build_config.h>
30 #include <common/color.h>
32 #include "drivers/light_ws2811strip.h"
33 #include "drivers/system.h"
34 #include "drivers/serial.h"
36 #include <common/maths.h>
37 #include <common/printf.h>
38 #include <common/typeconversion.h>
40 #include "sensors/battery.h"
42 #include "config/runtime_config.h"
43 #include "config/config.h"
45 #include "io/rc_controls.h"
46 #include "flight/failsafe.h"
48 #include "io/ledstrip.h"
50 static bool ledStripInitialised
= false;
51 static failsafe_t
* failsafe
;
53 #if MAX_LED_STRIP_LENGTH > WS2811_LED_STRIP_LENGTH
54 #error "Led strip length must match driver"
59 //#define USE_LED_ANIMATION
62 #define LED_BLACK { 0, 0, 0}
63 #define LED_WHITE { 0, 255, 255}
64 #define LED_RED { 0, 0, 255}
65 #define LED_ORANGE { 30, 0, 255}
66 #define LED_YELLOW { 60, 0, 255}
67 #define LED_LIME_GREEN { 90, 0, 255}
68 #define LED_GREEN {120, 0, 255}
69 #define LED_MINT_GREEN {150, 0, 255}
70 #define LED_CYAN {180, 0, 255}
71 #define LED_LIGHT_BLUE {210, 0, 255}
72 #define LED_BLUE {240, 0, 255}
73 #define LED_DARK_VIOLET {270, 0, 255}
74 #define LED_MAGENTA {300, 0, 255}
75 #define LED_DEEP_PINK {330, 0, 255}
77 const hsvColor_t hsv_black
= LED_BLACK
;
78 const hsvColor_t hsv_white
= LED_WHITE
;
79 const hsvColor_t hsv_red
= LED_RED
;
80 const hsvColor_t hsv_orange
= LED_ORANGE
;
81 const hsvColor_t hsv_yellow
= LED_YELLOW
;
82 const hsvColor_t hsv_limeGreen
= LED_LIME_GREEN
;
83 const hsvColor_t hsv_green
= LED_GREEN
;
84 const hsvColor_t hsv_mintGreen
= LED_MINT_GREEN
;
85 const hsvColor_t hsv_cyan
= LED_CYAN
;
86 const hsvColor_t hsv_lightBlue
= LED_LIGHT_BLUE
;
87 const hsvColor_t hsv_blue
= LED_BLUE
;
88 const hsvColor_t hsv_darkViolet
= LED_DARK_VIOLET
;
89 const hsvColor_t hsv_magenta
= LED_MAGENTA
;
90 const hsvColor_t hsv_deepPink
= LED_DEEP_PINK
;
92 #define LED_DIRECTION_COUNT 6
94 const hsvColor_t
* const defaultColors
[] = {
137 typedef struct modeColorIndexes_s
{
144 } modeColorIndexes_t
;
147 // Note, the color index used for the mode colors below refer to the default colors.
148 // if the colors are reconfigured the index is still valid but the displayed color might
150 // See colors[] and defaultColors[] and applyDefaultColors[]
152 static const modeColorIndexes_t orientationModeColors
= {
161 static const modeColorIndexes_t headfreeModeColors
= {
170 static const modeColorIndexes_t horizonModeColors
= {
179 static const modeColorIndexes_t angleModeColors
= {
188 static const modeColorIndexes_t magModeColors
= {
197 static const modeColorIndexes_t baroModeColors
= {
207 uint8_t ledGridWidth
;
208 uint8_t ledGridHeight
;
211 ledConfig_t
*ledConfigs
;
213 const ledConfig_t defaultLedStripConfig
[] = {
214 { CALCULATE_LED_XY( 2, 2), LED_DIRECTION_SOUTH
| LED_DIRECTION_EAST
| LED_FUNCTION_INDICATOR
| LED_FUNCTION_ARM_STATE
},
215 { CALCULATE_LED_XY( 2, 1), LED_DIRECTION_EAST
| LED_FUNCTION_FLIGHT_MODE
| LED_FUNCTION_WARNING
},
216 { CALCULATE_LED_XY( 2, 0), LED_DIRECTION_NORTH
| LED_DIRECTION_EAST
| LED_FUNCTION_INDICATOR
| LED_FUNCTION_ARM_STATE
},
217 { CALCULATE_LED_XY( 1, 0), LED_DIRECTION_NORTH
| LED_FUNCTION_FLIGHT_MODE
},
218 { CALCULATE_LED_XY( 0, 0), LED_DIRECTION_NORTH
| LED_DIRECTION_WEST
| LED_FUNCTION_INDICATOR
| LED_FUNCTION_ARM_STATE
},
219 { CALCULATE_LED_XY( 0, 1), LED_DIRECTION_WEST
| LED_FUNCTION_FLIGHT_MODE
| LED_FUNCTION_WARNING
},
220 { CALCULATE_LED_XY( 0, 2), LED_DIRECTION_SOUTH
| LED_DIRECTION_WEST
| LED_FUNCTION_INDICATOR
| LED_FUNCTION_ARM_STATE
},
221 { CALCULATE_LED_XY( 1, 2), LED_DIRECTION_SOUTH
| LED_FUNCTION_FLIGHT_MODE
| LED_FUNCTION_WARNING
},
222 { CALCULATE_LED_XY( 1, 1), LED_DIRECTION_UP
| LED_FUNCTION_FLIGHT_MODE
| LED_FUNCTION_WARNING
},
223 { CALCULATE_LED_XY( 1, 1), LED_DIRECTION_UP
| LED_FUNCTION_FLIGHT_MODE
| LED_FUNCTION_WARNING
},
224 { CALCULATE_LED_XY( 1, 1), LED_DIRECTION_DOWN
| LED_FUNCTION_FLIGHT_MODE
| LED_FUNCTION_WARNING
},
225 { CALCULATE_LED_XY( 1, 1), LED_DIRECTION_DOWN
| LED_FUNCTION_FLIGHT_MODE
| LED_FUNCTION_WARNING
},
234 * 16 * 32 leds = 512 bytes storage needed worst case.
235 * = not efficient to store led configs as strings in flash.
236 * = becomes a problem to send all the data via cli due to serial/cli buffers
246 #define PARSE_STATE_COUNT 4
248 static const char chunkSeparators
[PARSE_STATE_COUNT
] = {',', ':', ':', '\0' };
250 static const char directionCodes
[] = { 'N', 'E', 'S', 'W', 'U', 'D' };
251 #define DIRECTION_COUNT (sizeof(directionCodes) / sizeof(directionCodes[0]))
252 static const uint8_t directionMappings
[DIRECTION_COUNT
] = {
261 static const char functionCodes
[] = { 'I', 'W', 'F', 'A', 'T' };
262 #define FUNCTION_COUNT (sizeof(functionCodes) / sizeof(functionCodes[0]))
263 static const uint16_t functionMappings
[FUNCTION_COUNT
] = {
264 LED_FUNCTION_INDICATOR
,
265 LED_FUNCTION_WARNING
,
266 LED_FUNCTION_FLIGHT_MODE
,
267 LED_FUNCTION_ARM_STATE
,
268 LED_FUNCTION_THROTTLE
272 uint8_t highestYValueForNorth
;
273 uint8_t lowestYValueForSouth
;
274 uint8_t highestXValueForWest
;
275 uint8_t lowestXValueForEast
;
277 void determineLedStripDimensions(void)
283 const ledConfig_t
*ledConfig
;
285 for (ledIndex
= 0; ledIndex
< ledCount
; ledIndex
++) {
286 ledConfig
= &ledConfigs
[ledIndex
];
288 if (GET_LED_X(ledConfig
) >= ledGridWidth
) {
289 ledGridWidth
= GET_LED_X(ledConfig
) + 1;
291 if (GET_LED_Y(ledConfig
) >= ledGridHeight
) {
292 ledGridHeight
= GET_LED_Y(ledConfig
) + 1;
297 void determineOrientationLimits(void)
299 bool isOddHeight
= (ledGridHeight
& 1);
300 bool isOddWidth
= (ledGridWidth
& 1);
301 uint8_t heightModifier
= isOddHeight
? 1 : 0;
302 uint8_t widthModifier
= isOddWidth
? 1 : 0;
304 highestYValueForNorth
= (ledGridHeight
/ 2) - 1;
305 lowestYValueForSouth
= (ledGridHeight
/ 2) + heightModifier
;
306 highestXValueForWest
= (ledGridWidth
/ 2) - 1;
307 lowestXValueForEast
= (ledGridWidth
/ 2) + widthModifier
;
310 void updateLedCount(void)
314 for (ledIndex
= 0; ledIndex
< MAX_LED_STRIP_LENGTH
; ledIndex
++) {
315 if (ledConfigs
[ledIndex
].flags
== 0 && ledConfigs
[ledIndex
].xy
== 0) {
322 static void reevalulateLedConfig(void)
325 determineLedStripDimensions();
326 determineOrientationLimits();
329 #define CHUNK_BUFFER_SIZE 10
331 #define NEXT_PARSE_STATE(parseState) ((parseState + 1) % PARSE_STATE_COUNT)
334 bool parseLedStripConfig(uint8_t ledIndex
, const char *config
)
336 char chunk
[CHUNK_BUFFER_SIZE
];
340 uint8_t parseState
= X_COORDINATE
;
343 if (ledIndex
>= MAX_LED_STRIP_LENGTH
) {
347 ledConfig_t
*ledConfig
= &ledConfigs
[ledIndex
];
348 memset(ledConfig
, 0, sizeof(ledConfig_t
));
352 char chunkSeparator
= chunkSeparators
[parseState
];
354 memset(&chunk
, 0, sizeof(chunk
));
357 while (*config
&& chunkIndex
< CHUNK_BUFFER_SIZE
&& *config
!= chunkSeparator
) {
358 chunk
[chunkIndex
++] = *config
++;
361 if (*config
++ != chunkSeparator
) {
366 switch((parseState_e
)parseState
) {
369 ledConfig
->xy
|= CALCULATE_LED_X(val
);
373 ledConfig
->xy
|= CALCULATE_LED_Y(val
);
376 for (chunkIndex
= 0; chunk
[chunkIndex
] && chunkIndex
< CHUNK_BUFFER_SIZE
; chunkIndex
++) {
377 for (uint8_t mappingIndex
= 0; mappingIndex
< DIRECTION_COUNT
; mappingIndex
++) {
378 if (directionCodes
[mappingIndex
] == chunk
[chunkIndex
]) {
379 ledConfig
->flags
|= directionMappings
[mappingIndex
];
386 for (chunkIndex
= 0; chunk
[chunkIndex
] && chunkIndex
< CHUNK_BUFFER_SIZE
; chunkIndex
++) {
387 for (uint8_t mappingIndex
= 0; mappingIndex
< FUNCTION_COUNT
; mappingIndex
++) {
388 if (functionCodes
[mappingIndex
] == chunk
[chunkIndex
]) {
389 ledConfig
->flags
|= functionMappings
[mappingIndex
];
398 if (parseState
>= PARSE_STATE_COUNT
) {
404 memset(ledConfig
, 0, sizeof(ledConfig_t
));
407 reevalulateLedConfig();
412 void generateLedConfig(uint8_t ledIndex
, char *ledConfigBuffer
, size_t bufferSize
)
414 char functions
[FUNCTION_COUNT
];
415 char directions
[DIRECTION_COUNT
];
417 uint8_t mappingIndex
;
418 ledConfig_t
*ledConfig
= &ledConfigs
[ledIndex
];
420 memset(ledConfigBuffer
, 0, bufferSize
);
421 memset(&functions
, 0, sizeof(functions
));
422 memset(&directions
, 0, sizeof(directions
));
424 for (mappingIndex
= 0, index
= 0; mappingIndex
< FUNCTION_COUNT
; mappingIndex
++) {
425 if (ledConfig
->flags
& functionMappings
[mappingIndex
]) {
426 functions
[index
++] = functionCodes
[mappingIndex
];
430 for (mappingIndex
= 0, index
= 0; mappingIndex
< DIRECTION_COUNT
; mappingIndex
++) {
431 if (ledConfig
->flags
& directionMappings
[mappingIndex
]) {
432 directions
[index
++] = directionCodes
[mappingIndex
];
436 sprintf(ledConfigBuffer
, "%u,%u:%s:%s", GET_LED_X(ledConfig
), GET_LED_Y(ledConfig
), directions
, functions
);
440 uint32_t nextAnimationUpdateAt
= 0;
441 uint32_t nextIndicatorFlashAt
= 0;
442 uint32_t nextWarningFlashAt
= 0;
444 #define LED_STRIP_20HZ ((1000 * 1000) / 20)
445 #define LED_STRIP_10HZ ((1000 * 1000) / 10)
446 #define LED_STRIP_5HZ ((1000 * 1000) / 5)
448 void applyDirectionalModeColor(const uint8_t ledIndex
, const ledConfig_t
*ledConfig
, const modeColorIndexes_t
*modeColors
)
450 // apply up/down colors regardless of quadrant.
451 if ((ledConfig
->flags
& LED_DIRECTION_UP
)) {
452 setLedHsv(ledIndex
, &colors
[modeColors
->up
]);
455 if ((ledConfig
->flags
& LED_DIRECTION_DOWN
)) {
456 setLedHsv(ledIndex
, &colors
[modeColors
->down
]);
459 // override with n/e/s/w colors to each n/s e/w half - bail at first match.
460 if ((ledConfig
->flags
& LED_DIRECTION_WEST
) && GET_LED_X(ledConfig
) <= highestXValueForWest
) {
461 setLedHsv(ledIndex
, &colors
[modeColors
->west
]);
464 if ((ledConfig
->flags
& LED_DIRECTION_EAST
) && GET_LED_X(ledConfig
) >= lowestXValueForEast
) {
465 setLedHsv(ledIndex
, &colors
[modeColors
->east
]);
468 if ((ledConfig
->flags
& LED_DIRECTION_NORTH
) && GET_LED_Y(ledConfig
) <= highestYValueForNorth
) {
469 setLedHsv(ledIndex
, &colors
[modeColors
->north
]);
472 if ((ledConfig
->flags
& LED_DIRECTION_SOUTH
) && GET_LED_Y(ledConfig
) >= lowestYValueForSouth
) {
473 setLedHsv(ledIndex
, &colors
[modeColors
->south
]);
479 QUADRANT_NORTH_EAST
= 1,
485 void applyQuadrantColor(const uint8_t ledIndex
, const ledConfig_t
*ledConfig
, const quadrant_e quadrant
, const hsvColor_t
*color
)
488 case QUADRANT_NORTH_EAST
:
489 if (GET_LED_Y(ledConfig
) <= highestYValueForNorth
&& GET_LED_X(ledConfig
) >= lowestXValueForEast
) {
490 setLedHsv(ledIndex
, color
);
494 case QUADRANT_SOUTH_EAST
:
495 if (GET_LED_Y(ledConfig
) >= lowestYValueForSouth
&& GET_LED_X(ledConfig
) >= lowestXValueForEast
) {
496 setLedHsv(ledIndex
, color
);
500 case QUADRANT_SOUTH_WEST
:
501 if (GET_LED_Y(ledConfig
) >= lowestYValueForSouth
&& GET_LED_X(ledConfig
) <= highestXValueForWest
) {
502 setLedHsv(ledIndex
, color
);
506 case QUADRANT_NORTH_WEST
:
507 if (GET_LED_Y(ledConfig
) <= highestYValueForNorth
&& GET_LED_X(ledConfig
) <= highestXValueForWest
) {
508 setLedHsv(ledIndex
, color
);
514 void applyLedModeLayer(void)
516 const ledConfig_t
*ledConfig
;
519 for (ledIndex
= 0; ledIndex
< ledCount
; ledIndex
++) {
521 ledConfig
= &ledConfigs
[ledIndex
];
523 setLedHsv(ledIndex
, &hsv_black
);
525 if (!(ledConfig
->flags
& LED_FUNCTION_FLIGHT_MODE
)) {
526 if (ledConfig
->flags
& LED_FUNCTION_ARM_STATE
) {
527 if (!ARMING_FLAG(ARMED
)) {
528 setLedHsv(ledIndex
, &hsv_green
);
530 setLedHsv(ledIndex
, &hsv_blue
);
536 applyDirectionalModeColor(ledIndex
, ledConfig
, &orientationModeColors
);
538 if (FLIGHT_MODE(HEADFREE_MODE
)) {
539 applyDirectionalModeColor(ledIndex
, ledConfig
, &headfreeModeColors
);
541 } else if (FLIGHT_MODE(MAG_MODE
)) {
542 applyDirectionalModeColor(ledIndex
, ledConfig
, &magModeColors
);
545 } else if (FLIGHT_MODE(BARO_MODE
)) {
546 applyDirectionalModeColor(ledIndex
, ledConfig
, &baroModeColors
);
548 } else if (FLIGHT_MODE(HORIZON_MODE
)) {
549 applyDirectionalModeColor(ledIndex
, ledConfig
, &horizonModeColors
);
550 } else if (FLIGHT_MODE(ANGLE_MODE
)) {
551 applyDirectionalModeColor(ledIndex
, ledConfig
, &angleModeColors
);
557 WARNING_FLAG_NONE
= 0,
558 WARNING_FLAG_LOW_BATTERY
= (1 << 0),
559 WARNING_FLAG_FAILSAFE
= (1 << 1),
560 WARNING_FLAG_ARMING_DISABLED
= (1 << 2)
563 static uint8_t warningFlags
= WARNING_FLAG_NONE
;
565 void applyLedWarningLayer(uint8_t updateNow
)
567 const ledConfig_t
*ledConfig
;
569 static uint8_t warningFlashCounter
= 0;
571 if (updateNow
&& warningFlashCounter
== 0) {
572 warningFlags
= WARNING_FLAG_NONE
;
573 if (feature(FEATURE_VBAT
) && shouldSoundBatteryAlarm()) {
574 warningFlags
|= WARNING_FLAG_LOW_BATTERY
;
576 if (failsafe
->vTable
->hasTimerElapsed()) {
577 warningFlags
|= WARNING_FLAG_FAILSAFE
;
579 if (!ARMING_FLAG(ARMED
) && !ARMING_FLAG(OK_TO_ARM
)) {
580 warningFlags
|= WARNING_FLAG_ARMING_DISABLED
;
584 if (warningFlags
|| warningFlashCounter
> 0) {
585 const hsvColor_t
*warningColor
= &hsv_black
;
587 if ((warningFlashCounter
& 1) == 0) {
588 if (warningFlashCounter
< 4 && (warningFlags
& WARNING_FLAG_ARMING_DISABLED
)) {
589 warningColor
= &hsv_green
;
591 if (warningFlashCounter
>= 4 && warningFlashCounter
< 12 && (warningFlags
& WARNING_FLAG_LOW_BATTERY
)) {
592 warningColor
= &hsv_red
;
594 if (warningFlashCounter
>= 12 && warningFlashCounter
< 16 && (warningFlags
& WARNING_FLAG_FAILSAFE
)) {
595 warningColor
= &hsv_yellow
;
598 if (warningFlashCounter
>= 12 && warningFlashCounter
< 16 && (warningFlags
& WARNING_FLAG_FAILSAFE
)) {
599 warningColor
= &hsv_blue
;
603 for (ledIndex
= 0; ledIndex
< ledCount
; ledIndex
++) {
605 ledConfig
= &ledConfigs
[ledIndex
];
607 if (!(ledConfig
->flags
& LED_FUNCTION_WARNING
)) {
610 setLedHsv(ledIndex
, warningColor
);
614 if (updateNow
&& (warningFlags
|| warningFlashCounter
)) {
615 warningFlashCounter
++;
616 if (warningFlashCounter
== 20) {
617 warningFlashCounter
= 0;
622 #define INDICATOR_DEADBAND 25
624 void applyLedIndicatorLayer(uint8_t indicatorFlashState
)
626 const ledConfig_t
*ledConfig
;
627 static const hsvColor_t
*flashColor
;
630 if (indicatorFlashState
== 0) {
631 flashColor
= &hsv_orange
;
633 flashColor
= &hsv_black
;
638 for (ledIndex
= 0; ledIndex
< ledCount
; ledIndex
++) {
640 ledConfig
= &ledConfigs
[ledIndex
];
642 if (!(ledConfig
->flags
& LED_FUNCTION_INDICATOR
)) {
646 if (rcCommand
[ROLL
] > INDICATOR_DEADBAND
) {
647 applyQuadrantColor(ledIndex
, ledConfig
, QUADRANT_NORTH_EAST
, flashColor
);
648 applyQuadrantColor(ledIndex
, ledConfig
, QUADRANT_SOUTH_EAST
, flashColor
);
651 if (rcCommand
[ROLL
] < -INDICATOR_DEADBAND
) {
652 applyQuadrantColor(ledIndex
, ledConfig
, QUADRANT_NORTH_WEST
, flashColor
);
653 applyQuadrantColor(ledIndex
, ledConfig
, QUADRANT_SOUTH_WEST
, flashColor
);
656 if (rcCommand
[PITCH
] > INDICATOR_DEADBAND
) {
657 applyQuadrantColor(ledIndex
, ledConfig
, QUADRANT_NORTH_EAST
, flashColor
);
658 applyQuadrantColor(ledIndex
, ledConfig
, QUADRANT_NORTH_WEST
, flashColor
);
661 if (rcCommand
[PITCH
] < -INDICATOR_DEADBAND
) {
662 applyQuadrantColor(ledIndex
, ledConfig
, QUADRANT_SOUTH_EAST
, flashColor
);
663 applyQuadrantColor(ledIndex
, ledConfig
, QUADRANT_SOUTH_WEST
, flashColor
);
668 void applyLedThrottleLayer()
670 const ledConfig_t
*ledConfig
;
674 for (ledIndex
= 0; ledIndex
< ledCount
; ledIndex
++) {
675 ledConfig
= &ledConfigs
[ledIndex
];
676 if(!(ledConfig
->flags
& LED_FUNCTION_THROTTLE
)) {
680 getLedHsv(ledIndex
, &color
);
682 int scaled
= scaleRange(rcData
[THROTTLE
], PWM_RANGE_MIN
, PWM_RANGE_MAX
, -60, +60);
683 scaled
+= HSV_HUE_MAX
;
684 color
.h
= scaled
% HSV_HUE_MAX
;
685 setLedHsv(ledIndex
, &color
);
689 static uint8_t frameCounter
= 0;
691 static uint8_t previousRow
;
692 static uint8_t currentRow
;
693 static uint8_t nextRow
;
695 static void updateLedAnimationState(void)
697 uint8_t animationFrames
= ledGridHeight
;
699 previousRow
= (frameCounter
+ animationFrames
- 1) % animationFrames
;
700 currentRow
= frameCounter
;
701 nextRow
= (frameCounter
+ 1) % animationFrames
;
703 frameCounter
= (frameCounter
+ 1) % animationFrames
;
706 #ifdef USE_LED_ANIMATION
707 static void applyLedAnimationLayer(void)
709 const ledConfig_t
*ledConfig
;
711 if (ARMING_FLAG(ARMED
)) {
716 for (ledIndex
= 0; ledIndex
< ledCount
; ledIndex
++) {
718 ledConfig
= &ledConfigs
[ledIndex
];
720 if (GET_LED_Y(ledConfig
) == previousRow
) {
721 setLedHsv(ledIndex
, &white
);
722 setLedBrightness(ledIndex
, 50);
724 } else if (GET_LED_Y(ledConfig
) == currentRow
) {
725 setLedHsv(ledIndex
, &white
);
726 } else if (GET_LED_Y(ledConfig
) == nextRow
) {
727 setLedBrightness(ledIndex
, 50);
733 void updateLedStrip(void)
735 if (!(ledStripInitialised
&& isWS2811LedStripReady())) {
739 uint32_t now
= micros();
741 bool animationUpdateNow
= (int32_t)(now
- nextAnimationUpdateAt
) >= 0L;
742 bool indicatorFlashNow
= (int32_t)(now
- nextIndicatorFlashAt
) >= 0L;
743 bool warningFlashNow
= (int32_t)(now
- nextWarningFlashAt
) >= 0L;
745 if (!(warningFlashNow
|| indicatorFlashNow
|| animationUpdateNow
)) {
749 static uint8_t indicatorFlashState
= 0;
753 applyLedThrottleLayer();
757 if (warningFlashNow
) {
758 nextWarningFlashAt
= now
+ LED_STRIP_10HZ
;
760 applyLedWarningLayer(warningFlashNow
);
764 if (indicatorFlashNow
) {
766 uint8_t rollScale
= abs(rcCommand
[ROLL
]) / 50;
767 uint8_t pitchScale
= abs(rcCommand
[PITCH
]) / 50;
768 uint8_t scale
= max(rollScale
, pitchScale
);
769 nextIndicatorFlashAt
= now
+ (LED_STRIP_5HZ
/ max(1, scale
));
771 if (indicatorFlashState
== 0) {
772 indicatorFlashState
= 1;
774 indicatorFlashState
= 0;
778 applyLedIndicatorLayer(indicatorFlashState
);
780 if (animationUpdateNow
) {
781 nextAnimationUpdateAt
= now
+ LED_STRIP_20HZ
;
782 updateLedAnimationState();
785 #ifdef USE_LED_ANIMATION
786 applyLedAnimationLayer();
791 bool parseColor(uint8_t index
, char *colorConfig
)
793 char *remainingCharacters
= colorConfig
;
795 hsvColor_t
*color
= &colors
[index
];
799 uint8_t componentIndex
;
800 for (componentIndex
= 0; ok
&& componentIndex
< HSV_COLOR_COMPONENT_COUNT
; componentIndex
++) {
801 uint16_t val
= atoi(remainingCharacters
);
802 switch (componentIndex
) {
804 if (val
> HSV_HUE_MAX
) {
808 colors
[index
].h
= val
;
811 if (val
> HSV_SATURATION_MAX
) {
815 colors
[index
].s
= (uint8_t)val
;
818 if (val
> HSV_VALUE_MAX
) {
822 colors
[index
].v
= (uint8_t)val
;
825 remainingCharacters
= strstr(remainingCharacters
, ",");
826 if (remainingCharacters
) {
827 remainingCharacters
++;
829 if (componentIndex
< 2) {
836 memset(color
, 0, sizeof(hsvColor_t
));
842 void applyDefaultColors(hsvColor_t
*colors
, uint8_t colorCount
)
844 memset(colors
, 0, colorCount
* sizeof(colors
));
845 for (uint8_t colorIndex
= 0; colorIndex
< colorCount
&& colorIndex
< (sizeof(defaultColors
) / sizeof(defaultColors
[0])); colorIndex
++) {
846 *colors
++ = *defaultColors
[colorIndex
];
850 void applyDefaultLedStripConfig(ledConfig_t
*ledConfigs
)
852 memset(ledConfigs
, 0, MAX_LED_STRIP_LENGTH
* sizeof(ledConfig_t
));
853 memcpy(ledConfigs
, &defaultLedStripConfig
, sizeof(defaultLedStripConfig
));
855 reevalulateLedConfig();
858 void ledStripInit(ledConfig_t
*ledConfigsToUse
, hsvColor_t
*colorsToUse
, failsafe_t
* failsafeToUse
)
860 ledConfigs
= ledConfigsToUse
;
861 colors
= colorsToUse
;
862 failsafe
= failsafeToUse
;
863 ledStripInitialised
= false;
866 void ledStripEnable(void)
868 reevalulateLedConfig();
869 ledStripInitialised
= true;
871 ws2811LedStripInit();