1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-24 00:35:39 +03:00

Update LED strip code to allow configurable LED strips.

See documentation for details.
This commit is contained in:
Dominic Clifton 2014-09-14 21:40:20 +01:00
parent 3ef769bf7b
commit 6ce5736990
17 changed files with 983 additions and 236 deletions

View file

@ -18,14 +18,23 @@
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <platform.h>
#include <build_config.h>
#ifdef LED_STRIP
#include <common/maths.h>
#include "drivers/light_ws2811strip.h"
#include "drivers/system.h"
#include "drivers/serial.h"
#include <common/maths.h>
#include <common/printf.h>
#include <common/typeconversion.h>
#include "sensors/battery.h"
@ -36,142 +45,99 @@
#include "io/ledstrip.h"
#define LED_WHITE {255, 255, 255}
#define LED_BLACK {0, 0, 0 }
#define LED_RED {255, 0, 0 }
#define LED_GREEN {0, 255, 0 }
#define LED_BLUE {0, 0, 255}
#define LED_CYAN {0, 255, 255}
#define LED_YELLOW {255, 255, 0 }
#define LED_ORANGE {255, 128, 0 }
#define LED_PINK {255, 0, 128}
#define LED_PURPLE {192, 64, 255}
#if MAX_LED_STRIP_LENGTH > WS2811_LED_STRIP_LENGTH
#error "Led strip length must match driver"
#endif
//#define USE_LED_ANIMATION
#define LED_WHITE {255, 255, 255}
#define LED_BLACK {0, 0, 0 }
#define LED_RED {255, 0, 0 }
#define LED_ORANGE {255, 128, 0 }
#define LED_YELLOW {255, 255, 0 }
#define LED_LIME_GREEN {128, 255, 0 }
#define LED_CYAN {0, 255, 255}
#define LED_GREEN {0, 255, 0 }
#define LED_LIGHT_BLUE {0, 128, 255}
#define LED_BLUE {0, 0, 255}
#define LED_DARK_MAGENTA {128, 0, 128}
#define LED_PINK {255, 0, 255}
#define LED_DARK_VIOLET {128, 0, 255}
#define LED_DEEP_PINK {255, 0, 128}
const rgbColor24bpp_t black = { LED_BLACK };
const rgbColor24bpp_t white = { LED_WHITE };
const rgbColor24bpp_t red = { LED_RED };
const rgbColor24bpp_t orange = { LED_ORANGE };
const rgbColor24bpp_t white = { LED_WHITE };
const rgbColor24bpp_t green = { LED_GREEN };
const rgbColor24bpp_t blue = { LED_BLUE };
uint8_t ledGridWidth;
uint8_t ledGridHeight;
uint8_t ledCount;
ledConfig_t *ledConfigs;
const ledConfig_t defaultLedStripConfig[] = {
{ CALCULATE_LED_XY( 2, 2), LED_DIRECTION_SOUTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 2, 1), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 2, 0), LED_DIRECTION_NORTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 0, 0), LED_DIRECTION_NORTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 1), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 0, 2), LED_DIRECTION_SOUTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 2), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_UP | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_UP | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_DOWN | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_DOWN | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY },
};
/*
* 0..5 - rear right cluster, 0..2 rear 3..5 right
* 6..11 - front right cluster, 6..8 rear, 9..11 front
* 12..15 - front center cluster
* 16..21 - front left cluster, 16..18 front, 19..21 rear
* 22..27 - rear left cluster, 22..24 left, 25..27 rear
* 6 coords @nn,nn
* 4 direction @##
* 6 modes @####
* = 16 bytes per led
* 16 * 32 leds = 512 bytes storage needed worst case.
* = not efficient to store led configs as strings in flash.
* = becomes a problem to send all the data via cli due to serial/cli buffers
*/
typedef enum {
LED_DISABLED = 0,
LED_DIRECTION_NORTH = (1 << 0),
LED_DIRECTION_EAST = (1 << 1),
LED_DIRECTION_SOUTH = (1 << 2),
LED_DIRECTION_WEST = (1 << 3),
LED_DIRECTION_UP = (1 << 4),
LED_DIRECTION_DOWN = (1 << 5),
LED_FUNCTION_INDICATOR = (1 << 6),
LED_FUNCTION_BATTERY = (1 << 7),
LED_FUNCTION_MODE = (1 << 8),
LED_FUNCTION_ARM_STATE = (1 << 9)
} ledFlag_e;
X_COORDINATE,
Y_COORDINATE,
DIRECTIONS,
FUNCTIONS
} parseState_e;
#define LED_X_BIT_OFFSET 4
#define LED_Y_BIT_OFFSET 0
#define PARSE_STATE_COUNT 4
#define LED_XY_MASK (0x0F)
static const char chunkSeparators[PARSE_STATE_COUNT] = {',', ':', ':', '\0' };
#define LED_X(ledConfig) ((ledConfig->xy >> LED_X_BIT_OFFSET) & LED_XY_MASK)
#define LED_Y(ledConfig) ((ledConfig->xy >> LED_Y_BIT_OFFSET) & LED_XY_MASK)
#define LED_XY(x,y) (((x & LED_XY_MASK) << LED_X_BIT_OFFSET) | ((y & LED_XY_MASK) << LED_Y_BIT_OFFSET))
typedef struct ledConfig_s {
uint8_t xy; // see LED_X/Y_MASK defines
uint16_t flags; // see ledFlag_e
} ledConfig_t;
static uint8_t ledGridWidth;
static uint8_t ledGridHeight;
#ifdef USE_ALTERNATE_LED_LAYOUT
static const ledConfig_t ledConfigs[WS2811_LED_STRIP_LENGTH] = {
{ LED_XY( 1, 14), LED_DIRECTION_SOUTH | LED_FUNCTION_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 0, 13), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 0, 12), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 0, 11), LED_DIRECTION_WEST | LED_FUNCTION_MODE },
{ LED_XY( 0, 10), LED_DIRECTION_WEST | LED_FUNCTION_MODE },
{ LED_XY( 0, 9), LED_DIRECTION_WEST | LED_FUNCTION_MODE },
{ LED_XY( 0, 8), LED_DIRECTION_WEST | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 0, 7), LED_DIRECTION_WEST | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 0, 6), LED_DIRECTION_WEST | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 0, 5), LED_DIRECTION_WEST | LED_FUNCTION_MODE },
{ LED_XY( 0, 4), LED_DIRECTION_WEST | LED_FUNCTION_MODE },
{ LED_XY( 0, 3), LED_DIRECTION_WEST | LED_FUNCTION_MODE },
{ LED_XY( 0, 2), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 0, 1), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 1, 0), LED_DIRECTION_NORTH | LED_FUNCTION_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 2, 0), LED_DIRECTION_NORTH | LED_FUNCTION_MODE | LED_FUNCTION_ARM_STATE },
{ LED_XY( 3, 0), LED_DIRECTION_NORTH | LED_FUNCTION_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 4, 1), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 4, 2), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 4, 3), LED_DIRECTION_EAST | LED_FUNCTION_MODE },
{ LED_XY( 4, 4), LED_DIRECTION_EAST | LED_FUNCTION_MODE },
{ LED_XY( 4, 5), LED_DIRECTION_EAST | LED_FUNCTION_MODE },
{ LED_XY( 4, 6), LED_DIRECTION_EAST | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 4, 7), LED_DIRECTION_EAST | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 4, 8), LED_DIRECTION_EAST | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 4, 9), LED_DIRECTION_EAST | LED_FUNCTION_MODE },
{ LED_XY( 4, 10), LED_DIRECTION_EAST | LED_FUNCTION_MODE },
{ LED_XY( 4, 11), LED_DIRECTION_EAST | LED_FUNCTION_MODE },
{ LED_XY( 4, 12), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 4, 13), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 3, 14), LED_DIRECTION_SOUTH | LED_FUNCTION_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
static const char directionCodes[] = { 'N', 'E', 'S', 'W', 'U', 'D' };
#define DIRECTION_COUNT (sizeof(directionCodes) / sizeof(directionCodes[0]))
static const uint8_t directionMappings[DIRECTION_COUNT] = {
LED_DIRECTION_NORTH,
LED_DIRECTION_EAST,
LED_DIRECTION_SOUTH,
LED_DIRECTION_WEST,
LED_DIRECTION_UP,
LED_DIRECTION_DOWN
};
#else
static const ledConfig_t ledConfigs[WS2811_LED_STRIP_LENGTH] = {
{ LED_XY( 9, 9), LED_DIRECTION_SOUTH | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY(10, 10), LED_DIRECTION_SOUTH | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY(11, 11), LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY(11, 11), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY(10, 10), LED_DIRECTION_EAST | LED_FUNCTION_MODE },
{ LED_XY( 9, 9), LED_DIRECTION_EAST | LED_FUNCTION_MODE },
{ LED_XY(10, 5), LED_DIRECTION_SOUTH | LED_FUNCTION_MODE },
{ LED_XY(11, 4), LED_DIRECTION_SOUTH | LED_FUNCTION_MODE },
{ LED_XY(12, 3), LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY(12, 2), LED_DIRECTION_NORTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY(11, 1), LED_DIRECTION_NORTH | LED_FUNCTION_MODE },
{ LED_XY(10, 0), LED_DIRECTION_NORTH | LED_FUNCTION_MODE },
{ LED_XY( 7, 0), LED_DIRECTION_NORTH | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 6, 0), LED_DIRECTION_NORTH | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 5, 0), LED_DIRECTION_NORTH | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 4, 0), LED_DIRECTION_NORTH | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 2, 0), LED_DIRECTION_NORTH | LED_FUNCTION_MODE },
{ LED_XY( 1, 1), LED_DIRECTION_NORTH | LED_FUNCTION_MODE },
{ LED_XY( 0, 2), LED_DIRECTION_NORTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 0, 3), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 1, 4), LED_DIRECTION_WEST | LED_FUNCTION_MODE },
{ LED_XY( 2, 5), LED_DIRECTION_WEST | LED_FUNCTION_MODE },
{ LED_XY( 2, 9), LED_DIRECTION_WEST | LED_FUNCTION_MODE },
{ LED_XY( 1, 10), LED_DIRECTION_WEST | LED_FUNCTION_MODE },
{ LED_XY( 0, 11), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 0, 11), LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ LED_XY( 1, 10), LED_DIRECTION_SOUTH | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY },
{ LED_XY( 2, 9), LED_DIRECTION_SOUTH | LED_FUNCTION_MODE | LED_FUNCTION_BATTERY }
static const char functionCodes[] = { 'I', 'B', 'F', 'A' };
#define FUNCTION_COUNT (sizeof(functionCodes) / sizeof(functionCodes[0]))
static const uint16_t functionMappings[FUNCTION_COUNT] = {
LED_FUNCTION_INDICATOR,
LED_FUNCTION_BATTERY,
LED_FUNCTION_FLIGHT_MODE,
LED_FUNCTION_ARM_STATE
};
#endif
// grid offsets
uint8_t highestYValueForNorth;
@ -179,6 +145,168 @@ uint8_t lowestYValueForSouth;
uint8_t highestXValueForWest;
uint8_t lowestXValueForEast;
void determineLedStripDimensions(void)
{
ledGridWidth = 0;
ledGridHeight = 0;
uint8_t ledIndex;
const ledConfig_t *ledConfig;
for (ledIndex = 0; ledIndex < ledCount; ledIndex++) {
ledConfig = &ledConfigs[ledIndex];
if (GET_LED_X(ledConfig) >= ledGridWidth) {
ledGridWidth = GET_LED_X(ledConfig) + 1;
}
if (GET_LED_Y(ledConfig) >= ledGridHeight) {
ledGridHeight = GET_LED_Y(ledConfig) + 1;
}
}
}
void determineOrientationLimits(void)
{
bool isOddHeight = (ledGridHeight & 1);
bool isOddWidth = (ledGridWidth & 1);
uint8_t heightModifier = isOddHeight ? 1 : 0;
uint8_t widthModifier = isOddWidth ? 1 : 0;
highestYValueForNorth = (ledGridHeight / 2) - 1;
lowestYValueForSouth = (ledGridHeight / 2) + heightModifier;
highestXValueForWest = (ledGridWidth / 2) - 1;
lowestXValueForEast = (ledGridWidth / 2) + widthModifier;
}
void updateLedCount(void)
{
uint8_t ledIndex;
ledCount = 0;
for (ledIndex = 0; ledIndex < MAX_LED_STRIP_LENGTH; ledIndex++) {
if (ledConfigs[ledIndex].flags == 0 && ledConfigs[ledIndex].xy == 0) {
break;
}
ledCount++;
}
}
static void reevalulateLedConfig(void)
{
updateLedCount();
determineLedStripDimensions();
determineOrientationLimits();
}
#define CHUNK_BUFFER_SIZE 10
#define NEXT_PARSE_STATE(parseState) ((parseState + 1) % PARSE_STATE_COUNT)
bool parseLedStripConfig(uint8_t ledIndex, const char *config)
{
char chunk[CHUNK_BUFFER_SIZE];
uint8_t chunkIndex;
uint8_t val;
uint8_t parseState = X_COORDINATE;
bool ok = true;
if (ledIndex >= MAX_LED_STRIP_LENGTH) {
return !ok;
}
ledConfig_t *ledConfig = &ledConfigs[ledIndex];
memset(ledConfig, 0, sizeof(ledConfig_t));
while (ok) {
char chunkSeparator = chunkSeparators[parseState];
memset(&chunk, 0, sizeof(chunk));
chunkIndex = 0;
while (*config && chunkIndex < CHUNK_BUFFER_SIZE && *config != chunkSeparator) {
chunk[chunkIndex++] = *config++;
}
if (*config++ != chunkSeparator) {
ok = false;
break;
}
switch((parseState_e)parseState) {
case X_COORDINATE:
val = atoi(chunk);
ledConfig->xy |= CALCULATE_LED_X(val);
break;
case Y_COORDINATE:
val = atoi(chunk);
ledConfig->xy |= CALCULATE_LED_Y(val);
break;
case DIRECTIONS:
for (chunkIndex = 0; chunk[chunkIndex] && chunkIndex < CHUNK_BUFFER_SIZE; chunkIndex++) {
for (uint8_t mappingIndex = 0; mappingIndex < DIRECTION_COUNT; mappingIndex++) {
if (directionCodes[mappingIndex] == chunk[chunkIndex]) {
ledConfig->flags |= directionMappings[mappingIndex];
break;
}
}
}
break;
case FUNCTIONS:
for (chunkIndex = 0; chunk[chunkIndex] && chunkIndex < CHUNK_BUFFER_SIZE; chunkIndex++) {
for (uint8_t mappingIndex = 0; mappingIndex < FUNCTION_COUNT; mappingIndex++) {
if (functionCodes[mappingIndex] == chunk[chunkIndex]) {
ledConfig->flags |= functionMappings[mappingIndex];
break;
}
}
}
break;
}
parseState++;
if (parseState >= PARSE_STATE_COUNT) {
break;
}
}
if (!ok) {
memset(ledConfig, 0, sizeof(ledConfig_t));
}
reevalulateLedConfig();
return ok;
}
void generateLedConfig(uint8_t ledIndex, char *ledConfigBuffer, size_t bufferSize)
{
char functions[FUNCTION_COUNT];
char directions[DIRECTION_COUNT];
uint8_t index;
uint8_t mappingIndex;
ledConfig_t *ledConfig = &ledConfigs[ledIndex];
memset(ledConfigBuffer, 0, bufferSize);
memset(&functions, 0, sizeof(functions));
memset(&directions, 0, sizeof(directions));
for (mappingIndex = 0, index = 0; mappingIndex < FUNCTION_COUNT; mappingIndex++) {
if (ledConfig->flags & functionMappings[mappingIndex]) {
functions[index++] = functionCodes[mappingIndex];
}
}
for (mappingIndex = 0, index = 0; mappingIndex < DIRECTION_COUNT; mappingIndex++) {
if (ledConfig->flags & directionMappings[mappingIndex]) {
directions[index++] = directionCodes[mappingIndex];
}
}
sprintf(ledConfigBuffer, "%u,%u:%s:%s", GET_LED_X(ledConfig), GET_LED_Y(ledConfig), directions, functions);
}
// timers
uint32_t nextAnimationUpdateAt = 0;
uint32_t nextIndicatorFlashAt = 0;
@ -207,69 +335,97 @@ typedef union {
static const modeColors_t orientationModeColors = {
.raw = {
{LED_WHITE},
{LED_BLUE},
{LED_DARK_VIOLET},
{LED_RED},
{LED_GREEN},
{LED_PURPLE},
{LED_CYAN}
{LED_DEEP_PINK},
{LED_BLUE},
{LED_ORANGE}
}
};
static const modeColors_t headfreeModeColors = {
.raw = {
{LED_PINK},
{LED_BLACK},
{LED_LIME_GREEN},
{LED_DARK_VIOLET},
{LED_ORANGE},
{LED_BLACK},
{LED_BLACK},
{LED_BLACK}
{LED_DEEP_PINK},
{LED_BLUE},
{LED_ORANGE}
}
};
static const modeColors_t horizonModeColors = {
.raw = {
{LED_BLUE},
{LED_BLACK},
{LED_DARK_VIOLET},
{LED_YELLOW},
{LED_BLACK},
{LED_BLACK},
{LED_BLACK}
{LED_DEEP_PINK},
{LED_BLUE},
{LED_ORANGE}
}
};
static const modeColors_t angleModeColors = {
.raw = {
{LED_CYAN},
{LED_BLACK},
{LED_DARK_VIOLET},
{LED_YELLOW},
{LED_BLACK},
{LED_BLACK},
{LED_BLACK}
{LED_DEEP_PINK},
{LED_BLUE},
{LED_ORANGE}
}
};
static const modeColors_t magModeColors = {
.raw = {
{LED_PURPLE},
{LED_BLACK},
{LED_PINK},
{LED_DARK_VIOLET},
{LED_ORANGE},
{LED_BLACK},
{LED_BLACK},
{LED_BLACK}
{LED_DEEP_PINK},
{LED_BLUE},
{LED_ORANGE}
}
};
static const modeColors_t baroModeColors = {
.raw = {
{LED_LIGHT_BLUE},
{LED_DARK_VIOLET},
{LED_RED},
{LED_DEEP_PINK},
{LED_BLUE},
{LED_ORANGE}
}
};
void applyDirectionalModeColor(const uint8_t ledIndex, const ledConfig_t *ledConfig, const modeColors_t *modeColors)
{
if (ledConfig->flags & LED_DIRECTION_NORTH && LED_Y(ledConfig) < highestYValueForNorth) {
setLedColor(ledIndex, &modeColors->colors.north);
return;
// apply up/down colors regardless of quadrant.
if ((ledConfig->flags & LED_DIRECTION_UP)) {
setLedColor(ledIndex, &modeColors->colors.up);
}
if (ledConfig->flags & LED_DIRECTION_SOUTH && LED_Y(ledConfig) >= lowestYValueForSouth) {
setLedColor(ledIndex, &modeColors->colors.south);
return;
if ((ledConfig->flags & LED_DIRECTION_DOWN)) {
setLedColor(ledIndex, &modeColors->colors.down);
}
// override with n/e/s/w colors to each n/s e/w half - bail at first match.
if ((ledConfig->flags & LED_DIRECTION_WEST) && GET_LED_X(ledConfig) <= highestXValueForWest) {
setLedColor(ledIndex, &modeColors->colors.west);
}
if ((ledConfig->flags & LED_DIRECTION_EAST) && GET_LED_X(ledConfig) >= lowestXValueForEast) {
setLedColor(ledIndex, &modeColors->colors.east);
}
if ((ledConfig->flags & LED_DIRECTION_NORTH) && GET_LED_Y(ledConfig) <= highestYValueForNorth) {
setLedColor(ledIndex, &modeColors->colors.north);
}
if ((ledConfig->flags & LED_DIRECTION_SOUTH) && GET_LED_Y(ledConfig) >= lowestYValueForSouth) {
setLedColor(ledIndex, &modeColors->colors.south);
}
}
typedef enum {
@ -283,25 +439,25 @@ void applyQuadrantColor(const uint8_t ledIndex, const ledConfig_t *ledConfig, co
{
switch (quadrant) {
case QUADRANT_NORTH_EAST:
if (LED_Y(ledConfig) <= highestYValueForNorth && LED_X(ledConfig) >= lowestXValueForEast) {
if (GET_LED_Y(ledConfig) <= highestYValueForNorth && GET_LED_X(ledConfig) >= lowestXValueForEast) {
setLedColor(ledIndex, color);
}
return;
case QUADRANT_SOUTH_EAST:
if (LED_Y(ledConfig) >= lowestYValueForSouth && LED_X(ledConfig) >= lowestXValueForEast) {
if (GET_LED_Y(ledConfig) >= lowestYValueForSouth && GET_LED_X(ledConfig) >= lowestXValueForEast) {
setLedColor(ledIndex, color);
}
return;
case QUADRANT_SOUTH_WEST:
if (LED_Y(ledConfig) >= lowestYValueForSouth && LED_X(ledConfig) <= highestXValueForWest) {
if (GET_LED_Y(ledConfig) >= lowestYValueForSouth && GET_LED_X(ledConfig) <= highestXValueForWest) {
setLedColor(ledIndex, color);
}
return;
case QUADRANT_NORTH_WEST:
if (LED_Y(ledConfig) <= highestYValueForNorth && LED_X(ledConfig) <= highestXValueForWest) {
if (GET_LED_Y(ledConfig) <= highestYValueForNorth && GET_LED_X(ledConfig) <= highestXValueForWest) {
setLedColor(ledIndex, color);
}
return;
@ -313,13 +469,13 @@ void applyLedModeLayer(void)
const ledConfig_t *ledConfig;
uint8_t ledIndex;
for (ledIndex = 0; ledIndex < WS2811_LED_STRIP_LENGTH; ledIndex++) {
for (ledIndex = 0; ledIndex < ledCount; ledIndex++) {
ledConfig = &ledConfigs[ledIndex];
setLedColor(ledIndex, &black);
if (!(ledConfig->flags & LED_FUNCTION_MODE)) {
if (!(ledConfig->flags & LED_FUNCTION_FLIGHT_MODE)) {
if (ledConfig->flags & LED_FUNCTION_ARM_STATE) {
if (!ARMING_FLAG(ARMED)) {
setLedColor(ledIndex, &green);
@ -337,6 +493,10 @@ void applyLedModeLayer(void)
#ifdef MAG
} else if (FLIGHT_MODE(MAG_MODE)) {
applyDirectionalModeColor(ledIndex, ledConfig, &magModeColors);
#endif
#ifdef BARO
} else if (FLIGHT_MODE(BARO_MODE)) {
applyDirectionalModeColor(ledIndex, ledConfig, &baroModeColors);
#endif
} else if (FLIGHT_MODE(HORIZON_MODE)) {
applyDirectionalModeColor(ledIndex, ledConfig, &horizonModeColors);
@ -351,7 +511,7 @@ void applyLedLowBatteryLayer(uint8_t batteryFlashState)
const ledConfig_t *ledConfig;
uint8_t ledIndex;
for (ledIndex = 0; ledIndex < WS2811_LED_STRIP_LENGTH; ledIndex++) {
for (ledIndex = 0; ledIndex < ledCount; ledIndex++) {
ledConfig = &ledConfigs[ledIndex];
@ -381,7 +541,7 @@ void applyLedIndicatorLayer(uint8_t indicatorFlashState)
uint8_t ledIndex;
for (ledIndex = 0; ledIndex < WS2811_LED_STRIP_LENGTH; ledIndex++) {
for (ledIndex = 0; ledIndex < ledCount; ledIndex++) {
ledConfig = &ledConfigs[ledIndex];
@ -428,6 +588,7 @@ static void updateLedAnimationState(void)
frameCounter = (frameCounter + 1) % animationFrames;
}
#ifdef USE_LED_ANIMATION
static void applyLedAnimationLayer(void)
{
const ledConfig_t *ledConfig;
@ -437,21 +598,22 @@ static void applyLedAnimationLayer(void)
}
uint8_t ledIndex;
for (ledIndex = 0; ledIndex < WS2811_LED_STRIP_LENGTH; ledIndex++) {
for (ledIndex = 0; ledIndex < ledCount; ledIndex++) {
ledConfig = &ledConfigs[ledIndex];
if (LED_Y(ledConfig) == previousRow) {
if (GET_LED_Y(ledConfig) == previousRow) {
setLedColor(ledIndex, &white);
setLedBrightness(ledIndex, 50);
} else if (LED_Y(ledConfig) == currentRow) {
} else if (GET_LED_Y(ledConfig) == currentRow) {
setLedColor(ledIndex, &white);
} else if (LED_Y(ledConfig) == nextRow) {
} else if (GET_LED_Y(ledConfig) == nextRow) {
setLedBrightness(ledIndex, 50);
}
}
}
#endif
void updateLedStrip(void)
{
@ -519,57 +681,22 @@ void updateLedStrip(void)
updateLedAnimationState();
}
#ifdef USE_LED_ANIMATION
applyLedAnimationLayer();
#endif
ws2811UpdateStrip();
}
void determineLedStripDimensions()
void applyDefaultLedStripConfig(ledConfig_t *ledConfigs)
{
ledGridWidth = 0;
ledGridHeight = 0;
uint8_t ledIndex;
const ledConfig_t *ledConfig;
for (ledIndex = 0; ledIndex < WS2811_LED_STRIP_LENGTH; ledIndex++) {
ledConfig = &ledConfigs[ledIndex];
if (LED_X(ledConfig) >= ledGridWidth) {
ledGridWidth = LED_X(ledConfig) + 1;
}
if (LED_Y(ledConfig) >= ledGridHeight) {
ledGridHeight = LED_Y(ledConfig) + 1;
}
}
memset(ledConfigs, 0, MAX_LED_STRIP_LENGTH * sizeof(ledConfig_t));
memcpy(ledConfigs, &defaultLedStripConfig, sizeof(defaultLedStripConfig));
reevalulateLedConfig();
}
void determineOrientationLimits(void)
void ledStripInit(ledConfig_t *ledConfigsToUse)
{
highestYValueForNorth = (ledGridHeight / 2) - 1;
if (highestYValueForNorth > 1) { // support small grid (e.g. gridwidth 5)
highestYValueForNorth &= ~(1 << 0); // make even
}
lowestYValueForSouth = (ledGridHeight / 2) - 1;
if (lowestYValueForSouth & 1) {
lowestYValueForSouth = min(lowestYValueForSouth + 1, ledGridHeight - 1);
}
highestXValueForWest = (ledGridWidth / 2) - 1;
if (highestXValueForWest > 1) { // support small grid (e.g. gridwidth 5)
highestXValueForWest &= ~(1 << 0); // make even
}
lowestXValueForEast = (ledGridWidth / 2) - 1;
if (lowestXValueForEast & 1) {
lowestXValueForEast = min(lowestXValueForEast + 1, ledGridWidth - 1);
}
}
void ledStripInit(void)
{
determineLedStripDimensions();
determineOrientationLimits();
ledConfigs = ledConfigsToUse;
reevalulateLedConfig();
}
#endif