 /*
  * Description: Motion activated stair lights.
  * Author: Dean Montgomery
- * Version: 1.1
- * Date: Aug 8, 2015
+ * Version: 2.1
+ * Date: Feb 8, 2016
  * 
  * 2 PIR sesors at the top and bottom of the stairs.
  * WS28012B Addressable RGB lights - 2 LEDs on each stair - This spread out the strip of 30 and left 2-pairs for spare bulbs.
  * My Arduino is at the top of the stairs and the RGB strip is connected at the top.
  * This will cycle through several varitions of stair walkers.
  * 
+ * Version 2 is a rewrite to properly handle multi-tasking the PIR sensors in parallel with LED updates.
+ * TODO: Do some code cleanup, variable naming etc.
+ * 
 */
 
 #include "FastLED.h"
-#include <avr/eeprom.h>
+//#include <avr/eeprom.h>
 
 #define NUM_LEDS 26
+//#define NUM_LEDS 14
 #define LEDS_PER_STAIR 2        // Number of Leds per stair.  Not yet currenlty changable - just noteable
 #define BRIGHTNESS  120         // 0...255  ( used in fade7 )
 #define PIN_LED 3               // LED Data pin

        leds[gStair+1] = CHSV( 60, 200, gBright );
      }
    }
    FastLED.show();
    FastLED.delay(25);
  }
  // Blow out candles and leave an ember.
  for(gStair=0; gStair < NUM_LEDS; gStair+=2) {
    rnd = random8(4, 6);
    r = rnd+1;
    g = rnd-2;
    leds[gUpDown[gStair]] = CRGB( r,g,0 );
    leds[gUpDown[gStair + 1]] = CRGB( r,g,0 );
    FastLED.show();
    FastLED.delay(50);
  }
  for ( i=0; i<=200; i++) {
    rnd = random8(0, NUM_LEDS-1);
    leds[gUpDown[rnd]].fadeToBlackBy( 5 );
    FastLED.show();
    FastLED.delay(50);
  }
  fill_solid(leds, NUM_LEDS, CRGB( 0, 0, 0 ));
  FastLED.show();
  gLightsOn = LOW;  
}

// Fade7 effect with each led: r,rb,b,bg,g,gr rgb(white)
void fade7(){
  const uint8_t mx = BRIGHTNESS;
  uint8_t r = mx;
  uint8_t g = 0;
  uint8_t b = 0;
  const uint8_t del = 25;
  boolean glitter = ( random8() < 120 );
  for (gStair=0; gStair < NUM_LEDS; gStair+=2){
    for (r=0; r<mx; r+=2) {
      leds[gUpDown[gStair]] = CRGB( r, g, b );
      leds[gUpDown[gStair + 1]] = CRGB( r, g, b );
      FastLED.show();
      FastLED.delay(1);
    }
  }
  for (b=0; b<mx; b++){
    fill_solid(leds, NUM_LEDS, CRGB( r, g, b ));
    if (glitter) addGlitter(80);
    FastLED.show();
    delay(del);
  }
  for (r=mx; r>0; r--){
    fill_solid(leds, NUM_LEDS, CRGB( r, g, b ));
    if (glitter) addGlitter(70);
    FastLED.show();
    delay(del);
  }
  for (g=0; g<mx; g++){
    fill_solid(leds, NUM_LEDS, CRGB( r, g, b ));
    if (glitter) addGlitter(60);
    FastLED.show();
    delay(del);
  }
  for (b=mx; b>0; b--){
    fill_solid(leds, NUM_LEDS, CRGB( r, g, b ));
    if (glitter) addGlitter(50);
    FastLED.show();
    delay(del);
  }
  for (r=0; r<mx; r++){
    fill_solid(leds, NUM_LEDS, CRGB( r, g, b ));
    if (glitter) addGlitter(40);
    FastLED.show();
    delay(del);
  }
  for (b=0; b<mx; b++){
    fill_solid(leds, NUM_LEDS, CRGB( r, g, b ));
    if (glitter) addGlitter(30);
    FastLED.show();
    delay(del);
  }
  for (b=mx; b>0; b--){
    g=b;
    fill_solid(leds, NUM_LEDS, CRGB( r, g, b ));
    if (glitter) addGlitter(10);
    FastLED.show();
    delay(del);
  }
  for (gStair=0; gStair < NUM_LEDS; gStair+=2){
    for (r=mx; r>1; r--) { 
      leds[gUpDown[gStair]] = CRGB( r, g, b );
      leds[gUpDown[gStair + 1]] = CRGB( r, g, b );
      FastLED.show();
      FastLED.delay(1); 
    }
    r = 0; g = 0; b = 0;
    leds[gUpDown[gStair]] = CRGB( r, g, b );
    leds[gUpDown[gStair + 1]] = CRGB( r, g, b );
    FastLED.show();
  }
  gLightsOn = LOW;  
}



