You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1993 lines
57 KiB

/*
* 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
*/
#include "stm32f1xx_hal.h"
#include <stdlib.h>
#include "ws2812b.h"
#include "ws2812b_fx.h"
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)<(b))?(b):(a))
#define SEGMENT_LENGTH (Ws28b12b_Segments[mActualSegment].IdStop - Ws28b12b_Segments[mActualSegment].IdStart + 1)
#define IS_REVERSE Ws28b12b_Segments[mActualSegment].Reverse
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_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_icu
};
FX_STATUS WS2812BFX_Init(uint16_t Segments)
{
if(Segments == 0) return FX_ERROR;
if(Segments > (WS2812B_LEDS / 2))
{
if(Segments > WS2812B_LEDS)
{
return FX_ERROR;
}
}
uint16_t div = 0;
ws2812bfx_s *SegmentsTmp = NULL;
SegmentsTmp = calloc(Segments, sizeof(ws2812bfx_s)); // Assign the space for new segments
if(SegmentsTmp == NULL) return 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; // Sany 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)
{
WS2812B_Refresh();
trig = 0;
}
}
}
FX_STATUS WS2812BFX_SetMode(uint16_t Segment, fx_mode Mode)
{
if(Segment >= mSegments) return 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].red = mColor_w[i].red;
Ws28b12b_Segments[Segment].ModeColor_w[i].green = mColor_w[i].green;
Ws28b12b_Segments[Segment].ModeColor_w[i].blue = mColor_w[i].blue;
}
return FX_OK;
}
FX_STATUS WS2812BFX_GetMode(uint16_t Segment, fx_mode *Mode)
{
if(Segment >= mSegments) return FX_ERROR;
*Mode = Ws28b12b_Segments[Segment].ActualMode;
return FX_OK;
}
FX_STATUS WS2812BFX_NextMode(uint16_t Segment)
{
if(Segment >= mSegments) return 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)
{
if(Segment >= mSegments) return 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)
{
if(Segment >= mSegments) return 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)
{
if(Segment >= mSegments) return FX_ERROR;
*Reverse = Ws28b12b_Segments[Segment].Reverse;
return FX_OK;
}
FX_STATUS WS2812BFX_SegmentIncreaseStart(uint16_t Segment)
{
if(Segment >= mSegments) return 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)
{
if(Segment >= mSegments) return 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)
{
if(Segment >= mSegments) return 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)
{
if(Segment >= mSegments) return 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)
{
if(Segment >= mSegments) return 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)
{
if(Segment >= mSegments) return FX_ERROR;
*Start = Ws28b12b_Segments[Segment].IdStart;
*Stop = Ws28b12b_Segments[Segment].IdStop;
return FX_OK;
}
FX_STATUS WS2812BFX_Start(uint16_t Segment)
{
if(Segment >= mSegments) return 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)
{
if(Segment >= mSegments) return FX_ERROR;
Ws28b12b_Segments[Segment].Running = 0;
if(!WS2812BFX_IsAnyRunning())
mRunning = 0;
return FX_OK;
// strip_off();
}
FX_STATUS WS2812BFX_IsRunning(uint16_t Segment, uint8_t *Running)
{
if(Segment >= mSegments) return FX_ERROR;
*Running = Ws28b12b_Segments[Segment].Running;
return FX_OK;
}
void WS2812BFX_SetColorStruct(uint8_t id, ws2812b_color c)
{
mColor[id] = ((c.red<<16)|(c.green<<8)|c.blue);
mColor_w[id].red = c.red;
mColor_w[id].green = c.green;
mColor_w[id].blue = c.blue;
}
void WS2812BFX_SetColorRGB(uint8_t id, uint8_t r, uint8_t g, uint8_t b)
{
mColor[id] = ((r<<16)|(g<<8)|b);
mColor_w[id].red = r;
mColor_w[id].green = g;
mColor_w[id].blue = b;
}
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].red;
*g = mColor_w[id].green;
*b = mColor_w[id].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; // Sector 0 to 5
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;
default: // case 5:
*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].red, &mColor_w[id].green, &mColor_w[id].blue);
mColor[id] = ((mColor_w[id].red<<16)|(mColor_w[id].green<<8)|mColor_w[id]. blue);
}
void WS2812BFX_SetColor(uint8_t id, uint32_t c)
{
mColor[id] = c;
mColor_w[id].red = ((c>>16)&0x000000FF);
mColor_w[id].green = ((c>>8)&0x000000FF);
mColor_w[id].blue = (c&0x000000FF);
}
FX_STATUS WS2812BFX_SetAll(uint16_t Segment, uint32_t c)
{
if(Segment >= mSegments) return FX_ERROR;
for(uint16_t i = 0; i < (Ws28b12b_Segments[Segment].IdStop - Ws28b12b_Segments[Segment].IdStart + 1); i++)
{
WS2812B_SetDiodeRGB(Ws28b12b_Segments[Segment].IdStart + i, ((c>>16)&0xFF), ((c>>8)&0xFF), (c&0xFF));
}
return FX_OK;
}
FX_STATUS WS2812BFX_SetAllRGB(uint16_t Segment, uint8_t r, uint8_t g, uint8_t b)
{
if(Segment >= mSegments) return FX_ERROR;
for(uint16_t i = 0; i < SEGMENT_LENGTH; i++)
{
WS2812B_SetDiodeRGB(Ws28b12b_Segments[Segment].IdStart + i, r, g, b);
}
return FX_OK;
}
FX_STATUS WS2812BFX_SetSpeed(uint16_t Segment, uint16_t Speed)
{
if(Segment >= mSegments) return 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)
{
if(Segment >= mSegments) return 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++)
{
WS2812B_SetDiodeRGB(i, 0, 0, 0);
}
WS2812B_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 = WS2812B_GetColor(i);
if(rate == 0) { // old fade-to-black algorithm
WS2812B_SetDiodeColor(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);
WS2812B_SetDiodeRGB(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++) {
WS2812B_SetDiodeColorStruct(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 modifing
uint16_t h;
uint8_t s, v, r, g, b;
WS2812BFX_RGBtoHSV(Ws28b12b_Segments[mActualSegment].ModeColor_w[0].red, Ws28b12b_Segments[mActualSegment].ModeColor_w[0].green, Ws28b12b_Segments[mActualSegment].ModeColor_w[0].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].red * lum / 256;
uint8_t g = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].green * lum / 256;
uint8_t b = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].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)
{
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - led_offset, color1);
}
else
{
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + led_offset, color1);
}
}
else
{
uint32_t led_offset = Ws28b12b_Segments[mActualSegment].CounterModeStep - SEGMENT_LENGTH;
if(rev)
{
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - led_offset, color2);
}
else
{
WS2812B_SetDiodeColor(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++)
{
WS2812B_SetDiodeColor(i, color_wheel(rand()%256));
}
}
WS2812B_SetDiodeColor(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++)
{
WS2812B_SetDiodeColor(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++)
{
WS2812B_SetDiodeColor(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);
WS2812B_SetDiodeColor(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++) {
WS2812B_SetDiodeColor(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++) {
WS2812B_SetDiodeColor(i, Ws28b12b_Segments[mActualSegment].ModeColor[1]);
}
int led_offset = Ws28b12b_Segments[mActualSegment].CounterModeStep - (SEGMENT_LENGTH - 1);
led_offset = abs(led_offset);
if(IS_REVERSE) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - led_offset, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
} else {
WS2812B_SetDiodeColor(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 <Ws28b12b_Segments[mActualSegment].IdStop; i++)
{
WS2812B_SetDiodeColor(i, Ws28b12b_Segments[mActualSegment].ModeColor[1]);
}
int led_offset = Ws28b12b_Segments[mActualSegment].CounterModeStep - (SEGMENT_LENGTH - 1);
led_offset = abs(led_offset);
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + led_offset, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + SEGMENT_LENGTH - led_offset - 1, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
Ws28b12b_Segments[mActualSegment].CounterModeStep++;
Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed;
}
/*
* theater chase function
*/
void theater_chase(uint32_t color1, uint32_t color2)
{
Ws28b12b_Segments[mActualSegment].CounterModeCall = Ws28b12b_Segments[mActualSegment].CounterModeCall % 3;
for(uint16_t i=0; i < SEGMENT_LENGTH; i++) {
if((i % 3) == Ws28b12b_Segments[mActualSegment].CounterModeCall) {
if(IS_REVERSE) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - i, color1);
} else {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + i, color1);
}
} else {
if(IS_REVERSE) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - i, color2);
} else {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + i, color2);
}
}
}
Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed;
}
/*
* Theatre-style crawling lights.
* Inspired by the Adafruit examples.
*/
void mode_theater_chase(void)
{
return theater_chase(Ws28b12b_Segments[mActualSegment].ModeColor[0], Ws28b12b_Segments[mActualSegment].ModeColor[1]);
}
/*
* Theatre-style crawling lights with rainbow effect.
* Inspired by the Adafruit examples.
*/
void mode_theater_chase_rainbow(void)
{
Ws28b12b_Segments[mActualSegment].CounterModeStep = (Ws28b12b_Segments[mActualSegment].CounterModeStep + 1) & 0xFF;
theater_chase(color_wheel(Ws28b12b_Segments[mActualSegment].CounterModeStep), BLACK);
}
/*
* Running lights effect with smooth sine transition.
*/
void mode_running_lights(void) {
uint8_t r = ((Ws28b12b_Segments[mActualSegment].ModeColor[0] >> 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) {
WS2812B_SetDiodeRGB(Ws28b12b_Segments[mActualSegment].IdStart + i, (r * lum) / 256, (g * lum) / 256, (b * lum) / 256);
} else {
WS2812B_SetDiodeRGB(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++)
{
WS2812B_SetDiodeColor(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;
}
WS2812B_SetDiodeColor(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)
{
WS2812B_SetDiodeColor(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)
{
WS2812B_SetDiodeColor(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
WS2812B_SetDiodeColor(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++)
{
WS2812B_SetDiodeColor(i, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
}
}
WS2812B_SetDiodeColor(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
WS2812B_SetDiodeColor(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++)
{
WS2812B_SetDiodeColor(i, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
}
if(rand() % 5 < 2)
{
for(uint16_t i=0; i < MAX(1, SEGMENT_LENGTH/3); i++)
{
WS2812B_SetDiodeColor(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++)
{
WS2812B_SetDiodeColor(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++)
{
WS2812B_SetDiodeColor(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) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - a, color1);
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - b, color2);
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - c, color3);
} else {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + a, color1);
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + b, color2);
WS2812B_SetDiodeColor(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++)
{
WS2812B_SetDiodeColor(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)
{
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - n, WHITE);
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - m, WHITE);
}
else
{
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + n, WHITE);
WS2812B_SetDiodeColor(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++)
{
WS2812B_SetDiodeColor(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)
{
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + n, WHITE);
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + m, WHITE);
delay = 20;
}
else
{
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + n, color_wheel(Ws28b12b_Segments[mActualSegment].AuxParam));
WS2812B_SetDiodeColor(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) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + i, color1);
} else {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - i, color1);
}
} else {
if(IS_REVERSE) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + i, color1);
} else {
WS2812B_SetDiodeColor(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) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - i, WS2812B_GetColor(Ws28b12b_Segments[mActualSegment].IdStop - i + 1));
} else {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + i, WS2812B_GetColor(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) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop, color_wheel(Ws28b12b_Segments[mActualSegment].AuxParam));
} else {
WS2812B_SetDiodeColor(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) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - Ws28b12b_Segments[mActualSegment].CounterModeStep, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
} else {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + Ws28b12b_Segments[mActualSegment].CounterModeStep, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
}
}
else
{
if(IS_REVERSE) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - ((SEGMENT_LENGTH * 2) - Ws28b12b_Segments[mActualSegment].CounterModeStep) + 2, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
} else {
WS2812B_SetDiodeColor(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) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStop - Ws28b12b_Segments[mActualSegment].CounterModeStep, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
} else {
WS2812B_SetDiodeColor(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();
//// set brightness(i) = brightness(i-1)/4 + brightness(i) + brightness(i+1)/4
/*
// the old way, so many calls to the pokey getPixelColor() function made this super slow
for(uint16_t i=0 + 1; i <WS2812B_LEDS; i++) {
uint32_t prevLed = (Adafruit_NeoPixel::getPixelColor(i-1) >> 2) & 0x3F3F3F3F;
uint32_t thisLed = Adafruit_NeoPixel::getPixelColor(i);
uint32_t nextLed = (Adafruit_NeoPixel::getPixelColor(i+1) >> 2) & 0x3F3F3F3F;
WS2812B_SetDiodeColor(i, prevLed + thisLed + nextLed);
}
*/
// the new way, manipulate the Adafruit_NeoPixels pixels[] array directly, about 5x faster
uint8_t *pixels = WS2812B_GetPixels();
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 <stopPixel; i++)
{
uint16_t tmpPixel = (pixels[i - pixelsPerLed] >> 2) +
pixels[i] +
(pixels[i + pixelsPerLed] >> 2);
pixels[i] = tmpPixel > 255 ? 255 : tmpPixel;
}
if(!mTriggered)
{
for(uint16_t i=0; i<MAX(1, WS2812B_LEDS/20); i++)
{
if(rand()%10 == 0)
{
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + rand() % SEGMENT_LENGTH, color);
}
}
}
else
{
for(uint16_t i=0; i<MAX(1, SEGMENT_LENGTH/10); i++)
{
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + rand() % SEGMENT_LENGTH, color);
}
}
Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed;
}
/*
* Firework sparks.
*/
void mode_fireworks(void)
{
return fireworks(Ws28b12b_Segments[mActualSegment].ModeColor[0]);
}
/*
* Random colored firework sparks.
*/
void mode_fireworks_random(void)
{
return fireworks(color_wheel(rand()%256));
}
/*
* Fire flicker function
*/
void fire_flicker(int rev_intensity)
{
uint8_t r = (Ws28b12b_Segments[mActualSegment].ModeColor[0] >> 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;
WS2812B_SetDiodeRGB(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) {
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + i, color);
} else {
WS2812B_SetDiodeColor(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]);
}
/*
* 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;
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + dest, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
WS2812B_SetDiodeColor(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
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + dest, BLACK);
WS2812B_SetDiodeColor(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;
}
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + dest, BLACK);
WS2812B_SetDiodeColor(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--;
}
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + dest, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
WS2812B_SetDiodeColor(Ws28b12b_Segments[mActualSegment].IdStart + dest + SEGMENT_LENGTH/2, Ws28b12b_Segments[mActualSegment].ModeColor[0]);
Ws28b12b_Segments[mActualSegment].ModeDelay = Ws28b12b_Segments[mActualSegment].Speed;
}