diff --git a/Inc/ws2812b.h b/Inc/ws2812b.h deleted file mode 100644 index 59e9737..0000000 --- a/Inc/ws2812b.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ws2812b.h - * - * The MIT License. - * Created on: 14.07.2017 - * Author: Mateusz Salamon - * www.msalamon.pl - * mateusz@msalamon.pl - */ - -#ifndef WS2812B_H_ -#define WS2812B_H_ - -/* Includes */ -#include - -/* Defintions */ -#define WS2812B_LEDS (1) - -/* Data Structures */ -typedef union __attribute__((packed, aligned(4))) ws2812b_color_u { - struct __attribute__((packed, aligned(4))) rgbx_s { - uint8_t green; - uint8_t red; - uint8_t blue; - uint8_t x; - } rgbx; - struct __attribute__((packed, aligned(4))) rgb_s { - uint8_t _pad; - uint8_t green; - uint8_t red; - uint8_t blue; - } rgb; - uint32_t u32; - uint8_t u8[4]; -} ws2812b_color; - -/* Function Prototypes */ -void ws2812_init(SPI_HandleTypeDef *hspi); -void ws2812_set_led_color_val(uint16_t diode_id, uint32_t color); -void ws2812_set_led_color(uint16_t diode_id, ws2812b_color color); -void ws2812_set_led_rgb(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b); -void ws2812_set_led_rgbx(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b, uint8_t x); -void ws2812_set_led_hsv(uint16_t diode_id, uint16_t hue, uint8_t sat, uint8_t value); -uint32_t ws2812_get_color(uint16_t diode_id); -uint8_t *ws2812_get_pixels(); -void ws2812_refresh(); -uint8_t sine8(uint8_t x); -uint8_t gamma8(uint8_t x); - -#endif /* WS2812B_H_ */ diff --git a/Inc/ws2812b_fx.h b/Inc/ws2812b_fx.h deleted file mode 100644 index 72caac3..0000000 --- a/Inc/ws2812b_fx.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * ws2812b_fx.h - * - * Library based on Harm Aldick's Arduino library - * https://github.com/kitesurfer1404/WS2812FX - * - * The MIT License. - * Created on: 20.10.2018 - * Author: Mateusz Salamon - * www.msalamon.pl - * mateusz@msalamon.pl - */ - -#ifndef WS2812B_FX_H_ -#define WS2812B_FX_H_ - -/* Includes */ -#include - -/* Definitions */ -#define DEFAULT_COLOR (0x00F0000000) -#define NUM_COLORS (4) -#define SPEED_MIN (10) -#define DEFAULT_SPEED (150) -#define SPEED_MAX (65535) -#define MODE_COUNT (59) -#define DEFAULT_MODE (0) -#define FADE_RATE (2) -/* some common colors */ -#define RED (0xFF0000U) -#define GREEN (0x00FF00U) -#define BLUE (0x0000FFU) -#define WHITE (0xFFFFFFU) -#define BLACK (0x000000U) -#define YELLOW (0xFFFF00U) -#define CYAN (0x00FFFFU) -#define MAGENTA (0xFF00FFU) -#define PURPLE (0x400080U) -#define ORANGE (0xFF3000U) -#define PINK (0xFF1493U) - -/* Data Structures */ -typedef enum { - FX_OK = 0, - FX_ERROR = 1 -} FX_STATUS; -typedef enum { - FX_MODE_STATIC, - FX_MODE_WHITE_TO_COLOR, - FX_MODE_BLACK_TO_COLOR, - FX_MODE_BLINK, - FX_MODE_BLINK_RAINBOW, - FX_MODE_STROBE, - FX_MODE_STROBE_RAINBOW, - FX_MODE_BREATH, - FX_MODE_COLOR_WIPE, - FX_MODE_COLOR_WIPE_INV, - FX_MODE_COLOR_WIPE_REV, - FX_MODE_COLOR_WIPE_REV_INV, - FX_MODE_COLOR_WIPE_RANDOM, - FX_MODE_COLOR_SWEEP_RANDOM, - FX_MODE_RANDOM_COLOR, - FX_MODE_SINGLE_DYNAMIC, - FX_MODE_MULTI_DYNAMIC, - FX_MODE_RAINBOW, - FX_MODE_RAINBOW_CYCLE, - FX_MODE_FADE, - FX_MODE_SCAN, - FX_MODE_DUAL_SCAN, - FX_MODE_THEATER_CHASE, - FX_MODE_THEATER_CHASE_RAINBOW, - FX_MODE_RUNNING_LIGHTS, - FX_MODE_TWINKLE, - FX_MODE_TWINKLE_RANDOM, - FX_MODE_TWINKLE_FADE, - FX_MODE_TWINKLE_FADE_RANDOM, - FX_MODE_SPARKLE, - FX_MODE_FLASH_SPARKLE, - FX_MODE_HYPER_SPARKLE, - FX_MODE_MULTI_STROBE, - FX_MODE_CHASE_WHITE, - FX_MODE_CHASE_COLOR, - FX_MODE_CHASE_RANDOM, - FX_MODE_CHASE_RAINBOW, - FX_MODE_CHASE_FLASH, - FX_MODE_CHASE_FLASH_RANDOM, - FX_MODE_CHASE_RAINBOW_WHITE, - FX_MODE_CHASE_BLACKOUT, - FX_MODE_CHASE_BLACKOUT_RAINBOW, - FX_MODE_RUNNING_COLOR, - FX_MODE_RUNNING_RED_BLUE, - FX_MODE_RUNNING_RANDOM, - FX_MODE_LARSON_SCANNER, - FX_MODE_COMET, - FX_MODE_FIREWORKS, - FX_MODE_FIREWORKS_RANDOM, - FX_MODE_MERRY_CHRISTMAS, - FX_MODE_FIRE_FLICKER, - FX_MODE_FIRE_FLICKER_SOFT, - FX_MODE_FIRE_FLICKER_INTENSE, - FX_MODE_CIRCUS_COMBUSTUS, - FX_MODE_HALLOWEEN, - FX_MODE_BICOLOR_CHASE, - FX_MODE_TRICOLOR_CHASE, - FX_MODE_QUADCOLOR_CHASE, - FX_MODE_ICU -} fx_mode; - -/* Function Prototypes */ -FX_STATUS WS2812BFX_Init(uint16_t Segments); -FX_STATUS WS2812BFX_SegmentIncrease(void); -FX_STATUS WS2812BFX_SegmentDecrease(void); -uint8_t WS2812BFX_GetSegmentsQuantity(void); - -void WS2812BFX_SysTickCallback(void); -void WS2812BFX_Callback(void); - -FX_STATUS WS2812BFX_Start(uint16_t Segment); -FX_STATUS WS2812BFX_Stop(uint16_t Segment); -FX_STATUS WS2812BFX_IsRunning(uint16_t Segment, uint8_t *Running); - -FX_STATUS WS2812BFX_SetMode(uint16_t Segment, fx_mode Mode); -FX_STATUS WS2812BFX_GetMode(uint16_t Segment, fx_mode *Mode); -FX_STATUS WS2812BFX_NextMode(uint16_t Segment); -FX_STATUS WS2812BFX_PrevMode(uint16_t Segment); -FX_STATUS WS2812BFX_SetReverse(uint16_t Segment, uint8_t Reverse); -FX_STATUS WS2812BFX_GetReverse(uint16_t Segment, uint8_t *Reverse); - -FX_STATUS WS2812BFX_SetSegmentSize(uint16_t Segment, uint16_t Start, uint16_t Stop); -FX_STATUS WS2812BFX_GetSegmentSize(uint16_t Segment, uint16_t *Start, uint16_t *Stop); -FX_STATUS WS2812BFX_SegmentIncreaseEnd(uint16_t Segment); -FX_STATUS WS2812BFX_SegmentDecreaseEnd(uint16_t Segment); -FX_STATUS WS2812BFX_SegmentIncreaseStart(uint16_t Segment); -FX_STATUS WS2812BFX_SegmentDecreaseStart(uint16_t Segment); - -FX_STATUS WS2812BFX_SetSpeed(uint16_t Segment, uint16_t Speed); -FX_STATUS WS2812BFX_GetSpeed(uint16_t Segment, uint16_t *Speed); -FX_STATUS WS2812BFX_IncreaseSpeed(uint16_t Segment, uint16_t Speed); -FX_STATUS WS2812BFX_DecreaseSpeed(uint16_t Segment, uint16_t Speed); - -void WS2812BFX_SetColorStruct(uint8_t id, ws2812b_color c); -void WS2812BFX_SetColorRGB(uint8_t id, uint8_t r, uint8_t g, uint8_t b); -FX_STATUS WS2812BFX_GetColorRGB(uint8_t id, uint8_t *r, uint8_t *g, uint8_t *b); -void WS2812BFX_SetColorHSV(uint8_t id, uint16_t h, uint8_t s, uint8_t v); -void WS2812BFX_SetColor(uint8_t id, uint32_t c); - -FX_STATUS WS2812BFX_SetAll(uint16_t Segment, uint32_t c); -FX_STATUS WS2812BFX_SetAllRGB(uint16_t Segment, uint8_t r, uint8_t g, uint8_t b); - -void WS2812BFX_RGBtoHSV(uint8_t r, uint8_t g, uint8_t b, uint16_t *h, uint8_t *s, uint8_t *v); -void WS2812BFX_HSVtoRGB(uint16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b); - -#endif /* WS2812B_FX_H_ */ diff --git a/Inc/ws281x.h b/Inc/ws281x.h new file mode 100644 index 0000000..9a7b938 --- /dev/null +++ b/Inc/ws281x.h @@ -0,0 +1,47 @@ +/* + * ws281x.h + * + * The MIT License. + * Created on: 14.07.2017 + * Author: Mateusz Salamon + * www.msalamon.pl + * mateusz@msalamon.pl + */ + +#ifndef WS281X_H_ +#define WS281X_H_ + +/* Includes */ +#include +#include "main.h" + +/* Defintions */ + +/* Data Structures */ +typedef enum ws281x_type_e { + WS281X_TYPE_WS2811 = 0, + WS281X_TYPE_WS2812, + WS281X_TYPE_WS2812B, + WS281X_TYPE_SK6812, + WS281X_TYPE_SK6812RGBW, + WS281X_TYPE_WS2813B, + WS281X_TYPE_END +} ws281x_type_t; +typedef union __attribute__((packed, aligned(4))) ws281x_color_u { + struct __attribute__((packed, aligned(4))) rgbx_s { + uint8_t r; /* red */ + uint8_t g; /* green */ + uint8_t b; /* blue */ + uint8_t x; /* additional color channel - commonly white or warm white */ + } rgbx; + uint32_t u32; + uint8_t u8[4]; +} ws281x_color_t; +typedef struct ws281x_s ws281x_t; + +/* Function Prototypes */ +ws281x_t *ws281x_init(ws281x_type_t type, SPI_HandleTypeDef *hspi, ws281x_color_t *leds, int32_t num_leds); +void ws281x_refresh(ws281x_t *ws281x); +int32_t ws281x_set_led(ws281x_t *ws281x, uint16_t led_id, ws281x_color_t color); + +#endif /* WS281X_H_ */ diff --git a/Src/ws2812b.c b/Src/ws2812b.c deleted file mode 100644 index 748246e..0000000 --- a/Src/ws2812b.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * ws2812b.c - * - * The MIT License. - * Created on: 14.07.2017 - * Author: Mateusz Salamon - * www.msalamon.pl - * mateusz@msalamon.pl - */ - -/* Includes */ -#include "main.h" -#include "spi.h" -#include "dma.h" -#include "gpio.h" -#include "math.h" -#include "ws2812b.h" - -/* Definitions */ -#define ZERO (0b11000000) -#define ONE (0b11111000) -#define WORD_SIZE (32U) -#define BUFFER_SIZE (WORD_SIZE * 2) - -/* Macros */ -#define ws2812_return_if_fail(cond) if(!(cond)) { return; } -#define ws2812_return_val_if_fail(cond, val) if(!(cond)) { return (val); } -#define ws2812_return_null_if_fail(cond) ws2812_return_val_if_fail((cond), NULL) - -/* Private Constants */ -static const uint8_t sine_lut8[256] = { - 128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173, - 176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215, - 218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244, - 245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255, - 255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246, - 245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220, - 218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179, - 176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131, - 128,124,121,118,115,112,109,106,103,100, 97, 93, 90, 88, 85, 82, - 79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40, - 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11, - 10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, - 10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, - 37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76, - 79, 82, 85, 88, 90, 93, 97,100,103,106,109,112,115,118,121,124}; - -static const uint8_t gamma_lut8[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, - 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, - 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, - 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, - 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28, 29, 29, - 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 75, - 76, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, - 97, 99,100,102,103,105,106,108,109,111,112,114,115,117,119,120, - 122,124,125,127,129,130,132,134,136,137,139,141,143,145,146,148, - 150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180, - 182,184,186,188,191,193,195,197,199,202,204,206,209,211,213,215, - 218,220,223,225,227,230,232,235,237,240,242,245,247,250,252,255}; - -/* Public Global Variables */ -SPI_HandleTypeDef *hspi_ws2812b; -ws2812b_color ws2812b_array[WS2812B_LEDS]; - -/* Private Global Variables */ -static uint8_t buffer[BUFFER_SIZE]; -static uint16_t curr_led; -static uint8_t reset_sig; - -/* Function Definitions */ -void ws2812_init(SPI_HandleTypeDef *hspi) -{ - hspi_ws2812b = hspi; -} - -void ws2812_set_led_color_val(uint16_t diode_id, uint32_t color) -{ - ws2812_return_if_fail(diode_id < WS2812B_LEDS); - ws2812b_array[diode_id].u32 = color; -} - -void ws2812_set_led_color(uint16_t diode_id, ws2812b_color color) -{ - ws2812_return_if_fail(diode_id < WS2812B_LEDS); - ws2812b_array[diode_id] = color; -} - -void ws2812_set_led_rgb(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b) -{ - ws2812_return_if_fail(diode_id < WS2812B_LEDS); - ws2812b_array[diode_id].rgb.red = r; - ws2812b_array[diode_id].rgb.green = g; - ws2812b_array[diode_id].rgb.blue = b; -} - -void ws2812_set_led_rgbx(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b, uint8_t x) -{ - ws2812_return_if_fail(diode_id < WS2812B_LEDS); - ws2812b_array[diode_id].rgbx.red = r; - ws2812b_array[diode_id].rgbx.green = g; - ws2812b_array[diode_id].rgbx.blue = b; - ws2812b_array[diode_id].rgbx.x = x; -} - -/* - * Set diode with HSV model - * - * Hue 0-359 - * Saturation 0-255 - * Value 0-255 - */ -void ws2812_set_led_hsv(uint16_t diode_id, uint16_t hue, uint8_t sat, uint8_t value) -{ - uint16_t sector, fract, p, q, t; - - ws2812_return_if_fail(diode_id < WS2812B_LEDS); - - if(sat == 0) - { - ws2812b_array[diode_id].rgb.red = value; - ws2812b_array[diode_id].rgb.green = value; - ws2812b_array[diode_id].rgb.blue = value; - } - else - { - if(hue >= 360) hue = 359; - - sector = hue / 60; /* hexcone HSV model -- 6 sectors */ - fract = hue % 60; - p = (value * (255 - sat)) / 256; - q = (value * (255 - (sat * fract) / 60)) / 256; - t = (value * (255 - (sat * (59 - fract)) / 60)) / 256; - - - switch(sector) - { - case 0: - ws2812b_array[diode_id].rgb.red = value; - ws2812b_array[diode_id].rgb.green = (uint8_t)t; - ws2812b_array[diode_id].rgb.blue = (uint8_t)p; - break; - case 1: - ws2812b_array[diode_id].rgb.red = (uint8_t)q; - ws2812b_array[diode_id].rgb.green = value; - ws2812b_array[diode_id].rgb.blue = (uint8_t)p; - break; - case 2: - ws2812b_array[diode_id].rgb.red = (uint8_t)p; - ws2812b_array[diode_id].rgb.green = value; - ws2812b_array[diode_id].rgb.blue = (uint8_t)t; - break; - case 3: - ws2812b_array[diode_id].rgb.red = (uint8_t)p; - ws2812b_array[diode_id].rgb.green = (uint8_t)q; - ws2812b_array[diode_id].rgb.blue = value; - break; - case 4: - ws2812b_array[diode_id].rgb.red = (uint8_t)t; - ws2812b_array[diode_id].rgb.green = (uint8_t)p; - ws2812b_array[diode_id].rgb.blue = value; - break; - case 5: - default: - ws2812b_array[diode_id].rgb.red = value; - ws2812b_array[diode_id].rgb.green = (uint8_t)p; - ws2812b_array[diode_id].rgb.blue = (uint8_t)q; - break; - } - } -} - -uint32_t ws2812_get_color(uint16_t diode_id) -{ - ws2812_return_val_if_fail(diode_id < WS2812B_LEDS, 0); - - return ws2812b_array[diode_id].u32; -} - -uint8_t *ws2812_get_pixels() -{ - return (uint8_t*)ws2812b_array; -} - -void ws2812_refresh() -{ - curr_led = 0; - reset_sig = 0; - - for(uint8_t i = 0; i < BUFFER_SIZE; i++) - buffer[i] = 0x00; - HAL_SPI_Transmit_DMA(hspi_ws2812b, buffer, BUFFER_SIZE); - while(HAL_DMA_STATE_READY != HAL_DMA_GetState(hspi_ws2812b->hdmatx)); -} - -uint8_t sine8(uint8_t x) -{ - return sine_lut8[x]; -} - -uint8_t gamma8(uint8_t x) -{ - return gamma_lut8[x]; -} - -/* Private Function Definitions */ -void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi) -{ - if(hspi == hspi_ws2812b) - { - if(!reset_sig) - { - for(uint8_t k = 0; k < WORD_SIZE; k++) - { - buffer[k] = 0x00; - } - reset_sig = 1; /* End reset signal */ - } - else /* Odd LEDs 1, 3, 5, ... */ - { - if(curr_led > WS2812B_LEDS) - { - HAL_SPI_DMAStop(hspi_ws2812b); - } - else - { - uint8_t i = 0; - for(int8_t j = WORD_SIZE - 1; j >= 0; j--) - { - if((ws2812b_array[curr_led].u32 & (1 << j)) == 0) - buffer[i] = ZERO; - else - buffer[i] = ONE; - i++; - } - curr_led++; - } - } - } -} - -void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) -{ - if(hspi == hspi_ws2812b) - { - if(curr_led > WS2812B_LEDS) - { - HAL_SPI_DMAStop(hspi_ws2812b); - } - else - { - /* Even LEDs 0, 2, 4, ... */ - uint8_t i = WORD_SIZE; - for(int8_t j = WORD_SIZE - 1; j >= 0; j--) - { - if((ws2812b_array[curr_led].u32 & (1 << j)) == 0) - buffer[i] = ZERO; - else - buffer[i] = ONE; - i++; - } - curr_led++; - } - } - -} diff --git a/Src/ws2812b_fx.c b/Src/ws2812b_fx.c deleted file mode 100644 index d556fc8..0000000 --- a/Src/ws2812b_fx.c +++ /dev/null @@ -1,2042 +0,0 @@ -/* - * ws2812b_fx.c - * - * Library based on Harm Aldick's Arduino library - * https://github.com/kitesurfer1404/WS2812FX - * - * The MIT License. - * Created on: 20.10.2018 - * Author: Mateusz Salamon - * www.msalamon.pl - * mateusz@msalamon.pl - */ - -/* Includes */ -#include "main.h" -#include -#include "ws2812b.h" -#include "ws2812b_fx.h" - -/* Definitions */ -#define SEGMENT_LENGTH (Ws28b12b_Segments[mActualSegment].IdStop - Ws28b12b_Segments[mActualSegment].IdStart + 1) -#define IS_REVERSE (Ws28b12b_Segments[mActualSegment].Reverse) - -/* Macros */ -#define ws2812fx_return_if_fail(cond) if(!(cond)) { return; } -#define ws2812fx_return_val_if_fail(cond, val) if(!(cond)) { return (val); } -#define ws2812fx_return_null_if_fail(cond) ws2812_return_val_if_fail((cond), NULL) -/* MIN() and MAX() */ -#ifdef __GNUC__ -# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) -/* prevent double evaluation */ -# define MIN(a,b) \ - __extension__({ __auto_type _a = (a); \ - __auto_type _b = (b); \ - _a < _b ? _a : _b; }) -# define MAX(a,b) \ - __extension__({ __auto_type _a = (a); \ - __auto_type _b = (b); \ - _a > _b ? _a : _b; }) -# else -/* typesafety but double evaluation is possible */ -# define MIN(a,b) \ - __extension__({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a < _b ? _a : _b; }) -# define MAX(a,b) \ - __extension__({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _a : _b; }) -# endif -#else -/* no typesafety and double evaluation is possible */ -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -# define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif - -uint8_t mRunning; -uint8_t mTriggered; -uint8_t mActualSegment; - -uint16_t mSegments; - -uint32_t mColor[NUM_COLORS]; -ws2812b_color mColor_w[NUM_COLORS]; - -typedef struct ws2812bfx_s -{ - volatile uint32_t ModeDelay; /* Segment SW timer counter */ - - uint16_t IdStart; /* Start segment point */ - uint16_t IdStop; /* End segment point */ - - uint8_t Running : 1; /* Is sector running */ - uint8_t ActualMode; /* Sector mode setting */ - uint8_t Reverse : 1; /* Is reverted mode */ - uint32_t CounterModeCall; /* Numbers of calls */ - uint32_t CounterModeStep; /* Call step */ - - uint16_t Speed; /* Segment speed */ - - uint32_t ModeColor[NUM_COLORS]; /* Mode color 32 bit representation */ - ws2812b_color ModeColor_w[NUM_COLORS]; /* Mode color struct representation */ - - uint8_t AuxParam; /* Computing variable */ - uint16_t AuxParam16b; /* Computing variable */ - uint8_t Cycle : 1; /* Cycle variable */ - - void (*mModeCallback)(void); /* Sector mode callback */ -} ws2812bfx_s; - -ws2812bfx_s *Ws28b12b_Segments = NULL; - -void (*mModeCallback)(void); - - -/* - * - * MODES - * - */ -void -strip_off(void), -mode_static(void), -mode_white_to_color(void), -mode_black_to_color(void), -mode_blink(void), -mode_blink_rainbow(void), -mode_strobe(void), -mode_strobe_rainbow(void), -mode_breath(void), -mode_color_wipe(void), -mode_color_wipe_inv(void), -mode_color_wipe_rev(void), -mode_color_wipe_rev_inv(void), -mode_color_wipe_random(void), -mode_color_sweep_random(void), -mode_random_color(void), -mode_single_dynamic(void), -mode_multi_dynamic(void), -mode_rainbow(void), -mode_rainbow_cycle(void), -mode_fade(void), -mode_scan(void), -mode_dual_scan(void), -mode_theater_chase(void), -mode_theater_chase_rainbow(void), -mode_running_lights(void), -mode_twinkle(void), -mode_twinkle_random(void), -mode_twinkle_fade(void), -mode_twinkle_fade_random(void), -mode_sparkle(void), -mode_flash_sparkle(void), -mode_hyper_sparkle(void), -mode_multi_strobe(void), -mode_chase_white(void), -mode_chase_color(void), -mode_chase_random(void), -mode_chase_rainbow(void), -mode_chase_flash(void), -mode_chase_flash_random(void), -mode_chase_rainbow_white(void), -mode_chase_blackout(void), -mode_chase_blackout_rainbow(void), -mode_running_color(void), -mode_running_red_blue(void), -mode_running_random(void), -mode_larson_scanner(void), -mode_comet(void), -mode_fireworks(void), -mode_fireworks_random(void), -mode_merry_christmas(void), -mode_fire_flicker(void), -mode_fire_flicker_soft(void), -mode_fire_flicker_intense(void), -mode_circus_combustus(void), -mode_halloween(void), -mode_bicolor_chase(void), -mode_tricolor_chase(void), -mode_quadcolor_chase(void), -mode_icu(void) -; - -void (*mMode[MODE_COUNT])(void) = -{ - mode_static, - mode_white_to_color, - mode_black_to_color, - mode_blink, - mode_blink_rainbow, - mode_strobe, - mode_strobe_rainbow, - mode_breath, - mode_color_wipe, - mode_color_wipe_inv, - mode_color_wipe_rev, - mode_color_wipe_rev_inv, - mode_color_wipe_random, - mode_color_sweep_random, - mode_random_color, - mode_single_dynamic, - mode_multi_dynamic, - mode_rainbow, - mode_rainbow_cycle, - mode_fade, - mode_scan, - mode_dual_scan, - mode_theater_chase, - mode_theater_chase_rainbow, - mode_running_lights, - mode_twinkle, - mode_twinkle_random, - mode_twinkle_fade, - mode_twinkle_fade_random, - mode_sparkle, - mode_flash_sparkle, - mode_hyper_sparkle, - mode_multi_strobe, - mode_chase_white, - mode_chase_color, - mode_chase_random, - mode_chase_rainbow, - mode_chase_flash, - mode_chase_flash_random, - mode_chase_rainbow_white, - mode_chase_blackout, - mode_chase_blackout_rainbow, - mode_running_color, - mode_running_red_blue, - mode_running_random, - mode_larson_scanner, - mode_comet, - mode_fireworks, - mode_fireworks_random, - mode_merry_christmas, - mode_fire_flicker, - mode_fire_flicker_soft, - mode_fire_flicker_intense, - mode_circus_combustus, - mode_halloween, - mode_bicolor_chase, - mode_tricolor_chase, - mode_quadcolor_chase, - mode_icu -}; - -FX_STATUS WS2812BFX_Init(uint16_t Segments) -{ - uint16_t div = 0; - ws2812bfx_s *SegmentsTmp = NULL; - - ws2812fx_return_val_if_fail(Segments, FX_ERROR); - ws2812fx_return_val_if_fail(Segments < WS2812B_LEDS, FX_ERROR); - - SegmentsTmp = calloc(Segments, sizeof(ws2812bfx_s)); /* Assign the space for new segments */ - - ws2812fx_return_val_if_fail(SegmentsTmp, FX_ERROR); /* If assigning failed */ - - if(Ws28b12b_Segments == NULL) - { - mSegments = Segments; - - for(uint16_t i = 0; i < mSegments; i++) - { - SegmentsTmp[i].Speed = DEFAULT_SPEED; - SegmentsTmp[i].Running = DEFAULT_MODE; - - SegmentsTmp[i].IdStart = div; - div += ((WS2812B_LEDS + 1) / Segments) - 1; - SegmentsTmp[i].IdStop = div; - if(SegmentsTmp[i].IdStop >= WS2812B_LEDS) SegmentsTmp[i].IdStop = WS2812B_LEDS - 1; - div++; - } - } - else /* Ws28b12b_Segments was before initialized */ - { - for(uint16_t i = 0; i < (Segments>mSegments?mSegments:Segments); i++) - { - SegmentsTmp[i].ModeDelay = Ws28b12b_Segments[i].ModeDelay; - - SegmentsTmp[i].IdStart = div; - div += ((WS2812B_LEDS + 1) / Segments) - 1; - SegmentsTmp[i].IdStop = div; - if(SegmentsTmp[i].IdStop >= WS2812B_LEDS) Ws28b12b_Segments[i].IdStop = WS2812B_LEDS - 1; - div++; - - SegmentsTmp[i].Running = Ws28b12b_Segments[i].Running; - SegmentsTmp[i].ActualMode = Ws28b12b_Segments[i].ActualMode; - SegmentsTmp[i].Reverse = Ws28b12b_Segments[i].Reverse; - SegmentsTmp[i].CounterModeCall = Ws28b12b_Segments[i].CounterModeCall; - SegmentsTmp[i].CounterModeStep = Ws28b12b_Segments[i].CounterModeStep; - SegmentsTmp[i].Speed = Ws28b12b_Segments[i].Speed; - for(uint8_t j = 0; j < NUM_COLORS; j++) - { - SegmentsTmp[i].ModeColor[j] = Ws28b12b_Segments[i].ModeColor[j]; - SegmentsTmp[i].ModeColor_w[j] = Ws28b12b_Segments[i].ModeColor_w[j]; - } - SegmentsTmp[i].AuxParam = Ws28b12b_Segments[i].AuxParam; - SegmentsTmp[i].AuxParam16b = Ws28b12b_Segments[i].AuxParam16b; - SegmentsTmp[i].Cycle = Ws28b12b_Segments[i].Cycle; - SegmentsTmp[i].mModeCallback = Ws28b12b_Segments[i].mModeCallback; - } - - if(Segments > mSegments) /* Add new Segment */ - { - SegmentsTmp[Segments - 1].Speed = DEFAULT_SPEED; - SegmentsTmp[Segments - 1].ActualMode = DEFAULT_MODE; - SegmentsTmp[Segments - 1].Running = 0; /* any new segment is stopped by default */ - - SegmentsTmp[Segments - 1].IdStart = div; - div += ((WS2812B_LEDS + 1) / Segments) - 1; - SegmentsTmp[Segments - 1].IdStop = WS2812B_LEDS - 1; - } - - mSegments = Segments; - } - - free(Ws28b12b_Segments); /* Free previous array if reinit */ - Ws28b12b_Segments = SegmentsTmp; - return FX_OK; -} - -uint8_t WS2812BFX_GetSegmentsQuantity(void) -{ - return mSegments; -} - -FX_STATUS WS2812BFX_SegmentIncrease(void) -{ - if(mSegments < (WS2812B_LEDS - 1)) - { - WS2812BFX_Init(mSegments + 1); - return FX_OK; - } - return FX_ERROR; -} - -FX_STATUS WS2812BFX_SegmentDecrease(void) -{ - if(mSegments > 1) - { - WS2812BFX_Init(mSegments - 1); - return FX_OK; - } - return FX_ERROR; -} - -void WS2812BFX_SysTickCallback(void) -{ - for(uint16_t i = 0; i < mSegments; i++) - if(Ws28b12b_Segments[i].ModeDelay > 0) Ws28b12b_Segments[i].ModeDelay--; -} - -void WS2812BFX_Callback() - { - static uint8_t trig = 0;; - if(mRunning || mTriggered) - { - for(uint16_t i = 0; i < mSegments; i++) - { - if(Ws28b12b_Segments[i].ModeDelay == 0) - { - if(Ws28b12b_Segments[i].Running) - { - mActualSegment = i; - Ws28b12b_Segments[i].mModeCallback(); - Ws28b12b_Segments[i].CounterModeCall++; - trig = 1; - } - } - } - if(trig) - { - ws2812_refresh(); - trig = 0; - } - } -} - -FX_STATUS WS2812BFX_SetMode(uint16_t Segment, fx_mode Mode) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - Ws28b12b_Segments[Segment].CounterModeCall = 0; - Ws28b12b_Segments[Segment].CounterModeStep = 0; - Ws28b12b_Segments[Segment].ActualMode = Mode; - Ws28b12b_Segments[Segment].mModeCallback = mMode[Mode]; - for(uint8_t i = 0; i < NUM_COLORS; i++) - { - Ws28b12b_Segments[Segment].ModeColor[i] = mColor[i]; - Ws28b12b_Segments[Segment].ModeColor_w[i].u32 = mColor_w[i].u32; - } - return FX_OK; -} - -FX_STATUS WS2812BFX_GetMode(uint16_t Segment, fx_mode *Mode) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - *Mode = Ws28b12b_Segments[Segment].ActualMode; - return FX_OK; -} - -FX_STATUS WS2812BFX_NextMode(uint16_t Segment) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - Ws28b12b_Segments[Segment].CounterModeCall = 0; - Ws28b12b_Segments[Segment].CounterModeStep = 0; - Ws28b12b_Segments[Segment].ActualMode++; - if(Ws28b12b_Segments[Segment].ActualMode >= MODE_COUNT) Ws28b12b_Segments[mActualSegment].ActualMode = 0; - Ws28b12b_Segments[Segment].mModeCallback = mMode[Ws28b12b_Segments[mActualSegment].ActualMode]; - return FX_OK; -} - -FX_STATUS WS2812BFX_PrevMode(uint16_t Segment) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - Ws28b12b_Segments[Segment].CounterModeCall = 0; - Ws28b12b_Segments[Segment].CounterModeStep = 0; - Ws28b12b_Segments[Segment].ActualMode--; - if(Ws28b12b_Segments[Segment].ActualMode == 0) Ws28b12b_Segments[mActualSegment].ActualMode = MODE_COUNT; - Ws28b12b_Segments[Segment].mModeCallback = mMode[Ws28b12b_Segments[mActualSegment].ActualMode]; - return FX_OK; -} - -FX_STATUS WS2812BFX_SetReverse(uint16_t Segment, uint8_t Reverse) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - WS2812BFX_SetAll(Segment, BLACK); /* Set all 'old' segment black */ - - if(Reverse > 1) Reverse = 1; - - Ws28b12b_Segments[Segment].Reverse = Reverse; - return FX_OK; -} - -FX_STATUS WS2812BFX_GetReverse(uint16_t Segment, uint8_t *Reverse) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - *Reverse = Ws28b12b_Segments[Segment].Reverse; - return FX_OK; -} - -FX_STATUS WS2812BFX_SegmentIncreaseStart(uint16_t Segment) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - WS2812BFX_SetAll(Segment, BLACK); /* Set all 'old' segment black */ - - if((Ws28b12b_Segments[Segment].IdStop - Ws28b12b_Segments[Segment].IdStart) > 0) - { - Ws28b12b_Segments[Segment].IdStart++; - } - return FX_OK; -} - -FX_STATUS WS2812BFX_SegmentDecreaseStart(uint16_t Segment) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - WS2812BFX_SetAll(Segment, BLACK); /* Set all 'old' segment black */ - - if(Segment > 0) - { - if(Ws28b12b_Segments[Segment-1].IdStop < (Ws28b12b_Segments[Segment].IdStart - 1)) - { - Ws28b12b_Segments[Segment].IdStart--; - } - } - else /* Segment == 0 */ - { - if(0 < Ws28b12b_Segments[Segment].IdStart) - { - Ws28b12b_Segments[Segment].IdStart--; - } - } - return FX_OK; -} - -FX_STATUS WS2812BFX_SegmentIncreaseEnd(uint16_t Segment) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - WS2812BFX_SetAll(Segment, BLACK); /* Set all 'old' segment black */ - - if(Segment < (mSegments - 1)) - { - if(Ws28b12b_Segments[Segment].IdStop < (Ws28b12b_Segments[Segment+1].IdStart - 1)) - { - Ws28b12b_Segments[Segment].IdStop++; - } - - } - else /* last Segment */ - { - if(Ws28b12b_Segments[Segment].IdStop < (WS2812B_LEDS - 1)) - { - Ws28b12b_Segments[Segment].IdStop++; - - } - } - return FX_OK; -} - -FX_STATUS WS2812BFX_SegmentDecreaseEnd(uint16_t Segment) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - WS2812BFX_SetAll(Segment, BLACK); /* Set all 'old' segment black */ - - if((Ws28b12b_Segments[Segment].IdStop - Ws28b12b_Segments[Segment].IdStart) > 0) - { - Ws28b12b_Segments[Segment].IdStop--; - } - return FX_OK; -} - -FX_STATUS WS2812BFX_SetSegmentSize(uint16_t Segment, uint16_t Start, uint16_t Stop) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - if(Start >= (WS2812B_LEDS - 1)) return FX_ERROR; - if(Stop >= (WS2812B_LEDS - 1)) return FX_ERROR; - if(Start > Stop) return FX_ERROR; - - WS2812BFX_SetAll(Segment, BLACK); /* Set all 'old' segment black */ - - Ws28b12b_Segments[Segment].IdStart = Start; - Ws28b12b_Segments[Segment].IdStop = Stop; - return FX_OK; -} - -FX_STATUS WS2812BFX_GetSegmentSize(uint16_t Segment, uint16_t *Start, uint16_t *Stop) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - *Start = Ws28b12b_Segments[Segment].IdStart; - *Stop = Ws28b12b_Segments[Segment].IdStop; - return FX_OK; -} - -FX_STATUS WS2812BFX_Start(uint16_t Segment) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - Ws28b12b_Segments[Segment].CounterModeCall = 0; - Ws28b12b_Segments[Segment].CounterModeStep = 0; - Ws28b12b_Segments[Segment].ModeDelay = 0; - Ws28b12b_Segments[Segment].Running = 1; - mRunning = 1; - return FX_OK; -} - -uint8_t WS2812BFX_IsAnyRunning(void) -{ - for(uint8_t i = 0; i < mSegments; i++) - { - if(Ws28b12b_Segments[i].Running != 0) - return 1; - } - - return 0; -} - -FX_STATUS WS2812BFX_Stop(uint16_t Segment) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - Ws28b12b_Segments[Segment].Running = 0; - if(!WS2812BFX_IsAnyRunning()) - mRunning = 0; - return FX_OK; -} - -FX_STATUS WS2812BFX_IsRunning(uint16_t Segment, uint8_t *Running) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - *Running = Ws28b12b_Segments[Segment].Running; - return FX_OK; -} - -void WS2812BFX_SetColorStruct(uint8_t id, ws2812b_color c) -{ - mColor[id] = c.u32; - mColor_w[id].u32 = c.u32; -} - -void WS2812BFX_SetColorRGB(uint8_t id, uint8_t r, uint8_t g, uint8_t b) -{ - mColor_w[id].rgb.red = r; - mColor_w[id].rgb.green = g; - mColor_w[id].rgb.blue = b; - mColor[id] = mColor_w[id].u32; - -} - -FX_STATUS WS2812BFX_GetColorRGB(uint8_t id, uint8_t *r, uint8_t *g, uint8_t *b) -{ - if(id >= NUM_COLORS) return FX_ERROR; - *r = mColor_w[id].rgb.red; - *g = mColor_w[id].rgb.green; - *b = mColor_w[id].rgb.blue; - return FX_OK; -} - -void WS2812BFX_RGBtoHSV(uint8_t r, uint8_t g, uint8_t b, uint16_t *h, uint8_t *s, uint8_t *v) -{ - uint16_t min, max, delta; - int16_t h_tmp = *h; - - min = r < g ? r : g; - min = min < b ? min : b; - - max = r > g ? r : g; - max = max > b ? max : b; - - *v = max; /* v */ - delta = max - min; - if (delta < 1) - { - *s = 0; - *h = 0; /* undefined, maybe nan? */ - return; - } - if( max > 0 ) - { /* NOTE: if Max is == 0, this divide would cause a crash */ - *s = (((delta * 100) / max) * 255) / 100; /* s */ - } - else - { - /* - * if max is 0, then r = g = b = 0 - * s = 0, h is undefined - */ - *s = 0; - *h = 0; /* its now undefined */ - return; - } - - if( r == max ) - { - h_tmp = (( g - b )*100) / delta; /* between yellow & magenta *100 to avoid fracts */ - } - else - { - if( g == max ) - { - h_tmp = 720 + (( b - r )*100) / delta; /* between cyan & yellow */ - } - else - { - h_tmp = 1440 + (( r - g )*100) / delta; /* between magenta & cyan */ - } - } - h_tmp *= 60; /* Degrees */ - h_tmp /= 100; /* Back from fracts */ - - if( h_tmp < 0.0 ) - h_tmp += 360; - - *h = h_tmp; -} - -void WS2812BFX_HSVtoRGB(uint16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b) -{ - uint16_t Sector, Fracts, p, q, t; - - if(s == 0) - { - - *r = v; - *g = v; - *b = v; - } - else - { - if(h >= 360) h = 359; - - Sector = h / 60; /* hexcone HSV model -- 6 sectors */ - Fracts = h % 60; - p = (v * (255 - s)) / 256; - q = (v * (255 - (s * Fracts)/60)) / 256; - t = (v * (255 - (s * (59 - Fracts))/60)) / 256; - - - switch(Sector) - { - case 0: - *r = v; - *g = (uint8_t)t; - *b = (uint8_t)p; - break; - case 1: - *r = (uint8_t)q; - *g = v; - *b = (uint8_t)p; - break; - case 2: - *r = (uint8_t)p; - *g = v; - *b = (uint8_t)t; - break; - case 3: - *r = (uint8_t)p; - *g = (uint8_t)q; - *b = v; - break; - case 4: - *r = (uint8_t)t; - *g = (uint8_t)p; - *b = v; - break; - case 5: - default: - *r = v; - *g = (uint8_t)p; - *b = (uint8_t)q; - break; - } - } -} - -/* - * Set color with HSV model - * - * Hue 0-359 - * Saturation 0-255 - * Value 0-255 - */ -void WS2812BFX_SetColorHSV(uint8_t id, uint16_t h, uint8_t s, uint8_t v) -{ - WS2812BFX_HSVtoRGB(h, s, v, &mColor_w[id].rgb.red, &mColor_w[id].rgb.green, &mColor_w[id].rgb.blue); - mColor[id] = ((mColor_w[id].rgb.red<<16)|(mColor_w[id].rgb.green<<8)|mColor_w[id].rgb.blue); -} - -void WS2812BFX_SetColor(uint8_t id, uint32_t c) -{ - mColor[id] = c; - mColor_w[id].u32 = c; -} - -FX_STATUS WS2812BFX_SetAll(uint16_t Segment, uint32_t c) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - for(uint16_t i = 0; i < (Ws28b12b_Segments[Segment].IdStop - Ws28b12b_Segments[Segment].IdStart + 1); i++) - { - ws2812_set_led_color_val(Ws28b12b_Segments[Segment].IdStart + i, c); - } - return FX_OK; -} - -FX_STATUS WS2812BFX_SetAllRGB(uint16_t Segment, uint8_t r, uint8_t g, uint8_t b) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - for(uint16_t i = 0; i < SEGMENT_LENGTH; i++) - { - ws2812_set_led_rgb(Ws28b12b_Segments[Segment].IdStart + i, r, g, b); - } - return FX_OK; -} - -FX_STATUS WS2812BFX_SetSpeed(uint16_t Segment, uint16_t Speed) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - if(Speed < SPEED_MIN) Speed = SPEED_MIN; - if(Speed > SPEED_MAX) Speed = SPEED_MAX; - - Ws28b12b_Segments[Segment].Speed = Speed; - return FX_OK; -} - -FX_STATUS WS2812BFX_GetSpeed(uint16_t Segment, uint16_t *Speed) -{ - ws2812fx_return_val_if_fail(Segment < mSegments, FX_ERROR); - *Speed = Ws28b12b_Segments[Segment].Speed; - return FX_OK; -} - -FX_STATUS WS2812BFX_IncreaseSpeed(uint16_t Segment, uint16_t Speed) -{ - return WS2812BFX_SetSpeed(Segment, Ws28b12b_Segments[mActualSegment].Speed + Speed); -} - -FX_STATUS WS2812BFX_DecreaseSpeed(uint16_t Segment, uint16_t Speed) -{ - return WS2812BFX_SetSpeed(Segment, Ws28b12b_Segments[mActualSegment].Speed - Speed); -} - -/** - ** COLOR EFECTS FUNCTIONS - **/ - -/* - * Turns everything off. - */ -void strip_off() -{ - for(uint16_t i = 0; i < WS2812B_LEDS; i++) - { - ws2812_set_led_rgb(i, 0, 0, 0); - } - ws2812_refresh(); -} - -/* - * Put a value 0 to 255 in to get a color value. - * The colours are a transition r -> g -> b -> back to r - * Inspired by the Adafruit examples. - */ -uint32_t color_wheel(uint8_t pos) { - pos = 255 - pos; - if(pos < 85) { - return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3); - } else if(pos < 170) { - pos -= 85; - return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3); - } else { - pos -= 170; - return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0); - } -} - -/* - * Returns a new, random wheel index with a minimum distance of 42 from pos. - */ -uint8_t get_random_wheel_index(uint8_t pos) { - uint8_t r = 0; - uint8_t x = 0; - uint8_t y = 0; - uint8_t d = 0; - - while(d < 42) { - r = rand()%256; - x = abs(pos - r); - y = 255 - x; - d = MIN(x, y); - } - - return r; -} - -/* - * fade out function - */ -void fade_out() { - static const uint8_t rateMapH[] = {0, 1, 1, 1, 2, 3, 4, 6}; - static const uint8_t rateMapL[] = {0, 2, 3, 8, 8, 8, 8, 8}; - - uint8_t rate = FADE_RATE; - uint8_t rateH = rateMapH[rate]; - uint8_t rateL = rateMapL[rate]; - - uint32_t color = Ws28b12b_Segments[mActualSegment].ModeColor[1]; /* target color */ - - int r2 = (color >> 16) & 0xff; - int g2 = (color >> 8) & 0xff; - int b2 = color & 0xff; - - for(uint16_t i=Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) { - - color = ws2812_get_color(i); - if(rate == 0) { /* old fade-to-black algorithm */ - ws2812_set_led_color_val(i, (color >> 1) & 0x7F7F7F7F); - } else { /* new fade-to-color algorithm */ - int r1 = (color >> 16) & 0xff; - int g1 = (color >> 8) & 0xff; - int b1 = color & 0xff; - - /* calculate the color differences between the current and target colors */ - int rdelta = r2 - r1; - int gdelta = g2 - g1; - int bdelta = b2 - b1; - - /* - * If the current and target colors are almost the same, jump right to the target color, - * otherwise calculate an intermediate color. (fixes rounding issues) - */ - rdelta = abs(rdelta) < 3 ? rdelta : (rdelta >> rateH) + (rdelta >> rateL); - gdelta = abs(gdelta) < 3 ? gdelta : (gdelta >> rateH) + (gdelta >> rateL); - bdelta = abs(bdelta) < 3 ? bdelta : (bdelta >> rateH) + (bdelta >> rateL); - - ws2812_set_led_rgb(i, r1 + rdelta, g1 + gdelta, b1 + bdelta); - } - } -} - -/* - * color blend function - */ -uint32_t color_blend(uint32_t color1, uint32_t color2, uint8_t blend) -{ - if(blend == 0) return color1; - if(blend == 255) return color2; - - int w1 = (color1 >> 24) & 0xff; - int r1 = (color1 >> 16) & 0xff; - int g1 = (color1 >> 8) & 0xff; - int b1 = color1 & 0xff; - - int w2 = (color2 >> 24) & 0xff; - int r2 = (color2 >> 16) & 0xff; - int g2 = (color2 >> 8) & 0xff; - int b2 = color2 & 0xff; - - uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) / 256; - uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) / 256; - uint32_t g3 = ((g2 * blend) + (g1 * (255 - blend))) / 256; - uint32_t b3 = ((b2 * blend) + (b1 * (255 - blend))) / 256; - - return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3)); -} - -/* - * No blinking. Just plain old static light. - */ -void mode_static(void) -{ - - for(uint16_t i = Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) { - ws2812_set_led_color(i, Ws28b12b_Segments[mActualSegment].ModeColor_w[0]); - } - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - -/* from: 0 - black to color, 1 - white to color */ -void to_color(uint8_t from) -{ - /* HSV Saturatioin modifying */ - uint16_t h; - uint8_t s, v, r, g, b; - - WS2812BFX_RGBtoHSV(Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.red, Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.green, Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.blue, &h, &s, &v); - - if(from) - WS2812BFX_HSVtoRGB(h, s - Ws28b12b_Segments[mActualSegment].CounterModeStep, v, &r, &g, &b); - else - WS2812BFX_HSVtoRGB(h, s, v - Ws28b12b_Segments[mActualSegment].CounterModeStep, &r, &g, &b); - - WS2812BFX_SetAllRGB(mActualSegment, r, g, b); - - if(!Ws28b12b_Segments[mActualSegment].Cycle) - { - if(from) - { - if(Ws28b12b_Segments[mActualSegment].CounterModeStep < s) - Ws28b12b_Segments[mActualSegment].CounterModeStep++; - else - Ws28b12b_Segments[mActualSegment].Cycle = 1; - } - else - { - if(Ws28b12b_Segments[mActualSegment].CounterModeStep < v) - Ws28b12b_Segments[mActualSegment].CounterModeStep++; - else - Ws28b12b_Segments[mActualSegment].Cycle = 1; - } - } - else - { - if(Ws28b12b_Segments[mActualSegment].CounterModeStep > 0) - Ws28b12b_Segments[mActualSegment].CounterModeStep--; - else - Ws28b12b_Segments[mActualSegment].Cycle = 0; - } - - if(from) - { - Ws28b12b_Segments[mActualSegment].ModeDelay = (Ws28b12b_Segments[mActualSegment].Speed / s / 2); - } - else - { - Ws28b12b_Segments[mActualSegment].ModeDelay = (Ws28b12b_Segments[mActualSegment].Speed / v / 2); - } -} - - -void mode_white_to_color(void) -{ - to_color(1); -} - -void mode_black_to_color(void) -{ - to_color(0); -} - -/* Blink helper function */ -void blink(uint32_t color1, uint32_t color2, uint8_t strobe) -{ - uint32_t color = ((Ws28b12b_Segments[mActualSegment].CounterModeCall & 1) == 0) ? color1 : color2; - WS2812BFX_SetAll(mActualSegment, color); - if((Ws28b12b_Segments[mActualSegment].CounterModeCall & 1) == 0) - Ws28b12b_Segments[mActualSegment].ModeDelay = strobe ? 20 : Ws28b12b_Segments[mActualSegment].Speed / 2; - else - Ws28b12b_Segments[mActualSegment].ModeDelay = strobe? Ws28b12b_Segments[mActualSegment].Speed - 20 : (Ws28b12b_Segments[mActualSegment].Speed / 2); -} - -/* - * Normal blinking. 50% on/off time. - */ -void mode_blink(void) -{ - blink(Ws28b12b_Segments[mActualSegment].ModeColor[0], Ws28b12b_Segments[mActualSegment].ModeColor[1], 0); -} - -void mode_blink_rainbow(void) -{ - blink(color_wheel(Ws28b12b_Segments[mActualSegment].CounterModeCall & 0xFF), Ws28b12b_Segments[mActualSegment].ModeColor[1], 0); -} - -void mode_strobe(void) { - blink(Ws28b12b_Segments[mActualSegment].ModeColor[0], Ws28b12b_Segments[mActualSegment].ModeColor[1], 1); -} - -void mode_strobe_rainbow(void) -{ - blink(color_wheel(Ws28b12b_Segments[mActualSegment].CounterModeCall & 0xFF), Ws28b12b_Segments[mActualSegment].ModeColor[1], 1); -} - -/* - * Breathing effect - */ -void mode_breath(void) -{ - uint32_t lum = Ws28b12b_Segments[mActualSegment].CounterModeStep; - if(lum > 255) lum = 511 - lum; - - uint16_t delay; - if(lum == 15) delay = 970; /* 970 pause before each breath */ - else if(lum <= 25) delay = 38; /* 19 */ - else if(lum <= 50) delay = 36; /* 18 */ - else if(lum <= 75) delay = 28; /* 14 */ - else if(lum <= 100) delay = 20; /* 10 */ - else if(lum <= 125) delay = 14; /* 7 */ - else if(lum <= 150) delay = 11; /* 5 */ - else delay = 10; /* 4 */ - - uint8_t r = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.red * lum / 256; - uint8_t g = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.green * lum / 256; - uint8_t b = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.blue * lum / 256; - - WS2812BFX_SetAllRGB(mActualSegment, r, g, b); - Ws28b12b_Segments[mActualSegment].CounterModeStep += 2; - if(Ws28b12b_Segments[mActualSegment].CounterModeStep > (512-15)) Ws28b12b_Segments[mActualSegment].CounterModeStep = 15; - Ws28b12b_Segments[mActualSegment].ModeDelay = delay; -} - -/* - * Color wipe function - * LEDs are turned on (color1) in sequence, then turned off (color2) in sequence. - * if (bool rev == true) then LEDs are turned off in reverse order - */ -void color_wipe(uint32_t color1, uint32_t color2, uint8_t rev) -{ - if(Ws28b12b_Segments[mActualSegment].CounterModeStep < SEGMENT_LENGTH) - { - uint32_t led_offset = Ws28b12b_Segments[mActualSegment].CounterModeStep; - if(rev) - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - led_offset, color1); - } - else - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + led_offset, color1); - } - } - else - { - uint32_t led_offset = Ws28b12b_Segments[mActualSegment].CounterModeStep - SEGMENT_LENGTH; - if(rev) - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - led_offset, color2); - } - else - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + led_offset, color2); - } - - } - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % (SEGMENT_LENGTH * 2); - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - -/* - * Lights all LEDs one after another. - */ -void mode_color_wipe(void) -{ - color_wipe(Ws28b12b_Segments[mActualSegment].ModeColor[0], Ws28b12b_Segments[mActualSegment].ModeColor[1], 0); -} - -void mode_color_wipe_inv(void) -{ - color_wipe(Ws28b12b_Segments[mActualSegment].ModeColor[1], Ws28b12b_Segments[mActualSegment].ModeColor[0], 0); -} - -void mode_color_wipe_rev(void) -{ - color_wipe(Ws28b12b_Segments[mActualSegment].ModeColor[0], Ws28b12b_Segments[mActualSegment].ModeColor[1], 1); -} - -void mode_color_wipe_rev_inv(void) -{ - color_wipe(Ws28b12b_Segments[mActualSegment].ModeColor[1], Ws28b12b_Segments[mActualSegment].ModeColor[0], 1); -} - -void mode_color_wipe_random(void) -{ - if(Ws28b12b_Segments[mActualSegment].CounterModeStep % SEGMENT_LENGTH == 0) - { - Ws28b12b_Segments[mActualSegment].AuxParam = get_random_wheel_index(Ws28b12b_Segments[mActualSegment].AuxParam); - } - uint32_t color = color_wheel(Ws28b12b_Segments[mActualSegment].AuxParam); - - color_wipe(color, color, 0); - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - -/* - * Random color introduced alternating from start and end of strip. - */ -void mode_color_sweep_random(void) -{ - if(Ws28b12b_Segments[mActualSegment].CounterModeStep % SEGMENT_LENGTH == 0) - { /* aux_param will store our random color wheel index */ - Ws28b12b_Segments[mActualSegment].AuxParam = get_random_wheel_index(Ws28b12b_Segments[mActualSegment].AuxParam); - } - uint32_t color = color_wheel(Ws28b12b_Segments[mActualSegment].AuxParam); - color_wipe(color, color, 1); -} - -/* - * Lights all LEDs in one random color up. Then switches them - * to the next random color. - */ -void mode_random_color(void) -{ - Ws28b12b_Segments[mActualSegment].AuxParam = get_random_wheel_index(Ws28b12b_Segments[mActualSegment].AuxParam); /* aux_param will store our random color wheel index */ - WS2812BFX_SetAll(mActualSegment, color_wheel(Ws28b12b_Segments[mActualSegment].AuxParam)); - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - -/* - * Lights every LED in a random color. Changes one random LED after the other - * to another random color. - */ -void mode_single_dynamic(void) -{ - if(Ws28b12b_Segments[mActualSegment].CounterModeCall == 0) - { - for(uint16_t i = Ws28b12b_Segments[mActualSegment].IdStop; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) - { - ws2812_set_led_color_val(i, color_wheel(rand()%256)); - } - } - - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + rand() % SEGMENT_LENGTH, color_wheel(rand()%256)); - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Lights every LED in a random color. Changes all LED at the same time - * to new random colors. - */ -void mode_multi_dynamic(void) -{ - for(uint16_t i = Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) - { - ws2812_set_led_color_val(i, color_wheel(rand()%256)); - } - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - -/* - * Cycles all LEDs at once through a rainbow. - */ -void mode_rainbow(void) -{ - uint32_t color = color_wheel(Ws28b12b_Segments[mActualSegment].CounterModeStep); - for(uint16_t i = Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) - { - ws2812_set_led_color_val(i, color); - } - - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) & 0xFF; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Cycles a rainbow over the entire string of LEDs. - */ -void mode_rainbow_cycle(void) -{ - for(uint16_t i=0; i < SEGMENT_LENGTH; i++) - { - uint32_t color = color_wheel(((i * 256 / SEGMENT_LENGTH) + Ws28b12b_Segments[mActualSegment].CounterModeStep) & 0xFF); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + i, color); - } - - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) & 0xFF; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Fades the LEDs between two colors - */ -void mode_fade(void) { - int lum = Ws28b12b_Segments[mActualSegment].CounterModeStep; - if(lum > 255) lum = 511 - lum; /* lum = 0 -> 255 -> 0 */ - - uint32_t color = color_blend(Ws28b12b_Segments[mActualSegment].ModeColor[0], Ws28b12b_Segments[mActualSegment].ModeColor[1], lum); - - for(uint16_t i=Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) { - ws2812_set_led_color_val(i, color); - } - - Ws28b12b_Segments[mActualSegment].CounterModeStep += 4; - if(Ws28b12b_Segments[mActualSegment].CounterModeStep > 511) Ws28b12b_Segments[mActualSegment].CounterModeStep = 0; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Runs a single pixel back and forth. - */ -void mode_scan(void) { - if(Ws28b12b_Segments[mActualSegment].CounterModeStep > (SEGMENT_LENGTH * 2) - 3) { - Ws28b12b_Segments[mActualSegment].CounterModeStep = 0; - } - - for(uint16_t i = Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) { - ws2812_set_led_color_val(i, Ws28b12b_Segments[mActualSegment].ModeColor[1]); - } - - int led_offset = Ws28b12b_Segments[mActualSegment].CounterModeStep - (SEGMENT_LENGTH - 1); - led_offset = abs(led_offset); - - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - led_offset, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + led_offset, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } - - - Ws28b12b_Segments[mActualSegment].CounterModeStep++; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Runs two pixel back and forth in opposite directions. - */ -void mode_dual_scan(void) { - if(Ws28b12b_Segments[mActualSegment].CounterModeStep > (SEGMENT_LENGTH * 2) - 3) - { - Ws28b12b_Segments[mActualSegment].CounterModeStep = 0; - } - - for(uint16_t i=Ws28b12b_Segments[mActualSegment].IdStart; i > 16) & 0xFF); - uint8_t g = ((Ws28b12b_Segments[mActualSegment].ModeColor[0] >> 8) & 0xFF); - uint8_t b = (Ws28b12b_Segments[mActualSegment].ModeColor[0] & 0xFF); - - uint8_t sineIncr = MAX(1, (256 / WS2812B_LEDS)); - for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { - int lum = (int)sine8(((i + Ws28b12b_Segments[mActualSegment].CounterModeStep) * sineIncr)); - if(IS_REVERSE) { - ws2812_set_led_rgb(Ws28b12b_Segments[mActualSegment].IdStart + i, (r * lum) / 256, (g * lum) / 256, (b * lum) / 256); - } else { - ws2812_set_led_rgb(Ws28b12b_Segments[mActualSegment].IdStop - i, (r * lum) / 256, (g * lum) / 256, (b * lum) / 256); - } - } - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % 256; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * twinkle function - */ -void twinkle(uint32_t color1, uint32_t color2) -{ - if(Ws28b12b_Segments[mActualSegment].CounterModeStep == 0) - { - for(uint16_t i=Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) - { - ws2812_set_led_color_val(i, color2); - } - uint16_t min_leds = MAX(1, WS2812B_LEDS / 5); /* make sure, at least one LED is on */ - uint16_t max_leds = MAX(1, WS2812B_LEDS / 2); /* make sure, at least one LED is on */ - Ws28b12b_Segments[mActualSegment].CounterModeStep = rand() % (max_leds + 1 - min_leds) + min_leds; - } - - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + rand() % SEGMENT_LENGTH, color1); - - Ws28b12b_Segments[mActualSegment].CounterModeStep--; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - -/* - * Blink several LEDs on, reset, repeat. - * Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/ - */ -void mode_twinkle(void) -{ - return twinkle(Ws28b12b_Segments[mActualSegment].ModeColor[0], Ws28b12b_Segments[mActualSegment].ModeColor[1]); -} - -/* - * Blink several LEDs in random colors on, reset, repeat. - * Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/ - */ -void mode_twinkle_random(void) -{ - return twinkle(color_wheel(rand() % 256), Ws28b12b_Segments[mActualSegment].ModeColor[1]); -} - -/* - * twinkle_fade function - */ -void twinkle_fade(uint32_t color) -{ - fade_out(); - - if((rand() %3) == 0) - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + rand() % SEGMENT_LENGTH, color); - } - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Blink several LEDs on, fading out. - */ -void mode_twinkle_fade(void) -{ - twinkle_fade(Ws28b12b_Segments[mActualSegment].ModeColor[0]); -} - - -/* - * Blink several LEDs in random colors on, fading out. - */ -void mode_twinkle_fade_random(void) -{ - twinkle_fade(color_wheel(rand() % 256)); -} - -/* - * Blinks one LED at a time. - * Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/ - */ -void mode_sparkle(void) -{ - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + Ws28b12b_Segments[mActualSegment].AuxParam16b, Ws28b12b_Segments[mActualSegment].ModeColor[1]); - Ws28b12b_Segments[mActualSegment].AuxParam16b = rand() % SEGMENT_LENGTH; /* aux_param3 stores the random led index */ - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + Ws28b12b_Segments[mActualSegment].AuxParam16b, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Lights all LEDs in the color. Flashes single white pixels randomly. - * Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/ - */ -void mode_flash_sparkle(void) -{ - if(Ws28b12b_Segments[mActualSegment].CounterModeCall == 0) - { - for(uint16_t i=Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) - { - ws2812_set_led_color_val(i, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } - } - - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + Ws28b12b_Segments[mActualSegment].AuxParam16b, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - - if(rand() % 5 == 0) - { - Ws28b12b_Segments[mActualSegment].AuxParam16b = rand() % SEGMENT_LENGTH; /* aux_param3 stores the random led index */ - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + Ws28b12b_Segments[mActualSegment].AuxParam16b, WHITE); - Ws28b12b_Segments[mActualSegment].ModeDelay = 20; - } - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Like flash sparkle. With more flash. - * Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/ - */ -void mode_hyper_sparkle(void) -{ - for(uint16_t i=Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) - { - ws2812_set_led_color_val(i, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } - - if(rand() % 5 < 2) - { - for(uint16_t i=0; i < MAX(1, SEGMENT_LENGTH/3); i++) - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + rand() % SEGMENT_LENGTH, WHITE); - } - Ws28b12b_Segments[mActualSegment].ModeDelay = 20; - } - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - -/* - * Strobe effect with different strobe count and pause, controlled by speed. - */ -void mode_multi_strobe(void) -{ - for(uint16_t i=Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) - { - ws2812_set_led_color_val(i, BLACK); - } - - uint16_t delay = 200 + ((9 - (Ws28b12b_Segments[mActualSegment].Speed % 10)) * 100); - uint16_t count = 2 * ((Ws28b12b_Segments[mActualSegment].Speed / 100) + 1); - if(Ws28b12b_Segments[mActualSegment].CounterModeStep < count) - { - if((Ws28b12b_Segments[mActualSegment].CounterModeStep & 1) == 0) - { - for(uint16_t i=Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) - { - ws2812_set_led_color_val(i, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } - delay = 20; - } - else - { - delay = 50; - } - } - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % (count + 1); - Ws28b12b_Segments[mActualSegment].ModeDelay = delay; -} - -/* - * color chase function. - * color1 = background color - * color2 and color3 = colors of two adjacent leds - */ -void chase(uint32_t color1, uint32_t color2, uint32_t color3) -{ - uint16_t a = Ws28b12b_Segments[mActualSegment].CounterModeStep; - uint16_t b = (a + 1) % SEGMENT_LENGTH; - uint16_t c = (b + 1) % SEGMENT_LENGTH; - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - a, color1); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - b, color2); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - c, color3); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + a, color1); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + b, color2); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + c, color3); - } - - if(b == 0) Ws28b12b_Segments[mActualSegment].Cycle = 1; - else Ws28b12b_Segments[mActualSegment].Cycle = 0; - - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % WS2812B_LEDS; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Bicolor chase mode - */ -void mode_bicolor_chase(void) -{ - return chase(Ws28b12b_Segments[mActualSegment].ModeColor[0], Ws28b12b_Segments[mActualSegment].ModeColor[1], Ws28b12b_Segments[mActualSegment].ModeColor[2]); -} - - -/* - * White running on _color. - */ -void mode_chase_color(void) -{ - return chase(Ws28b12b_Segments[mActualSegment].ModeColor[0], WHITE, WHITE); -} - - -/* - * Black running on _color. - */ -void mode_chase_blackout(void) -{ - return chase(Ws28b12b_Segments[mActualSegment].ModeColor[0], BLACK, BLACK); -} - - -/* - * _color running on white. - */ -void mode_chase_white(void) -{ - return chase(WHITE, Ws28b12b_Segments[mActualSegment].ModeColor[0], Ws28b12b_Segments[mActualSegment].ModeColor[0]); -} - - -/* - * White running followed by random color. - */ -void mode_chase_random(void) -{ - if(Ws28b12b_Segments[mActualSegment].CounterModeStep == 0) - { - Ws28b12b_Segments[mActualSegment].AuxParam = get_random_wheel_index(Ws28b12b_Segments[mActualSegment].AuxParam); - } - return chase(color_wheel(Ws28b12b_Segments[mActualSegment].AuxParam), WHITE, WHITE); -} - - -/* - * Rainbow running on white. - */ -void mode_chase_rainbow_white(void) -{ - uint16_t n = Ws28b12b_Segments[mActualSegment].CounterModeStep; - uint16_t m = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % WS2812B_LEDS; - uint32_t color2 = color_wheel(((n * 256 / SEGMENT_LENGTH) + (Ws28b12b_Segments[mActualSegment].CounterModeCall & 0xFF)) & 0xFF); - uint32_t color3 = color_wheel(((m * 256 / SEGMENT_LENGTH) + (Ws28b12b_Segments[mActualSegment].CounterModeCall & 0xFF)) & 0xFF); - - return chase(WHITE, color2, color3); -} - - -/* - * White running on rainbow. - */ -void mode_chase_rainbow(void) -{ - uint8_t color_sep = 256 / SEGMENT_LENGTH; - uint8_t color_index = Ws28b12b_Segments[mActualSegment].CounterModeCall & 0xFF; - uint32_t color = color_wheel(((Ws28b12b_Segments[mActualSegment].CounterModeStep * color_sep) + color_index) & 0xFF); - - return chase(color, WHITE, WHITE); -} - - -/* - * Black running on rainbow. - */ -void mode_chase_blackout_rainbow(void) -{ - uint8_t color_sep = 256 / SEGMENT_LENGTH; - uint8_t color_index = Ws28b12b_Segments[mActualSegment].CounterModeCall & 0xFF; - uint32_t color = color_wheel(((Ws28b12b_Segments[mActualSegment].CounterModeStep * color_sep) + color_index) & 0xFF); - - return chase(color, 0, 0); -} - -/* - * White flashes running on _color. - */ -void mode_chase_flash(void) -{ - const static uint8_t flash_count = 4; - uint8_t flash_step = Ws28b12b_Segments[mActualSegment].CounterModeCall % ((flash_count * 2) + 1); - - for(uint16_t i=Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) - { - ws2812_set_led_color_val(i, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } - - uint16_t delay = Ws28b12b_Segments[mActualSegment].Speed; - if(flash_step < (flash_count * 2)) - { - if(flash_step % 2 == 0) - { - uint16_t n = Ws28b12b_Segments[mActualSegment].CounterModeStep; - uint16_t m = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % SEGMENT_LENGTH; - if(IS_REVERSE) - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - n, WHITE); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - m, WHITE); - } - else - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + n, WHITE); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + m, WHITE); - } - delay = 20; - } - else - { - delay = 30; - } - } - else - { - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % SEGMENT_LENGTH; - } - Ws28b12b_Segments[mActualSegment].ModeDelay = delay; -} - - -/* - * White flashes running, followed by random color. - */ -void mode_chase_flash_random(void) -{ - const static uint8_t flash_count = 4; - uint8_t flash_step = Ws28b12b_Segments[mActualSegment].CounterModeCall % ((flash_count * 2) + 1); - - for(uint16_t i=0; i < Ws28b12b_Segments[mActualSegment].CounterModeStep; i++) - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + i, color_wheel(Ws28b12b_Segments[mActualSegment].AuxParam)); - } - - uint16_t delay = Ws28b12b_Segments[mActualSegment].Speed; - if(flash_step < (flash_count * 2)) - { - uint16_t n = Ws28b12b_Segments[mActualSegment].CounterModeStep; - uint16_t m = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % SEGMENT_LENGTH; - if(flash_step % 2 == 0) - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + n, WHITE); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + m, WHITE); - delay = 20; - } - else - { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + n, color_wheel(Ws28b12b_Segments[mActualSegment].AuxParam)); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + m, BLACK); - delay = 30; - } - } - else - { - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % SEGMENT_LENGTH; - - if(Ws28b12b_Segments[mActualSegment].CounterModeStep == 0) - { - Ws28b12b_Segments[mActualSegment].AuxParam = get_random_wheel_index(Ws28b12b_Segments[mActualSegment].AuxParam); - } - } - Ws28b12b_Segments[mActualSegment].ModeDelay = delay; -} - - -/* - * Alternating pixels running function. - */ -void running(uint32_t color1, uint32_t color2) -{ - for(uint16_t i=0; i < SEGMENT_LENGTH; i++) - { - if((i + Ws28b12b_Segments[mActualSegment].CounterModeStep) % 4 < 2) - { - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + i, color1); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - i, color1); - } - } else { - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + i, color1); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - i, color2); - } - } - } - - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) & 0x3; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - -/* - * Alternating color/white pixels running. - */ -void mode_running_color(void) -{ - return running(Ws28b12b_Segments[mActualSegment].ModeColor[0], WHITE); -} - - -/* - * Alternating red/blue pixels running. - */ -void mode_running_red_blue(void) -{ - return running(RED, BLUE); -} - - -/* - * Alternating red/green pixels running. - */ -void mode_merry_christmas(void) -{ - return running(RED, GREEN); -} - -/* - * Alternating orange/purple pixels running. - */ -void mode_halloween(void) -{ - return running(PURPLE, ORANGE); -} - -/* - * Random colored pixels running. - */ -void mode_running_random(void) { - for(uint16_t i=SEGMENT_LENGTH-1; i > 0; i--) { - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - i, ws2812_get_color(Ws28b12b_Segments[mActualSegment].IdStop - i + 1)); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + i, ws2812_get_color(Ws28b12b_Segments[mActualSegment].IdStart + i - 1)); - } - } - - if(Ws28b12b_Segments[mActualSegment].CounterModeStep == 0) - { - Ws28b12b_Segments[mActualSegment].AuxParam = get_random_wheel_index(Ws28b12b_Segments[mActualSegment].AuxParam); - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop, color_wheel(Ws28b12b_Segments[mActualSegment].AuxParam)); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart, color_wheel(Ws28b12b_Segments[mActualSegment].AuxParam)); - } - } - - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep == 0) ? 1 : 0; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * K.I.T.T. - */ -void mode_larson_scanner(void) { - fade_out(); - - if(Ws28b12b_Segments[mActualSegment].CounterModeStep < SEGMENT_LENGTH) - { - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - Ws28b12b_Segments[mActualSegment].CounterModeStep, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + Ws28b12b_Segments[mActualSegment].CounterModeStep, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } - } - else - { - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - ((SEGMENT_LENGTH * 2) - Ws28b12b_Segments[mActualSegment].CounterModeStep) + 2, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + ((SEGMENT_LENGTH * 2) - Ws28b12b_Segments[mActualSegment].CounterModeStep) - 2, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } - } - - if(Ws28b12b_Segments[mActualSegment].CounterModeStep % SEGMENT_LENGTH == 0) Ws28b12b_Segments[mActualSegment].Cycle = 1; - else Ws28b12b_Segments[mActualSegment].Cycle = 1; - - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % ((SEGMENT_LENGTH * 2) - 2); - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Firing comets from one end. - */ -void mode_comet(void) { - fade_out(); - - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - Ws28b12b_Segments[mActualSegment].CounterModeStep, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + Ws28b12b_Segments[mActualSegment].CounterModeStep, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - } - - Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) % SEGMENT_LENGTH; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Fireworks function. - */ -void fireworks(uint32_t color) { - fade_out(); - - uint8_t *pixels = ws2812_get_pixels(); - uint8_t pixelsPerLed = 3; - uint16_t startPixel = Ws28b12b_Segments[mActualSegment].IdStart * pixelsPerLed + pixelsPerLed; - uint16_t stopPixel = Ws28b12b_Segments[mActualSegment].IdStop * pixelsPerLed ; - for(uint16_t i=startPixel; i > 2) + - pixels[i] + - (pixels[i + pixelsPerLed] >> 2); - pixels[i] = tmpPixel > 255 ? 255 : tmpPixel; - } - - if(!mTriggered) - { - for(uint16_t i=0; i> 16) & 0xFF; - uint8_t g = (Ws28b12b_Segments[mActualSegment].ModeColor[0] >> 8) & 0xFF; - uint8_t b = (Ws28b12b_Segments[mActualSegment].ModeColor[0] & 0xFF); - uint8_t lum = MAX(r, MAX(g, b)) / rev_intensity; - for(uint16_t i=Ws28b12b_Segments[mActualSegment].IdStart; i <= Ws28b12b_Segments[mActualSegment].IdStop; i++) - { - int flicker = rand()%lum; - ws2812_set_led_rgb(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0)); - } - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - -/* - * Random flickering. - */ -void mode_fire_flicker(void) -{ - return fire_flicker(3); -} - -/* -* Random flickering, less intensity. -*/ -void mode_fire_flicker_soft(void) -{ - return fire_flicker(6); -} - -/* -* Random flickering, more intensity. -*/ -void mode_fire_flicker_intense(void) -{ - return fire_flicker(1.7); -} - - -/* - * Tricolor chase function - */ -void tricolor_chase(uint32_t color1, uint32_t color2, uint32_t color3) -{ - uint16_t index = Ws28b12b_Segments[mActualSegment].CounterModeStep % 6; - for(uint16_t i=0; i < SEGMENT_LENGTH; i++, index++) - { - if(index > 5) index = 0; - - uint32_t color = color3; - if(index < 2) color = color1; - else if(index < 4) color = color2; - - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + i, color); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - i, color); - } - } - - Ws28b12b_Segments[mActualSegment].CounterModeStep++; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Tricolor chase mode - */ -void mode_tricolor_chase(void) -{ - return tricolor_chase(Ws28b12b_Segments[mActualSegment].ModeColor[0], Ws28b12b_Segments[mActualSegment].ModeColor[1], Ws28b12b_Segments[mActualSegment].ModeColor[2]); -} - - -/* - * Quadcolor chase function - */ -void quadcolor_chase(uint32_t color1, uint32_t color2, uint32_t color3, uint32_t color4) -{ - uint16_t index = Ws28b12b_Segments[mActualSegment].CounterModeStep % 8; - uint16_t i; - uint32_t color; - - for(i = 0; i < SEGMENT_LENGTH; i++, index++) - { - index %= 8; - - color = color1; - if(index < 2) color = color2; - else if(index < 4) color = color3; - else if(index < 6) color = color4; - - if(IS_REVERSE) { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + i, color); - } else { - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStop - i, color); - } - } - - Ws28b12b_Segments[mActualSegment].CounterModeStep++; - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} - - -/* - * Quadcolor chase mode - */ -void mode_quadcolor_chase(void) -{ - return quadcolor_chase(Ws28b12b_Segments[mActualSegment].ModeColor[0], - Ws28b12b_Segments[mActualSegment].ModeColor[1], - Ws28b12b_Segments[mActualSegment].ModeColor[2], - Ws28b12b_Segments[mActualSegment].ModeColor[3]); -} - - -/* - * Alternating white/red/black pixels running. - */ -void mode_circus_combustus(void) -{ - return tricolor_chase(RED, WHITE, BLACK); -} - -/* - * ICU mode - */ -void mode_icu(void) -{ - uint16_t dest = Ws28b12b_Segments[mActualSegment].CounterModeStep & 0xFFFF; - - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + dest, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + dest + WS2812B_LEDS/2, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - - if(Ws28b12b_Segments[mActualSegment].AuxParam16b == dest) - { /* pause between eye movements */ - if(rand()%6 == 0) - { /* blink once in a while */ - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + dest, BLACK); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + dest + SEGMENT_LENGTH/2, BLACK); - Ws28b12b_Segments[mActualSegment].ModeDelay = 200; - } - Ws28b12b_Segments[mActualSegment].AuxParam16b = rand() %(SEGMENT_LENGTH/2); - Ws28b12b_Segments[mActualSegment].ModeDelay = 1000 + rand() %2000; - } - - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + dest, BLACK); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + dest + SEGMENT_LENGTH/2, BLACK); - - if(Ws28b12b_Segments[mActualSegment].AuxParam16b > Ws28b12b_Segments[mActualSegment].CounterModeStep) - { - Ws28b12b_Segments[mActualSegment].CounterModeStep++; - dest++; - } else if (Ws28b12b_Segments[mActualSegment].AuxParam16b < Ws28b12b_Segments[mActualSegment].CounterModeStep) - { - Ws28b12b_Segments[mActualSegment].CounterModeStep--; - dest--; - } - - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + dest, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - ws2812_set_led_color_val(Ws28b12b_Segments[mActualSegment].IdStart + dest + SEGMENT_LENGTH/2, Ws28b12b_Segments[mActualSegment].ModeColor[0]); - - Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed; -} diff --git a/Src/ws281x.c b/Src/ws281x.c new file mode 100644 index 0000000..36ca011 --- /dev/null +++ b/Src/ws281x.c @@ -0,0 +1,213 @@ +/* + * ws281x.c + * + * The MIT License. + * Created on: 14.07.2017 + * Author: Mateusz Salamon + * www.msalamon.pl + * mateusz@msalamon.pl + */ + +/* Includes */ +#include + +/* Definitions */ +#define WS281X_MAX (16U) +#define ZERO (0b11000000) +#define ONE (0b11111000) + +/* Macros */ +#define ws281x_return_if_fail(cond) if(!(cond)) { return; } +#define ws281x_return_val_if_fail(cond, val) if(!(cond)) { return (val); } +#define ws281x_return_null_if_fail(cond) ws281x_return_val_if_fail((cond), NULL) + +/* Data Structures */ +struct ws281x_s { + ws281x_type_t type; + SPI_HandleTypeDef *hspi; + ws281x_color_t *leds; + int32_t num_leds; + int32_t curr_led; + uint8_t wordlen; + uint8_t buf[64]; /* enough to hold even/odd 32-bit words */ + uint8_t reset; +}; + +/* Private Constants */ + +/* Public Global Variables */ + +/* Private Global Variables */ +static ws281x_t ws281x[WS281X_MAX]; +static int32_t ws281x_count = 0; +static uint8_t wordlen[WS281X_TYPE_END] = { + 24, /* WS281X_TYPE_WS2811 */ + 24, /* WS281X_TYPE_WS2812*/ + 24, /* WS281X_TYPE_WS2812B */ + 24, /* WS281X_TYPE_SK6812 */ + 32, /* WS281X_TYPE_SK6812RGBW */ + 24 /* WS281X_TYPE_WS2813B */ +}; + +/* Function Prototypes */ +static ws281x_t *ws281x_lookup(SPI_HandleTypeDef *hspi); +static void ws281x_update_half(ws281x_t *ws281x, uint8_t even); + +/* Function Definitions */ +/** + * \brief Creates a new `ws281x_t` instance. + * + * This function initializes a new `ws281x_t` object which is controlled by + * a SPI peripheral and DMA. + * + * \param type The type of addressable LED(s). + * \param hspi Pointer to the SPI device handle. The `hspi` handle must be + * unique for each obect initialized. + * \param leds Pointer to an array of `ws281x_color_t` which holds all of the + * LED color information. + * \param num_leds The number of LEDs to control. + * + * \return Pointer to the created ws281x_t object, NULL on failure. + */ +ws281x_t *ws281x_init(ws281x_type_t type, SPI_HandleTypeDef *hspi, ws281x_color_t *leds, int32_t num_leds) +{ + ws281x_return_null_if_fail(ws281x_count < WS281X_MAX); + ws281x_return_null_if_fail(type < WS281X_TYPE_END); + ws281x_return_null_if_fail(hspi); + ws281x_return_null_if_fail(leds); + ws281x_return_null_if_fail(num_leds > 0); + ws281x_return_null_if_fail(ws281x_lookup(hspi) == NULL); + + ws281x[ws281x_count].hspi = hspi; + ws281x[ws281x_count].type = type; + ws281x[ws281x_count].leds = leds; + ws281x[ws281x_count].num_leds = num_leds; + ws281x[ws281x_count].curr_led = 0; + ws281x[ws281x_count].wordlen = wordlen[type]; + ws281x[ws281x_count].reset = 0; + + return &ws281x[ws281x_count++]; +} + +/** + * \brief Refreshes the LED(s). + * + * All of the LEDs in the string are sent the current color information. + * + * \param ws281x Pointer to a `ws281x_t` object. + */ +void ws281x_refresh(ws281x_t *ws281x) +{ + uint8_t i; + + ws281x_return_if_fail(ws281x); + + ws281x->curr_led = 0; + ws281x->reset = 1; + for(i = 0; i < ws281x->wordlen * 2; i++) + { + ws281x->buf[i] = 0x00; + } + HAL_SPI_Transmit_DMA(ws281x->hspi, ws281x->buf, ws281x->wordlen * 2); + while(HAL_DMA_GetState(ws281x->hspi->hdmatx) != HAL_DMA_STATE_READY); +} + +/** + * \brief Sets an LED color. + * + * This function sets the color of the LED at index `led_id`. + * + * \param ws281x Pointer to a `ws281x_t` object. + * \param led_id Index of the LED which is to have its color assigned. + * \param color A ws281x_color_t object which contains the color information + * to be assigned. + * + * \return `led_id` on success, -1 on failure. + */ +int32_t ws281x_set_led(ws281x_t *ws281x, uint16_t led_id, ws281x_color_t color) +{ + ws281x_return_val_if_fail(ws281x, -1); + ws281x_return_val_if_fail(led_id < ws281x->num_leds, -1); + + ws281x->leds[led_id] = color; + + return led_id; +} + +/* Private Function Definitions */ +static ws281x_t *ws281x_lookup(SPI_HandleTypeDef *hspi) +{ + int32_t i; + + ws281x_return_val_if_fail(hspi, NULL); + ws281x_return_val_if_fail(ws281x_count > 0, NULL); + + for(i = 0; i < ws281x_count; i++) + { + if(ws281x[i].hspi == hspi) + { + return &ws281x[i]; + } + } + + return NULL; +} + +static void ws281x_update_half(ws281x_t *ws281x, uint8_t even) +{ + uint8_t i = even ? ws281x->wordlen : 0; + int8_t j; + + if(ws281x->curr_led > ws281x->num_leds) + { + HAL_SPI_DMAStop(ws281x->hspi); + } + else + { + for(j = ws281x->wordlen - 1; j >= 0; j--) + { + if((ws281x->leds[ws281x->curr_led].u32 & (1 << j))) + { + ws281x->buf[i] = ONE; + } + else + { + ws281x->buf[i] = ZERO; + } + i++; + } + ws281x->curr_led++; + } +} + +/* HAL Callbacks */ +void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi) +{ + ws281x_t *ws281x = ws281x_lookup(hspi); + uint8_t i; + + ws281x_return_if_fail(ws281x); + + if(ws281x->reset) + { + for(i = 0; i < ws281x->wordlen; i++) + { + ws281x->buf[i] = 0x00; + } + ws281x->reset = 0; + } + else /* odd LEDs -- 1, 3, 5, ... */ + { + ws281x_update_half(ws281x, 0); + } +} + +void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) +{ + ws281x_t *ws281x = ws281x_lookup(hspi); + + ws281x_return_if_fail(ws281x); + + /* even LEDs -- 2, 4, 6, ... */ + ws281x_update_half(ws281x, 1); +}