From 69ff076b0ee8471e648e34fc6f6742363c602655 Mon Sep 17 00:00:00 2001 From: Daniel Peter Chokola Date: Thu, 28 Dec 2023 12:53:13 -0500 Subject: [PATCH] rewrite to provide generic interface to ws281x addressable LEDS supports WS2811, WS2812, WS2813, SK6812, and SK6812RGBW families does not yet map colors correctly (e.g. WS2812 orders colors 'GRB' whereas others use RGB) removed ws2812b_fx code --- Inc/ws2812b.h | 51 -- Inc/ws2812b_fx.h | 153 ---- Inc/ws281x.h | 47 ++ Src/ws2812b.c | 271 ------ Src/ws2812b_fx.c | 2042 ---------------------------------------------- Src/ws281x.c | 213 +++++ 6 files changed, 260 insertions(+), 2517 deletions(-) delete mode 100644 Inc/ws2812b.h delete mode 100644 Inc/ws2812b_fx.h create mode 100644 Inc/ws281x.h delete mode 100644 Src/ws2812b.c delete mode 100644 Src/ws2812b_fx.c create mode 100644 Src/ws281x.c 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); +}