#include "Arduino.h" #include "Adafruit_NeoPixel.h" #include "BackgroundRingClass.h" #include "WS2812_Definitions.h" BackgroundRingClass::BackgroundRingClass(int led_count, int pin) : Adafruit_NeoPixel(led_count+1, pin, NEO_GRB + NEO_KHZ800) { this->led_count = led_count; this->action = Idle; this->begin(); } void BackgroundRingClass::tick() { switch(this->action) { case Idle: this->tick_idle(); break; case Solid: this->tick_solid(); break; case Pulse: this->tick_pulse(); break; case PulseAndBeep: this->tick_pulse_and_beep(); break; case Spin: this->tick_spin(); break; case Flip: this->tick_flip(); break; case Slowroll: this->tick_slowroll(); break; default: this->action = Idle; } } /* Ring Functions */ void BackgroundRingClass::setColor(unsigned long color, uint8_t brightness, bool show) { this->setBrightness(brightness); for(int i=0; i < this->led_count; i++) { this->setPixelColor(i, color); } if(show) { this->show(); } } void BackgroundRingClass::setRepeating(unsigned long* colors, int elements, int rotation) { this->setBrightness(50); int curcolor = 0; for(int i = 0; i < this->led_count; i++) { this->setPixelColor(i, colors[(i+rotation) % elements]); } this->show(); } ///////////////////////// Idle void BackgroundRingClass::init_idle() { this->action = Idle; this->setColor(BLACK, 255, true); } void BackgroundRingClass::tick_idle() { // noop. Here for consistency } ///////////////////////// Random int BackgroundRingClass::random_event(int copy) { int draw = random(0, 480); // this lets us choose events with weighted probability if(copy >= 0) { // we wish to copy the other one's action draw = copy; } // Christmas Colors if(draw < 50) this->init_pulse(DARKRED, 80, 2000); else if(draw < 100) this->init_pulse(DARKGREEN, 80, 2000); else if(draw < 150) this->init_spin(DARKRED, DARKGREEN); else if(draw < 200) this->init_spin(DARKGREEN, DARKRED); else if(draw < 250) this->init_flip(DARKRED, DARKGREEN); else if(draw < 300) this->init_flip(DARKGREEN, DARKRED); else if(draw < 350) this->init_slowroll(DARKRED, DARKGREEN); else if(draw < 400) this->init_slowroll(DARKGREEN, DARKRED); // random colors else if(draw < 410) this->init_pulse(random(0, 0xFFFFFF), 80, 2000); else if(draw < 420) this->init_pulse(random(0, 0xFFFFFF), 80, 2000); else if(draw < 430) this->init_spin(random(0, 0xFFFFFF), random(0, 0xFFFFFF)); else if(draw < 440) this->init_spin(random(0, 0xFFFFFF), random(0, 0xFFFFFF)); else if(draw < 450) this->init_flip(random(0, 0xFFFFFF), random(0, 0xFFFFFF)); else if(draw < 460) this->init_flip(random(0, 0xFFFFFF), random(0, 0xFFFFFF)); else if(draw < 470) this->init_slowroll(random(0, 0xFFFFFF), random(0, 0xFFFFFF)); else if(draw < 480) this->init_slowroll(random(0, 0xFFFFFF), random(0, 0xFFFFFF)); return draw; } ///////////////////////// Solid void BackgroundRingClass::init_solid(unsigned long color, uint8_t brightness) { this->action = Solid; this->setColor(color, brightness, true); } void BackgroundRingClass::tick_solid() { // noop. Here for consistency } ///////////////////////// Pulse void BackgroundRingClass::init_pulse(unsigned long color, uint8_t maxbrightness, unsigned long ms) { Serial.println("Initializing pulse"); this->action = Pulse; this->pulseinfo.color = color; this->pulseinfo.maxbrightness = maxbrightness; this->pulseinfo.ms = ms * 1000; this->pulseinfo.starttime = micros(); this->pulseinfo.curbrightness = 1; this->pulseinfo.steptime = (ms * 1000) / (2 * (unsigned long)maxbrightness); this->setColor(this->pulseinfo.color, this->pulseinfo.curbrightness, true); // dimmest setting } void BackgroundRingClass::tick_pulse() { unsigned long elapsed = micros() - this->pulseinfo.starttime; int newbrightness; if(elapsed < this->pulseinfo.ms/2) { // increasing newbrightness = (elapsed / this->pulseinfo.steptime) + 1; //Serial.print("Increasing. elapsed="); Serial.print(elapsed); //Serial.print("; steptime="); Serial.print(this->pulseinfo.steptime); //Serial.print("; curbrightness="); Serial.print(this->pulseinfo.curbrightness); //Serial.print("; newbrightenss="); Serial.println(newbrightness); } else if(elapsed < this->pulseinfo.ms) { // decreasing newbrightness = ((this->pulseinfo.ms - elapsed) / this->pulseinfo.steptime) + 1; //Serial.print("Decreasing. elapsed="); Serial.print(elapsed); //Serial.print("; steptime="); Serial.print(this->pulseinfo.steptime); //Serial.print("; curbrightness="); Serial.print(this->pulseinfo.curbrightness); //Serial.print("; newbrightenss="); Serial.println(newbrightness); } else { // done //Serial.print("DONE. elapsed="); Serial.print(elapsed); this->init_idle(); return; } if(newbrightness != this->pulseinfo.curbrightness) { this->pulseinfo.curbrightness = newbrightness; this->setColor(this->pulseinfo.color, this->pulseinfo.curbrightness, true); this->show(); } return; } ///////////////////////// Pulse and Beep // // We can't call show() while beeping because it disabled interrupts, // so we beep at the peak of the pulse. // void BackgroundRingClass::init_pulse_and_beep( unsigned long color, uint8_t maxbrightness, unsigned long ms, int pin, unsigned int frequency, unsigned long duration ) { Serial.println("Initializing pulse and beep"); this->action = PulseAndBeep; this->pulseinfo.color = color; this->pulseinfo.maxbrightness = maxbrightness; this->pulseinfo.ms = ms * 1000; this->pulseinfo.starttime = micros(); this->pulseinfo.curbrightness = 1; this->pulseinfo.steptime = ( (ms - duration) * 1000) / ((2 * (unsigned long)maxbrightness) - 1); this->beepinfo.pin = pin; this->beepinfo.frequency = frequency; this->beepinfo.duration = duration; this->beepinfo.state = Beeping; this->setColor(this->pulseinfo.color, this->pulseinfo.curbrightness, true); // dimmest setting } void BackgroundRingClass::tick_pulse_and_beep() { // What we're doing should be based on time. // Increasing: 0 to (ms - duration)/2)) // Beeping: (ms - duration)/2 to (ms - duration/2)+duration // Decreasing: (ms - duration/2)+duration - ms unsigned long elapsed = micros() - this->pulseinfo.starttime; int newbrightness; if(elapsed < (this->pulseinfo.ms/2 - 1000*this->beepinfo.duration/2)) { // increasing this->beepinfo.state = Increasing; newbrightness = (elapsed / this->pulseinfo.steptime) + 1; //Serial.print("Increasing. elapsed="); Serial.print(elapsed); //Serial.print("; ms="); Serial.print(this->pulseinfo.ms); //Serial.print("; duration="); Serial.print(this->beepinfo.duration); //Serial.print("; steptime="); Serial.print(this->pulseinfo.steptime); //Serial.print("; curbrightness="); Serial.print(this->pulseinfo.curbrightness); //Serial.print("; newbrightenss="); Serial.println(newbrightness); } else if(elapsed < (this->pulseinfo.ms/2 + 1000*this->beepinfo.duration/2)) { if(this->beepinfo.state != Beeping && this->beepinfo.frequency != 0) { tone(this->beepinfo.pin, this->beepinfo.frequency, this->beepinfo.duration); this->beepinfo.state = Beeping; } //Serial.print("Beeping. elapsed="); Serial.print(elapsed); //Serial.print("; steptime="); Serial.print(this->pulseinfo.steptime); //Serial.print("; curbrightness="); Serial.println(this->pulseinfo.curbrightness); return; } else if(elapsed < this->pulseinfo.ms) { // decreasing this->beepinfo.state = Decreasing; //newbrightness = ((this->pulseinfo.ms - this->beepinfo.duration/2) / this->pulseinfo.steptime) + 1; newbrightness = ((this->pulseinfo.ms - elapsed) / this->pulseinfo.steptime) + 1; //Serial.print("Decreasing. elapsed="); Serial.print(elapsed); //Serial.print("; ms="); Serial.print(this->pulseinfo.ms); //Serial.print("; duration="); Serial.print(this->beepinfo.duration); //Serial.print("; steptime="); Serial.print(this->pulseinfo.steptime); //Serial.print("; curbrightness="); Serial.print(this->pulseinfo.curbrightness); //Serial.print("; newbrightenss="); Serial.println(newbrightness); } else { // done //Serial.print("DONE. elapsed="); Serial.print(elapsed); this->init_idle(); return; } if(newbrightness != this->pulseinfo.curbrightness) { this->pulseinfo.curbrightness = newbrightness; this->setColor(this->pulseinfo.color, this->pulseinfo.curbrightness, true); this->show(); } return; } /* void BackgroundRingClass::tick_pulse_and_beep() { int stepspassed = 0; if(this->beepinfo.state == Beeping && (micros() - this->beepinfo.beepstart < 1000*this->beepinfo.duration)) { return; } else if(this->beepinfo.state == Beeping) { Serial.print("Beep Duration was: "); Serial.println((micros() - this->beepinfo.beepstart)/1000); Serial.print("Stopping beeping at t="); Serial.println((micros() - this->beepinfo.truestart)/1000); this->beepinfo.state = Decreasing; this->pulseinfo.starttime = micros() + this->pulseinfo.steptime; } if((micros() - this->pulseinfo.starttime) < this->pulseinfo.steptime) { return; } else { stepspassed = (micros() - this->pulseinfo.starttime)/this->pulseinfo.steptime; } //Serial.print("Taking action at t="); Serial.print(micros() - this->beepinfo.truestart); //Serial.print("; brightness="); Serial.print(this->pulseinfo.curbrightness); //Serial.print("; Steps to take="); Serial.println(stepspassed); this->pulseinfo.starttime = micros(); if(this->beepinfo.state == Increasing && this->pulseinfo.curbrightness == this->pulseinfo.maxbrightness) { this->beepinfo.state = Beeping; this->beepinfo.beepstart = micros(); if(this->beepinfo.frequency != 0) { Serial.print("Beginning beeping at t="); Serial.println((micros() - this->beepinfo.truestart)/1000); tone(this->beepinfo.pin, this->beepinfo.frequency, this->beepinfo.duration); return; } } if(this->beepinfo.state == Increasing) { if(this->pulseinfo.curbrightness < this->pulseinfo.maxbrightness - stepspassed) { this->pulseinfo.curbrightness += stepspassed; } else { this->pulseinfo.curbrightness = this->pulseinfo.maxbrightness; } } else { if(this->pulseinfo.curbrightness > stepspassed) { this->pulseinfo.curbrightness -= stepspassed; } else { this->pulseinfo.curbrightness = 0; } } if(this->pulseinfo.curbrightness == 0) { // We are done Serial.print("Stopping pulse at t="); Serial.println((micros() - this->beepinfo.truestart)/1000); this->init_idle(); } else { //Serial.print("Setting Brightness: "); Serial.println(this->pulseinfo.curbrightness); this->setColor(this->pulseinfo.color, this->pulseinfo.curbrightness, true); this->show(); } } */ ///////////////////////// Spin void BackgroundRingClass::init_spin(unsigned long color1, unsigned long color2, unsigned long ms, unsigned long tickdelay) { this->action = Spin; this->spininfo.color1 = color1; this->spininfo.color2 = color2; this->spininfo.ms = ms * 1000; this->spininfo.tickdelay = tickdelay * 1000; this->spininfo.starttime = micros(); this->spininfo.lasttick = micros() - this->spininfo.tickdelay; this->spininfo.rotation = 0; } void BackgroundRingClass::tick_spin() { if(micros() - this->spininfo.starttime > this->spininfo.ms) { // we're done Serial.println(micros() - this->spininfo.starttime); this->init_idle(); return; } if(micros() - this->spininfo.lasttick > this->spininfo.tickdelay) { // Time to spin this->spininfo.lasttick = micros(); this->spininfo.rotation = (this->spininfo.rotation + 1) % 3; //unsigned long tickcolors[] = { this->spininfo.color1, this->spininfo.color1, this->spininfo.color1, this->spininfo.color2 }; //unsigned long tickcolors[] = { BLACK, this->spininfo.color1, this->spininfo.color2 }; unsigned long tickcolors[] = { BLACK, this->spininfo.color1, this->spininfo.color1, this->spininfo.color2 }; this->setRepeating(tickcolors, 4, this->spininfo.rotation); } } ///////////////////////// Flip void BackgroundRingClass::init_flip(unsigned long color1, unsigned long color2, unsigned long ms, unsigned long tickdelay) { this->action = Flip; this->flipinfo.color1 = color1; this->flipinfo.color2 = color2; this->flipinfo.ms = ms * 1000; this->flipinfo.tickdelay = tickdelay * 1000; this->flipinfo.starttime = micros(); this->flipinfo.lasttick = micros() - this->flipinfo.tickdelay; this->flipinfo.flipper = false; } void BackgroundRingClass::tick_flip() { if(micros() - this->flipinfo.starttime > this->flipinfo.ms) { // we're done Serial.println(micros() - this->flipinfo.starttime); this->init_idle(); return; } if(micros() - this->flipinfo.lasttick > this->flipinfo.tickdelay) { // Time to flip this->flipinfo.lasttick = micros(); unsigned long tickcolors[] = { this->flipinfo.color1, this->flipinfo.color2 }; this->setRepeating(tickcolors, 2, (this->flipinfo.flipper ? 0 : 1)); this->flipinfo.flipper = not(this->flipinfo.flipper); } } ///////////////////////// Slowroll void BackgroundRingClass::init_slowroll(unsigned long color1, unsigned long color2, unsigned long ms, unsigned long tickdelay) { this->action = Slowroll; this->slowrollinfo.color1 = color1; this->slowrollinfo.color2 = color2; this->slowrollinfo.ms = ms * 1000; this->slowrollinfo.tickdelay = tickdelay * 1000; this->slowrollinfo.starttime = micros(); this->slowrollinfo.lasttick = micros() - this->slowrollinfo.tickdelay; this->slowrollinfo.flipper = false; } void BackgroundRingClass::tick_slowroll() { if(micros() - this->slowrollinfo.starttime > this->slowrollinfo.ms) { // we're done Serial.println(micros() - this->slowrollinfo.starttime); this->init_idle(); return; } if(micros() - this->slowrollinfo.lasttick > this->slowrollinfo.tickdelay) { // Time to slowroll this->slowrollinfo.lasttick = micros(); unsigned long tickcolors[] = { this->slowrollinfo.color1, this->slowrollinfo.color2, BLACK }; this->setRepeating(tickcolors, 3, (this->slowrollinfo.flipper ? 0 : 2)); this->slowrollinfo.flipper = not(this->slowrollinfo.flipper); } }