diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..ce84c76420 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.md eol=crlf + diff --git a/docs/LedStrip.md b/docs/LedStrip.md index 849e3bf23c..7bea700ade 100644 --- a/docs/LedStrip.md +++ b/docs/LedStrip.md @@ -1,290 +1,293 @@ -# Led Strip - -Cleanflight supports the use of addressable LED strips. Addressable LED strips allow each LED in the strip to -be programmed with a unique and independant color. This is far more advanced than the normal RGB strips which -require that all the LEDs in the strip show the same color. - -Addressable LED strips can be used to show information from the flight controller system, the current implementation -supports the following: - -* Up to 32 LEDs. -* Indicators showing pitch/roll stick positions. -* Heading/Orientation lights. -* Flight mode specific color schemes. -* Low battery warning. - -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. - -## Supported hardware - -Only strips of 32 WS2812 LEDs are supported currently. If the strip is longer than 32 leds it does not matter, -but only the first 32 are used. - -WS2812 LEDs require an 800khz signal and precise timings and thus requires the use of a dedicated hardware timer. - -Note: The initial code may work with WS2801 + External LEDs since the protocol is the same, WS2811/WS2812B should also work but -may require very simple timing adjustments to be made in the source. -Not all WS2812 ICs use the same timings, some batches use different timings. - -It could be possible to be able to specify the timings required via CLI if users request it. - -## Connections - -WS2812 LED strips generally require a single data line, 5V and GND. - -WS2812 LEDs on full brightness can consume quite a bit of current. It is recommended to verify the current draw and ensure your -supply can cope with the load. On a multirotor that uses multiple BEC ESC's you can try use a different BEC to the one the FC -uses. e.g. ESC1/BEC1 -> FC, ESC2/BEC2 -> LED strip. It's also possible to power one half of the strip from one BEC and the other half -from another BEC. Just ensure that the GROUND is the same for all BEC outputs and LEDs. - - -| Target | Pin | Led Strip | Signal | -| --------------------- | --- | --------- | -------| -| Naze/Olimexino | RC5 | Data In | PA6 | -| CC3D | ??? | Data In | PB4 | -| ChebuzzF3/F3Discovery | PB8 | Data In | PB8 | - - -Since RC5 is also used for SoftSerial on the Naze/Olimexino it means that you cannot use softserial and led strips at the same time. -Additionally, since RC5 is also used for Parallel PWM RC input on both the Naze, Chebuzz and STM32F3Discovery targets, led strips -can not be used at the same time at Parallel PWM. - - -## Configuration - -Enable the `LED_STRIP` feature via the cli: - -``` -feature LED_STRIP -``` - -If you enable LED_STRIP feature and the feature is turned off again after a reboot then check your config does not conflict with other features, as above. - -Configure the LEDs using the `led` command. - -The `led` command takes either zero or two arguments - an zero-based led number and a pair of coordinates, direction flags and mode flags. - -If used with zero arguments it prints out the led configuration which can be copied for future reference. - -Each led is configured using the following template: `x,y:ddd:mmm` - -`x` and `y` are grid coordinates of a 0 based 16x16 grid, north west is 0,0, south east is 15,15 -`ddd` specifies the directions, since an led can face in any direction it can have multiple directions. Directions are: - - `N` - North - `E` - East - `S` - South - `W` - West - `U` - Up - `D` - Down - -For instance, an LED that faces South-east at a 45 degree downwards angle could be configured as `SED`. - -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: - -* `B` - `B`attery warning. -* `F` - `F`light mode & Orientation -* `I` - `I`ndicator. -* `A` - `A`rmed state. - -Example: - -``` -led 0 0,15:SD:IAB -led 1 15,0:ND:IAB -led 2 0,0:ND:IAB -led 3 0,15:SD:IAB -``` - -to erase an led, and to mark the end of the chain, use `0,0::` as the second argument, like this: - -``` -led 4 0,0:: -``` - - -### Modes - -#### Battery Warning - -This mode simply flashes the LED RED when the battery is low if battery monitoring is enabled. - -#### Flight Mode & Orientation - -This mode shows the flight mode and orientation. - -When flight modes are active then the leds are updated to show different colors depending on the mode, placement on the grid and direction. - -Leds are set in a specific order: - * Leds that marked as facing up or down. - * Leds that marked as facing west or east AND are on the west or east side of the grid. - * Leds that marked as facing north or south AND are on the north or south side of the grid. - -That is, south facing leds have priority. - -#### Indicator - -This mode flashes LEDs that correspond to roll and pitch stick positions. i.e. they indicate the direction the craft is going to turn. - -#### Armed state - -This mode toggles LEDs between green and blue when disarmed and armed, respectively. - -Note: Armed State cannot be used with Flight Mode. - -## 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. -e.g. connect 5V out to 5V in, GND to GND and Data Out to Data In. - -Orientation is when viewed with the front of the aircraft facing away from you and viewed from above. - -### Example 12 LED config - -The default configuration is as follows -``` -led 0 2,2:ES:IA -led 1 2,1:E:BF -led 2 2,0:NE:IA -led 3 1,0:N:F -led 4 0,0:NW:IA -led 5 0,1:W:BF -led 6 0,2:SW:IA -led 7 1,2:S:BF -led 8 1,1:U:BF -led 9 1,1:U:BF -led 10 1,1:D:BF -led 11 1,1:D:BF -``` - -Which translates into the following positions: - -``` - 5 3 - \ / - \ 4 / - \ FRONT / - 6 | 9-12 | 2 - / BACK \ - / 8 \ - / \ - 7 1 -``` - -LEDs 1,3,5 and 7 should be placed underneath the quad, facing downwards. -LEDs 2, 4, 6 and 8 should be positioned so the face east/north/west/south, respectively. -LEDs 9-10 should be placed facing down, in the middle -LEDs 11-12 should be placed facing up, in the middle - -This is the default so that if you don't want to place LEDs top and bottom in the middle just connect the first 8 leds. - -### Example 16 LED config - -``` -15,15:SD:IA -8,8:E:FB -8,7:E:FB -15,0:ND:IA -7,7:N:FB -8,7:N:FB -0,0:ND:IA -7,7:W:FB -7,8:W:FB -0,15:SD:IA -7,8:S:FB -8,8:S:FB -7,7:D:FB -8,7:D:FB -7,7:U:FB -8,7:U:FB -``` - -Which translates into the following positions: - -``` - 7 4 - \ / - \ 6-5 / - 8 \ FRONT / 3 - | 13-16 | - 9 / BACK \ 2 - / 11-12 \ - / \ - 10 1 -``` - -LEDs 1,4,7 and 10 should be placed underneath the quad, facing downwards. -LEDs 2-3, 6-5, 8-9 and 11-12 should be positioned so the face east/north/west/south, respectively. -LEDs 13-14 should be placed facing down, in the middle -LEDs 15-16 should be placed facing up, in the middle - -### Exmple 28 LED config - -``` -9,9:S:FB -10,10:S:FB -11,11:S:IA -11,11:E:IA -10,10:E:F -9,9:E:F -10,5:S:F -11,4:S:F -12,3:S:IA -12,2:N:IA -11,1:N:F -10,0:N:F -7,0:N:FB -6,0:N:FB -5,0:N:FB -4,0:N:FB -2,0:N:F -1,1:N:F -0,2:N:IA -0,3:W:IA -1,4:W:F -2,5:W:F -2,9:W:F -1,10:W:F -0,11:W:IA -0,11:S:IA -1,10:S:FB -2,9:S:FB -``` - -``` - 17-19 10-12 -20-22 \ / 7-9 - \ 13-16 / - \ FRONT / - / BACK \ - / \ -23-25 / \ 4-6 - 26-28 1-3 -``` - -All LEDs should face outwards from the chassis in this configuration. - -Note: -This configuration is specifically designed for the Alien Spider AQ50D PRO 250mm frame. - -http://www.goodluckbuy.com/alien-spider-aq50d-pro-250mm-mini-quadcopter-carbon-fiber-micro-multicopter-frame.html - -## Troubleshooting - -On initial power up the LEDs on the strip will be set to WHITE. This means you can attach a current meter to verify -the current draw if your measurement equipment is fast enough. This also means that you can make sure that each R,G and B LED -in each LED module on the strip is also functioning. - -After a short delay the LEDs will show the unarmed color sequence and or low-battery warning sequence. - -If the LEDs flash intermittently or do not show the correct colors verify all connections and check the specifications of the -LEDs you have against the supported timings (for now, you'll have to look in the source). - -Also check that the feature `LED_STRIP` was correctly enabled and that it does not conflict with other features, as above. +# Led Strip + +Cleanflight supports the use of addressable LED strips. Addressable LED strips allow each LED in the strip to +be programmed with a unique and independant color. This is far more advanced than the normal RGB strips which +require that all the LEDs in the strip show the same color. + +Addressable LED strips can be used to show information from the flight controller system, the current implementation +supports the following: + +* Up to 32 LEDs. +* Indicators showing pitch/roll stick positions. +* Heading/Orientation lights. +* Flight mode specific color schemes. +* Low battery warning. + +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. + +## Supported hardware + +Only strips of 32 WS2812 LEDs are supported currently. If the strip is longer than 32 leds it does not matter, +but only the first 32 are used. + +WS2812 LEDs require an 800khz signal and precise timings and thus requires the use of a dedicated hardware timer. + +Note: The initial code may work with WS2801 + External LEDs since the protocol is the same, WS2811/WS2812B should also work but +may require very simple timing adjustments to be made in the source. +Not all WS2812 ICs use the same timings, some batches use different timings. + +It could be possible to be able to specify the timings required via CLI if users request it. + +## Connections + +WS2812 LED strips generally require a single data line, 5V and GND. + +WS2812 LEDs on full brightness can consume quite a bit of current. It is recommended to verify the current draw and ensure your +supply can cope with the load. On a multirotor that uses multiple BEC ESC's you can try use a different BEC to the one the FC +uses. e.g. ESC1/BEC1 -> FC, ESC2/BEC2 -> LED strip. It's also possible to power one half of the strip from one BEC and the other half +from another BEC. Just ensure that the GROUND is the same for all BEC outputs and LEDs. + + +| Target | Pin | Led Strip | Signal | +| --------------------- | --- | --------- | -------| +| Naze/Olimexino | RC5 | Data In | PA6 | +| CC3D | ??? | Data In | PB4 | +| ChebuzzF3/F3Discovery | PB8 | Data In | PB8 | + + +Since RC5 is also used for SoftSerial on the Naze/Olimexino it means that you cannot use softserial and led strips at the same time. +Additionally, since RC5 is also used for Parallel PWM RC input on both the Naze, Chebuzz and STM32F3Discovery targets, led strips +can not be used at the same time at Parallel PWM. + + +## Configuration + +Enable the `LED_STRIP` feature via the cli: + +``` +feature LED_STRIP +``` + +If you enable LED_STRIP feature and the feature is turned off again after a reboot then check your config does not conflict with other features, as above. + +Configure the LEDs using the `led` command. + +The `led` command takes either zero or two arguments - an zero-based led number and a pair of coordinates, direction flags and mode flags. + +If used with zero arguments it prints out the led configuration which can be copied for future reference. + +Each led is configured using the following template: `x,y:ddd:mmm` + +`x` and `y` are grid coordinates of a 0 based 16x16 grid, north west is 0,0, south east is 15,15 +`ddd` specifies the directions, since an led can face in any direction it can have multiple directions. Directions are: + + `N` - North + `E` - East + `S` - South + `W` - West + `U` - Up + `D` - Down + +For instance, an LED that faces South-east at a 45 degree downwards angle could be configured as `SED`. + +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: + +* `W` - `W`warnings. +* `F` - `F`light mode & Orientation +* `I` - `I`ndicator. +* `A` - `A`rmed state. + +Example: + +``` +led 0 0,15:SD:IAW +led 1 15,0:ND:IAW +led 2 0,0:ND:IAW +led 3 0,15:SD:IAW +``` + +to erase an led, and to mark the end of the chain, use `0,0::` as the second argument, like this: + +``` +led 4 0,0:: +``` + + +### Modes + +#### Warning + +This mode simply uses the leds to flash when warnings occur. + +* Battery warning flashes the LEDs between red and off when the battery is low if battery monitoring is enabled. +* Failsafe warning flashes the LEDs between light blue and lime green when failsafe is active. + +#### Flight Mode & Orientation + +This mode shows the flight mode and orientation. + +When flight modes are active then the leds are updated to show different colors depending on the mode, placement on the grid and direction. + +Leds are set in a specific order: + * Leds that marked as facing up or down. + * Leds that marked as facing west or east AND are on the west or east side of the grid. + * Leds that marked as facing north or south AND are on the north or south side of the grid. + +That is, south facing leds have priority. + +#### Indicator + +This mode flashes LEDs that correspond to roll and pitch stick positions. i.e. they indicate the direction the craft is going to turn. + +#### Armed state + +This mode toggles LEDs between green and blue when disarmed and armed, respectively. + +Note: Armed State cannot be used with Flight Mode. + +## 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. +e.g. connect 5V out to 5V in, GND to GND and Data Out to Data In. + +Orientation is when viewed with the front of the aircraft facing away from you and viewed from above. + +### Example 12 LED config + +The default configuration is as follows +``` +led 0 2,2:ES:IA +led 1 2,1:E:WF +led 2 2,0:NE:IA +led 3 1,0:N:F +led 4 0,0:NW:IA +led 5 0,1:W:WF +led 6 0,2:SW:IA +led 7 1,2:S:WF +led 8 1,1:U:WF +led 9 1,1:U:WF +led 10 1,1:D:WF +led 11 1,1:D:WF +``` + +Which translates into the following positions: + +``` + 5 3 + \ / + \ 4 / + \ FRONT / + 6 | 9-12 | 2 + / BACK \ + / 8 \ + / \ + 7 1 +``` + +LEDs 1,3,5 and 7 should be placed underneath the quad, facing downwards. +LEDs 2, 4, 6 and 8 should be positioned so the face east/north/west/south, respectively. +LEDs 9-10 should be placed facing down, in the middle +LEDs 11-12 should be placed facing up, in the middle + +This is the default so that if you don't want to place LEDs top and bottom in the middle just connect the first 8 leds. + +### Example 16 LED config + +``` +15,15:SD:IA +8,8:E:FW +8,7:E:FW +15,0:ND:IA +7,7:N:FW +8,7:N:FW +0,0:ND:IA +7,7:W:FW +7,8:W:FW +0,15:SD:IA +7,8:S:FW +8,8:S:FW +7,7:D:FW +8,7:D:FW +7,7:U:FW +8,7:U:FW +``` + +Which translates into the following positions: + +``` + 7 4 + \ / + \ 6-5 / + 8 \ FRONT / 3 + | 13-16 | + 9 / BACK \ 2 + / 11-12 \ + / \ + 10 1 +``` + +LEDs 1,4,7 and 10 should be placed underneath the quad, facing downwards. +LEDs 2-3, 6-5, 8-9 and 11-12 should be positioned so the face east/north/west/south, respectively. +LEDs 13-14 should be placed facing down, in the middle +LEDs 15-16 should be placed facing up, in the middle + +### Exmple 28 LED config + +``` +9,9:S:FW +10,10:S:FW +11,11:S:IA +11,11:E:IA +10,10:E:F +9,9:E:F +10,5:S:F +11,4:S:F +12,3:S:IA +12,2:N:IA +11,1:N:F +10,0:N:F +7,0:N:FW +6,0:N:FW +5,0:N:FW +4,0:N:FW +2,0:N:F +1,1:N:F +0,2:N:IA +0,3:W:IA +1,4:W:F +2,5:W:F +2,9:W:F +1,10:W:F +0,11:W:IA +0,11:S:IA +1,10:S:FW +2,9:S:FW +``` + +``` + 17-19 10-12 +20-22 \ / 7-9 + \ 13-16 / + \ FRONT / + / BACK \ + / \ +23-25 / \ 4-6 + 26-28 1-3 +``` + +All LEDs should face outwards from the chassis in this configuration. + +Note: +This configuration is specifically designed for the Alien Spider AQ50D PRO 250mm frame. + +http://www.goodluckbuy.com/alien-spider-aq50d-pro-250mm-mini-quadcopter-carbon-fiber-micro-multicopter-frame.html + +## Troubleshooting + +On initial power up the LEDs on the strip will be set to WHITE. This means you can attach a current meter to verify +the current draw if your measurement equipment is fast enough. This also means that you can make sure that each R,G and B LED +in each LED module on the strip is also functioning. + +After a short delay the LEDs will show the unarmed color sequence and or low-battery warning sequence. + +If the LEDs flash intermittently or do not show the correct colors verify all connections and check the specifications of the +LEDs you have against the supported timings (for now, you'll have to look in the source). + +Also check that the feature `LED_STRIP` was correctly enabled and that it does not conflict with other features, as above. diff --git a/src/main/io/ledstrip.c b/src/main/io/ledstrip.c index 8c23177080..b3a05cfcd5 100644 --- a/src/main/io/ledstrip.c +++ b/src/main/io/ledstrip.c @@ -42,9 +42,12 @@ #include "config/config.h" #include "rx/rx.h" #include "io/rc_controls.h" +#include "flight/failsafe.h" #include "io/ledstrip.h" +static failsafe_t* failsafe; + #if MAX_LED_STRIP_LENGTH > WS2811_LED_STRIP_LENGTH #error "Led strip length must match driver" #endif @@ -74,6 +77,8 @@ const rgbColor24bpp_t red = { LED_RED }; const rgbColor24bpp_t orange = { LED_ORANGE }; const rgbColor24bpp_t green = { LED_GREEN }; const rgbColor24bpp_t blue = { LED_BLUE }; +const rgbColor24bpp_t lightBlue = { LED_LIGHT_BLUE }; +const rgbColor24bpp_t limeGreen = { LED_LIME_GREEN }; uint8_t ledGridWidth; @@ -84,17 +89,17 @@ 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, 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_BATTERY }, + { 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_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 }, + { 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 }, }; @@ -130,11 +135,11 @@ static const uint8_t directionMappings[DIRECTION_COUNT] = { LED_DIRECTION_DOWN }; -static const char functionCodes[] = { 'I', 'B', 'F', 'A' }; +static const char functionCodes[] = { 'I', 'W', '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_WARNING, LED_FUNCTION_FLIGHT_MODE, LED_FUNCTION_ARM_STATE }; @@ -310,7 +315,7 @@ void generateLedConfig(uint8_t ledIndex, char *ledConfigBuffer, size_t bufferSiz // timers uint32_t nextAnimationUpdateAt = 0; uint32_t nextIndicatorFlashAt = 0; -uint32_t nextBatteryFlashAt = 0; +uint32_t nextWarningFlashAt = 0; #define LED_STRIP_20HZ ((1000 * 1000) / 20) #define LED_STRIP_10HZ ((1000 * 1000) / 10) @@ -506,23 +511,45 @@ void applyLedModeLayer(void) } } -void applyLedLowBatteryLayer(uint8_t batteryFlashState) +typedef enum { + WARNING_FLAG_NONE = 0, + WARNING_FLAG_LOW_BATTERY = (1 << 0), + WARNING_FLAG_FAILSAFE = (1 << 1) +} warningFlags_e; + +void applyLedWarningLayer(uint8_t warningState, uint8_t warningFlags) { const ledConfig_t *ledConfig; + static uint8_t warningFlashCounter = 0; + + if (warningState) { + warningFlashCounter++; + warningFlashCounter = warningFlashCounter % 4; + } uint8_t ledIndex; for (ledIndex = 0; ledIndex < ledCount; ledIndex++) { ledConfig = &ledConfigs[ledIndex]; - if (!(ledConfig->flags & LED_FUNCTION_BATTERY)) { + if (!(ledConfig->flags & LED_FUNCTION_WARNING)) { continue; } - if (batteryFlashState == 0) { - setLedColor(ledIndex, &red); + if (warningState == 0) { + if (warningFlashCounter == 0 && warningFlags & WARNING_FLAG_LOW_BATTERY) { + setLedColor(ledIndex, &red); + } + if (warningFlashCounter > 1 && warningFlags & WARNING_FLAG_FAILSAFE) { + setLedColor(ledIndex, &lightBlue); + } } else { - setLedColor(ledIndex, &black); + if (warningFlashCounter == 0 && warningFlags & WARNING_FLAG_LOW_BATTERY) { + setLedColor(ledIndex, &black); + } + if (warningFlashCounter > 1 && warningFlags & WARNING_FLAG_FAILSAFE) { + setLedColor(ledIndex, &limeGreen); + } } } } @@ -625,15 +652,15 @@ void updateLedStrip(void) bool animationUpdateNow = (int32_t)(now - nextAnimationUpdateAt) >= 0L; bool indicatorFlashNow = (int32_t)(now - nextIndicatorFlashAt) >= 0L; - bool batteryFlashNow = (int32_t)(now - nextBatteryFlashAt) >= 0L; + bool warningFlashNow = (int32_t)(now - nextWarningFlashAt) >= 0L; - if (!(batteryFlashNow || indicatorFlashNow || animationUpdateNow)) { + if (!(warningFlashNow || indicatorFlashNow || animationUpdateNow)) { return; } static uint8_t indicatorFlashState = 0; - static uint8_t batteryFlashState = 0; - static bool batteryWarningEnabled = false; + static uint8_t warningState = 0; + static uint8_t warningFlags; // LAYER 1 @@ -641,21 +668,27 @@ void updateLedStrip(void) // LAYER 2 - if (batteryFlashNow) { - nextBatteryFlashAt = now + LED_STRIP_10HZ; + if (warningFlashNow) { + nextWarningFlashAt = now + LED_STRIP_10HZ; - if (batteryFlashState == 0) { - batteryFlashState = 1; + if (warningState == 0) { + warningState = 1; + + warningFlags = WARNING_FLAG_NONE; + if (feature(FEATURE_VBAT) && shouldSoundBatteryAlarm()) { + warningFlags |= WARNING_FLAG_LOW_BATTERY; + } + if (failsafe->vTable->hasTimerElapsed()) { + warningFlags |= WARNING_FLAG_FAILSAFE; + } - batteryWarningEnabled = feature(FEATURE_VBAT) && shouldSoundBatteryAlarm(); } else { - batteryFlashState = 0; - + warningState = 0; } } - if (batteryWarningEnabled) { - applyLedLowBatteryLayer(batteryFlashState); + if (warningFlags) { + applyLedWarningLayer(warningState, warningFlags); } // LAYER 3 @@ -694,9 +727,10 @@ void applyDefaultLedStripConfig(ledConfig_t *ledConfigs) reevalulateLedConfig(); } -void ledStripInit(ledConfig_t *ledConfigsToUse) +void ledStripInit(ledConfig_t *ledConfigsToUse, failsafe_t* failsafeToUse) { ledConfigs = ledConfigsToUse; + failsafe = failsafeToUse; reevalulateLedConfig(); } #endif diff --git a/src/main/io/ledstrip.h b/src/main/io/ledstrip.h index 9ce3e00823..27828c40ba 100644 --- a/src/main/io/ledstrip.h +++ b/src/main/io/ledstrip.h @@ -41,7 +41,7 @@ typedef enum { LED_DIRECTION_UP = (1 << 4), LED_DIRECTION_DOWN = (1 << 5), LED_FUNCTION_INDICATOR = (1 << 6), - LED_FUNCTION_BATTERY = (1 << 7), + LED_FUNCTION_WARNING = (1 << 7), LED_FUNCTION_FLIGHT_MODE = (1 << 8), LED_FUNCTION_ARM_STATE = (1 << 9) } ledFlag_e; diff --git a/src/main/main.c b/src/main/main.c index b3f87890ea..2446659415 100755 --- a/src/main/main.c +++ b/src/main/main.c @@ -89,8 +89,7 @@ void gpsInit(serialConfig_t *serialConfig, gpsConfig_t *initialGpsConfig); void navigationInit(gpsProfile_t *initialGpsProfile, pidProfile_t *pidProfile); bool sensorsAutodetect(sensorAlignmentConfig_t *sensorAlignmentConfig, uint16_t gyroLpf, uint8_t accHardwareToUse, int16_t magDeclinationFromConfig); void imuInit(void); -void ledStripInit(ledConfig_t *ledConfigs); - +void ledStripInit(ledConfig_t *ledConfigsToUse, failsafe_t* failsafeToUse); void loop(void); // FIXME bad naming - this appears to be for some new board that hasn't been made available yet. @@ -238,7 +237,7 @@ void init(void) #ifdef LED_STRIP if (feature(FEATURE_LED_STRIP)) { ws2811LedStripInit(); - ledStripInit(masterConfig.ledConfigs); + ledStripInit(masterConfig.ledConfigs, failsafe); } #endif diff --git a/src/test/unit/ledstrip_unittest.cc b/src/test/unit/ledstrip_unittest.cc index 9d711cfd01..f34c355a19 100644 --- a/src/test/unit/ledstrip_unittest.cc +++ b/src/test/unit/ledstrip_unittest.cc @@ -15,6 +15,7 @@ * along with Cleanflight. If not, see . */ #include +#include #include @@ -56,8 +57,8 @@ TEST(LedStripTest, parseLedStripConfig) // given static const ledConfig_t expectedLedStripConfig[WS2811_LED_STRIP_LENGTH] = { - { CALCULATE_LED_XY( 9, 9), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, - { CALCULATE_LED_XY(10, 10), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, + { CALCULATE_LED_XY( 9, 9), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, + { CALCULATE_LED_XY(10, 10), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, { CALCULATE_LED_XY(11, 11), LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE }, { CALCULATE_LED_XY(11, 11), LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE }, { CALCULATE_LED_XY(10, 10), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE }, @@ -70,10 +71,10 @@ TEST(LedStripTest, parseLedStripConfig) { CALCULATE_LED_XY(11, 1), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY(10, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE }, - { CALCULATE_LED_XY( 7, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, - { CALCULATE_LED_XY( 6, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, - { CALCULATE_LED_XY( 5, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, - { CALCULATE_LED_XY( 4, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, + { CALCULATE_LED_XY( 7, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, + { CALCULATE_LED_XY( 6, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, + { CALCULATE_LED_XY( 5, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, + { CALCULATE_LED_XY( 4, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, { CALCULATE_LED_XY( 2, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY( 1, 1), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE }, @@ -86,8 +87,8 @@ TEST(LedStripTest, parseLedStripConfig) { CALCULATE_LED_XY( 1, 10), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY( 0, 11), LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE }, { CALCULATE_LED_XY( 0, 11), LED_DIRECTION_SOUTH | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE }, - { CALCULATE_LED_XY( 1, 10), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, - { CALCULATE_LED_XY( 2, 9), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, + { CALCULATE_LED_XY( 1, 10), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, + { CALCULATE_LED_XY( 2, 9), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, { 0, 0 }, { 0, 0 }, @@ -100,8 +101,8 @@ TEST(LedStripTest, parseLedStripConfig) // Spider quad // right rear cluster - "9,9:S:FB", - "10,10:S:FB", + "9,9:S:FW", + "10,10:S:FW", "11,11:S:IA", "11,11:E:IA", "10,10:E:F", @@ -116,10 +117,10 @@ TEST(LedStripTest, parseLedStripConfig) "10,0:N:F", // center front cluster - "7,0:N:FB", - "6,0:N:FB", - "5,0:N:FB", - "4,0:N:FB", + "7,0:N:FW", + "6,0:N:FW", + "5,0:N:FW", + "4,0:N:FW", // left front cluster "2,0:N:F", @@ -134,8 +135,8 @@ TEST(LedStripTest, parseLedStripConfig) "1,10:W:F", "0,11:W:IA", "0,11:S:IA", - "1,10:S:FB", - "2,9:S:FB" + "1,10:S:FW", + "2,9:S:FW" }; // and memset(&systemLedConfigs, 0, sizeof(systemLedConfigs)); @@ -182,13 +183,13 @@ TEST(LedStripTest, smallestGridWithCenter) // and static const ledConfig_t testLedConfigs[] = { { 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, 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 | LED_FUNCTION_BATTERY }, + { CALCULATE_LED_XY( 1, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, { 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, 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_BATTERY } + { CALCULATE_LED_XY( 1, 2), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING } }; memcpy(&systemLedConfigs, &testLedConfigs, sizeof(testLedConfigs)); @@ -250,9 +251,9 @@ TEST(LedStripTest, smallestGrid) { CALCULATE_LED_XY( 0, 11), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY( 0, 10), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY( 0, 9), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE }, - { CALCULATE_LED_XY( 0, 8), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, - { CALCULATE_LED_XY( 0, 7), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, - { CALCULATE_LED_XY( 0, 6), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, + { CALCULATE_LED_XY( 0, 8), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, + { CALCULATE_LED_XY( 0, 7), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, + { CALCULATE_LED_XY( 0, 6), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, { CALCULATE_LED_XY( 0, 5), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY( 0, 4), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY( 0, 3), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE }, @@ -270,9 +271,9 @@ TEST(LedStripTest, smallestGrid) { CALCULATE_LED_XY( 4, 3), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY( 4, 4), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY( 4, 5), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE }, - { CALCULATE_LED_XY( 4, 6), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, - { CALCULATE_LED_XY( 4, 7), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, - { CALCULATE_LED_XY( 4, 8), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_BATTERY }, + { CALCULATE_LED_XY( 4, 6), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, + { CALCULATE_LED_XY( 4, 7), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, + { CALCULATE_LED_XY( 4, 8), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING }, { CALCULATE_LED_XY( 4, 9), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY( 4, 10), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE }, { CALCULATE_LED_XY( 4, 11), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE },