1
0
Fork 0
mirror of https://github.com/iNavFlight/inav.git synced 2025-07-23 00:05:28 +03:00

LED strip rework (#362)

* Implement new LED strip functions from CF and BF.
* Warnings: blink to black instead of function color
This commit is contained in:
Gaël James 2016-07-24 09:49:37 +02:00 committed by Konstantin Sharlaimov
parent be470a5c8d
commit 53e872cee8
15 changed files with 1453 additions and 951 deletions

View file

@ -12,14 +12,12 @@ supports the following:
* Heading/Orientation lights.
* Flight mode specific color schemes.
* Low battery warning.
* AUX operated on/off switch
* AUX operated on/off switch.
* GPS state.
* RSSI level.
* Battery level.
The function and orientation configuration is fixed for now but later it should be able to be set via the UI or CLI..
In the future, if someone codes it, they could be used to show GPS navigation status, thrust levels, RSSI, etc.
Lots of scope for ideas and improvements.
Likewise, support for more than 32 LEDs is possible, it just requires additional development.
Support for more than 32 LEDs is possible, it just requires additional development.
## Supported hardware
@ -71,12 +69,12 @@ The datasheet can be found here: http://www.adafruit.com/datasheets/WS2812.pdf
## Configuration
The led strip feature can be configured via the GUI
The led strip feature can be configured via the GUI.
GUI:
Enable the Led Strip feature via the GUI under setup.
Configure the leds from the Led Strip tab in the cleanflight GUI.
Configure the leds from the Led Strip tab in the INAV GUI.
First setup how the led's are laid out so that you can visualize it later as you configure and so the flight controller knows how many led's there are available.
There is a step by step guide on how to use the GUI to configure the Led Strip feature using the GUI http://blog.oscarliang.net/setup-rgb-led-cleanflight/ which was published early 2015 by Oscar Liang which may or may not be up-to-date by the time you read this.
@ -112,27 +110,39 @@ For instance, an LED that faces South-east at a 45 degree downwards angle could
Note: It is perfectly possible to configure an LED to have all directions `NESWUD` but probably doesn't make sense.
`mmm` specifies the modes that should be applied an LED. Modes are:
`mmm` specifies the modes that should be applied an LED.
Each LED has one base function:
* `C` - `C`olor.
* `F` - `F`light mode & Orientation
* `A` - `A`rmed state.
* `R` - `R`ing thrust state.
* `G` - `G`PS state.
* `S` - R`S`SSI level.
* `L` - Battery `L`evel.
And each LED has overlays:
* `W` - `W`warnings.
* `F` - `F`light mode & Orientation
* `I` - `I`ndicator.
* `A` - `A`rmed state.
* `T` - `T`hrust state.
* `R` - `R`ing thrust state.
* `C` - `C`olor.
* `B` - `B`link (flash twice) mode.
* `O` - Lars`O`n Scanner (Cylon Effect).
* `N` - Blink on la`N`ding (throttle < 50%).
`cc` specifies the color number (0 based index).
Example:
```
led 0 0,15:SD:IAW:0
led 1 15,0:ND:IAW:0
led 2 0,0:ND:IAW:0
led 3 0,15:SD:IAW:0
led 0 0,15:SD:AWI:0
led 1 15,0:ND:AWI:0
led 2 0,0:ND:AWI:0
led 3 0,15:SD:AWI:0
led 4 7,7::C:1
led 5 8,8::C:2
led 6 8,9::B:1
```
To erase an led, and to mark the end of the chain, use `0,0::` as the second argument, like this:
@ -157,6 +167,61 @@ This mode simply uses the LEDs to flash when warnings occur.
Flash patterns appear in order, so that it's clear which warnings are enabled.
#### GPS state
This mode shows the GPS state and satellite count.
No fix = red LED
3D fix = green LED
The LEDs will blink as many times as the satellite count, then pause and start again.
#### RSSI level
This mode binds the LED color to RSSI level.
| Color | RSSI |
| ---------- | ---------|
| Green | 100% |
| Lime green | 80% |
| Yellow | 60% |
| Orange | 40% |
| Red | 20% |
| Deep pink | 0% |
When RSSI is below 50% is reached, LEDs will blink slowly, and they will blink fast when under 20%.
#### Battery level
This mode binds the LED color to remaining battery capacity.
| Color | Capacity |
| ---------- | ---------|
| Green | 100% |
| Lime green | 80% |
| Yellow | 60% |
| Orange | 40% |
| Red | 20% |
| Deep pink | 0% |
When Warning or Critial voltage is reached, LEDs will blink slowly or fast.
Note: this mode requires a current sensor. If you don't have the actual device you can set up a virtual current sensor (see [Battery](Battery.md)).
#### Blink
This mode blinks the current LED, alternatively from black to the current active color.
#### Blink on landing
This mode blinks the current LED, alternatively from black to the current active color, when throttle is below 50% and the craft is armed.
#### Larson Scanner (Cylon Effect)
The Larson Scanner replicates the scanning "eye" effect seen on the mechanical Cylons and on Kitt from Knight Rider.
This overlay merely varies the brightness of each LED's current color.
#### Flight Mode & Orientation
This mode shows the flight mode and orientation.
@ -234,7 +299,7 @@ the same time. Thrust should normally be combined with Color or Mode/Orientatio
#### 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.
This mode is allows you to use one or multiple led rings (e.g. NeoPixel ring) for an afterburner effect. The light pattern rotates clockwise as throttle increases.
A better effect is acheived when LEDs configured for thrust ring have no other functions.
@ -314,6 +379,57 @@ color 14 0,0,0
color 15 0,0,0
```
### Mode Colors Assignement
Mode Colors can be configured using the cli `mode_color` command.
- No arguments: lists all mode colors
- arguments: mode, function, color
First 6 groups of ModeIndexes are :
| mode | name |
|------|-------------|
| 0 | orientation |
| 1 | headfree |
| 2 | horizon |
| 3 | angle |
| 4 | mag |
| 5 | baro |
| 6 | special |
Modes 0 to 5 functions:
| function | name |
|----------|-------|
| 0 | north |
| 1 | east |
| 2 | south |
| 3 | west |
| 4 | up |
| 5 | down |
Mode 6 use these functions:
| function | name |
|----------|--------------------|
| 0 | disarmed |
| 1 | armed |
| 2 | animation |
| 3 | background |
| 4 | blink background |
| 5 | gps: no satellites |
| 6 | gps: no fix |
| 7 | gps: 3D fix |
The ColorIndex is picked from the colors array ("palette").
Examples (using the default colors):
- set armed color to red: ```mode_color 6 1 2```
- set disarmed color to yellow: ```mode_color 6 0 4```
- set Headfree mode 'south' to Cyan: ```mode_color 1 2 8```
## 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.

View file

@ -71,4 +71,15 @@ http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
static inline int16_t cmp16(uint16_t a, uint16_t b) { return a-b; }
static inline int32_t cmp32(uint32_t a, uint32_t b) { return a-b; }
// using memcpy_fn will force memcpy function call, instead of inlining it. In most cases function call takes fewer instructions
// than inlined version (inlining is cheaper for very small moves < 8 bytes / 2 store instructions)
#ifdef UNIT_TEST
// Call memcpy when building unittest - this is easier that asm symbol name mangling (symbols start with _underscore on win32)
#include <string.h>
static inline void memcpy_fn ( void * destination, const void * source, size_t num ) { memcpy(destination, source, num); };
#else
void * memcpy_fn ( void * destination, const void * source, size_t num ) asm("memcpy");
#endif
#endif

View file

@ -616,8 +616,11 @@ static void resetConf(void)
masterConfig.customMotorMixer[i].throttle = 0.0f;
#ifdef LED_STRIP
applyDefaultColors(masterConfig.colors, CONFIGURABLE_COLOR_COUNT);
applyDefaultColors(masterConfig.colors);
applyDefaultLedStripConfig(masterConfig.ledConfigs);
applyDefaultModeColors(masterConfig.modeColors);
applyDefaultSpecialColors(&(masterConfig.specialColors));
masterConfig.ledstrip_visual_beeper = 0;
#endif
#ifdef BLACKBOX

View file

@ -94,9 +94,13 @@ typedef struct master_t {
telemetryConfig_t telemetryConfig;
#ifdef LED_STRIP
ledConfig_t ledConfigs[MAX_LED_STRIP_LENGTH];
hsvColor_t colors[CONFIGURABLE_COLOR_COUNT];
ledConfig_t ledConfigs[LED_MAX_STRIP_LENGTH];
hsvColor_t colors[LED_CONFIGURABLE_COLOR_COUNT];
modeColorIndexes_t modeColors[LED_MODE_COUNT];
specialColorIndexes_t specialColors;
uint8_t ledstrip_visual_beeper; // suppress LEDLOW mode if beeper is on
#endif
profile_t profile[MAX_PROFILE_COUNT];

View file

@ -48,6 +48,3 @@ bool isWS2811LedStripReady(void);
extern uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
extern volatile uint8_t ws2811LedDataTransferInProgress;
extern const hsvColor_t hsv_white;
extern const hsvColor_t hsv_black;

View file

@ -100,6 +100,8 @@ void ws2811LedStripHardwareInit(void)
DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
const hsvColor_t hsv_white = { 0, 255, 255};
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;

View file

@ -112,6 +112,8 @@ void ws2811LedStripHardwareInit(void)
DMA_ITConfig(WS2811_DMA_CHANNEL, DMA_IT_TC, ENABLE);
const hsvColor_t hsv_white = { 0, 255, 255};
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = WS2811_IRQ;

File diff suppressed because it is too large Load diff

View file

@ -17,82 +17,163 @@
#pragma once
#define MAX_LED_STRIP_LENGTH 32
#define CONFIGURABLE_COLOR_COUNT 16
#define LED_MAX_STRIP_LENGTH 32
#define LED_CONFIGURABLE_COLOR_COUNT 16
#define LED_MODE_COUNT 6
#define LED_DIRECTION_COUNT 6
#define LED_BASEFUNCTION_COUNT 7
#define LED_OVERLAY_COUNT 6
#define LED_SPECIAL_COLOR_COUNT 11
#define LED_POS_OFFSET 0
#define LED_FUNCTION_OFFSET 8
#define LED_OVERLAY_OFFSET 12
#define LED_COLOR_OFFSET 18
#define LED_DIRECTION_OFFSET 22
#define LED_PARAMS_OFFSET 28
#define LED_POS_BITCNT 8
#define LED_FUNCTION_BITCNT 4
#define LED_OVERLAY_BITCNT 6
#define LED_COLOR_BITCNT 4
#define LED_DIRECTION_BITCNT 6
#define LED_PARAMS_BITCNT 4
#define LED_FLAG_OVERLAY_MASK ((1 << LED_OVERLAY_BITCNT) - 1)
#define LED_FLAG_DIRECTION_MASK ((1 << LED_DIRECTION_BITCNT) - 1)
#define LED_MOV_POS(pos) ((pos) << LED_POS_OFFSET)
#define LED_MOV_FUNCTION(func) ((func) << LED_FUNCTION_OFFSET)
#define LED_MOV_OVERLAY(overlay) ((overlay) << LED_OVERLAY_OFFSET)
#define LED_MOV_COLOR(colorId) ((colorId) << LED_COLOR_OFFSET)
#define LED_MOV_DIRECTION(direction) ((direction) << LED_DIRECTION_OFFSET)
#define LED_MOV_PARAMS(param) ((param) << LED_PARAMS_OFFSET)
#define LED_BIT_MASK(len) ((1 << (len)) - 1)
#define LED_POS_MASK LED_MOV_POS(((1 << LED_POS_BITCNT) - 1))
#define LED_FUNCTION_MASK LED_MOV_FUNCTION(((1 << LED_FUNCTION_BITCNT) - 1))
#define LED_OVERLAY_MASK LED_MOV_OVERLAY(LED_FLAG_OVERLAY_MASK)
#define LED_COLOR_MASK LED_MOV_COLOR(((1 << LED_COLOR_BITCNT) - 1))
#define LED_DIRECTION_MASK LED_MOV_DIRECTION(LED_FLAG_DIRECTION_MASK)
#define LED_PARAMS_MASK LED_MOV_PARAMS(((1 << LED_PARAMS_BITCNT) - 1))
#define LED_FLAG_OVERLAY(id) (1 << (id))
#define LED_FLAG_DIRECTION(id) (1 << (id))
#define LED_X_BIT_OFFSET 4
#define LED_Y_BIT_OFFSET 0
#define LED_XY_MASK (0x0F)
#define GET_LED_X(ledConfig) ((ledConfig->xy >> LED_X_BIT_OFFSET) & LED_XY_MASK)
#define GET_LED_Y(ledConfig) ((ledConfig->xy >> LED_Y_BIT_OFFSET) & LED_XY_MASK)
#define CALCULATE_LED_X(x) ((x & LED_XY_MASK) << LED_X_BIT_OFFSET)
#define CALCULATE_LED_Y(y) ((y & LED_XY_MASK) << LED_Y_BIT_OFFSET)
#define CALCULATE_LED_XY(x,y) (CALCULATE_LED_X(x) | CALCULATE_LED_Y(y))
#define LED_XY_MASK 0x0F
#define CALCULATE_LED_XY(x, y) ((((x) & LED_XY_MASK) << LED_X_BIT_OFFSET) | (((y) & LED_XY_MASK) << LED_Y_BIT_OFFSET))
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_WARNING = (1 << 7),
LED_FUNCTION_FLIGHT_MODE = (1 << 8),
LED_FUNCTION_ARM_STATE = (1 << 9),
LED_FUNCTION_THROTTLE = (1 << 10),
LED_FUNCTION_THRUST_RING = (1 << 11),
LED_FUNCTION_COLOR = (1 << 12),
} ledFlag_e;
LED_MODE_ORIENTATION = 0,
LED_MODE_HEADFREE,
LED_MODE_HORIZON,
LED_MODE_ANGLE,
LED_MODE_MAG,
LED_MODE_BARO,
LED_SPECIAL
} ledModeIndex_e;
#define LED_DIRECTION_BIT_OFFSET 0
#define LED_DIRECTION_MASK ( \
LED_DIRECTION_NORTH | \
LED_DIRECTION_EAST | \
LED_DIRECTION_SOUTH | \
LED_DIRECTION_WEST | \
LED_DIRECTION_UP | \
LED_DIRECTION_DOWN \
)
#define LED_FUNCTION_BIT_OFFSET 6
#define LED_FUNCTION_MASK ( \
LED_FUNCTION_INDICATOR | \
LED_FUNCTION_WARNING | \
LED_FUNCTION_FLIGHT_MODE | \
LED_FUNCTION_ARM_STATE | \
LED_FUNCTION_THROTTLE | \
LED_FUNCTION_THRUST_RING | \
LED_FUNCTION_COLOR \
)
typedef enum {
LED_SCOLOR_DISARMED = 0,
LED_SCOLOR_ARMED,
LED_SCOLOR_ANIMATION,
LED_SCOLOR_BACKGROUND,
LED_SCOLOR_BLINKBACKGROUND,
LED_SCOLOR_GPSNOSATS,
LED_SCOLOR_GPSNOLOCK,
LED_SCOLOR_GPSLOCKED
} ledSpecialColorIds_e;
typedef enum {
LED_DIRECTION_NORTH = 0,
LED_DIRECTION_EAST,
LED_DIRECTION_SOUTH,
LED_DIRECTION_WEST,
LED_DIRECTION_UP,
LED_DIRECTION_DOWN
} ledDirectionId_e;
typedef enum {
LED_FUNCTION_COLOR,
LED_FUNCTION_FLIGHT_MODE,
LED_FUNCTION_ARM_STATE,
LED_FUNCTION_BATTERY,
LED_FUNCTION_RSSI,
LED_FUNCTION_GPS,
LED_FUNCTION_THRUST_RING,
} ledBaseFunctionId_e;
typedef enum {
LED_OVERLAY_THROTTLE,
LED_OVERLAY_LARSON_SCANNER,
LED_OVERLAY_BLINK,
LED_OVERLAY_LANDING_FLASH,
LED_OVERLAY_INDICATOR,
LED_OVERLAY_WARNING,
} ledOverlayId_e;
typedef struct modeColorIndexes_s {
uint8_t color[LED_DIRECTION_COUNT];
} modeColorIndexes_t;
typedef struct specialColorIndexes_s {
uint8_t color[LED_SPECIAL_COLOR_COUNT];
} specialColorIndexes_t;
typedef uint32_t ledConfig_t;
typedef struct ledCounts_s {
uint8_t count;
uint8_t ring;
uint8_t larson;
uint8_t ringSeqLen;
} ledCounts_t;
typedef struct ledConfig_s {
uint8_t xy; // see LED_X/Y_MASK defines
uint8_t color; // see colors (config_master)
uint16_t flags; // see ledFlag_e
} ledConfig_t;
ledConfig_t *ledConfigs;
hsvColor_t *colors;
modeColorIndexes_t *modeColors;
specialColorIndexes_t specialColors;
extern uint8_t ledCount;
extern uint8_t ledsInRingCount;
#define DEFINE_LED(x, y, col, dir, func, ol, params) (LED_MOV_POS(CALCULATE_LED_XY(x, y)) | LED_MOV_COLOR(col) | LED_MOV_DIRECTION(dir) | LED_MOV_FUNCTION(func) | LED_MOV_OVERLAY(ol) | LED_MOV_PARAMS(params))
static inline uint8_t ledGetXY(const ledConfig_t *lcfg) { return ((*lcfg >> LED_POS_OFFSET) & LED_BIT_MASK(LED_POS_BITCNT)); }
static inline uint8_t ledGetX(const ledConfig_t *lcfg) { return ((*lcfg >> (LED_POS_OFFSET + LED_X_BIT_OFFSET)) & LED_XY_MASK); }
static inline uint8_t ledGetY(const ledConfig_t *lcfg) { return ((*lcfg >> (LED_POS_OFFSET + LED_Y_BIT_OFFSET)) & LED_XY_MASK); }
static inline uint8_t ledGetFunction(const ledConfig_t *lcfg) { return ((*lcfg >> LED_FUNCTION_OFFSET) & LED_BIT_MASK(LED_FUNCTION_BITCNT)); }
static inline uint8_t ledGetOverlay(const ledConfig_t *lcfg) { return ((*lcfg >> LED_OVERLAY_OFFSET) & LED_BIT_MASK(LED_OVERLAY_BITCNT)); }
static inline uint8_t ledGetColor(const ledConfig_t *lcfg) { return ((*lcfg >> LED_COLOR_OFFSET) & LED_BIT_MASK(LED_COLOR_BITCNT)); }
static inline uint8_t ledGetDirection(const ledConfig_t *lcfg) { return ((*lcfg >> LED_DIRECTION_OFFSET) & LED_BIT_MASK(LED_DIRECTION_BITCNT)); }
static inline uint8_t ledGetParams(const ledConfig_t *lcfg) { return ((*lcfg >> LED_PARAMS_OFFSET) & LED_BIT_MASK(LED_PARAMS_BITCNT)); }
static inline bool ledGetOverlayBit(const ledConfig_t *lcfg, int id) { return ((ledGetOverlay(lcfg) >> id) & 1); }
static inline bool ledGetDirectionBit(const ledConfig_t *lcfg, int id) { return ((ledGetDirection(lcfg) >> id) & 1); }
/*
PG_DECLARE_ARR(ledConfig_t, LED_MAX_STRIP_LENGTH, ledConfigs);
PG_DECLARE_ARR(hsvColor_t, LED_CONFIGURABLE_COLOR_COUNT, colors);
PG_DECLARE_ARR(modeColorIndexes_t, LED_MODE_COUNT, modeColors);
PG_DECLARE(specialColorIndexes_t, specialColors);
*/
bool parseColor(int index, const char *colorConfig);
bool parseLedStripConfig(uint8_t ledIndex, const char *config);
bool parseLedStripConfig(int ledIndex, const char *config);
void generateLedConfig(int ledIndex, char *ledConfigBuffer, size_t bufferSize);
void reevaluateLedConfig(void);
void ledStripInit(ledConfig_t *ledConfigsToUse, hsvColor_t *colorsToUse, modeColorIndexes_t *modeColorsToUse, specialColorIndexes_t *specialColorsToUse);
void ledStripEnable(void);
void updateLedStrip(void);
void updateLedRing(void);
bool setModeColor(ledModeIndex_e modeIndex, int modeColorIndex, int colorIndex);
extern uint16_t rssi; // FIXME dependency on mw.c
void applyDefaultLedStripConfig(ledConfig_t *ledConfig);
void generateLedConfig(uint8_t ledIndex, char *ledConfigBuffer, size_t bufferSize);
bool parseColor(uint8_t index, const char *colorConfig);
void applyDefaultColors(hsvColor_t *colors, uint8_t colorCount);
void ledStripEnable(void);
void reevalulateLedConfig(void);
void applyDefaultColors(hsvColor_t *colors);
void applyDefaultModeColors(modeColorIndexes_t *modeColors);
void applyDefaultSpecialColors(specialColorIndexes_t *specialColors);

View file

@ -60,7 +60,7 @@
#define MSP_PROTOCOL_VERSION 0
#define API_VERSION_MAJOR 1 // increment when major changes are made
#define API_VERSION_MINOR 17 // increment when any change is made, reset to zero when major changes are released after changing API_VERSION_MAJOR
#define API_VERSION_MINOR 20 // increment when any change is made, reset to zero when major changes are released after changing API_VERSION_MAJOR
#define API_VERSION_LENGTH 2

View file

@ -144,6 +144,7 @@ static void cliMap(char *cmdline);
#ifdef LED_STRIP
static void cliLed(char *cmdline);
static void cliColor(char *cmdline);
static void cliModeColor(char *cmdline);
#endif
#ifndef USE_QUAD_MIXER_ONLY
@ -249,6 +250,7 @@ const clicmd_t cmdTable[] = {
CLI_COMMAND_DEF("aux", "configure modes", NULL, cliAux),
#ifdef LED_STRIP
CLI_COMMAND_DEF("color", "configure colors", NULL, cliColor),
CLI_COMMAND_DEF("mode_color", "configure mode and special colors", NULL, cliModeColor),
#endif
CLI_COMMAND_DEF("defaults", "reset to defaults and reboot", NULL, cliDefaults),
CLI_COMMAND_DEF("dump", "dump configuration",
@ -796,6 +798,9 @@ const clivalue_t valueTable[] = {
{ "acczero_x", VAR_INT16 | MASTER_VALUE, &masterConfig.accZero.raw[X], .config.minmax = { -32768, 32767 }, 0 },
{ "acczero_y", VAR_INT16 | MASTER_VALUE, &masterConfig.accZero.raw[Y], .config.minmax = { -32768, 32767 }, 0 },
{ "acczero_z", VAR_INT16 | MASTER_VALUE, &masterConfig.accZero.raw[Z], .config.minmax = { -32768, 32767 }, 0 },
#ifdef LED_STRIP
{ "ledstrip_visual_beeper", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, &masterConfig.ledstrip_visual_beeper, .config.lookup = { TABLE_OFF_ON } },
#endif
{ "accgain_x", VAR_INT16 | MASTER_VALUE, &masterConfig.accGain.raw[X], .config.minmax = { 1, 8192 }, 0 },
{ "accgain_y", VAR_INT16 | MASTER_VALUE, &masterConfig.accGain.raw[Y], .config.minmax = { 1, 8192 }, 0 },
@ -1299,20 +1304,20 @@ static void cliLed(char *cmdline)
char ledConfigBuffer[20];
if (isEmpty(cmdline)) {
for (i = 0; i < MAX_LED_STRIP_LENGTH; i++) {
for (i = 0; i < LED_MAX_STRIP_LENGTH; i++) {
generateLedConfig(i, ledConfigBuffer, sizeof(ledConfigBuffer));
cliPrintf("led %u %s\r\n", i, ledConfigBuffer);
}
} else {
ptr = cmdline;
i = atoi(ptr);
if (i < MAX_LED_STRIP_LENGTH) {
if (i < LED_MAX_STRIP_LENGTH) {
ptr = strchr(cmdline, ' ');
if (!parseLedStripConfig(i, ++ptr)) {
cliShowParseError();
}
} else {
cliShowArgumentRangeError("index", 0, MAX_LED_STRIP_LENGTH - 1);
cliShowArgumentRangeError("index", 0, LED_MAX_STRIP_LENGTH - 1);
}
}
}
@ -1323,7 +1328,7 @@ static void cliColor(char *cmdline)
char *ptr;
if (isEmpty(cmdline)) {
for (i = 0; i < CONFIGURABLE_COLOR_COUNT; i++) {
for (i = 0; i < LED_CONFIGURABLE_COLOR_COUNT; i++) {
cliPrintf("color %u %d,%u,%u\r\n",
i,
masterConfig.colors[i].h,
@ -1334,16 +1339,57 @@ static void cliColor(char *cmdline)
} else {
ptr = cmdline;
i = atoi(ptr);
if (i < CONFIGURABLE_COLOR_COUNT) {
if (i < LED_CONFIGURABLE_COLOR_COUNT) {
ptr = strchr(cmdline, ' ');
if (!parseColor(i, ++ptr)) {
cliShowParseError();
}
} else {
cliShowArgumentRangeError("index", 0, CONFIGURABLE_COLOR_COUNT - 1);
cliShowArgumentRangeError("index", 0, LED_CONFIGURABLE_COLOR_COUNT - 1);
}
}
}
static void cliModeColor(char *cmdline)
{
if (isEmpty(cmdline)) {
for (int i = 0; i < LED_MODE_COUNT; i++) {
for (int j = 0; j < LED_DIRECTION_COUNT; j++) {
int colorIndex = modeColors[i].color[j];
cliPrintf("mode_color %u %u %u\r\n", i, j, colorIndex);
}
}
for (int j = 0; j < LED_SPECIAL_COLOR_COUNT; j++) {
int colorIndex = specialColors.color[j];
cliPrintf("mode_color %u %u %u\r\n", LED_SPECIAL, j, colorIndex);
}
} else {
enum {MODE = 0, FUNCTION, COLOR, ARGS_COUNT};
int args[ARGS_COUNT];
int argNo = 0;
char* ptr = strtok(cmdline, " ");
while (ptr && argNo < ARGS_COUNT) {
args[argNo++] = atoi(ptr);
ptr = strtok(NULL, " ");
}
if (ptr != NULL || argNo != ARGS_COUNT) {
cliShowParseError();
return;
}
int modeIdx = args[MODE];
int funIdx = args[FUNCTION];
int color = args[COLOR];
if(!setModeColor(modeIdx, funIdx, color)) {
cliShowParseError();
return;
}
// values are validated
cliPrintf("mode_color %u %u %u\r\n", modeIdx, funIdx, color);
}
}
#endif
#ifdef USE_SERVOS
@ -1814,6 +1860,9 @@ static void cliDump(char *cmdline)
cliPrint("\r\n\r\n# color\r\n");
cliColor("");
cliPrint("\r\n\r\n# mode_color\r\n");
cliModeColor("");
#endif
printSectionBreak();
dumpValues(MASTER_VALUE);

View file

@ -48,6 +48,7 @@
#include "drivers/buf_writer.h"
#include "rx/rx.h"
#include "rx/msp.h"
#include "blackbox/blackbox.h"
#include "io/escservo.h"
#include "io/rc_controls.h"
@ -1047,8 +1048,8 @@ static bool processOutCommand(uint8_t cmdMSP)
#ifdef LED_STRIP
case MSP_LED_COLORS:
headSerialReply(CONFIGURABLE_COLOR_COUNT * 4);
for (i = 0; i < CONFIGURABLE_COLOR_COUNT; i++) {
headSerialReply(LED_CONFIGURABLE_COLOR_COUNT * 4);
for (i = 0; i < LED_CONFIGURABLE_COLOR_COUNT; i++) {
hsvColor_t *color = &masterConfig.colors[i];
serialize16(color->h);
serialize8(color->s);
@ -1057,14 +1058,27 @@ static bool processOutCommand(uint8_t cmdMSP)
break;
case MSP_LED_STRIP_CONFIG:
headSerialReply(MAX_LED_STRIP_LENGTH * 7);
for (i = 0; i < MAX_LED_STRIP_LENGTH; i++) {
headSerialReply(LED_MAX_STRIP_LENGTH * 4);
for (i = 0; i < LED_MAX_STRIP_LENGTH; i++) {
ledConfig_t *ledConfig = &masterConfig.ledConfigs[i];
serialize16((ledConfig->flags & LED_DIRECTION_MASK) >> LED_DIRECTION_BIT_OFFSET);
serialize16((ledConfig->flags & LED_FUNCTION_MASK) >> LED_FUNCTION_BIT_OFFSET);
serialize8(GET_LED_X(ledConfig));
serialize8(GET_LED_Y(ledConfig));
serialize8(ledConfig->color);
serialize32(*ledConfig);
}
break;
case MSP_LED_STRIP_MODECOLOR:
headSerialReply(((LED_MODE_COUNT * LED_DIRECTION_COUNT) + LED_SPECIAL_COLOR_COUNT) * 3);
for (int i = 0; i < LED_MODE_COUNT; i++) {
for (int j = 0; j < LED_DIRECTION_COUNT; j++) {
serialize8(i);
serialize8(j);
serialize8(masterConfig.modeColors[i].color[j]);
}
}
for (int j = 0; j < LED_SPECIAL_COLOR_COUNT; j++) {
serialize8(LED_MODE_COUNT);
serialize8(j);
serialize8(masterConfig.specialColors.color[j]);
}
break;
#endif
@ -1092,18 +1106,18 @@ static bool processOutCommand(uint8_t cmdMSP)
break;
case MSP_3D:
headSerialReply(2 * 4);
headSerialReply(2 * 3);
serialize16(masterConfig.flight3DConfig.deadband3d_low);
serialize16(masterConfig.flight3DConfig.deadband3d_high);
serialize16(masterConfig.flight3DConfig.neutral3d);
serialize16(masterConfig.flight3DConfig.deadband3d_throttle);
break;
case MSP_RC_DEADBAND:
headSerialReply(3);
headSerialReply(5);
serialize8(currentProfile->rcControlsConfig.deadband);
serialize8(currentProfile->rcControlsConfig.yaw_deadband);
serialize8(currentProfile->rcControlsConfig.alt_hold_deadband);
serialize16(masterConfig.flight3DConfig.deadband3d_throttle);
break;
case MSP_SENSOR_ALIGNMENT:
headSerialReply(3);
@ -1553,7 +1567,7 @@ static bool processInCommand(void)
#ifdef LED_STRIP
case MSP_SET_LED_COLORS:
for (i = 0; i < CONFIGURABLE_COLOR_COUNT; i++) {
for (i = 0; i < LED_CONFIGURABLE_COLOR_COUNT; i++) {
hsvColor_t *color = &masterConfig.colors[i];
color->h = read16();
color->s = read8();
@ -1564,29 +1578,24 @@ static bool processInCommand(void)
case MSP_SET_LED_STRIP_CONFIG:
{
i = read8();
if (i >= MAX_LED_STRIP_LENGTH || currentPort->dataSize != (1 + 7)) {
if (i >= LED_MAX_STRIP_LENGTH || currentPort->dataSize != (1 + 4)) {
headSerialError(0);
break;
}
ledConfig_t *ledConfig = &masterConfig.ledConfigs[i];
uint16_t mask;
// currently we're storing directions and functions in a uint16 (flags)
// the msp uses 2 x uint16_t to cater for future expansion
mask = read16();
ledConfig->flags = (mask << LED_DIRECTION_BIT_OFFSET) & LED_DIRECTION_MASK;
*ledConfig = read32();
reevaluateLedConfig();
}
break;
mask = read16();
ledConfig->flags |= (mask << LED_FUNCTION_BIT_OFFSET) & LED_FUNCTION_MASK;
case MSP_SET_LED_STRIP_MODECOLOR:
{
ledModeIndex_e modeIdx = read8();
int funIdx = read8();
int color = read8();
mask = read8();
ledConfig->xy = CALCULATE_LED_X(mask);
mask = read8();
ledConfig->xy |= CALCULATE_LED_Y(mask);
ledConfig->color = read8();
reevalulateLedConfig();
if (!setModeColor(modeIdx, funIdx, color))
return false;
}
break;
#endif
@ -1596,6 +1605,7 @@ static bool processInCommand(void)
#ifdef USE_SERIAL_4WAY_BLHELI_INTERFACE
case MSP_SET_4WAY_IF:
// get channel number
// switch all motor lines HI
// reply the count of ESC found
headSerialReply(1);

View file

@ -118,7 +118,7 @@ void gpsPreInit(gpsConfig_t *initialGpsConfig);
void gpsInit(serialConfig_t *serialConfig, gpsConfig_t *initialGpsConfig);
void imuInit(void);
void displayInit(rxConfig_t *intialRxConfig);
void ledStripInit(ledConfig_t *ledConfigsToUse, hsvColor_t *colorsToUse);
void ledStripInit(ledConfig_t *ledConfigsToUse, hsvColor_t *colorsToUse, modeColorIndexes_t *modeColorsToUse, specialColorIndexes_t *specialColorsToUse);
void spektrumBind(rxConfig_t *rxConfig);
const sonarHcsr04Hardware_t *sonarGetHardwareConfiguration(currentSensor_e currentSensor);
@ -468,7 +468,7 @@ void init(void)
#endif
#ifdef LED_STRIP
ledStripInit(masterConfig.ledConfigs, masterConfig.colors);
ledStripInit(masterConfig.ledConfigs, masterConfig.colors, masterConfig.modeColors, &masterConfig.specialColors);
if (feature(FEATURE_LED_STRIP)) {
ledStripEnable();

View file

@ -208,7 +208,7 @@ void updateCurrentMeter(int32_t lastUpdateAt, rxConfig_t *rxConfig, uint16_t dea
uint8_t calculateBatteryPercentage(void)
{
return (((uint32_t)vbat - (batteryConfig->vbatmincellvoltage * batteryCellCount)) * 100) / ((batteryConfig->vbatmaxcellvoltage - batteryConfig->vbatmincellvoltage) * batteryCellCount);
return constrain((((uint32_t)vbat - (batteryConfig->vbatmincellvoltage * batteryCellCount)) * 100) / ((batteryConfig->vbatmaxcellvoltage - batteryConfig->vbatmincellvoltage) * batteryCellCount), 0, 100);
}
uint8_t calculateBatteryCapacityRemainingPercentage(void)

View file

@ -26,6 +26,7 @@ extern "C" {
#include "common/color.h"
#include "common/axis.h"
#include "common/utils.h"
#include "sensors/battery.h"
#include "config/runtime_config.h"
@ -43,62 +44,66 @@ extern "C" {
#include "gtest/gtest.h"
extern "C" {
extern ledConfig_t *ledConfigs;
extern uint8_t highestYValueForNorth;
extern uint8_t lowestYValueForSouth;
extern uint8_t highestXValueForWest;
extern uint8_t lowestXValueForEast;
extern uint8_t ledGridWidth;
extern uint8_t ledGridHeight;
extern ledCounts_t ledCounts;
void updateLedCount(void);
void determineLedStripDimensions(void);
void determineOrientationLimits(void);
ledConfig_t systemLedConfigs[MAX_LED_STRIP_LENGTH];
}
// utility macros
#define LF(name) LED_FUNCTION_ ## name
#define LO(name) LED_FLAG_OVERLAY(LED_OVERLAY_ ## name)
#define LD(name) LED_FLAG_DIRECTION(LED_DIRECTION_ ## name)
TEST(LedStripTest, parseLedStripConfig)
{
// given
static const ledConfig_t expectedLedStripConfig[WS2811_LED_STRIP_LENGTH] = {
{ CALCULATE_LED_XY( 9, 9), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY(10, 10), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY(11, 11), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY(11, 11), 0, LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY(10, 10), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
DEFINE_LED( 9, 9, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
DEFINE_LED(10, 10, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
DEFINE_LED(11, 11, 0, LD(SOUTH) , LF(ARM_STATE) , LO(INDICATOR) , 0),
DEFINE_LED(11, 11, 0, LD(EAST) , LF(ARM_STATE) , LO(INDICATOR) , 0),
DEFINE_LED(10, 10, 0, LD(EAST) , LF(FLIGHT_MODE) , 0, 0),
{ CALCULATE_LED_XY(10, 5), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY(11, 4), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY(12, 3), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY(12, 2), 0, LED_DIRECTION_NORTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY(11, 1), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY(10, 0), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
DEFINE_LED(10, 5, 0, LD(SOUTH) , LF(FLIGHT_MODE) , 0, 0),
DEFINE_LED(11, 4, 0, LD(SOUTH) , LF(FLIGHT_MODE) , 0, 0),
DEFINE_LED(12, 3, 0, LD(SOUTH) , LF(ARM_STATE) , LO(INDICATOR) , 0),
DEFINE_LED(12, 2, 0, LD(NORTH) , LF(ARM_STATE) , LO(INDICATOR) , 0),
DEFINE_LED(11, 1, 0, LD(NORTH) , LF(FLIGHT_MODE) , 0, 0),
DEFINE_LED(10, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , 0, 0),
{ CALCULATE_LED_XY( 7, 0), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 6, 0), 1, LED_DIRECTION_NORTH | LED_FUNCTION_COLOR | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 5, 0), 1, LED_DIRECTION_NORTH | LED_FUNCTION_COLOR | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 4, 0), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
DEFINE_LED( 7, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
DEFINE_LED( 6, 0, 1, LD(NORTH) , LF(COLOR) , LO(WARNING) , 0),
DEFINE_LED( 5, 0, 1, LD(NORTH) , LF(COLOR) , LO(WARNING) , 0),
DEFINE_LED( 4, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
{ CALCULATE_LED_XY( 2, 0), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 1, 1), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 2), 0, LED_DIRECTION_NORTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 3), 0, LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 4), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 2, 5), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
DEFINE_LED( 2, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , 0, 0),
DEFINE_LED( 1, 1, 0, LD(NORTH) , LF(FLIGHT_MODE) , 0, 0),
DEFINE_LED( 0, 2, 0, LD(NORTH) , LF(ARM_STATE) , LO(INDICATOR) , 0),
DEFINE_LED( 0, 3, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0),
DEFINE_LED( 1, 4, 0, LD(WEST) , LF(FLIGHT_MODE) , 0, 0),
DEFINE_LED( 2, 5, 0, LD(WEST) , LF(FLIGHT_MODE) , 0, 0),
{ CALCULATE_LED_XY( 1, 10), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 11), 0, LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 11), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 10), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 2, 9), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
DEFINE_LED( 1, 10, 0, LD(WEST) , LF(FLIGHT_MODE) , 0, 0),
DEFINE_LED( 0, 11, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0),
DEFINE_LED( 0, 11, 0, LD(SOUTH) , LF(ARM_STATE) , LO(INDICATOR) , 0),
DEFINE_LED( 1, 10, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
DEFINE_LED( 2, 9, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
{ CALCULATE_LED_XY( 7, 7), 14, LED_FUNCTION_THRUST_RING },
{ CALCULATE_LED_XY( 8, 7), 15, LED_FUNCTION_THRUST_RING },
{ CALCULATE_LED_XY( 8, 8), 14, LED_FUNCTION_THRUST_RING },
{ CALCULATE_LED_XY( 7, 8), 15, LED_FUNCTION_THRUST_RING },
DEFINE_LED( 7, 7, 14, 0, LF(THRUST_RING) , 0 , 0),
DEFINE_LED( 8, 7, 15, 0, LF(THRUST_RING) , 0 , 0),
DEFINE_LED( 8, 8, 14, 0, LF(THRUST_RING) , 0 , 0),
DEFINE_LED( 7, 8, 15, 0, LF(THRUST_RING) , 0 , 0),
{ 0, 0, 0 },
{ 0, 0, 0 },
DEFINE_LED( 0, 0, 0, 0 , 0 , 0 , 0),
DEFINE_LED( 0, 0, 0, 0 , 0 , 0 , 0),
};
// and
@ -108,15 +113,15 @@ TEST(LedStripTest, parseLedStripConfig)
// right rear cluster
"9,9:S:FW:0",
"10,10:S:FW:0",
"11,11:S:IA:0",
"11,11:E:IA:0",
"11,11:S:AI:0",
"11,11:E:AI:0",
"10,10:E:F:0",
// right front cluster
"10,5:S:F:0",
"11,4:S:F:0",
"12,3:S:IA:0",
"12,2:N:IA:0",
"12,3:S:AI:0",
"12,2:N:AI:0",
"11,1:N:F:0",
"10,0:N:F:0",
@ -129,15 +134,15 @@ TEST(LedStripTest, parseLedStripConfig)
// left front cluster
"2,0:N:F:0",
"1,1:N:F:0",
"0,2:N:IA:0",
"0,3:W:IA:0",
"0,2:N:AI:0",
"0,3:W:AI:0",
"1,4:W:F:0",
"2,5:W:F:0",
// left rear cluster
"1,10:W:F:0",
"0,11:W:IA:0",
"0,11:S:IA:0",
"0,11:W:AI:0",
"0,11:S:AI:0",
"1,10:S:FW:0",
"2,9:S:FW:0",
@ -148,31 +153,33 @@ TEST(LedStripTest, parseLedStripConfig)
"7,8::R:15"
};
// and
memset(&systemLedConfigs, 0, sizeof(systemLedConfigs));
ledConfigs = systemLedConfigs;
memset(ledConfigs_arr(), 0, sizeof(*ledConfigs_arr()));
// and
bool ok = false;
bool result = true;
// when
for (uint8_t index = 0; index < (sizeof(ledStripConfigCommands) / sizeof(ledStripConfigCommands[0])); index++) {
ok |= parseLedStripConfig(index, ledStripConfigCommands[index]);
for (unsigned index = 0; index < ARRAYLEN(ledStripConfigCommands); index++) {
result = result && parseLedStripConfig(index, ledStripConfigCommands[index]);
}
// then
EXPECT_EQ(true, ok);
EXPECT_EQ(30, ledCount);
EXPECT_EQ(4, ledsInRingCount);
EXPECT_EQ(true, result);
EXPECT_EQ(30, ledCounts.count);
EXPECT_EQ(4, ledCounts.ring);
// and
for (uint8_t index = 0; index < WS2811_LED_STRIP_LENGTH; index++) {
for (int index = 0; index < WS2811_LED_STRIP_LENGTH; index++) {
#ifdef DEBUG_LEDSTRIP
printf("iteration: %d\n", index);
#endif
EXPECT_EQ(expectedLedStripConfig[index].xy, ledConfigs[index].xy);
EXPECT_EQ(expectedLedStripConfig[index].flags, ledConfigs[index].flags);
EXPECT_EQ(expectedLedStripConfig[index].color, ledConfigs[index].color);
EXPECT_EQ(ledGetXY(&expectedLedStripConfig[index]), ledGetXY(ledConfigs(index)));
EXPECT_EQ(ledGetFunction(&expectedLedStripConfig[index]), ledGetFunction(ledConfigs(index)));
EXPECT_EQ(ledGetOverlay(&expectedLedStripConfig[index]), ledGetOverlay(ledConfigs(index)));
EXPECT_EQ(ledGetColor(&expectedLedStripConfig[index]), ledGetColor(ledConfigs(index)));
EXPECT_EQ(ledGetDirection(&expectedLedStripConfig[index]), ledGetDirection(ledConfigs(index)));
EXPECT_EQ(ledGetParams(&expectedLedStripConfig[index]), ledGetParams(ledConfigs(index)));
}
// then
@ -189,26 +196,27 @@ TEST(LedStripTest, parseLedStripConfig)
TEST(LedStripTest, smallestGridWithCenter)
{
// given
memset(&systemLedConfigs, 0, sizeof(systemLedConfigs));
ledConfigs = systemLedConfigs;
memset(ledConfigs_arr(), 0, sizeof(*ledConfigs_arr()));
// and
static const ledConfig_t testLedConfigs[] = {
{ 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 | LED_FUNCTION_WARNING },
{ 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 }
DEFINE_LED( 2, 2, 0, LD(SOUTH) | LD(EAST) , LF(ARM_STATE) , LO(INDICATOR), 0),
DEFINE_LED( 2, 1, 0, LD(EAST) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
DEFINE_LED( 2, 0, 0, LD(NORTH) | LD(EAST) , LF(ARM_STATE) , LO(INDICATOR), 0),
DEFINE_LED( 1, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
DEFINE_LED( 0, 0, 0, LD(NORTH) | LD(WEST) , LF(ARM_STATE) , LO(INDICATOR), 0),
DEFINE_LED( 0, 1, 0, LD(WEST) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
DEFINE_LED( 0, 2, 0, LD(SOUTH) | LD(WEST) , LF(ARM_STATE) , LO(INDICATOR), 0),
DEFINE_LED( 1, 2, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(WARNING) , 0),
};
memcpy(&systemLedConfigs, &testLedConfigs, sizeof(testLedConfigs));
memcpy(ledConfigs_arr(), &testLedConfigs, sizeof(testLedConfigs));
// when
updateLedCount();
determineLedStripDimensions();
// then
EXPECT_EQ(8, ledCounts.count);
EXPECT_EQ(3, ledGridWidth);
EXPECT_EQ(3, ledGridHeight);
@ -225,22 +233,23 @@ TEST(LedStripTest, smallestGridWithCenter)
TEST(LedStripTest, smallestGrid)
{
// given
memset(&systemLedConfigs, 0, sizeof(systemLedConfigs));
ledConfigs = systemLedConfigs;
memset(ledConfigs_arr(), 0, sizeof(*ledConfigs_arr()));
// and
static const ledConfig_t testLedConfigs[] = {
{ CALCULATE_LED_XY( 1, 1), 0, LED_DIRECTION_SOUTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 1, 0), 0, LED_DIRECTION_NORTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 0), 0, LED_DIRECTION_NORTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 1), 0, LED_DIRECTION_SOUTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_FLIGHT_MODE },
DEFINE_LED( 1, 1, 0, LD(SOUTH) | LD(EAST) , LF(FLIGHT_MODE) , LO(INDICATOR), 0),
DEFINE_LED( 1, 0, 0, LD(NORTH) | LD(EAST) , LF(FLIGHT_MODE) , LO(INDICATOR), 0),
DEFINE_LED( 0, 0, 0, LD(NORTH) | LD(WEST) , LF(FLIGHT_MODE) , LO(INDICATOR), 0),
DEFINE_LED( 0, 1, 0, LD(SOUTH) | LD(WEST) , LF(FLIGHT_MODE) , LO(INDICATOR), 0),
};
memcpy(&systemLedConfigs, &testLedConfigs, sizeof(testLedConfigs));
memcpy(ledConfigs_arr(), &testLedConfigs, sizeof(testLedConfigs));
// when
updateLedCount();
determineLedStripDimensions();
// then
EXPECT_EQ(4, ledCounts.count);
EXPECT_EQ(2, ledGridWidth);
EXPECT_EQ(2, ledGridHeight);
@ -255,59 +264,56 @@ TEST(LedStripTest, smallestGrid)
}
/*
{ CALCULATE_LED_XY( 1, 14), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_FLIGHT_MODE },
LED( 1, 14, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(INDICATOR) , 0 ),
{ CALCULATE_LED_XY( 0, 13), 0, LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 12), 0, LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
LED( 0, 13, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
LED( 0, 12, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
{ CALCULATE_LED_XY( 0, 11), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 10), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 9), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 8), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 0, 7), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 0, 6), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 0, 5), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 4), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 3), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE },
LED( 0, 11, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 0, 10, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 0, 9, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 0, 8, 0, LD(WEST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
LED( 0, 7, 0, LD(WEST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
LED( 0, 6, 0, LD(WEST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
LED( 0, 5, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 0, 4, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 0, 3, 0, LD(WEST) , LF(FLIGHT_MODE) , 0 , 0 ),
{ CALCULATE_LED_XY( 0, 2), 0, LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 1), 0, LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
LED( 0, 2, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
LED( 0, 1, 0, LD(WEST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
{ CALCULATE_LED_XY( 1, 0), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 2, 0), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 3, 0), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
LED( 1, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , LO(INDICATOR) , 0 ),
LED( 2, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 3, 0, 0, LD(NORTH) , LF(FLIGHT_MODE) , LO(INDICATOR) , 0 ),
{ CALCULATE_LED_XY( 4, 1), 0, LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 4, 2), 0, LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
LED( 4, 1, 0, LD(EAST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
LED( 4, 2, 0, LD(EAST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
{ CALCULATE_LED_XY( 4, 3), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 4), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 5), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 6), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 4, 7), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 4, 8), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 4, 9), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 10), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 4, 11), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },
LED( 4, 3, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 4, 4, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 4, 5, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 4, 6, 0, LD(EAST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
LED( 4, 7, 0, LD(EAST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
LED( 4, 8, 0, LD(EAST) , LF(FLIGHT_MODE) , LO(WARNING) , 0 ),
LED( 4, 9, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 4, 10, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
LED( 4, 11, 0, LD(EAST) , LF(FLIGHT_MODE) , 0 , 0 ),
{ CALCULATE_LED_XY( 4, 12), 0, LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 4, 13), 0, LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
LED( 4, 12, 0, LD(EAST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
LED( 4, 13, 0, LD(EAST) , LF(ARM_STATE) , LO(INDICATOR) , 0 ),
{ CALCULATE_LED_XY( 3, 14), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
LED( 3, 14, 0, LD(SOUTH) , LF(FLIGHT_MODE) , LO(INDICATOR) , 0 ),
*/
hsvColor_t testColors[CONFIGURABLE_COLOR_COUNT];
extern hsvColor_t *colors;
hsvColor_t testColors[LED_CONFIGURABLE_COLOR_COUNT];
#define TEST_COLOR_COUNT 4
TEST(ColorTest, parseColor)
{
// given
colors = testColors;
memset(colors, 0, sizeof(colors) * CONFIGURABLE_COLOR_COUNT);
memset(colors_arr(), 0, sizeof(*colors_arr()));
// and
const hsvColor_t expectedColors[TEST_COLOR_COUNT] = {
@ -326,7 +332,7 @@ TEST(ColorTest, parseColor)
};
// when
for (uint8_t index = 0; index < TEST_COLOR_COUNT; index++) {
for (int index = 0; index < TEST_COLOR_COUNT; index++) {
#ifdef DEBUG_LEDSTRIP
printf("parse iteration: %d\n", index);
#endif
@ -336,14 +342,14 @@ TEST(ColorTest, parseColor)
// then
for (uint8_t index = 0; index < TEST_COLOR_COUNT; index++) {
for (int index = 0; index < TEST_COLOR_COUNT; index++) {
#ifdef DEBUG_LEDSTRIP
printf("iteration: %d\n", index);
#endif
EXPECT_EQ(expectedColors[index].h, colors[index].h);
EXPECT_EQ(expectedColors[index].s, colors[index].s);
EXPECT_EQ(expectedColors[index].v, colors[index].v);
EXPECT_EQ(expectedColors[index].h, colors(index)->h);
EXPECT_EQ(expectedColors[index].s, colors(index)->s);
EXPECT_EQ(expectedColors[index].v, colors(index)->v);
}
}
@ -362,23 +368,23 @@ batteryState_e getBatteryState(void) {
void ws2811LedStripInit(void) {}
void ws2811UpdateStrip(void) {}
void setLedValue(uint16_t index, const uint8_t value) {
void setLedValue(int index, const uint8_t value) {
UNUSED(index);
UNUSED(value);
}
void setLedHsv(uint16_t index, const hsvColor_t *color) {
void setLedHsv(int index, const hsvColor_t *color) {
UNUSED(index);
UNUSED(color);
}
void getLedHsv(uint16_t index, hsvColor_t *color) {
void getLedHsv(int index, hsvColor_t *color) {
UNUSED(index);
UNUSED(color);
}
void scaleLedValue(uint16_t index, const uint8_t scalePercent) {
void scaleLedValue(int index, const uint8_t scalePercent) {
UNUSED(index);
UNUSED(scalePercent);
}
@ -418,7 +424,14 @@ int scaleRange(int x, int srcMin, int srcMax, int destMin, int destMax) {
return 0;
}
bool rcModeIsActive(boxId_e modeId) { return rcModeActivationMask & (1 << modeId); }
bool failsafeIsActive() { return false; }
bool rxIsReceivingSignal() { return true; }
bool sensors(uint32_t mask) { UNUSED(mask); return true; }
uint8_t calculateBatteryCapacityRemainingPercentage(void) { return 40; }
uint8_t GPS_numSat;
uint8_t stateFlags;
uint16_t rssi;
}