diff --git a/Makefile b/Makefile index c95049d08f..d9b039c163 100644 --- a/Makefile +++ b/Makefile @@ -188,6 +188,7 @@ COMMON_SRC = build_config.c \ HIGHEND_SRC = flight/autotune.c \ flight/navigation.c \ flight/gps_conversion.c \ + common/colorconversion.c \ io/gps.c \ io/ledstrip.c \ io/display.c \ diff --git a/src/main/common/color.h b/src/main/common/color.h new file mode 100644 index 0000000000..42e83ad4e7 --- /dev/null +++ b/src/main/common/color.h @@ -0,0 +1,52 @@ +/* + * This file is part of Cleanflight. + * + * Cleanflight is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cleanflight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cleanflight. If not, see . + */ + +#pragma once + + +typedef enum { + RGB_RED = 0, + RGB_GREEN, + RGB_BLUE +} colorComponent_e; + +#define RGB_COLOR_COMPONENT_COUNT (RGB_BLUE + 1) + +struct rgbColor24bpp_s { + uint8_t r; + uint8_t g; + uint8_t b; +}; + +typedef union { + struct rgbColor24bpp_s rgb; + uint8_t raw[RGB_COLOR_COMPONENT_COUNT]; +} rgbColor24bpp_t; + +typedef enum { + HSV_RED = 0, + HSV_GREEN, + HSV_BLUE +} hsvColorComponent_e; + +#define HSV_COLOR_COMPONENT_COUNT (HSV_BLUE + 1) + +typedef struct hsvColor_s { + uint16_t h; // 0 - 360 + uint8_t s; // 0 - 255 + uint8_t v; // 0 - 255 +} hsvColor_t; diff --git a/src/main/common/colorconversion.c b/src/main/common/colorconversion.c new file mode 100644 index 0000000000..45f13fbcb8 --- /dev/null +++ b/src/main/common/colorconversion.c @@ -0,0 +1,84 @@ +/* + * This file is part of Cleanflight. + * + * Cleanflight is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cleanflight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cleanflight. If not, see . + */ + +#include "stdint.h" + +#include "color.h" +#include "colorconversion.h" + +/* + * Source below found here: http://www.kasperkamperman.com/blog/arduino/arduino-programming-hsb-to-rgb/ + */ + +rgbColor24bpp_t* hsvToRgb24(const hsvColor_t* c) +{ + static rgbColor24bpp_t r; + + uint16_t val = c->v; + uint16_t sat = 255 - c->s; + uint32_t base; + uint16_t hue = c->h; + + if (sat == 0) { // Acromatic color (gray). Hue doesn't mind. + r.rgb.r = val; + r.rgb.g = val; + r.rgb.b = val; + } else { + + base = ((255- sat) * val) >> 8; + + switch (hue / 60) { + case 0: + r.rgb.r = val; + r.rgb.g = (((val - base) * hue) / 60) + base; + r.rgb.b = base; + break; + case 1: + r.rgb.r = (((val - base) * (60 - (hue % 60))) / 60) + base; + r.rgb.g = val; + r.rgb.b = base; + break; + + case 2: + r.rgb.r = base; + r.rgb.g = val; + r.rgb.b = (((val - base) * (hue % 60)) / 60) + base; + break; + + case 3: + r.rgb.r = base; + r.rgb.g = (((val - base) * (60 - (hue % 60))) / 60) + base; + r.rgb.b = val; + break; + + case 4: + r.rgb.r = (((val - base) * (hue % 60)) / 60) + base; + r.rgb.g = base; + r.rgb.b = val; + break; + + case 5: + r.rgb.r = val; + r.rgb.g = base; + r.rgb.b = (((val - base) * (60 - (hue % 60))) / 60) + base; + break; + + } + } + return &r; +} + diff --git a/src/main/common/colorconversion.h b/src/main/common/colorconversion.h new file mode 100644 index 0000000000..cd7e80e9e5 --- /dev/null +++ b/src/main/common/colorconversion.h @@ -0,0 +1,3 @@ +#pragma once + +rgbColor24bpp_t* hsvToRgb24(const hsvColor_t *c); diff --git a/src/main/drivers/light_ws2811strip.c b/src/main/drivers/light_ws2811strip.c index 6d66350eef..0820e33eb0 100644 --- a/src/main/drivers/light_ws2811strip.c +++ b/src/main/drivers/light_ws2811strip.c @@ -28,49 +28,49 @@ #include "platform.h" +#include "common/color.h" +#include "common/colorconversion.h" #include "drivers/light_ws2811strip.h" uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE]; volatile uint8_t ws2811LedDataTransferInProgress = 0; -static rgbColor24bpp_t ledColorBuffer[WS2811_LED_STRIP_LENGTH]; +static hsvColor_t ledColorBuffer[WS2811_LED_STRIP_LENGTH]; -void setLedColor(uint16_t index, const rgbColor24bpp_t *color) +void setLedHsv(uint16_t index, const hsvColor_t *color) { - ledColorBuffer[index].rgb = color->rgb; + ledColorBuffer[index] = *color; } -/** - * use this after you set the color - */ -void setLedBrightness(uint16_t index, const uint8_t scalePercent) +void setLedValue(uint16_t index, const uint8_t value) { - ledColorBuffer[index].rgb.r = ((uint16_t)ledColorBuffer[index].rgb.r * scalePercent / 100); - ledColorBuffer[index].rgb.g = ((uint16_t)ledColorBuffer[index].rgb.g * scalePercent / 100); - ledColorBuffer[index].rgb.b = ((uint16_t)ledColorBuffer[index].rgb.b * scalePercent / 100); + ledColorBuffer[index].v = value; } -void setStripColor(const rgbColor24bpp_t *color) +void scaleLedValue(uint16_t index, const uint8_t scalePercent) +{ + ledColorBuffer[index].v = ((uint16_t)ledColorBuffer[index].v * scalePercent / 100); +} + +void setStripColor(const hsvColor_t *color) { uint16_t index; for (index = 0; index < WS2811_LED_STRIP_LENGTH; index++) { - setLedColor(index, color); + setLedHsv(index, color); } } -void setStripColors(const rgbColor24bpp_t *colors) +void setStripColors(const hsvColor_t *colors) { uint16_t index; for (index = 0; index < WS2811_LED_STRIP_LENGTH; index++) { - setLedColor(index, colors++); + setLedHsv(index, colors++); } } void ws2811LedStripInit(void) { ws2811LedStripHardwareInit(); - - setStripColor(&white); ws2811UpdateStrip(); } @@ -107,21 +107,25 @@ void updateLEDDMABuffer(uint8_t componentValue) void ws2811UpdateStrip(void) { static uint32_t waitCounter = 0; + static rgbColor24bpp_t *rgb24; + // wait until previous transfer completes while(ws2811LedDataTransferInProgress) { waitCounter++; } dmaBufferOffset = 0; // reset buffer memory index - ledIndex = 0; // reset led index + ledIndex = 0; // reset led index // fill transmit buffer with correct compare values to achieve // correct pulse widths according to color values while (ledIndex < WS2811_LED_STRIP_LENGTH) { - updateLEDDMABuffer(ledColorBuffer[ledIndex].rgb.g); - updateLEDDMABuffer(ledColorBuffer[ledIndex].rgb.r); - updateLEDDMABuffer(ledColorBuffer[ledIndex].rgb.b); + rgb24 = hsvToRgb24(&ledColorBuffer[ledIndex]); + + updateLEDDMABuffer(rgb24->rgb.g); + updateLEDDMABuffer(rgb24->rgb.r); + updateLEDDMABuffer(rgb24->rgb.b); ledIndex++; } diff --git a/src/main/drivers/light_ws2811strip.h b/src/main/drivers/light_ws2811strip.h index 86b6bab89e..efca5a4707 100644 --- a/src/main/drivers/light_ws2811strip.h +++ b/src/main/drivers/light_ws2811strip.h @@ -23,41 +23,24 @@ #define WS2811_DMA_BUFFER_SIZE (WS2811_BITS_PER_LED * WS2811_LED_STRIP_LENGTH + WS2811_DELAY_BUFFER_LENGTH) // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes) -typedef enum { - CC_RED = 0, - CC_GREEN, - CC_BLUE -} colorComponent_e; - -#define COLOR_COMPONENT_COUNT (CC_BLUE + 1) - -struct rgbColor24bpp_s { - uint8_t r; - uint8_t g; - uint8_t b; -}; - -typedef union { - struct rgbColor24bpp_s rgb; - uint8_t raw[COLOR_COMPONENT_COUNT]; -} rgbColor24bpp_t; - void ws2811LedStripInit(void); void ws2811LedStripHardwareInit(void); void ws2811LedStripDMAEnable(void); void ws2811UpdateStrip(void); -void setLedColor(uint16_t index, const rgbColor24bpp_t *color); -void setLedBrightness(uint16_t index, const uint8_t scalePercent); -void setStripColor(const rgbColor24bpp_t *color); -void setStripColors(const rgbColor24bpp_t *colors); + +void setLedHsv(uint16_t index, const hsvColor_t *color); +void scaleLedValue(uint16_t index, const uint8_t scalePercent); +void setLedValue(uint16_t index, const uint8_t value); + +void setStripColor(const hsvColor_t *color); +void setStripColors(const hsvColor_t *colors); bool isWS2811LedStripReady(void); extern uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE]; extern volatile uint8_t ws2811LedDataTransferInProgress; -extern const rgbColor24bpp_t black; -extern const rgbColor24bpp_t white; -extern const rgbColor24bpp_t orange; +extern const hsvColor_t hsv_white; +extern const hsvColor_t hsv_black; diff --git a/src/main/drivers/light_ws2811strip_stm32f10x.c b/src/main/drivers/light_ws2811strip_stm32f10x.c index 49bf409cec..19e30f6e98 100644 --- a/src/main/drivers/light_ws2811strip_stm32f10x.c +++ b/src/main/drivers/light_ws2811strip_stm32f10x.c @@ -20,6 +20,7 @@ #include "platform.h" +#include "common/color.h" #include "drivers/light_ws2811strip.h" void ws2811LedStripHardwareInit(void) @@ -100,7 +101,7 @@ void ws2811LedStripHardwareInit(void) NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); - setStripColor(&white); + setStripColor(&hsv_white); ws2811UpdateStrip(); } diff --git a/src/main/drivers/light_ws2811strip_stm32f30x.c b/src/main/drivers/light_ws2811strip_stm32f30x.c index 424fa245be..06deca25d6 100644 --- a/src/main/drivers/light_ws2811strip_stm32f30x.c +++ b/src/main/drivers/light_ws2811strip_stm32f30x.c @@ -22,6 +22,7 @@ #include "gpio.h" +#include "common/color.h" #include "drivers/light_ws2811strip.h" #define WS2811_GPIO GPIOB @@ -105,7 +106,7 @@ void ws2811LedStripHardwareInit(void) NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); - setStripColor(&white); + setStripColor(&hsv_white); ws2811UpdateStrip(); } diff --git a/src/main/io/ledstrip.c b/src/main/io/ledstrip.c index e916be7998..9cd848978c 100644 --- a/src/main/io/ledstrip.c +++ b/src/main/io/ledstrip.c @@ -27,6 +27,8 @@ #ifdef LED_STRIP +#include + #include "drivers/light_ws2811strip.h" #include "drivers/system.h" #include "drivers/serial.h" @@ -35,7 +37,6 @@ #include #include - #include "sensors/battery.h" #include "config/runtime_config.h" @@ -55,31 +56,30 @@ static failsafe_t* failsafe; //#define USE_LED_ANIMATION -#define LED_WHITE {255, 255, 255} -#define LED_BLACK {0, 0, 0 } +// H S V +#define LED_WHITE { 0, 255, 255} +#define LED_BLACK { 0, 0, 0} +#define LED_RED { 0, 0, 255} +#define LED_ORANGE { 30, 0, 255} +#define LED_YELLOW { 60, 0, 255} +#define LED_LIME_GREEN { 90, 0, 255} +#define LED_GREEN {120, 0, 255} +#define LED_CYAN {180, 0, 255} +#define LED_LIGHT_BLUE {210, 0, 255} +#define LED_BLUE {240, 0, 255} +#define LED_DARK_MAGENTA {300, 0, 128} +#define LED_PINK {300, 0, 255} +#define LED_DARK_VIOLET {270, 0, 255} +#define LED_DEEP_PINK {330, 0, 255} -#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 green = { LED_GREEN }; -const rgbColor24bpp_t blue = { LED_BLUE }; -const rgbColor24bpp_t lightBlue = { LED_LIGHT_BLUE }; -const rgbColor24bpp_t limeGreen = { LED_LIME_GREEN }; +const hsvColor_t hsv_black = LED_BLACK; +const hsvColor_t hsv_white = LED_WHITE; +const hsvColor_t hsv_red = LED_RED; +const hsvColor_t hsv_orange = LED_ORANGE; +const hsvColor_t hsv_green = LED_GREEN; +const hsvColor_t hsv_blue = LED_BLUE; +const hsvColor_t hsv_lightBlue = LED_LIGHT_BLUE; +const hsvColor_t hsv_limeGreen = LED_LIME_GREEN; uint8_t ledGridWidth; @@ -325,82 +325,82 @@ uint32_t nextWarningFlashAt = 0; #define LED_DIRECTION_COUNT 6 struct modeColors_s { - rgbColor24bpp_t north; - rgbColor24bpp_t east; - rgbColor24bpp_t south; - rgbColor24bpp_t west; - rgbColor24bpp_t up; - rgbColor24bpp_t down; + hsvColor_t north; + hsvColor_t east; + hsvColor_t south; + hsvColor_t west; + hsvColor_t up; + hsvColor_t down; }; typedef union { - rgbColor24bpp_t raw[LED_DIRECTION_COUNT]; + hsvColor_t raw[LED_DIRECTION_COUNT]; struct modeColors_s colors; } modeColors_t; static const modeColors_t orientationModeColors = { .raw = { - {LED_WHITE}, - {LED_DARK_VIOLET}, - {LED_RED}, - {LED_DEEP_PINK}, - {LED_BLUE}, - {LED_ORANGE} + LED_WHITE, + LED_DARK_VIOLET, + LED_RED, + LED_DEEP_PINK, + LED_BLUE, + LED_ORANGE } }; static const modeColors_t headfreeModeColors = { .raw = { - {LED_LIME_GREEN}, - {LED_DARK_VIOLET}, - {LED_ORANGE}, - {LED_DEEP_PINK}, - {LED_BLUE}, - {LED_ORANGE} + LED_LIME_GREEN, + LED_DARK_VIOLET, + LED_ORANGE, + LED_DEEP_PINK, + LED_BLUE, + LED_ORANGE } }; static const modeColors_t horizonModeColors = { .raw = { - {LED_BLUE}, - {LED_DARK_VIOLET}, - {LED_YELLOW}, - {LED_DEEP_PINK}, - {LED_BLUE}, - {LED_ORANGE} + LED_BLUE, + LED_DARK_VIOLET, + LED_YELLOW, + LED_DEEP_PINK, + LED_BLUE, + LED_ORANGE } }; static const modeColors_t angleModeColors = { .raw = { - {LED_CYAN}, - {LED_DARK_VIOLET}, - {LED_YELLOW}, - {LED_DEEP_PINK}, - {LED_BLUE}, - {LED_ORANGE} + LED_CYAN, + LED_DARK_VIOLET, + LED_YELLOW, + LED_DEEP_PINK, + LED_BLUE, + LED_ORANGE } }; static const modeColors_t magModeColors = { .raw = { - {LED_PINK}, - {LED_DARK_VIOLET}, - {LED_ORANGE}, - {LED_DEEP_PINK}, - {LED_BLUE}, - {LED_ORANGE} + LED_PINK, + LED_DARK_VIOLET, + LED_ORANGE, + 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} + LED_LIGHT_BLUE, + LED_DARK_VIOLET, + LED_RED, + LED_DEEP_PINK, + LED_BLUE, + LED_ORANGE } }; @@ -408,28 +408,28 @@ void applyDirectionalModeColor(const uint8_t ledIndex, const ledConfig_t *ledCon { // apply up/down colors regardless of quadrant. if ((ledConfig->flags & LED_DIRECTION_UP)) { - setLedColor(ledIndex, &modeColors->colors.up); + setLedHsv(ledIndex, &modeColors->colors.up); } if ((ledConfig->flags & LED_DIRECTION_DOWN)) { - setLedColor(ledIndex, &modeColors->colors.down); + setLedHsv(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); + setLedHsv(ledIndex, &modeColors->colors.west); } if ((ledConfig->flags & LED_DIRECTION_EAST) && GET_LED_X(ledConfig) >= lowestXValueForEast) { - setLedColor(ledIndex, &modeColors->colors.east); + setLedHsv(ledIndex, &modeColors->colors.east); } if ((ledConfig->flags & LED_DIRECTION_NORTH) && GET_LED_Y(ledConfig) <= highestYValueForNorth) { - setLedColor(ledIndex, &modeColors->colors.north); + setLedHsv(ledIndex, &modeColors->colors.north); } if ((ledConfig->flags & LED_DIRECTION_SOUTH) && GET_LED_Y(ledConfig) >= lowestYValueForSouth) { - setLedColor(ledIndex, &modeColors->colors.south); + setLedHsv(ledIndex, &modeColors->colors.south); } } @@ -441,30 +441,30 @@ typedef enum { QUADRANT_NORTH_WEST } quadrant_e; -void applyQuadrantColor(const uint8_t ledIndex, const ledConfig_t *ledConfig, const quadrant_e quadrant, const rgbColor24bpp_t *color) +void applyQuadrantColor(const uint8_t ledIndex, const ledConfig_t *ledConfig, const quadrant_e quadrant, const hsvColor_t *color) { switch (quadrant) { case QUADRANT_NORTH_EAST: if (GET_LED_Y(ledConfig) <= highestYValueForNorth && GET_LED_X(ledConfig) >= lowestXValueForEast) { - setLedColor(ledIndex, color); + setLedHsv(ledIndex, color); } return; case QUADRANT_SOUTH_EAST: if (GET_LED_Y(ledConfig) >= lowestYValueForSouth && GET_LED_X(ledConfig) >= lowestXValueForEast) { - setLedColor(ledIndex, color); + setLedHsv(ledIndex, color); } return; case QUADRANT_SOUTH_WEST: if (GET_LED_Y(ledConfig) >= lowestYValueForSouth && GET_LED_X(ledConfig) <= highestXValueForWest) { - setLedColor(ledIndex, color); + setLedHsv(ledIndex, color); } return; case QUADRANT_NORTH_WEST: if (GET_LED_Y(ledConfig) <= highestYValueForNorth && GET_LED_X(ledConfig) <= highestXValueForWest) { - setLedColor(ledIndex, color); + setLedHsv(ledIndex, color); } return; } @@ -479,14 +479,14 @@ void applyLedModeLayer(void) ledConfig = &ledConfigs[ledIndex]; - setLedColor(ledIndex, &black); + setLedHsv(ledIndex, &hsv_black); if (!(ledConfig->flags & LED_FUNCTION_FLIGHT_MODE)) { if (ledConfig->flags & LED_FUNCTION_ARM_STATE) { if (!ARMING_FLAG(ARMED)) { - setLedColor(ledIndex, &green); + setLedHsv(ledIndex, &hsv_green); } else { - setLedColor(ledIndex, &blue); + setLedHsv(ledIndex, &hsv_blue); } } continue; @@ -539,17 +539,17 @@ void applyLedWarningLayer(uint8_t warningState, uint8_t warningFlags) if (warningState == 0) { if (warningFlashCounter == 0 && warningFlags & WARNING_FLAG_LOW_BATTERY) { - setLedColor(ledIndex, &red); + setLedHsv(ledIndex, &hsv_red); } if (warningFlashCounter > 1 && warningFlags & WARNING_FLAG_FAILSAFE) { - setLedColor(ledIndex, &lightBlue); + setLedHsv(ledIndex, &hsv_lightBlue); } } else { if (warningFlashCounter == 0 && warningFlags & WARNING_FLAG_LOW_BATTERY) { - setLedColor(ledIndex, &black); + setLedHsv(ledIndex, &hsv_black); } if (warningFlashCounter > 1 && warningFlags & WARNING_FLAG_FAILSAFE) { - setLedColor(ledIndex, &limeGreen); + setLedHsv(ledIndex, &hsv_limeGreen); } } } @@ -558,13 +558,13 @@ void applyLedWarningLayer(uint8_t warningState, uint8_t warningFlags) void applyLedIndicatorLayer(uint8_t indicatorFlashState) { const ledConfig_t *ledConfig; - static const rgbColor24bpp_t *flashColor; + static const hsvColor_t *flashColor; if (indicatorFlashState == 0) { - flashColor = &orange; + flashColor = &hsv_orange; } else { - flashColor = &black; + flashColor = &hsv_black; } @@ -631,11 +631,11 @@ static void applyLedAnimationLayer(void) ledConfig = &ledConfigs[ledIndex]; if (GET_LED_Y(ledConfig) == previousRow) { - setLedColor(ledIndex, &white); + setLedHsv(ledIndex, &white); setLedBrightness(ledIndex, 50); } else if (GET_LED_Y(ledConfig) == currentRow) { - setLedColor(ledIndex, &white); + setLedHsv(ledIndex, &white); } else if (GET_LED_Y(ledConfig) == nextRow) { setLedBrightness(ledIndex, 50); } diff --git a/src/main/main.c b/src/main/main.c index 2785afd6cb..d5feb7b5fd 100755 --- a/src/main/main.c +++ b/src/main/main.c @@ -23,6 +23,7 @@ #include "platform.h" #include "common/axis.h" +#include "common/color.h" #include "drivers/system.h" #include "drivers/gpio.h"