Files @ 05931ab4f666
Branch filter:

Location: Wearables/Neopixel-Goggles/Neopixel_Goggles.ino

Dennis Fink
Added Spinner pattern
#include <Adafruit_NeoPixel.h>

#ifdef __AVR_ATtiny85__
#include <avr/power.h>
#endif

// Begin config section

#define PIN 0

#define BRIGHTNESS 64

#define MODE_CHANGE_TIME 10000

#define COLOR_MIN 0
#define COLOR_MAX 255

#define STEPS_MIN 5
#define STEPS_MAX 10

#define SLOW_INTERVAL_MIN 25
#define SLOW_INTERVAL_MAX 55

#define RAINBOW_CYCLE_MIN_INTERVAL 1
#define RAINBOW_CYCLE_MAX_INTERVAL 10

#define BLINK_MIN_INTERVAL 250
#define BLINK_MAX_INTERVAL 500

#define SPINNER_PIXELS_MIN 1
#define SPINNER_PIXELS_MAX 10

// End config section

enum  pattern {
  RAINBOW_CYCLE,
  COLOR_WIPE,
  DOUBLE_COLOR_WIPE,
  SCANNER,
  DOUBLE_SCANNER,
  RANDOM,
  DOUBLE_RANDOM,
  BLINK,
  DOT,
  SPINNER
};

class NeoPatterns : public Adafruit_NeoPixel {
  public:
    pattern  ActivePattern;

    uint16_t Interval;
    unsigned long lastUpdate;
    uint32_t PixelColor;
    uint16_t TotalSteps;
    uint16_t Index;
    uint8_t SpinnerPixels;

    void (*OnComplete)();

    NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)()) : Adafruit_NeoPixel(pixels, pin, type) {
      OnComplete = callback;
    }

    void Update() {
      if ((millis() - lastUpdate) > Interval) {
        lastUpdate = millis();
        switch (ActivePattern) {
          case RAINBOW_CYCLE:
            RainbowCycleUpdate();
            break;
          case COLOR_WIPE:
            ColorWipeUpdate();
            break;
          case DOUBLE_COLOR_WIPE:
            DoubleColorWipeUpdate();
            break;
          case SCANNER:
            ScannerUpdate();
            break;
          case DOUBLE_SCANNER:
            DoubleScannerUpdate();
            break;
          case RANDOM:
            RandomUpdate();
            break;
          case DOUBLE_RANDOM:
            DoubleRandomUpdate();
            break;
          case BLINK:
            BlinkUpdate();
            break;
          case DOT:
            DotUpdate();
            break;
          case SPINNER:
            SpinnerUpdate();
            break;
          default:
            break;
        }
      }
    }

    void Increment() {
      show();
      Index++;
      if (Index >= TotalSteps) {
        Index = 0;
        OnComplete();
      }
    }

    void RainbowCycle(uint16_t interval) {
      ActivePattern = RAINBOW_CYCLE;
      Interval = interval;
      TotalSteps = 255;
      Index = 0;
    }

    void RainbowCycleUpdate() {
      for (int i = 0; i < numPixels(); i++) {
        setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255));
      }
      Increment();
    }

    void ColorWipe(uint32_t color, uint16_t interval) {
      ActivePattern = COLOR_WIPE;
      Interval = interval;
      TotalSteps = numPixels();
      PixelColor = color;
      Index = 0;
    }

    void ColorWipeUpdate() {
      setPixelColor(Index, PixelColor);
      Increment();
    }

    void DoubleColorWipe(uint32_t color, uint16_t interval) {
      ActivePattern = DOUBLE_COLOR_WIPE;
      Interval = interval;
      TotalSteps = numPixels() / 2;
      PixelColor = color;
      Index = 0;
    }

    void DoubleColorWipeUpdate() {
      DoubleSet(Index, PixelColor);
      Increment();
    }

    void Scanner(uint32_t color, uint16_t interval) {
      ActivePattern = SCANNER;
      Interval = interval;
      TotalSteps = (numPixels() - 1) * 2;
      PixelColor = color;
      Index = 0;
    }

    void ScannerUpdate() {
      for (int i = 0; i < numPixels(); i++) {
        uint32_t c;
        if (i == Index || i == TotalSteps - Index) {
          c = PixelColor;
        }
        else {
          c = DimColor(getPixelColor(i));
        }
        setPixelColor(i, c);
      }
      Increment();
    }

    void DoubleScanner(uint32_t color, uint16_t interval) {
      ActivePattern = DOUBLE_SCANNER;
      Interval = interval;
      TotalSteps = (numPixels() / 2);
      PixelColor = color;
      Index = 0;
    }

    void DoubleScannerUpdate() {
      for (int i = 0; i < numPixels() / 2; i++) {
        uint32_t c;
        if (i == Index) {
          c = PixelColor;
        }
        else {
          c = DimColor(getPixelColor(i));
        }
        DoubleSet(i, c);
      }
      Increment();
    }

    void Random(uint32_t color, uint16_t steps, uint16_t interval) {
      ActivePattern = RANDOM;
      Interval = interval;
      TotalSteps = steps;
      PixelColor = color;
      Index = 0;
    }

    void RandomUpdate() {
      setPixelColor(random(numPixels()), PixelColor);
      Increment();
    }

    void DoubleRandom(uint32_t color, uint16_t steps, uint16_t interval) {
      ActivePattern = DOUBLE_RANDOM;
      Interval = interval;
      TotalSteps = steps;
      PixelColor = color;
      Index = 0;
    }

    void DoubleRandomUpdate() {
      int i = random(numPixels() / 2); // this saves 4 bytes instead of calling random in the function call of DoubleSet
      DoubleSet(i, PixelColor);
      Increment();
    }

    void Blink(uint32_t color, uint16_t steps, uint16_t interval) {
      ActivePattern = BLINK;
      Interval = interval;
      if (steps % 2 != 0) {
        steps++;
      }
      TotalSteps = steps;
      PixelColor = color;
      Index = 0;
    }

    void BlinkUpdate() {
      uint32_t c;
      if (Index % 2 == 0) {
        c = PixelColor;
      } else {
        c = Color(0, 0, 0);
      }
      ColorSet(c);
      Increment();
    }

    void Dot(uint32_t color, uint16_t steps, uint16_t interval) {
      ActivePattern = DOT;
      Interval = interval;
      TotalSteps = steps;
      PixelColor = color;
      Index = 0;
    }

    void DotUpdate() {
      ColorSet(Color(0, 0, 0));
      show();
      setPixelColor(random(numPixels()), PixelColor);
      Increment();
    }

    void Spinner(uint32_t color, uint16_t spinner_pixels, uint16_t interval) {
      ActivePattern = SPINNER;
      Interval = interval;
      TotalSteps = 32;
      PixelColor = color;
      Index = 0;
      SpinnerPixels = spinner_pixels;
    }

    void SpinnerUpdate() {
      ColorSet(Color(0, 0, 0));
      for (int i = 0; i < numPixels() / 2; i++) {
        if ((Index + i) % SpinnerPixels == 0) {
          DoubleSet(i, PixelColor);
        }
      }
      Increment();
    }

    uint32_t DimColor(uint32_t color) {
      return Color(((color >> 16) & 0xFF) >> 1, ((color >> 8) & 0xFF) >> 1, (color & 0xFF) >> 1);
    }

    uint32_t Wheel(byte WheelPos) {
      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);
      }
    }

    void ColorSet(uint32_t color) {
      for (int i = 0; i < numPixels(); i++) {
        setPixelColor(i, color);
      }
    }

    void DoubleSet(uint16_t i, uint32_t color) {
      setPixelColor(i, color);
      setPixelColor(numPixels() - 1 - i, color);
    }
};

