#include <Adafruit_NeoPixel.h>
enum { PIN = A3, NUMPIXELS = 144, FULLY_SATURATED = 255 };
typedef struct RgbColor
{
unsigned char r;
unsigned char g;
unsigned char b;
} RgbColor;
typedef struct HsvColor
{
unsigned char h;
unsigned char s;
unsigned char v;
HsvColor( void ) { h = s = v = 0; }
HsvColor( int a, int b, int c )
{
h = a;
s = b;
v = c;
}
} HsvColor;
RgbColor HsvToRgb( HsvColor hsv )
{
RgbColor rgb;
unsigned char region, p, q, t;
unsigned int h, s, v, remainder;
if( hsv.s == 0 )
{
rgb.r = hsv.v;
rgb.g = hsv.v;
rgb.b = hsv.v;
return rgb;
}
// converting to 16 bit to prevent overflow
h = hsv.h;
s = hsv.s;
v = hsv.v;
region = h / 43;
remainder = (h - (region * 43)) * 6;
p = (v * (255 - s)) >> 8;
q = (v * (255 - ((s * remainder) >> 8))) >> 8;
t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
switch (region)
{
case 0:
rgb.r = v;
rgb.g = t;
rgb.b = p;
break;
case 1:
rgb.r = q;
rgb.g = v;
rgb.b = p;
break;
case 2:
rgb.r = p;
rgb.g = v;
rgb.b = t;
break;
case 3:
rgb.r = p;
rgb.g = q;
rgb.b = v;
break;
case 4:
rgb.r = t;
rgb.g = p;
rgb.b = v;
break;
default:
rgb.r = v;
rgb.g = p;
rgb.b = q;
break;
}
return rgb;
}
HsvColor RgbToHsv( RgbColor rgb )
{
HsvColor hsv;
unsigned char rgbMin, rgbMax;
rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
hsv.v = rgbMax;
if( hsv.v == 0 )
{
hsv.h = 0;
hsv.s = 0;
return hsv;
}
hsv.s = 255 * ((long)(rgbMax - rgbMin)) / hsv.v;
if( hsv.s == 0 )
{
hsv.h = 0;
return hsv;
}
if( rgbMax == rgb.r )
hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin);
else if( rgbMax == rgb.g )
hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
else
hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);
return hsv;
}
Adafruit_NeoPixel pixels = Adafruit_NeoPixel( NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800 );
void
setup( void )
{
pixels.begin();
}
unsigned char hue = 0;
int train_length = 10;
int train_position = 0;
void
train( void )
{
for( int i = 0; i < NUMPIXELS; i++ )
{
int bright = 0;
if( i > train_position && i < train_position + train_length )
bright = 255;
int low = (train_position + train_length) - NUMPIXELS;
if( i < low )
bright = 255;
HsvColor hsv( hue, FULLY_SATURATED, bright );
RgbColor rgb = HsvToRgb( hsv );
pixels.setPixelColor( i, pixels.Color( rgb.r, rgb.g, rgb.b ) );
}
pixels.show();
hue++;
train_position++;
train_position %= (NUMPIXELS + train_length);
}
void
collide( void )
{
int reverse = NUMPIXELS + train_length/2 - train_position;
for( int i = 0; i < NUMPIXELS; i++ )
{
int bright = 0;
if( i > train_position && i < train_position + train_length/2 )
bright = 255;
int low = (train_position + train_length/2) - NUMPIXELS;
if( i < low )
bright = 255;
if( i < reverse && i > reverse - train_length/2 )
bright = 255;
int high = reverse - NUMPIXELS;
if( i < high )
bright = 255;
HsvColor hsv( hue, FULLY_SATURATED, bright );
RgbColor rgb = HsvToRgb( hsv );
pixels.setPixelColor( i, pixels.Color( rgb.r, rgb.g, rgb.b ) );
}
pixels.show();
hue++;
train_position++;
train_position %= (NUMPIXELS + train_length);
}
void
chaser( void )
{
for( int i = 0; i < NUMPIXELS; i++ )
{
int bright = 0;
if( (i + train_position) % 20 == 0 )
bright = 255;
HsvColor hsv( hue, FULLY_SATURATED, bright );
RgbColor rgb = HsvToRgb( hsv );
pixels.setPixelColor( i, pixels.Color( rgb.r, rgb.g, rgb.b ) );
hue += 7;
}
pixels.show();
train_position++;
train_position %= NUMPIXELS;
}
unsigned char stars[5];
void
sparkle( void )
{
for( unsigned x = 0; x < sizeof stars; x++ )
stars[x] = random( NUMPIXELS );
for( int i = 0; i < NUMPIXELS; i++ )
{
int bright = 0;
for( unsigned x = 0; x < sizeof stars; x++ )
if( stars[x] == i )
bright = 255;
hue = random( 255 );
HsvColor hsv( hue, FULLY_SATURATED, bright );
RgbColor rgb = HsvToRgb( hsv );
pixels.setPixelColor( i, pixels.Color( rgb.r, rgb.g, rgb.b ) );
}
pixels.show();
}
enum
{
CHASER,
TRAIN,
COLLIDE,
SPARKLE,
SLOWTRAIN,
SLOWCHASER,
SLOWCOLLIDE,
SLOWSPARKLE,
THE_END
};
unsigned count = 0, mode = CHASER;
void
loop( void )
{
if( mode == CHASER )
chaser();
else if( mode == TRAIN )
train();
else if( mode == SPARKLE )
sparkle();
else if( mode == COLLIDE )
collide();
else if( mode == SLOWCHASER )
{
chaser();
count += 9;
delay( 50 );
}
else if( mode == SLOWTRAIN )
{
train();
count += 9;
delay( 50 );
}
else if( mode == SLOWSPARKLE )
{
sparkle();
count += 9;
delay( 50 );
}
else if( mode == SLOWCOLLIDE )
{
collide();
count += 9;
delay( 50 );
}
if( count++ > 1000 )
{
mode = random( THE_END );
count = 0;
}
}