Skip to content

Commit

Permalink
Add support for LED thrust ring. (St7ven)
Browse files Browse the repository at this point in the history
This commit includes various fixed not included in the original pull request.
  • Loading branch information
St7ven authored and hydra committed Jan 22, 2015
1 parent d2536e3 commit ddc7a39
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 33 deletions.
19 changes: 19 additions & 0 deletions docs/LedStrip.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ Note: It is perfectly possible to configure an LED to have all directions `NESWU
* `I` - `I`ndicator.
* `A` - `A`rmed state.
* `T` - `T`hrust state.
* `R` - `R`ing thrust state.

Example:

Expand Down Expand Up @@ -171,6 +172,24 @@ This mode fades the LED current LED color to the previous/next color in the HSB
throttle is in the middle position the color is unaffected, thus it can be mixed with orientation colors to indicate orientation and throttle at
the same time.

#### Thrust ring state

This mode is allows you to use a 12, 16 or 24 leds ring (e.g. NeoPixel ring) for an afterburner effect. When armed the leds use the following sequences: 2 On, 4 Off, 2 On, 4 Off, and so on. The light pattern rotates clockwise as throttle increases.

A better effect is acheived when LEDs configured for thrust ring have no other functions.

LED direction and X/Y positions are irrelevant for thrust ring LED state. The order of the LEDs that have the state determines how the LED behaves.

Each LED of the ring can be a different color. The color can be selected between the 15 colors availables.

For example, led 0 is set as a `R`ing thrust state led in color 13 as follow.

```
led 0 2,2::R:13
```

LED strips and rings can be combined.

## Positioning

Cut the strip into sections as per diagrams below. When the strips are cut ensure you reconnect each output to each input with cable where the break is made.
Expand Down
181 changes: 151 additions & 30 deletions src/main/io/ledstrip.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ static failsafe_t* failsafe;
static void ledStripDisable(void);

//#define USE_LED_ANIMATION
//#define USE_LED_RING_DEFAULT_CONFIG

// timers
#ifdef USE_LED_ANIMATION
Expand All @@ -63,6 +64,7 @@ static uint32_t nextAnimationUpdateAt = 0;

static uint32_t nextIndicatorFlashAt = 0;
static uint32_t nextWarningFlashAt = 0;
static uint32_t nextRotationUpdateAt = 0;

#define LED_STRIP_20HZ ((1000 * 1000) / 20)
#define LED_STRIP_10HZ ((1000 * 1000) / 10)
Expand Down Expand Up @@ -225,23 +227,44 @@ static const modeColorIndexes_t baroModeColors = {
uint8_t ledGridWidth;
uint8_t ledGridHeight;
uint8_t ledCount;
uint8_t ledsInRingCount;

ledConfig_t *ledConfigs;
hsvColor_t *colors;


#ifdef USE_LED_RING_DEFAULT_CONFIG
const ledConfig_t defaultLedStripConfig[] = {
{ CALCULATE_LED_XY( 2, 2), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 2, 1), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 2, 0), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 0), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 0, 0), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 0, 1), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 0, 2), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 2), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 1), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 1), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 1), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 1), 3, LED_FUNCTION_THRUST_RING},
};
#else
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_WARNING },
{ 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 },
{ 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_WARNING },
{ 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_WARNING },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_UP | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_UP | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_DOWN | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_DOWN | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 2, 2), 0, LED_DIRECTION_SOUTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 2, 1), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 2, 0), 0, LED_DIRECTION_NORTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 0), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 0), 0, LED_DIRECTION_NORTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 1), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 0, 2), 0, LED_DIRECTION_SOUTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 2), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), 0, LED_DIRECTION_UP | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), 0, LED_DIRECTION_UP | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), 0, LED_DIRECTION_DOWN | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), 0, LED_DIRECTION_DOWN | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
};
#endif



/*
Expand All @@ -258,12 +281,13 @@ typedef enum {
X_COORDINATE,
Y_COORDINATE,
DIRECTIONS,
FUNCTIONS
FUNCTIONS,
RING_COLORS
} parseState_e;

#define PARSE_STATE_COUNT 4
#define PARSE_STATE_COUNT 5

static const char chunkSeparators[PARSE_STATE_COUNT] = {',', ':', ':', '\0' };
static const char chunkSeparators[PARSE_STATE_COUNT] = {',', ':', ':',':', '\0' };

static const char directionCodes[] = { 'N', 'E', 'S', 'W', 'U', 'D' };
#define DIRECTION_COUNT (sizeof(directionCodes) / sizeof(directionCodes[0]))
Expand All @@ -276,14 +300,15 @@ static const uint8_t directionMappings[DIRECTION_COUNT] = {
LED_DIRECTION_DOWN
};

static const char functionCodes[] = { 'I', 'W', 'F', 'A', 'T' };
static const char functionCodes[] = { 'I', 'W', 'F', 'A', 'T', 'R' };
#define FUNCTION_COUNT (sizeof(functionCodes) / sizeof(functionCodes[0]))
static const uint16_t functionMappings[FUNCTION_COUNT] = {
LED_FUNCTION_INDICATOR,
LED_FUNCTION_WARNING,
LED_FUNCTION_FLIGHT_MODE,
LED_FUNCTION_ARM_STATE,
LED_FUNCTION_THROTTLE
LED_FUNCTION_THROTTLE,
LED_FUNCTION_THRUST_RING
};

// grid offsets
Expand Down Expand Up @@ -327,13 +352,24 @@ void determineOrientationLimits(void)

void updateLedCount(void)
{
const ledConfig_t *ledConfig;
uint8_t ledIndex;
ledCount = 0;
ledsInRingCount = 0;

for (ledIndex = 0; ledIndex < MAX_LED_STRIP_LENGTH; ledIndex++) {
if (ledConfigs[ledIndex].flags == 0 && ledConfigs[ledIndex].xy == 0) {

ledConfig = &ledConfigs[ledIndex];

if (ledConfig->flags == 0 && ledConfig->xy == 0) {
break;
}

ledCount++;

if ((ledConfig->flags & LED_FUNCTION_THRUST_RING)) {
ledsInRingCount++;
}
}
}

Expand Down Expand Up @@ -410,6 +446,15 @@ bool parseLedStripConfig(uint8_t ledIndex, const char *config)
}
}
break;
case RING_COLORS:
if (atoi(chunk) < CONFIGURABLE_COLOR_COUNT) {
ledConfig->color = atoi(chunk);
} else {
ledConfig->color = 0;
}
break;
default :
break;
}

parseState++;
Expand All @@ -433,11 +478,13 @@ void generateLedConfig(uint8_t ledIndex, char *ledConfigBuffer, size_t bufferSiz
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));
//memset(&ringColors, 0 ,sizeof(ringColors));

for (mappingIndex = 0, index = 0; mappingIndex < FUNCTION_COUNT; mappingIndex++) {
if (ledConfig->flags & functionMappings[mappingIndex]) {
Expand All @@ -451,7 +498,7 @@ void generateLedConfig(uint8_t ledIndex, char *ledConfigBuffer, size_t bufferSiz
}
}

sprintf(ledConfigBuffer, "%u,%u:%s:%s", GET_LED_X(ledConfig), GET_LED_Y(ledConfig), directions, functions);
sprintf(ledConfigBuffer, "%u,%u:%s:%s:%u", GET_LED_X(ledConfig), GET_LED_Y(ledConfig), directions, functions, ledConfig->color);
}

void applyDirectionalModeColor(const uint8_t ledIndex, const ledConfig_t *ledConfig, const modeColorIndexes_t *modeColors)
Expand Down Expand Up @@ -529,7 +576,9 @@ void applyLedModeLayer(void)

ledConfig = &ledConfigs[ledIndex];

setLedHsv(ledIndex, &hsv_black);
if (!(ledConfig->flags & LED_FUNCTION_THRUST_RING)) {
setLedHsv(ledIndex, &hsv_black);
}

if (!(ledConfig->flags & LED_FUNCTION_FLIGHT_MODE)) {
if (ledConfig->flags & LED_FUNCTION_ARM_STATE) {
Expand Down Expand Up @@ -682,7 +731,7 @@ void applyLedThrottleLayer()
uint8_t ledIndex;
for (ledIndex = 0; ledIndex < ledCount; ledIndex++) {
ledConfig = &ledConfigs[ledIndex];
if(!(ledConfig->flags & LED_FUNCTION_THROTTLE)) {
if (!(ledConfig->flags & LED_FUNCTION_THROTTLE)) {
continue;
}

Expand All @@ -695,15 +744,77 @@ void applyLedThrottleLayer()
}
}

#ifdef USE_LED_ANIMATION
static uint8_t frameCounter = 0;
int applyLedThrustRingLayer(void)
{
uint8_t oppositeLedIndex = ledsInRingCount >> 1;
uint8_t ledIndex;
int returnedValue = 1;
int throttleScaled = scaleRange(rcData[THROTTLE], PWM_RANGE_MIN, PWM_RANGE_MAX, 1, 10);
static uint8_t rotationPhase = 0;
static bool nextLedOn = false;
hsvColor_t ringColor;
const ledConfig_t *ledConfig;


for (ledIndex = 0; ledIndex < ledCount; ledIndex++) {

ledConfig = &ledConfigs[ledIndex];

static uint8_t previousRow;
static uint8_t currentRow;
static uint8_t nextRow;
ringColor = colors[ledConfig->color];

static void updateLedAnimationState(void)
if ((ledConfig->flags & LED_FUNCTION_THRUST_RING)) {

if (!ARMING_FLAG(ARMED)) {

if (nextLedOn == false) {
nextLedOn = true;
}
else {
nextLedOn = false;
ringColor = hsv_black;
}

returnedValue = 1;
}
else {
if (rotationPhase == ((oppositeLedIndex) - 1)) {
if (!((ledIndex == rotationPhase) || (ledIndex == (rotationPhase + oppositeLedIndex))
|| (ledIndex == (rotationPhase +1)) || (ledIndex == 0))) {
ringColor = hsv_black;
}
}
else if (!((ledIndex == rotationPhase) || (ledIndex == (rotationPhase + oppositeLedIndex))
|| (ledIndex == (rotationPhase +1)) || (ledIndex == (rotationPhase + oppositeLedIndex +1 )))) {
ringColor = hsv_black;
}
else {
// Led stay on
}

returnedValue = throttleScaled;
}
setLedHsv(ledIndex, &ringColor);
}
}

if (rotationPhase >= (oppositeLedIndex - 1)) {
rotationPhase = 0;
}
else {
rotationPhase++;
}

return returnedValue;
}

#ifdef USE_LED_ANIMATION
void updateLedAnimationState(void)
{
static uint8_t frameCounter = 0;

static uint8_t previousRow;
static uint8_t currentRow;
static uint8_t nextRow;
uint8_t animationFrames = ledGridHeight;

previousRow = (frameCounter + animationFrames - 1) % animationFrames;
Expand Down Expand Up @@ -741,7 +852,8 @@ static void applyLedAnimationLayer(void)

void updateLedStrip(void)
{
if (!(ledStripInitialised && isWS2811LedStripReady())) {

if (!(ledStripInitialised && isWS2811LedStripReady())) {
return;
}

Expand All @@ -762,12 +874,14 @@ void updateLedStrip(void)
uint32_t now = micros();

bool indicatorFlashNow = indicatorFlashNow = (int32_t)(now - nextIndicatorFlashAt) >= 0L;
bool warningFlashNow =warningFlashNow = (int32_t)(now - nextWarningFlashAt) >= 0L;
bool warningFlashNow = warningFlashNow = (int32_t)(now - nextWarningFlashAt) >= 0L;
bool rotationUpdateNow = (int32_t)(now - nextRotationUpdateAt) >= 0L;
#ifdef USE_LED_ANIMATION
bool animationUpdateNow = animationUpdateNow = (int32_t)(now - nextAnimationUpdateAt) >= 0L;
#endif
if (!(
indicatorFlashNow ||
rotationUpdateNow ||
warningFlashNow
#ifdef USE_LED_ANIMATION
|| animationUpdateNow
Expand Down Expand Up @@ -812,10 +926,16 @@ void updateLedStrip(void)
nextAnimationUpdateAt = now + LED_STRIP_20HZ;
updateLedAnimationState();
}

applyLedAnimationLayer();
#endif

if (rotationUpdateNow) {

int animationSpeedScaled = applyLedThrustRingLayer();

nextRotationUpdateAt = now + LED_STRIP_5HZ/animationSpeedScaled; // TODO will be changed with more specifics animation
}

ws2811UpdateStrip();
}

Expand All @@ -835,6 +955,7 @@ bool parseColor(uint8_t index, const char *colorConfig)
if (val > HSV_HUE_MAX) {
ok = false;
continue;

}
colors[index].h = val;
break;
Expand Down
Loading

0 comments on commit ddc7a39

Please sign in to comment.