// Walk the stairs adding random effects.
void walk() {
  
  if ( stage == stage_init ){
    valTop = 200;
    // Pick two colors from the palette. 
    choosePalette();
    c1 = gPalette[gLastPalette];
    c2 = gPalette[gLastPalette+1];
    // chance of a random palette
    if ( random8( 5 ) == 3 ){
      c1 = CRGB(random8(3,100),random8(3,100),random8(3,100));
      c2 = CRGB(random8(3,100),random8(3,100),random8(3,100));
    }
    // fix random Black palette.
    if ( (int(c1.r) + int(c1.g) + int(c1.b)) < 8 ){
      c1 = gPalette[2];
      c2 = gPalette[4];
    }
    trans = CRGB::Black;
    trans2 = CRGB::Black;
    z[0] = c2;
    z[1] = c1;
    z[2] = CRGB(random8(2,100),random8(2,100),random8(2,100));
    z[3] = c1;
    z[4] = c2;
    //(r2-r1)/ticks * tick)
    gStair=0;
    gBright=0;
    interval=5;
    i = 0;
    x = 0;
    r = 0;
    g = 0;
    b = 0;
    walk_effect = (WalkEffects)random8( 0, 4 );
    stage = stage_grow;
  } else if ( stage == stage_grow ) {
    if (gBright < 255){
      if ( gStair < NUM_LEDS ){
        trans = blend(CRGB::Black,c1,gBright); // fade in next two
        leds[gUpDown[gStair]] = trans;
        leds[gUpDown[gStair + 1]] = trans;
      }
      if (  gStair >= 2 ) { // shift last two stairs to the 2nd color.
        trans2 = blend(c1,c2,gBright);
        leds[gUpDown[gStair - 1]] = trans2;
        leds[gUpDown[gStair - 2]] = trans2;
      }
      gBright = qadd8(gBright, 4);
    } else {
      if ( gStair < NUM_LEDS - 2 ) {
        gStair+=2;  //next stair.
      } else {
        stage = stage_init_run;
        gStair = 0;
      }
      gBright = 0;
    }
  } else if ( stage == stage_init_run ) {
    fill_solid(leds, NUM_LEDS, c2);
    x = 0;
    stage = stage_run;
  } else if ( stage == stage_run ) {
    trans2 = c2;
    randomEffect();  // waits for timer to run out.
  } else if ( stage == stage_init_dim ) {
    interval = 3;
    for(b=0; b<255; b++) {
      trans = blend(trans2,c2,b);
      fill_solid(leds, NUM_LEDS, trans);
      FastLED.show();
      FastLED.delay(8);
    }
    interval = 8;
    gBright = 0;
    gStair = 0;
    stage = stage_dim;
  } else if ( stage == stage_dim ) {
    if ( gBright <= valTop  ) {
      if ( gStair < NUM_LEDS ){
        leds[gUpDown[gStair]].fadeToBlackBy( 6 );
        leds[gUpDown[gStair + 1]].fadeToBlackBy( 6 );
        gBright+=4;
      } else {
        stage = off;
      }
    } else {
      leds[gUpDown[gStair]] = CRGB( 0, 0, 0);
      leds[gUpDown[gStair + 1]] = CRGB( 0, 0, 0);
      gStair += 2; 
      gBright = 0;
    }
  } else {
    stage = off;
  }  
}

// Random effects for the walk() stair function.
void randomEffect(){
  if ( walk_effect == sparkle ) { 
    interval = 8;
    fill_solid(leds, NUM_LEDS, c2);
    addGlitter(80);
  } else if ( walk_effect == pulsate1 ) {
    interval = 10;
    if ( b < 255 ){
      if ( i < 4 ) {
        trans2 = blend(z[i],z[i+1],b);
        fill_solid(leds, NUM_LEDS, trans2);
        b=qadd8(b,1);
      } else {
        i = 0;
      }
    } else {
      i++;
      b=0;
    }
  } else if ( walk_effect == pulsate2 ) {
    interval = 5;
    for(gStair=0; gStair < NUM_LEDS; gStair++) {
      trans2 = blend(c1,c2,quadwave8(r+=( -20 * gupDownDir )));
      leds[gStair] = trans2;
    }
    gStair = 0;
    r = ++g;
  } else if ( walk_effect == flash ) {
    if ( x == 0 ) {
      for(gStair=0; gStair < NUM_LEDS; gStair+=2) {
        leds[gUpDown[gStair]] = CRGB( 100, 100, 100);
        leds[gUpDown[gStair + 1]] = CRGB( 100, 100, 100);
        FastLED.show();
        FastLED.delay(1);
      }
      for(gStair=0; gStair < NUM_LEDS; gStair+=2) {
        leds[gUpDown[gStair]] = c2;
        leds[gUpDown[gStair+1]] = c2;
        FastLED.show();
        FastLED.delay(1);
      }
      x = 1;
      gStair=0;
    } 
  }
}

// Sparkle rainbow welcome give delay to calibrate pir sensors.  This also indicates if program crashed.
