#include <Adafruit_NeoPixel.h>
#define NUM_SEGMENTS 5
#define NUM_LEDS_PER_SEG 30
#define NUMPIXEL_TOTAL (NUM_SEGMENTS * NUM_LEDS_PER_SEG)
//
#define LED_PIN 5
Adafruit_NeoPixel Stick(NUMPIXEL_TOTAL, LED_PIN, NEO_RGB + NEO_KHZ800);
// Pattern types supported:
enum pattern
{
NONE,
RAINBOW_CYCLE,
SPLATOON3_CYCLE,
SPLATOON3_CYCLE_2,
SPLATOON2_CYCLE,
COLOR_WIPE,
SCANNER,
FADE,
DAMAGE
};
// Patern directions supported:
enum direction
{
FORWARD,
REVERSE
};
// NeoPattern Class - derived from the Adafruit_NeoPixel class
class NeoPatterns
{
private:
// Member Variables:
pattern ActivePattern; // which pattern is running
direction Direction; // direction to run the pattern
unsigned long Interval; // milliseconds between updates
unsigned long lastUpdate; // last update of position
uint32_t Color1, Color2; // What colors are in use
uint16_t TotalSteps; // total number of steps in the pattern
uint16_t _startPix;
uint16_t _numPix;
Adafruit_NeoPixel *_pStick;
uint16_t Index; // current step within the pattern
void (*OnComplete)(); // Callback on completion of pattern
public:
// Constructor - calls base-class constructor to initialize strip
NeoPatterns(uint16_t startPix, uint16_t numPix, Adafruit_NeoPixel *pStick, void (*callback)())
{
_startPix = startPix;
_numPix = numPix;
_pStick = pStick;
OnComplete = callback;
}
// Update the pattern
void Update()
{
if((millis() - lastUpdate) > Interval) // time to update
{
lastUpdate = millis();
switch(ActivePattern)
{
case RAINBOW_CYCLE:
RainbowCycleUpdate();
break;
case SPLATOON3_CYCLE:
Splatoon3CycleUpdate();
break;
case SPLATOON3_CYCLE_2:
Splatoon3Cycle_2Update();
break;
case SPLATOON2_CYCLE:
Splatoon2CycleUpdate();
break;
case COLOR_WIPE:
ColorWipeUpdate();
break;
case DAMAGE:
DamageUpdate();
break;
case SCANNER:
ScannerUpdate();
break;
case FADE:
FadeUpdate();
break;
default:
break;
}
}
}
// Increment the Index and reset at the end
void Increment()
{
if (Direction == FORWARD)
{
Index++;
if (Index >= TotalSteps)
{
Index = 0;
if (OnComplete != NULL)
{
OnComplete(); // call the comlpetion callback
}
}
}
else // Direction == REVERSE
{
--Index;
if (Index <= 0)
{
Index = TotalSteps-1;
if (OnComplete != NULL)
{
OnComplete(); // call the comlpetion callback
}
}
}
}
// Reverse pattern direction
void Reverse()
{
if (Direction == FORWARD)
{
Direction = REVERSE;
Index = TotalSteps-1;
}
else
{
Direction = FORWARD;
Index = 0;
}
}
void PrintParms( void )
{
Serial.println( _startPix );
Serial.println( _numPix );
}
// Initialize for a RainbowCycle
void RainbowCycle(uint8_t interval, direction dir = FORWARD)
{
ActivePattern = RAINBOW_CYCLE;
Interval = interval;
TotalSteps = 255;
Index = 0;
Direction = dir;
}
// Update the Rainbow Cycle Pattern
void RainbowCycleUpdate()
{
for(int i=0; i<_numPix; i++)
{
_pStick->setPixelColor(_startPix+i, Wheel(((i * 256 / _numPix) + Index) & 255));
}
_pStick->show();
Increment();
}
// Initialize for a Rainbow cycle with pink, white, purple, pink
void Splatoon3Cycle(uint8_t interval, direction dir = FORWARD)
{
ActivePattern = SPLATOON3_CYCLE;
Interval = interval;
TotalSteps = 255;
Index = 0;
Direction = dir;
}
// Update the Splatoon 3 Cycle Pattern
void Splatoon3CycleUpdate()
{
for(int i=0; i<_numPix; i++)
{
_pStick->setPixelColor(_startPix+i, Wheel_l3gS(((i * 256 / _numPix) + Index) & 255));
}
_pStick->show();
Increment();
}
// Initialize for a Rainbow cycle with pink, white, purple, pink
void Splatoon3Cycle_2(uint8_t interval, direction dir = FORWARD)
{
ActivePattern = SPLATOON3_CYCLE_2;
Interval = interval;
TotalSteps = 255;
Index = 0;
Direction = dir;
}
// Update the Splatoon 3 Cycle Pattern
void Splatoon3Cycle_2Update()
{
for(int i=0; i<_numPix; i++)
{
_pStick->setPixelColor(_startPix+i, Wheel_OG(((i * 256 / _numPix) + Index) & 255));
}
_pStick->show();
Increment();
}
// Initialize for a Rainbow cycle with pink, white, purple, pink
void Splatoon2Cycle(uint8_t interval, direction dir = FORWARD)
{
ActivePattern = SPLATOON2_CYCLE;
Interval = interval;
TotalSteps = 255;
Index = 0;
Direction = dir;
}
// Update the Splatoon 3 Cycle Pattern
void Splatoon2CycleUpdate()
{
for(int i=0; i<_numPix; i++)
{
_pStick->setPixelColor(_startPix+i, Wheel_V2(((i * 256 / _numPix) + Index) & 255));
}
_pStick->show();
Increment();
}
// Initialize for a ColorWipe
void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = COLOR_WIPE;
Interval = interval;
TotalSteps = _numPix;
Color1 = color;
Index = 0;
Direction = dir;
}
// Update the Color Wipe Pattern
void ColorWipeUpdate()
{
_pStick->setPixelColor(Index, Color1);
_pStick->show();
Increment();
}
void Damage(uint8_t interval, direction dir = REVERSE)
{
ActivePattern = DAMAGE;
Interval = interval;
TotalSteps = 255;
Index = 0;
Direction = dir;
}
// Update the Splatoon 3 Cycle Pattern
void DamageUpdate()
{
for(int i=0; i<_numPix; i++)
{
_pStick->setPixelColor(_startPix+i, Wheel_damage(((i * 256 / _numPix) + Index) & 255));
}
_pStick->show();
Increment();
}
// Initialize for a SCANNNER
void Scanner(uint32_t color1, uint8_t interval)
{
ActivePattern = SCANNER;
Interval = interval;
TotalSteps = (_numPix - 1) * 2;
Color1 = color1;
Index = 0;
}
// Update the Scanner Pattern
void ScannerUpdate()
{
for (int i =0; i<_numPix; i++)
{
if (i == Index) // Scan Pixel to the right
{
_pStick->setPixelColor(_startPix+i, Color1);
}
else if (i == TotalSteps - Index) // Scan Pixel to the left
{
_pStick->setPixelColor(_startPix+i, Color1);
}
else // Fading tail
{
_pStick->setPixelColor(_startPix+i, DimColor(_pStick->getPixelColor(_startPix+i)));
}
}
_pStick->show();
Increment();
}
// Initialize for a Fade
void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = FADE;
Interval = interval;
TotalSteps = steps;
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}
// Update the Fade Pattern
void FadeUpdate()
{
// Calculate linear interpolation between Color1 and Color2
// Optimise order of operations to minimize truncation error
uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;
ColorSet(_pStick->Color(red, green, blue));
_pStick->show();
Increment();
}
// Calculate 50% dimmed version of a color (used by ScannerUpdate)
uint32_t DimColor(uint32_t color)
{
// Shift R, G and B components one bit to the right
uint32_t dimColor = _pStick->Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
return dimColor;
}
// Set all pixels to a color (synchronously)
void ColorSet(uint32_t color)
{
for (int i =0; i<_numPix; i++)
{
_pStick->setPixelColor(_startPix+i, color);
}
_pStick->show();
}
// Returns the Red component of a 32-bit color
uint8_t Red(uint32_t color)
{
return (color >> 16) & 0xFF;
}
// Returns the Green component of a 32-bit color
uint8_t Green(uint32_t color)
{
return (color >> 8) & 0xFF;
}
// Returns the Blue component of a 32-bit color
uint8_t Blue(uint32_t color)
{
return color & 0xFF;
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos)
{
WheelPos = 255 - WheelPos;
if(WheelPos < 85)
{
return _pStick->Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else if(WheelPos < 170)
{
WheelPos -= 85;
return _pStick->Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
else
{
WheelPos -= 170;
return _pStick->Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
uint32_t Wheel_damage(byte WheelPos)
{
WheelPos = 255 - WheelPos;
if(WheelPos < 85)
{
return _pStick->Color(255, 0, 0);
}
else
{
WheelPos -= 170;
return _pStick->Color(0, 0, 0);
}
}
uint32_t Wheel_l3gS(byte WheelPos)
{
WheelPos = 120 - WheelPos;
if(WheelPos < 20)
{
return _pStick->Color(150 ,40 , 130);
}
else if(WheelPos < 40)
{
WheelPos -= 20;
return _pStick->Color(200 ,200 , 200);
}
else if(WheelPos < 60)
{
WheelPos -= 40;
return _pStick->Color(255 , 80 , 220);
}
else if(WheelPos < 80)
{
WheelPos -= 60;
return _pStick->Color(150 ,40 , 130);
}
else
{
WheelPos -= 80;
return _pStick->Color(0, 0, 0);
}
}
uint32_t Wheel_OG(byte WheelPos)
{
WheelPos = 120 - WheelPos;
if(WheelPos < 20)
{
return _pStick->Color(110 ,255 , 0);
}
else if(WheelPos < 40)
{
WheelPos -= 20;
return _pStick->Color(250 ,255 , 0);
}
else if(WheelPos < 60)
{
WheelPos -= 40;
return _pStick->Color(200 , 200 , 200);
}
else if(WheelPos < 80)
{
WheelPos -= 60;
return _pStick->Color(110 ,255 , 0);
}
else
{
WheelPos -= 80;
return _pStick->Color(0, 0, 0);
}
}
uint32_t Wheel_V2(byte WheelPos)
{
if(WheelPos < 51)
{
return _pStick->Color(255 - WheelPos, 255 - WheelPos, 0);
}
else if(WheelPos < 102)
{
WheelPos -= 51;
return _pStick->Color(0, 0, 0);
}
else if(WheelPos < 153)
{
WheelPos -= 102;
return _pStick->Color(255 - WheelPos, 255 - WheelPos, 0);
}
else if(WheelPos < 204)
{
WheelPos -= 153;
return _pStick->Color(0, 0, 0);
}
else
{
WheelPos -= 204;
return _pStick->Color(255 - WheelPos, 255 - WheelPos, 0);
}
}
};//class NeoPatterns
void StickComplete();
// Define some NeoPatterns for the two rings and the stick
// as well as some completion routines
NeoPatterns Seg1(0, 30, (Adafruit_NeoPixel *)&Stick, NULL );
NeoPatterns Seg2(30, 30, (Adafruit_NeoPixel *)&Stick, NULL );
NeoPatterns Seg3(60, 30, (Adafruit_NeoPixel *)&Stick, NULL );
NeoPatterns Seg4(90, 30, (Adafruit_NeoPixel *)&Stick, NULL );
NeoPatterns Seg5(120, 30, (Adafruit_NeoPixel *)&Stick, NULL );
int mode = 6; //currently-active animation mode on switch 1, 0-6
int const speed = 12;
// Initialize everything and prepare to start
void setup()
{
Serial.begin(115200);
// Initialize all the pixelStrips
Stick.begin();
Seg1.RainbowCycle(speed);
Seg2.Splatoon3Cycle(speed);
Seg3.Splatoon3Cycle_2(speed);
Seg4.Fade(0x00000000, 0x00ffffff, 50, speed);
Seg5.Scanner( 0x00ff00ff, speed);
}//setup
// Main loop
void loop()
{
Seg1.Update();
Seg2.Update();
Seg3.Update();
Seg4.Update();
Seg5.Update();
}//loop