2017-02-16 23:40:42 +00:00
# include "NeoPatterns.h"
2018-10-23 19:02:55 +00:00
NeoPatterns : : NeoPatterns ( uint16_t pixels , uint8_t pin , uint8_t type , void ( * callback ) ( ) , void ( * callbackDebug ) ( String ) ) :
Adafruit_NeoPixel ( pixels , pin , type )
2017-02-16 23:40:42 +00:00
{
2018-10-23 19:02:55 +00:00
OnComplete = callback ;
OnDebugOutput = callbackDebug ;
//Allocate a zero initialized block of memory big enough to hold "pixels" uint8_t.
pixelR = ( uint8_t * ) calloc ( pixels , sizeof ( uint8_t ) ) ;
pixelG = ( uint8_t * ) calloc ( pixels , sizeof ( uint8_t ) ) ;
pixelB = ( uint8_t * ) calloc ( pixels , sizeof ( uint8_t ) ) ;
pixelR_buffer = ( uint8_t * ) calloc ( pixels , sizeof ( uint8_t ) ) ;
pixelG_buffer = ( uint8_t * ) calloc ( pixels , sizeof ( uint8_t ) ) ;
pixelB_buffer = ( uint8_t * ) calloc ( pixels , sizeof ( uint8_t ) ) ;
// Max. MAX_DROPS Drops: Location
drop = ( uint8_t * ) calloc ( MAX_DROPS , sizeof ( uint8_t ) ) ;
// Max. MAX_DROPS Drops: Brightness (Default to 0)
dropBrightness = ( uint8_t * ) calloc ( MAX_DROPS , sizeof ( uint8_t ) ) ;
// Max. MAX_RINGS Rings: Location
ring = ( uint8_t * ) calloc ( MAX_RINGS , sizeof ( uint8_t ) ) ;
// Max. MAX_RINGS Rings: Brightness (Default to 0)
ringBrightness = ( uint8_t * ) calloc ( MAX_RINGS , sizeof ( uint8_t ) ) ;
ringDistance = ( uint8_t * ) calloc ( MAX_RINGS , sizeof ( uint8_t ) ) ;
2017-02-16 23:40:42 +00:00
}
2018-10-23 19:02:55 +00:00
void NeoPatterns : : Update ( ) {
if ( ( millis ( ) - lastUpdate ) > Interval ) // time to update
{
// OnDebugOutput(String("Updating at " ) + String(millis()));
lastUpdate = millis ( ) ;
switch ( ActivePattern )
{
case RAINBOW_CYCLE :
RainbowCycleUpdate ( ) ;
break ;
case THEATER_CHASE :
TheaterChaseUpdate ( ) ;
break ;
case BVB :
BVBChaseUpdate ( ) ;
break ;
case COLOR_WIPE :
ColorWipeUpdate ( ) ;
break ;
case SCANNER :
ScannerUpdate ( ) ;
break ;
case FADE :
FadeUpdate ( ) ;
break ;
case RANDOM_FADE :
RandomFadeUpdate ( ) ;
break ;
case RANDOM_FADE_SINGLE :
RandomFadeSingleUpdate ( ) ;
break ;
case SMOOTH :
SmoothUpdate ( ) ;
break ;
case PLASMA :
PlasmaUpdate ( ) ;
break ;
case FILL :
break ;
case RANDOM :
break ;
case FIRE :
FireUpdate ( ) ;
break ;
case FIREWORKS :
FireworksUpdate ( ) ;
break ;
case DROP :
DropUpdate ( ) ;
break ;
case RINGS :
RingsUpdate ( ) ;
break ;
case SCANNER_RANDOM :
ScannerRandomUpdate ( ) ;
break ;
case NONE :
break ;
default :
break ;
}
} else {
delay ( 1 ) ;
// Serial.print(".");
}
2017-02-16 23:40:42 +00:00
}
2019-03-17 17:19:54 +00:00
void NeoPatterns : : setInterval ( uint8_t interval )
{
Interval = interval ;
}
2017-02-16 23:40:42 +00:00
void NeoPatterns : : Increment ( )
{
2018-10-23 19:02:55 +00:00
// OnDebugOutput(String(Index) + " / " + String(TotalSteps));
if ( Direction = = FORWARD )
{
Index + + ;
if ( Index > = TotalSteps )
{
Index = 0 ;
if ( OnComplete ! = NULL )
{
OnComplete ( ) ; // call the completion callback
}
}
}
else // Direction == REVERSE
{
- - Index ;
if ( Index < = 0 )
{
Index = TotalSteps - 1 ;
if ( OnComplete ! = NULL )
{
OnComplete ( ) ; // call the completion callback
}
}
}
2017-02-16 23:40:42 +00:00
}
2018-10-23 19:02:55 +00:00
void NeoPatterns : : Reverse ( ) {
if ( Direction = = FORWARD )
{
Direction = REVERSE ;
// Index = TotalSteps - 1;
}
else
{
Direction = FORWARD ;
// Index = numPixels()-TotalSteps;
}
2017-02-16 23:40:42 +00:00
}
2018-10-23 19:02:55 +00:00
void NeoPatterns : : None ( uint8_t interval ) {
Interval = interval ;
if ( ActivePattern ! = NONE ) {
clear ( ) ;
show ( ) ;
}
ActivePattern = NONE ;
2017-02-16 23:40:42 +00:00
}
2018-10-23 19:02:55 +00:00
/****************** Effects ******************/
void NeoPatterns : : RainbowCycle ( uint8_t interval , direction dir ) {
ActivePattern = RAINBOW_CYCLE ;
Interval = interval ;
TotalSteps = 255 ;
Index = 0 ;
Direction = dir ;
2017-02-16 23:40:42 +00:00
}
void NeoPatterns : : RainbowCycleUpdate ( )
{
2018-10-23 19:02:55 +00:00
for ( int i = 0 ; i < numPixels ( ) ; i + + )
{
setPixelColor ( i , Wheel ( ( ( i * 256 / numPixels ( ) ) + Index ) & 255 ) ) ;
}
show ( ) ;
Increment ( ) ;
2017-02-16 23:40:42 +00:00
}
2018-10-23 19:02:55 +00:00
void NeoPatterns : : TheaterChase ( uint32_t color1 , uint32_t color2 , uint8_t interval , direction dir ) {
ActivePattern = THEATER_CHASE ;
Interval = interval ;
TotalSteps = numPixels ( ) ;
Color1 = color1 ;
Color2 = color2 ;
Index = 0 ;
Direction = dir ;
2017-02-16 23:40:42 +00:00
}
2018-10-23 19:02:55 +00:00
void NeoPatterns : : TheaterChaseUpdate ( ) {
for ( int i = 0 ; i < numPixels ( ) ; i + + )
{
if ( ( i + Index ) % 8 = = 0 )
{
setPixelColor ( i , Color1 ) ;
}
else
{
// Reduce brightness for the base pixels
float _brightness = 0.2 ;
uint8_t _r = ( uint8_t ) ( Color2 > > 16 ) ;
uint8_t _g = ( uint8_t ) ( Color2 > > 8 ) ;
uint8_t _b = ( uint8_t ) Color2 ;
setPixelColor ( i , Color ( _r * _brightness , _g * _brightness , _b * _brightness ) ) ;
}
}
show ( ) ;
Increment ( ) ;
}
void NeoPatterns : : BVBChase ( uint32_t color1 , uint32_t color2 , uint8_t interval , direction dir ) {
ActivePattern = BVB ;
Interval = interval ;
TotalSteps = numPixels ( ) ;
Color1 = color1 ;
Color2 = color2 ;
Index = 0 ;
Direction = dir ;
}
void NeoPatterns : : BVBChaseUpdate ( ) {
for ( int i = 0 ; i < numPixels ( ) ; i + + )
{
if ( ( i + Index ) % 8 = = 0 )
{
setPixelColor ( i , Color1 ) ;
}
else
{
// Reduce brightness for the base pixels
float _brightness = 0.2 ;
uint8_t _r = ( uint8_t ) ( Color2 > > 16 ) ;
uint8_t _g = ( uint8_t ) ( Color2 > > 8 ) ;
uint8_t _b = ( uint8_t ) Color2 ;
setPixelColor ( i , Color ( _r * _brightness , _g * _brightness , _b * _brightness ) ) ;
}
}
show ( ) ;
Increment ( ) ;
2017-02-16 23:40:42 +00:00
}
2018-10-23 19:02:55 +00:00
2017-02-16 23:40:42 +00:00
void NeoPatterns : : ColorWipe ( uint32_t color , uint8_t interval , direction dir )
{
2018-10-23 19:02:55 +00:00
ActivePattern = COLOR_WIPE ;
Interval = interval ;
TotalSteps = numPixels ( ) ;
Color1 = color ;
Index = 0 ;
Direction = dir ;
2017-02-16 23:40:42 +00:00
}
// Update the Color Wipe Pattern
void NeoPatterns : : ColorWipeUpdate ( )
{
2018-10-23 19:02:55 +00:00
setPixelColor ( Index , Color1 ) ;
show ( ) ;
Increment ( ) ;
2017-02-16 23:40:42 +00:00
}
// Initialize for a SCANNNER
2018-10-23 19:02:55 +00:00
void NeoPatterns : : Scanner ( uint32_t color1 , uint8_t interval , bool colorful , bool spiral )
2017-02-16 23:40:42 +00:00
{
2018-10-23 19:02:55 +00:00
ActivePattern = SCANNER ;
Interval = interval ;
TotalSteps = ( numPixels ( ) - 1 ) * 2 ;
Color1 = color1 ;
Index = 0 ;
wPos = 0 ;
this - > colorful = colorful ;
this - > spiral = spiral ;
2017-02-16 23:40:42 +00:00
}
// Update the Scanner Pattern
void NeoPatterns : : ScannerUpdate ( )
{
2018-10-23 19:02:55 +00:00
if ( colorful ) {
Color1 = Wheel ( wPos ) ;
if ( wPos > = 255 ) {
wPos = 0 ;
}
else {
wPos + + ;
}
}
for ( int i = 0 ; i < numPixels ( ) ; i + + )
{
int finalpos ;
if ( spiral ) {
finalpos = numToSpiralPos ( i ) ;
}
else
{
finalpos = i ;
}
if ( i = = Index ) // Scan Pixel to the right
{
setPixelColor ( finalpos , Color1 ) ;
}
else if ( i = = TotalSteps - Index ) // Scan Pixel to the left
{
setPixelColor ( finalpos , Color1 ) ;
}
else // Fading tail
{
setPixelColor ( finalpos , DimColor ( getPixelColor ( finalpos ) ) ) ;
}
}
show ( ) ;
Increment ( ) ;
}
// Initialize for a SCANNNER_RANDOM
void NeoPatterns : : ScannerRandom ( uint32_t color1 , uint8_t interval , bool colorful , bool spiral )
{
ActivePattern = SCANNER_RANDOM ;
Interval = interval ;
TotalSteps = ( numPixels ( ) - 1 ) * 2 ;
Color1 = color1 ;
Index = numPixels ( ) / 2 ;
wPos = 0 ;
this - > colorful = colorful ;
this - > spiral = spiral ;
}
// Update the Scanner Pattern
void NeoPatterns : : ScannerRandomUpdate ( )
{
if ( colorful ) {
Color1 = Wheel ( wPos ) ;
if ( wPos > = 255 ) {
wPos = 0 ;
}
else {
wPos + + ;
}
}
if ( random ( 0 , 1000 ) < 5 )
{
Reverse ( ) ;
}
for ( int i = 0 ; i < numPixels ( ) ; i + + )
{
int finalpos ;
if ( spiral ) {
finalpos = numToSpiralPos ( i ) ;
}
else
{
finalpos = i ;
}
if ( i = = Index ) // Scan Pixel to the right
{
setPixelColor ( finalpos , Color1 ) ;
}
else if ( i = = TotalSteps - Index ) // Scan Pixel to the left
{
setPixelColor ( finalpos , Color1 ) ;
}
else // Fading tail
{
setPixelColor ( finalpos , DimColor ( getPixelColor ( finalpos ) ) ) ;
}
}
show ( ) ;
Increment ( ) ;
2017-02-17 02:49:22 +00:00
2017-02-16 23:40:42 +00:00
}
2018-10-23 19:02:55 +00:00
2017-02-16 23:40:42 +00:00
void NeoPatterns : : Fade ( uint32_t color1 , uint32_t color2 , uint16_t steps , uint8_t interval , direction dir )
{
2018-10-23 19:02:55 +00:00
ActivePattern = FADE ;
Interval = interval ;
TotalSteps = steps ;
Color1 = color1 ;
Color2 = color2 ;
Index = 0 ;
Direction = dir ;
2017-02-16 23:40:42 +00:00
}
// Update the Fade Pattern
void NeoPatterns : : FadeUpdate ( )
{
2018-10-23 19:02:55 +00:00
// 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 ;
2017-02-16 23:40:42 +00:00
2018-10-23 19:02:55 +00:00
ColorSet ( Color ( red , green , blue ) ) ;
show ( ) ;
Increment ( ) ;
2017-02-16 23:40:42 +00:00
}
2018-10-23 19:02:55 +00:00
void NeoPatterns : : RandomFade ( uint8_t interval ) {
ActivePattern = RANDOM_FADE ;
Interval = interval ;
TotalSteps = 255 ;
Index = 0 ;
2017-02-17 02:49:22 +00:00
}
2018-10-23 19:02:55 +00:00
void NeoPatterns : : RandomFadeUpdate ( ) {
ColorSet ( Wheel ( Index ) ) ;
Increment ( ) ;
2017-02-17 02:49:22 +00:00
}
2018-10-23 19:02:55 +00:00
void NeoPatterns : : RandomFadeSingle ( uint8_t interval , uint8_t speed ) {
ActivePattern = RANDOM_FADE_SINGLE ;
Interval = interval ;
TotalSteps = 255 ;
Index = 0 ;
WheelSpeed = speed ;
RandomBuffer ( ) ;
2017-02-19 20:43:23 +00:00
}
2018-10-23 19:02:55 +00:00
void NeoPatterns : : RandomFadeSingleUpdate ( ) {
for ( int i = 0 ; i < numPixels ( ) ; i + + ) {
pixelR_buffer [ i ] + = random ( 0 , random ( 0 , WheelSpeed + 1 ) + 1 ) ; //use buffer red channel for color wheel
setPixelColor ( i , Wheel ( pixelR_buffer [ i ] ) ) ;
}
show ( ) ;
Increment ( ) ;
}
void NeoPatterns : : RandomBuffer ( )
{
for ( int i = 0 ; i < numPixels ( ) ; i + + ) {
uint32_t c = Wheel ( random ( 0 , 256 ) ) ;
pixelR_buffer [ i ] = ( uint8_t ) ( c > > 16 ) ;
pixelG_buffer [ i ] = ( uint8_t ) ( c > > 8 ) ;
pixelB_buffer [ i ] = ( uint8_t ) c ;
}
}
void NeoPatterns : : Random ( )
{
None ( ) ; // Stop all other effects
ActivePattern = RANDOM ;
for ( int i = 0 ; i < numPixels ( ) ; i + + ) {
setPixelColor ( i , Wheel ( random ( 0 , 256 ) ) ) ;
}
show ( ) ;
}
/********** FIRE ********/
void NeoPatterns : : Fire ( uint8_t interval )
{
ActivePattern = FIRE ;
Interval = interval ;
TotalSteps = 255 ;
Index = 0 ;
}
void NeoPatterns : : FireUpdate ( )
{
int r = 255 ;
int g = r - 140 ;
int b = 0 ;
for ( int i = 0 ; i < numPixels ( ) ; i + + ) {
int flicker = random ( 0 , 70 ) ;
int r1 = r - flicker ;
int g1 = g - flicker ;
int b1 = b - flicker ;
if ( g1 < 0 ) g1 = 0 ;
if ( r1 < 0 ) r1 = 0 ;
if ( b1 < 0 ) b1 = 0 ;
setPixelColor ( i , r1 , g1 , b1 ) ;
}
show ( ) ;
Interval = random ( 50 , 150 ) ;
}
/********** FIRE END ****/
/********** FIREWORKS ********/
// Manchmal noch instabil und lässt den ESP abstürzen. Müsste mal mit Serial mal gedebuggt werden...
void NeoPatterns : : Fireworks ( )
{
ActivePattern = FIREWORKS ;
Interval = 20 ; // 12ms ist so ziemlich die untere Grenze, durch die Berechnugen und Speicherzugriffe.
// Calculate "good" explosion speed
// 60 LED Strip: 50, 100, 0.985 is a good choice (with Interval = 25)
// Start 0, with maximum speed (100), the rocket should explode at the LATEST at position 50 (of 60). (Which is 10 pixels before maximum)
// rocket_speed_max should not be >100, as this would skip LEDs.
explosion_speed = 0.25f ;
rocket_speed_max = 100 ;
rocket_slowdown = pow ( explosion_speed , ( float ) ( ( float ) 1 / ( float ) ( 2 * numPixels ( ) - 10 ) ) ) ; // 0.985f;
rocket_speed_min = int ( log ( explosion_speed ) / ( ( numPixels ( ) / 4 ) * log ( rocket_slowdown ) ) ) + 1 ;
if ( rocket_speed_min / 100 < explosion_speed )
{
rocket_speed_min + = explosion_speed * 100 ;
}
// OnDebugOutput(String(rocket_slowdown, 6));
// OnDebugOutput(String(rocket_speed_min));
}
/** Debug Output
haus / RGB5m / strip / DEBUG Start : 0 : Speed : 0.960 Pos : 0
haus / RGB5m / strip / DEBUG Explode 0 : Speed 0.249 Pos : 149 Iterations : 282 // Die Anzahl der Iterationen ist gut berechnet (0.96 -- 282 von 290 max). Nur wurde der Slowdown nicht mit einberechnet
*/
void NeoPatterns : : explosion ( int pos , float rocketspeed )
{
uint8_t hue = random ( 0 , 256 ) ;
uint8_t explosionsize = random ( EXPLOSION_SIZE_MIN , EXPLOSION_SIZE_MAX + 1 ) ;
for ( int i = 0 ; i < explosionsize ; i + + )
{
particle_arr . push_back ( Particle ( this , pos + i - 3 , ( float ) ( ( ( float ) random ( - 50 , 50 ) ) / 100 ) + rocketspeed / 2 , hue , 1 , 0.99f ) ) ;
}
}
void NeoPatterns : : FireworksUpdate ( )
{
if ( millis ( ) > currentRocketMillis + rocketTimeout )
{
// Start a new rocket
if ( random ( 0 , 2 ) = = 0 )
{
Rocket tmpr = Rocket ( this , 0 , ( float ) ( ( ( float ) random ( rocket_speed_min , rocket_speed_max ) ) / 100 ) , rocket_slowdown ) ;
// OnDebugOutput(String("Start: ") + String(tmpr.id()) + String(": Speed: ") + String(tmpr.rocketspeed(), 3) + String(" Pos: 0"));
rocket_arr . push_back ( tmpr ) ;
}
else
{
Rocket tmpr = Rocket ( this , numPixels ( ) , - ( float ) ( ( ( float ) random ( rocket_speed_min , rocket_speed_max ) ) / 100 ) , rocket_slowdown ) ;
// OnDebugOutput(String("Start: ") + String(tmpr.id()) + String(": Speed: ") + String(tmpr.rocketspeed(), 3) + String(" Pos: ") + String(numPixels()));
rocket_arr . push_back ( tmpr ) ;
}
rocketTimeout = random ( ROCKET_LAUNCH_TIMEOUT_MIN , ROCKET_LAUNCH_TIMEOUT_MAX + 1 ) ;
currentRocketMillis = millis ( ) ;
}
clear ( ) ;
// Iterate through all particles
for ( std : : vector < Particle > : : iterator it = particle_arr . begin ( ) ; it ! = particle_arr . end ( ) ; + + it )
{
Particle & p = * it ;
p . update ( ) ;
// Erase Particles which are too dark
if ( p . brightness ( ) < 0.1 )
{
it = particle_arr . erase ( it ) ; // After erasing, it is now pointing the next element.
- - it ;
}
}
// Iterate through all rockets
for ( std : : vector < Rocket > : : iterator it = rocket_arr . begin ( ) ; it ! = rocket_arr . end ( ) ; + + it )
{
Rocket & r = * it ;
// Create Trail on old position
particle_arr . push_back ( Particle ( this , r . pos ( ) , 0 , 20 , 0.3 ) ) ;
r . update ( ) ;
if ( ( r . rocketspeed ( ) < = explosion_speed ) & & ( r . rocketspeed ( ) > = - explosion_speed ) )
{
// OnDebugOutput(String("Explode ") + String(r.id()) + String(": Speed ") + String(r.rocketspeed(), 3) + String(" Pos: ") + String(r.pos()) + String(" Iterations: ") + String(r.iteration()));
explosion ( r . pos ( ) , r . rocketspeed ( ) ) ;
it = rocket_arr . erase ( it ) ; // After erasing, it is now pointing the next element.
- - it ;
}
}
show ( ) ;
}
/********** FIREWORKS END ****/
/********** DROP ********/
void NeoPatterns : : Drop ( uint8_t interval )
{
ActivePattern = DROP ;
Interval = interval ;
TotalSteps = 255 ;
Index = 0 ;
for ( int i = 0 ; i < 10 ; i + + ) {
drop [ i ] = 0 ;
dropBrightness [ i ] = 0 ;
}
clear ( ) ;
}
void NeoPatterns : : DropUpdate ( )
{
// Generate new drop?
if ( random ( 0 , 100 ) > 50 )
{
Serial . println ( " Will generate a new drop " ) ;
// New drop
// Find first free drop and discard, if no free place
for ( int i = 0 ; i < MAX_DROPS ; i + + ) {
if ( drop [ i ] = = 0 )
{
Serial . print ( " Found a free position for a drop: " ) ;
// Random position
drop [ i ] = random ( 0 , numPixels ( ) ) ;
dropBrightness [ i ] = 255 ; // Initial brightness
Serial . print ( i ) ;
Serial . print ( " pos " ) ;
Serial . println ( drop [ i ] ) ;
break ;
}
}
}
// Work for all other drops
for ( int i = 0 ; i < MAX_DROPS ; i + + ) {
if ( drop [ i ] > 0 )
{
Serial . print ( " Updating drop on " ) ;
Serial . println ( i ) ;
// Current drop
// dropBrightness[i] = dropBrightness[i]>>1;
dropBrightness [ i ] * = 0.9 ;
if ( dropBrightness [ i ] < = 8 )
{
// Brightness to zero for all neighbours
dropBrightness [ i ] = 0 ;
}
setPixelColor ( drop [ i ] , 0 , 0 , dropBrightness [ i ] ) ; // TODO: Other colors?
// Set neighbouring drops
int nBright ;
for ( int neighbour = 1 ; neighbour < 5 ; neighbour + + ) {
//nBright = dropBrightness[i] >> neighbour;
nBright = dropBrightness [ i ] ;
for ( int j = 1 ; j < neighbour ; j + + )
{
nBright * = 0.6 ;
}
Serial . print ( neighbour ) ;
Serial . print ( " : " ) ;
Serial . println ( nBright ) ;
if ( ( drop [ i ] - neighbour ) > = 0 )
{
setPixelColor ( drop [ i ] - neighbour , 0 , 0 , nBright ) ;
}
if ( ( drop [ i ] + neighbour ) < = numPixels ( ) )
{
setPixelColor ( drop [ i ] + neighbour , 0 , 0 , nBright ) ;
}
}
if ( dropBrightness [ i ] < = 8 )
{
// Disable this drop
drop [ i ] = 0 ;
}
}
}
show ( ) ;
}
/********** DROP END ****/
/********** RINGS ********/
void NeoPatterns : : Rings ( uint8_t interval )
{
ActivePattern = RINGS ;
Interval = interval ;
TotalSteps = 255 ;
Index = 0 ;
for ( int i = 0 ; i < 10 ; i + + ) {
ring [ i ] = 0 ;
ringBrightness [ i ] = 0 ;
ringDistance [ i ] = 0 ;
}
clear ( ) ;
}
void NeoPatterns : : RingsUpdate ( )
{
// Generate new ring?
if ( random ( 0 , 100 ) > 50 )
{
Serial . println ( " Will generate a new ring " ) ;
// New ring
// Find first free ring and discard, if no free place
for ( int i = 0 ; i < MAX_RINGS ; i + + ) {
if ( ring [ i ] = = 0 )
{
Serial . print ( " Found a free position for a ring: " ) ;
// Random position
ring [ i ] = random ( 0 , numPixels ( ) ) ;
ringBrightness [ i ] = 255 < < 1 ; // Initial brightness
ringDistance [ i ] = 0 ;
Serial . print ( i ) ;
Serial . print ( " pos " ) ;
Serial . println ( ring [ i ] ) ;
break ;
}
}
}
// Work for all other rings
for ( int i = 0 ; i < MAX_RINGS ; i + + ) {
if ( ring [ i ] > 0 )
{
Serial . print ( " Updating ring on " ) ;
Serial . println ( i ) ;
// Center of the ring
ringBrightness [ i ] * = 0.9 ;
if ( ringBrightness [ i ] < = 8 )
{
// Brightness to zero for the middle
ringBrightness [ i ] = 0 ;
}
setPixelColor ( ring [ i ] , 0 , 0 , ringBrightness [ i ] ) ; // TODO: Other colors?
// Set neighbouring rings
int nBright ;
// Maximum distance for rings is 10
// General idea: Start with the middle (max brightness), continue left and right with brightness * 0.9
// For each step, dim current brightness for ALL pixels simply by 0.7, below thershold -> off
ringDistance [ i ] + + ;
// Neighbours: Color of middle, dimmed by 0.9 to max distance
for ( int neighbour = 1 ; neighbour < ringDistance [ i ] ; neighbour + + )
{
Serial . print ( " Neighbour " ) ;
Serial . print ( neighbour ) ;
nBright = 255 ;
if ( ringBrightness [ i ] = = 0 )
{
nBright = 0 ;
}
else
{
for ( int j = 0 ; j < ringDistance [ i ] - neighbour ; j + + )
{
nBright * = 0.8 ;
}
nBright * = ( 1 - 0.1 * ringDistance [ i ] ) ;
}
if ( nBright < 10 ) {
nBright = 0 ;
}
Serial . print ( " brightness: " ) ;
Serial . println ( nBright ) ;
if ( ( ring [ i ] - neighbour ) > = 0 )
{
setPixelColor ( ring [ i ] - neighbour , 0 , 0 , nBright ) ;
}
if ( ( ring [ i ] + neighbour ) < = numPixels ( ) )
{
setPixelColor ( ring [ i ] + neighbour , 0 , 0 , nBright ) ;
}
}
if ( ringBrightness [ i ] < = 8 )
{
// Disable this ring
ring [ i ] = 0 ;
}
}
}
show ( ) ;
}
/********** RINGS END ****/
void NeoPatterns : : Smooth ( uint8_t wheelSpeed , uint8_t smoothing , uint8_t strength , uint8_t interval ) {
ActivePattern = SMOOTH ;
Interval = interval ;
Index = 0 ;
WheelSpeed = wheelSpeed ;
Smoothing = smoothing ;
Strength = strength ;
movingPoint_x = 3 ;
movingPoint_y = 3 ;
// Clear buffer (from previous or different effects)
for ( int i = 0 ; i < numPixels ( ) ; i + + ) {
pixelR_buffer [ i ] = 0 ;
pixelG_buffer [ i ] = 0 ;
pixelB_buffer [ i ] = 0 ;
}
}
void NeoPatterns : : SmoothUpdate ( ) {
uint32_t c = Wheel ( wPos ) ;
wPosSlow + = WheelSpeed ;
wPos = ( wPos + ( wPosSlow / 10 ) ) % 255 ;
wPosSlow = wPosSlow % 16 ;
uint8_t r = ( uint8_t ) ( c > > 16 ) ;
uint8_t g = ( uint8_t ) ( c > > 8 ) ;
uint8_t b = ( uint8_t ) c ;
movingPoint_x = movingPoint_x + 8 + random ( - random ( 0 , 1 + 1 ) , random ( 0 , 1 + 1 ) + 1 ) ;
movingPoint_y = movingPoint_y + 8 + random ( - random ( 0 , 1 + 1 ) , random ( 0 , 1 + 1 ) + 1 ) ;
if ( movingPoint_x < 8 ) {
movingPoint_x = 8 - movingPoint_x ;
} else if ( movingPoint_x > = 16 ) {
movingPoint_x = 22 - movingPoint_x ;
} else {
movingPoint_x - = 8 ;
}
if ( movingPoint_y < 8 ) {
movingPoint_y = 8 - movingPoint_y ;
} else if ( movingPoint_y > = 16 ) {
movingPoint_y = 22 - movingPoint_y ;
} else {
movingPoint_y - = 8 ;
}
uint8_t startx = movingPoint_x ;
uint8_t starty = movingPoint_y ;
for ( int i = 0 ; i < Strength ; i + + ) {
movingPoint_x = startx + 8 + random ( - random ( 0 , 2 + 1 ) , random ( 0 , 2 + 1 ) + 1 ) ;
movingPoint_y = starty + 8 + random ( - random ( 0 , 2 + 1 ) , random ( 0 , 2 + 1 ) + 1 ) ;
if ( movingPoint_x < 8 ) {
movingPoint_x = 8 - movingPoint_x ;
} else if ( movingPoint_x > = 16 ) {
movingPoint_x = 22 - movingPoint_x ;
} else {
movingPoint_x - = 8 ;
}
if ( movingPoint_y < 8 ) {
movingPoint_y = 8 - movingPoint_y ;
} else if ( movingPoint_y > = 16 ) {
movingPoint_y = 22 - movingPoint_y ;
} else {
movingPoint_y - = 8 ;
}
if ( pixelR [ xyToPos ( movingPoint_x , movingPoint_y ) ] < r ) {
pixelR [ xyToPos ( movingPoint_x , movingPoint_y ) ] + + ;
} else if ( pixelR [ xyToPos ( movingPoint_x , movingPoint_y ) ] > r ) {
pixelR [ xyToPos ( movingPoint_x , movingPoint_y ) ] - - ;
}
if ( pixelG [ xyToPos ( movingPoint_x , movingPoint_y ) ] < g ) {
pixelG [ xyToPos ( movingPoint_x , movingPoint_y ) ] + + ;
} else if ( pixelG [ xyToPos ( movingPoint_x , movingPoint_y ) ] > g ) {
pixelG [ xyToPos ( movingPoint_x , movingPoint_y ) ] - - ;
}
if ( pixelB [ xyToPos ( movingPoint_x , movingPoint_y ) ] < b ) {
pixelB [ xyToPos ( movingPoint_x , movingPoint_y ) ] + + ;
} else if ( pixelB [ xyToPos ( movingPoint_x , movingPoint_y ) ] > b ) {
pixelB [ xyToPos ( movingPoint_x , movingPoint_y ) ] - - ;
}
}
movingPoint_x = startx ;
movingPoint_y = starty ;
for ( int i = 0 ; i < numPixels ( ) ; i + + ) {
pixelR_buffer [ i ] = ( Smoothing / 100.0 ) * pixelR [ i ] + ( 1.0 - ( Smoothing / 100.0 ) ) * getAverage ( pixelR , i , 0 , 0 ) ;
pixelG_buffer [ i ] = ( Smoothing / 100.0 ) * pixelG [ i ] + ( 1.0 - ( Smoothing / 100.0 ) ) * getAverage ( pixelG , i , 0 , 0 ) ;
pixelB_buffer [ i ] = ( Smoothing / 100.0 ) * pixelB [ i ] + ( 1.0 - ( Smoothing / 100.0 ) ) * getAverage ( pixelB , i , 0 , 0 ) ;
}
for ( int i = 0 ; i < numPixels ( ) ; i + + ) {
pixelR [ i ] = pixelR_buffer [ i ] ;
pixelG [ i ] = pixelG_buffer [ i ] ;
pixelB [ i ] = pixelB_buffer [ i ] ;
setPixelColor ( i , pixelR [ i ] , pixelG [ i ] , pixelB [ i ] ) ;
}
show ( ) ;
}
// Based upon https://github.com/johncarl81/neopixelplasma
void NeoPatterns : : Plasma ( float phase , float phaseIncrement , float colorStretch , uint8_t interval )
{
ActivePattern = PLASMA ;
Interval = interval ;
PlasmaPhase = phase ;
PlasmaPhaseIncrement = phaseIncrement ;
PlasmaColorStretch = colorStretch ;
}
void NeoPatterns : : PlasmaUpdate ( )
{
PlasmaPhase + = PlasmaPhaseIncrement ;
int edge = ( int ) sqrt ( numPixels ( ) ) ;
// The two points move along Lissajious curves, see: http://en.wikipedia.org/wiki/Lissajous_curve
// The sin() function returns values in the range of -1.0..1.0, so scale these to our desired ranges.
// The phase value is multiplied by various constants; I chose these semi-randomly, to produce a nice motion.
Point p1 = { ( sin ( PlasmaPhase * 1.000 ) + 1.0 ) * ( edge / 2 ) , ( sin ( PlasmaPhase * 1.310 ) + 1.0 ) * ( edge / 2 ) } ;
Point p2 = { ( sin ( PlasmaPhase * 1.770 ) + 1.0 ) * ( edge / 2 ) , ( sin ( PlasmaPhase * 2.865 ) + 1.0 ) * ( edge / 2 ) } ;
Point p3 = { ( sin ( PlasmaPhase * 0.250 ) + 1.0 ) * ( edge / 2 ) , ( sin ( PlasmaPhase * 0.750 ) + 1.0 ) * ( edge / 2 ) } ;
byte row , col ;
// For each row...
for ( row = 0 ; row < edge ; row + + ) {
float row_f = float ( row ) ; // Optimization: Keep a floating point value of the row number, instead of recasting it repeatedly.
// For each column...
for ( col = 0 ; col < edge ; col + + ) {
float col_f = float ( col ) ; // Optimization.
// Calculate the distance between this LED, and p1.
Point dist1 = { col_f - p1 . x , row_f - p1 . y } ; // The vector from p1 to this LED.
float distance1 = sqrt ( dist1 . x * dist1 . x + dist1 . y * dist1 . y ) ;
// Calculate the distance between this LED, and p2.
Point dist2 = { col_f - p2 . x , row_f - p2 . y } ; // The vector from p2 to this LED.
float distance2 = sqrt ( dist2 . x * dist2 . x + dist2 . y * dist2 . y ) ;
// Calculate the distance between this LED, and p3.
Point dist3 = { col_f - p3 . x , row_f - p3 . y } ; // The vector from p3 to this LED.
float distance3 = sqrt ( dist3 . x * dist3 . x + dist3 . y * dist3 . y ) ;
// Warp the distance with a sin() function. As the distance value increases, the LEDs will get light,dark,light,dark,etc...
// You can use a cos() for slightly different shading, or experiment with other functions. Go crazy!
float color_1 = distance1 ; // range: 0.0...1.0
float color_2 = distance2 ;
float color_3 = distance3 ;
float color_4 = ( sin ( distance1 * distance2 * PlasmaColorStretch ) ) + 2.0 * 0.5 ;
// Square the color_f value to weight it towards 0. The image will be darker and have higher contrast.
color_1 * = color_1 * color_4 ;
color_2 * = color_2 * color_4 ;
color_3 * = color_3 * color_4 ;
color_4 * = color_4 ;
// Scale the color up to 0..7 . Max brightness is 7.
//strip.setPixelColor(col + (edge * row), strip.Color(color_4, 0, 0) );
setPixelColor ( col + ( edge * row ) , Color ( color_1 , color_2 , color_3 ) ) ;
}
}
show ( ) ;
}
/****************** Helper functions ******************/
void NeoPatterns : : SetColor1 ( uint32_t color ) {
Color1 = color ;
}
void NeoPatterns : : SetColor2 ( uint32_t color ) {
Color2 = color ;
2017-02-19 20:43:23 +00:00
}
2017-02-16 23:40:42 +00:00
// Calculate 50% dimmed version of a color (used by ScannerUpdate)
uint32_t NeoPatterns : : DimColor ( uint32_t color )
{
2018-10-23 19:02:55 +00:00
// Shift R, G and B components one bit to the right
uint32_t dimColor = Color ( Red ( color ) > > 1 , Green ( color ) > > 1 , Blue ( color ) > > 1 ) ;
return dimColor ;
2017-02-16 23:40:42 +00:00
}
// Set all pixels to a color (synchronously)
void NeoPatterns : : ColorSet ( uint32_t color )
{
2018-10-23 19:02:55 +00:00
for ( int i = 0 ; i < numPixels ( ) ; i + + )
{
setPixelColor ( i , color ) ;
}
show ( ) ;
}
void NeoPatterns : : ColorSetParameters ( String parameters )
{
None ( ) ;
ActivePattern = FILL ;
ColorSet ( parseColor ( parameters ) ) ;
2017-02-16 23:40:42 +00:00
}
// Returns the Red component of a 32-bit color
uint8_t NeoPatterns : : Red ( uint32_t color )
{
2018-10-23 19:02:55 +00:00
return ( color > > 16 ) & 0xFF ;
2017-02-16 23:40:42 +00:00
}
// Returns the Green component of a 32-bit color
uint8_t NeoPatterns : : Green ( uint32_t color )
{
2018-10-23 19:02:55 +00:00
return ( color > > 8 ) & 0xFF ;
2017-02-16 23:40:42 +00:00
}
// Returns the Blue component of a 32-bit color
uint8_t NeoPatterns : : Blue ( uint32_t color )
{
2018-10-23 19:02:55 +00:00
return color & 0xFF ;
2017-02-16 23:40:42 +00:00
}
// Input a value 0 to 255 to get a color value.
2018-10-23 19:02:55 +00:00
// The colors are a transition r - g - b - back to r.
2017-02-16 23:40:42 +00:00
uint32_t NeoPatterns : : Wheel ( byte WheelPos )
{
2018-10-23 19:02:55 +00:00
WheelPos = 255 - WheelPos ;
if ( WheelPos < 85 )
{
return Color ( 255 - WheelPos * 3 , 0 , WheelPos * 3 ) ;
}
else if ( WheelPos < 170 )
{
WheelPos - = 85 ;
return Color ( 0 , WheelPos * 3 , 255 - WheelPos * 3 ) ;
}
else
{
WheelPos - = 170 ;
return Color ( WheelPos * 3 , 255 - WheelPos * 3 , 0 ) ;
}
}
uint32_t NeoPatterns : : Wheel ( byte WheelPos , float brightness ) {
WheelPos = 255 - WheelPos ;
// OnDebugOutput(String("Value ") + String (WheelPos * 3) + String(" converted by brightness ") + String(brightness, 6) + String(" to ") + String(int((float)(WheelPos * 3) * brightness)));
if ( WheelPos < 85 ) {
return Color ( int ( ( float ) ( 255 - WheelPos * 3 ) * brightness ) , 0 , int ( ( float ) ( WheelPos * 3 ) * brightness ) ) ;
}
if ( WheelPos < 170 ) {
WheelPos - = 85 ;
return Color ( 0 , int ( ( float ) ( WheelPos * 3 ) * brightness ) , int ( ( float ) ( 255 - WheelPos * 3 ) * brightness ) ) ;
}
WheelPos - = 170 ;
return Color ( int ( ( float ) ( WheelPos * 3 ) * brightness ) , int ( ( float ) ( 255 - WheelPos * 3 ) * brightness ) , 0 ) ;
}
// Convert x y pixel position to matrix position
uint8_t NeoPatterns : : xyToPos ( int x , int y ) {
if ( y % 2 = = 0 ) {
return ( y * 8 + x ) ;
} else {
return ( y * 8 + ( 7 - x ) ) ;
}
}
//convert pixel number to actual 8x8 matrix position
uint8_t NeoPatterns : : numToPos ( int num ) {
int x = num % 8 ;
int y = num / 8 ;
return xyToPos ( x , y ) ;
}
// Convert pixel number to actual 8x8 matrix position in a spiral
uint8_t NeoPatterns : : numToSpiralPos ( int num ) {
int edge = ( int ) sqrt ( numPixels ( ) ) ;
int findx = edge - 1 ; // 7
int findy = 0 ;
int stepsize = edge - 1 ; // initial value (0..7)
int stepnumber = 0 ; // each "step" should be used twice
int count = - 1 ;
int dir = 1 ; // direction: 0 = incX, 1=incY, 2=decX, 3=decY
if ( num < edge ) {
return num ; // trivial
}
for ( int i = edge ; i < = num ; i + + )
{
count + + ;
if ( count = = stepsize ) {
count = 0 ;
// Change direction
dir + + ;
stepnumber + + ;
if ( stepnumber = = 2 ) {
stepsize - = 1 ;
stepnumber = 0 ;
}
if ( dir = = 4 ) {
dir = 0 ;
}
}
switch ( dir ) {
case 0 :
findx + + ;
break ;
case 1 :
findy + + ;
break ;
case 2 :
findx - - ;
break ;
case 3 :
findy - - ;
break ;
}
}
return xyToPos ( findx , findy ) ;
}
uint8_t NeoPatterns : : getAverage ( uint8_t array [ ] , uint8_t i , int x , int y )
{
// TODO: This currently works only with 8x8 (64 pixel)!
uint16_t sum = 0 ;
uint8_t count = 0 ;
if ( i > = 8 ) { //up
sum + = array [ i - 8 ] ;
count + + ;
}
if ( i < ( 64 - 8 ) ) { //down
sum + = array [ i + 8 ] ;
count + + ;
}
if ( i > = 1 ) { //left
sum + = array [ i - 1 ] ;
count + + ;
}
if ( i < ( 64 - 1 ) ) { //right
sum + = array [ i + 1 ] ;
count + + ;
}
return sum / count ;
}
uint32_t NeoPatterns : : parseColor ( String value ) {
if ( value . charAt ( 0 ) = = ' # ' ) { //solid fill
String color = value . substring ( 1 ) ;
int number = ( int ) strtol ( & color [ 0 ] , NULL , 16 ) ;
// Split them up into r, g, b values
int r = number > > 16 ;
int g = number > > 8 & 0xFF ;
int b = number & 0xFF ;
return Color ( r , g , b ) ;
}
return 0 ;
2017-02-16 23:40:42 +00:00
}