void RingsComplete();

NeoPatterns Rings(32, PIN, NEO_GRB + NEO_KHZ800, &RingsComplete);
uint8_t mode = 0;
uint32_t prev_time;

void setup() {
#ifdef __AVR_ATtiny85__
  if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
  Rings.begin();
  Rings.setBrightness(BRIGHTNESS);
  Rings.RainbowCycle(random(RAINBOW_CYCLE_MIN_INTERVAL, RAINBOW_CYCLE_MAX_INTERVAL + 1));
  prev_time = millis();
}

void loop() {
  Rings.Update();
  /*
     We could store the return of the first millis call in a variable.
     But this routine is fast, so we only loose some milliseconds (if even)
     and we are not that time critical, that the MODE changes extacly after
     MODE_CHANGE_TIME. Calling millis twice, saves us 8 bytes, which is critical
     for the small storage space we have.
  */
  if ((millis() - prev_time) >= MODE_CHANGE_TIME) {
    mode = random(0, 9);
    prev_time = millis();
  }
}

void RingsComplete() {
  uint16_t slow_interval = random(SLOW_INTERVAL_MIN, SLOW_INTERVAL_MAX + 1);
  uint16_t steps = random(STEPS_MIN, STEPS_MAX + 1);
  uint32_t color = Rings.Wheel(random(COLOR_MIN, COLOR_MAX + 1));

  switch (mode) {
    case 0:
      Rings.RainbowCycle(random(RAINBOW_CYCLE_MIN_INTERVAL, RAINBOW_CYCLE_MAX_INTERVAL + 1));
      break;
    case 1:
      Rings.ColorWipe(color, slow_interval);
      break;
    case 2:
      Rings.DoubleColorWipe(color, slow_interval);
      break;
    case 3:
      Rings.Scanner(color, slow_interval);
      break;
    case 4:
      Rings.DoubleScanner(color, slow_interval);
      break;
    case 5:
      Rings.Random(color, steps, slow_interval);
      break;
    case 6:
      Rings.DoubleRandom(color, steps, slow_interval);
      break;
    case 7:
      Rings.Blink(color, steps, random(BLINK_MIN_INTERVAL, BLINK_MAX_INTERVAL + 1));
      break;
    case 8:
      Rings.Dot(color, steps, slow_interval);
      break;
    case 9:
      Rings.Spinner(color, random(SPINNER_PIXELS_MIN, SPINNER_PIXELS_MAX + 1), slow_interval);
      break;
    default:
      break;
  }
}