├── Examples ├── NeoEfx_BasicUse │ └── NeoEfx_BasicUse.ino ├── NeoEfx_Example2 │ └── NeoEfx_Example2.ino └── NeoEfx_Subclass │ ├── NeoEfx_Subclass.ino │ ├── NeoSubclassWindow.cpp │ └── NeoSubclassWindow.h ├── LICENSE ├── NeoEffects.h ├── NeoStrip.cpp ├── NeoStrip.h ├── NeoWindow.cpp ├── NeoWindow.h └── README.md /Examples/NeoEfx_BasicUse/NeoEfx_BasicUse.ino: -------------------------------------------------------------------------------- 1 | // Example to show basic use of the NeoEffects library: NeoStrip and NeoWindow classes 2 | // we have four rings wired as a single strand and setup 4 simultaneous effects 3 | // 4 | 5 | #include 6 | #include 7 | 8 | // we are using the smaller Adafruit NeoPixel with 12 leds 9 | // http://www.adafruit.com/products/1643 10 | #define SMALL_NEORING_SIZE 12 11 | 12 | // Strip is connected to Arduino Pin 1 13 | #define STRIP_PIN 1 14 | 15 | // 4 rings on shoulder piece 16 | const int RING_1_START = 0; 17 | const int RING_2_START = (RING_1_START + SMALL_NEORING_SIZE); 18 | const int RING_3_START = (RING_2_START + SMALL_NEORING_SIZE); 19 | const int RING_4_START = (RING_3_START + SMALL_NEORING_SIZE); 20 | const int numRings = 4; 21 | 22 | // Parameter 1 = number of pixels in strip 23 | // Parameter 2 = pin number (most are valid) 24 | // Parameter 3 = pixel type flags, add together as needed: 25 | // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) 26 | // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) 27 | // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) 28 | // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) 29 | NeoStrip strip1 = NeoStrip(SMALL_NEORING_SIZE * numRings, STRIP_PIN, NEO_GRB + NEO_KHZ800); 30 | 31 | NeoWindow ring1 = NeoWindow(&strip1, RING_1_START, SMALL_NEORING_SIZE); 32 | NeoWindow ring2 = NeoWindow(&strip1, RING_2_START, SMALL_NEORING_SIZE); 33 | NeoWindow ring3 = NeoWindow(&strip1, RING_3_START, SMALL_NEORING_SIZE); 34 | NeoWindow ring4 = NeoWindow(&strip1, RING_4_START, SMALL_NEORING_SIZE); 35 | 36 | void setup() { 37 | // use serial line for debugging output 38 | Serial.begin(115200); 39 | delay(500); // delay a bit when we start so we can open arduino serial monitor window 40 | 41 | Serial.println("Starting NeoEffects Test"); 42 | 43 | // start the strip. do this first for all strips 44 | strip1.begin(); 45 | 46 | // NeoPixels can be very bright, and at full power can use lots of power 47 | // longer 'strips' require extra power to run full bright. 48 | // brightness runs 0-255 and scales all colors to match that dark->bright 49 | // strip1.setBrightness(100); 50 | 51 | // first we Blink the whole strip to show app is running 52 | strip1.clearStrip(); 53 | strip1.show(); 54 | delay(1000); 55 | strip1.fillStrip(Adafruit_NeoPixel::Color(255,255,255)); 56 | strip1.show(); 57 | delay(1000); 58 | strip1.clearStrip(); 59 | strip1.show(); 60 | delay(1000); 61 | 62 | // Now set up effects to run on each of 4 rings 63 | ring1.setWipeEfx(strip1.randomColor(),100 ); // wipe on a random color 64 | ring2.setBlinkEfx(strip1.randomColor(), 250, 10); // blink a random color 65 | ring3.setCircleEfx(strip1.randomColor(), 200); // run one pixel across window 66 | ring4.setFadeEfx(0, strip1.randomColor(), 100, ring4.fadeTypeCycle, 0); // fade between two colors 67 | 68 | Serial.println("Setup Done"); 69 | } 70 | 71 | 72 | void loop() { 73 | // Basic NeoEffects loop: 74 | // update time 75 | // check inputs & effectsDone - change behavior as needed 76 | // update each active Window 77 | // show the strips 78 | 79 | // grab the current time using the class method. thus it is only called once, regardless of # windows 80 | NeoWindow::updateTime(); 81 | 82 | // here we might check inputs and EffectDone() to change effects 83 | 84 | // Simple wipe completed? chose another random color 85 | if (ring1.effectDone()) 86 | ring1.setWipeEfx(strip1.randomColor(),100 ); 87 | // completed circle, pick new color 88 | if (ring3.effectDone()) 89 | ring3.setCircleEfx(strip1.randomColor(), 200); 90 | 91 | // now update each Window - does one 'frame' of effect on the window 92 | ring1.updateWindow(); 93 | ring2.updateWindow(); 94 | ring3.updateWindow(); 95 | ring4.updateWindow(); 96 | 97 | // if the strip changed, send commands out to it. 98 | strip1.show(); 99 | 100 | //Serial.print("BottomLoop "); Serial.println(millis()); 101 | // delay(1000); 102 | } 103 | -------------------------------------------------------------------------------- /Examples/NeoEfx_Example2/NeoEfx_Example2.ino: -------------------------------------------------------------------------------- 1 | // somewhat more elaborate example of the NeoStrip and NeoWindow classes 2 | // using an array of Windows to simplify updates, 3 | // some more complex actions on Effects Done 4 | 5 | #include 6 | #include 7 | 8 | // we are using the smaller Adafruit NeoPixel with 12 leds 9 | // http://www.adafruit.com/products/1643 10 | #define SMALL_NEORING_SIZE 12 11 | 12 | // Pins for strips connected via OctoWS2811 13 | // these are assigned to odd ordering of pins for reasons internal to Octo library 14 | // although we are not using the library, we may use the Octo interface board 15 | // which provides access to these pins via 2 RJ45 connectors. 16 | //#define STRIP_1_PIN 2 17 | // strip moved to pin 1 for shoulder piece 18 | #define STRIP_1_PIN 1 19 | 20 | // 4 rings on shoulder piece 21 | const int RING_1_START = 0; 22 | const int RING_2_START = (RING_1_START + SMALL_NEORING_SIZE); 23 | const int RING_3_START = (RING_2_START + SMALL_NEORING_SIZE); 24 | const int RING_4_START = (RING_3_START + SMALL_NEORING_SIZE); 25 | const int numRings = 4; 26 | 27 | // Parameter 1 = number of pixels in strip 28 | // Parameter 2 = pin number (most are valid) 29 | // Parameter 3 = pixel type flags, add together as needed: 30 | // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) 31 | // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) 32 | // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) 33 | // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) 34 | NeoStrip strip1 = NeoStrip(SMALL_NEORING_SIZE * numRings, STRIP_1_PIN, NEO_GRB + NEO_KHZ800); 35 | 36 | NeoWindow ring1 = NeoWindow(&strip1, RING_1_START, SMALL_NEORING_SIZE); 37 | NeoWindow ring2 = NeoWindow(&strip1, RING_2_START, SMALL_NEORING_SIZE); 38 | NeoWindow ring3 = NeoWindow(&strip1, RING_3_START, SMALL_NEORING_SIZE); 39 | NeoWindow ring4 = NeoWindow(&strip1, RING_4_START, SMALL_NEORING_SIZE); 40 | 41 | // we create an array of ings (windows) to make updating simpler 42 | NeoWindow *rings[] = {&ring1, &ring2, &ring3, &ring4 }; 43 | 44 | const uint32_t aNicePurple = strip1.Color(128, 0, 50); 45 | 46 | void setup() { 47 | // use serial line for debugging output 48 | Serial.begin(115200); 49 | delay(500); // delay a bit when we start so we can open arduino serial monitor window 50 | 51 | Serial.println("Starting NeoEffects Example2"); 52 | 53 | // start the strip. do this first for all strips 54 | strip1.begin(); 55 | 56 | // NeoPixels can be very bright, and at full power can use lots of power 57 | // longer 'strips' require extra power to run full bright. 58 | // brightness runs 0-255 and scales all colors to match that dark->bright 59 | // strip1.setBrightness(100); 60 | 61 | // first we Blink the whole strip to show app is running 62 | strip1.clearStrip(); 63 | strip1.show(); 64 | delay(1000); 65 | strip1.fillStrip(Adafruit_NeoPixel::Color(255,255,255)); 66 | strip1.show(); 67 | delay(1000); 68 | strip1.clearStrip(); 69 | strip1.show(); 70 | delay(1000); 71 | 72 | // put your setup code here, to run once: 73 | ring1.setWipeEfx(strip1.randomColor(),100 ); // wipe on a random color 74 | 75 | ring2.setWipeEfx(aNicePurple,100 ); 76 | ring3.setBlinkEfx(aNicePurple, 250, 10); 77 | 78 | ring4.setCircleEfx(strip1.randomColor(), 200); 79 | 80 | Serial.println("Setup Done"); 81 | } 82 | 83 | // Ring 2 will have two states and implement a wipe on/wipe off effect 84 | int ring2State = false; 85 | // Ring 3 has three states 86 | int ring3State = 0; 87 | 88 | void loop() { 89 | 90 | // grab the current time in class method 91 | NeoWindow::updateTime(); 92 | 93 | // check all inputs and update Effects per Window, etc 94 | // ring1: wipe with random color 95 | if (ring1.effectDone()) 96 | ring1.setWipeEfx(strip1.randomColor(),100 ); 97 | 98 | // two states: wipe on purple, wipe on black 99 | if (ring2.effectDone()){ 100 | if (ring2State) 101 | { 102 | // wipe with black 103 | ring2.setWipeEfx(0,100 ); 104 | ring2State = false; 105 | } else { 106 | // wipe with purple 107 | ring2.setWipeEfx(aNicePurple,100 ); 108 | ring2State = true; 109 | } 110 | } 111 | 112 | // 3rd ring has 3 states: effectively On/Off and blinking 113 | if (ring3.effectDone()) { 114 | switch (ring3State) { 115 | case 0: 116 | ring3.fillColor(aNicePurple); 117 | ring3.setHoldEfx(5000); 118 | ring3State = 1; 119 | break; 120 | case 1: 121 | ring3.fillBlack(); 122 | ring3.setHoldEfx(5000); 123 | ring3State = 2; 124 | break; 125 | case 2: 126 | default: 127 | ring3.setBlinkEfx(aNicePurple, 250, 10); 128 | ring3State = 0; 129 | } 130 | } 131 | // 4th ring, switch to new color 132 | if (ring4.effectDone()) 133 | ring4.setCircleEfx(strip1.randomColor(), 200); 134 | 135 | // now update each Window, using the array 136 | for (int i=0; i< numRings;i++) 137 | { 138 | rings[i]->updateWindow(); 139 | } 140 | 141 | // if the strip changed, send commands out to it. 142 | strip1.show(); 143 | 144 | //Serial.print("BottomLoop "); Serial.println(millis()); 145 | // delay(1000); 146 | } 147 | -------------------------------------------------------------------------------- /Examples/NeoEfx_Subclass/NeoEfx_Subclass.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * NeoEfx_Subclass - example showing how to create a subclass of NeoWindow to add new Effect 3 | * editor notes: while developing this, changes cant be saved back into the live 4 | * Examples folder. So save to regular area and then copy back to Examples 5 | */ 6 | 7 | #include 8 | #include "NeoEffects.h" 9 | #include "NeoSubclassWindow.h" 10 | 11 | ////////////////////////////////////////// 12 | #define NEORING_SIZE 16 13 | 14 | #define STRIP_1_PIN 2 15 | 16 | const int RING_1_START = 0; 17 | const int RING_2_START = (RING_1_START + NEORING_SIZE); 18 | const int RING_3_START = (RING_2_START + NEORING_SIZE); 19 | const int numRings = 3; 20 | 21 | // Parameter 1 = number of pixels in strip 22 | // Parameter 2 = pin number (most are valid) 23 | // Parameter 3 = pixel type flags, add together as needed: 24 | // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) 25 | // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) 26 | // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) 27 | // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) 28 | 29 | NeoStrip strip1 = NeoStrip(NEORING_SIZE * numRings, STRIP_1_PIN, NEO_GRB + NEO_KHZ800); 30 | 31 | // ring1 & ring2 use subclass ring3 is same as BasicUse example 32 | NeoSubclassWindow ring1 = NeoSubclassWindow(&strip1, RING_1_START, NEORING_SIZE); 33 | NeoSubclassWindow ring2 = NeoSubclassWindow(&strip1, RING_2_START, NEORING_SIZE); 34 | NeoWindow ring3 = NeoWindow(&strip1, RING_3_START, NEORING_SIZE); 35 | 36 | const uint32_t aNicePurple = strip1.Color(128, 0, 50); 37 | 38 | ////////////////////////////////////////// 39 | void setup() { 40 | 41 | // use serial line for debugging output 42 | Serial.begin(115200); 43 | delay(500); // delay a bit when we start so we can open arduino serial monitor window 44 | 45 | Serial.println("Starting NeoEffects Subclass Rainbow Example"); 46 | 47 | // start the strip. do this first for all strips 48 | strip1.begin(); 49 | 50 | // NeoPixels can be very bright, and at full power can use lots of power 51 | // longer 'strips' require extra power to run full bright. 52 | // brightness runs 0-255 and scales all colors to match that dark->bright 53 | // strip1.setBrightness(100); 54 | 55 | blinkWholeStrip(); 56 | 57 | ring1.setRainbowEfx( 100, 0 ); 58 | ring2.setWipeEfx(strip1.randomColor(),100 ); // wipe on a random color 59 | ring3.setFadeEfx(0, aNicePurple, 100, ring1.fadeTypeCycle, 0); // fade between two colors 60 | Serial.println("Begin Loop"); 61 | } 62 | 63 | int stateOne = 0; // update to change ring1 effects 64 | int stateTwo = 0; 65 | 66 | void loop() { 67 | // grab the current time in class method 68 | NeoWindow::updateTime(); 69 | 70 | if (ring1.effectDone()) { 71 | if (stateOne == 0) { 72 | ring1.setRainbowEfx( 100, 1 ); 73 | stateOne = 1; 74 | } else { 75 | ring1.setRainbowEfx( 100, 0 ); 76 | stateOne = 0; 77 | } 78 | } 79 | 80 | // ring2 state machine 81 | if (ring2.effectDone()) { 82 | stateTwo++; 83 | Serial.print("Ring2 state:");Serial.print(stateTwo); 84 | switch (stateTwo) { 85 | case 1: 86 | Serial.println(" Sparkle"); 87 | ring2.setSparkleEfx(strip1.randomColor(), 50, 50, 100); 88 | break; 89 | case 2: 90 | Serial.println(" Fade"); 91 | ring2.setFadeEfx(0, strip1.randomColor(), 10, ring1.fadeTypeCycle, 0); // fade between two colors 92 | break; 93 | case 3: 94 | Serial.println(" Circle"); 95 | ring2.setCircleEfx(strip1.randomColor(), 200); 96 | break; 97 | case 4: 98 | Serial.println(" Blink"); 99 | ring2.setBlinkEfx(aNicePurple, 250, 10); 100 | break; 101 | case 5: 102 | Serial.println(" MultiSparkle"); 103 | ring2.setMultiSparkleEfx(aNicePurple, 250, 100,NEORING_SIZE/4,20); 104 | break; 105 | default: 106 | Serial.println(" WipeEfx"); 107 | stateTwo = 0; 108 | ring2.setWipeEfx(strip1.randomColor(),100 ); 109 | } 110 | } 111 | // now update each Window - does one 'frame' of effect on the window 112 | ring1.updateWindow(); 113 | ring2.updateWindow(); 114 | ring3.updateWindow(); 115 | 116 | strip1.show(); 117 | } 118 | 119 | 120 | void blinkWholeStrip(void) 121 | { 122 | strip1.clearStrip(); 123 | strip1.show(); 124 | delay(1000); 125 | strip1.fillStrip(aNicePurple); 126 | strip1.show(); 127 | delay(1000); 128 | strip1.clearStrip(); 129 | strip1.show(); 130 | delay(1000); 131 | } 132 | 133 | -------------------------------------------------------------------------------- /Examples/NeoEfx_Subclass/NeoSubclassWindow.cpp: -------------------------------------------------------------------------------- 1 | // NeoSubclassWindow - a subclass of NeoWindow to add rainbow efx 2 | // yes it is similar to RainbowEffect in NeoWindow, but this shows subclassing 3 | // effect is taken from the Adafruit_NeoPixel Library's strandtest example 4 | // type 0 = window shows myPixelCount portion of wheel each update, thru all 255 colors 5 | // type 1 = evenly distributes wheel across N pixels in window (full rainbow in window) 6 | 7 | #include "NeoSubclassWindow.h" 8 | 9 | NeoSubclassWindow::NeoSubclassWindow(NeoStrip *strip, int startPixel, int len) 10 | : NeoWindow(strip, startPixel, len) 11 | { 12 | 13 | } 14 | 15 | void NeoSubclassWindow:: setNewEffect(uint16_t waitTime, int type) 16 | { 17 | // members common to all effects 18 | setNoEfx();// reset counters 19 | effectDelay = waitTime; 20 | // effect specfic members 21 | curColor = 0; 22 | rainbowType = type; 23 | 24 | // and set the update function - magic of function poiners 25 | curUpdateFunc = (NeoWindowUpdateFunc) &NeoSubclassWindow::NewEffectUpdate; 26 | } 27 | 28 | void NeoSubclassWindow::NewEffectUpdate(void) 29 | { 30 | // put a color in each pixel of window, depending on type 31 | for (int i=0; i < myPixelCount; i++) 32 | { 33 | // colorWheel has 255 colors, from Adafruit NeoPixel strandtest example 34 | if (rainbowType == 0) { 35 | myStrip->setPixelColor(i+myStartPixel, NeoStrip::colorWheel((i+curColor) & 255)); 36 | } else { 37 | myStrip->setPixelColor(i+myStartPixel, NeoStrip::colorWheel(((i*256/myPixelCount)+curColor) & 255)); 38 | } 39 | } 40 | 41 | curColor++; 42 | if (curColor > 255) 43 | { 44 | // reached end of colors, mark effect done 45 | effectCount++; 46 | efxDone = true; 47 | // and set color index back to start so we can keep cycling 48 | curColor = 0; 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Examples/NeoEfx_Subclass/NeoSubclassWindow.h: -------------------------------------------------------------------------------- 1 | // NeoSubclassWindow - a subclass of NeoWindow to add rainbow efx 2 | // effect is taken from the Adafruit_NeoPixel Library's strandtest example 3 | #include "NeoEffects.h" 4 | #include "NeoWindow.h" 5 | 6 | class NeoSubclassWindow : public NeoWindow 7 | { 8 | public: 9 | NeoSubclassWindow(NeoStrip *strip, int startPixel, int len); 10 | 11 | void setNewEffect(uint16_t wait, int type); // type 0 or 1; 1 evenly distributes color 12 | private: 13 | void NewEffectUpdate(void); 14 | int curColor; 15 | int rainbowType; 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /NeoEffects.h: -------------------------------------------------------------------------------- 1 | /** @file NeoWindow.h 2 | * @brief NeoEffects implements concurrent effects on NeoPixel devices 3 | * NeoEffects provides multiple simultaneous lighting pattern effects 4 | * on a NeoPixel (rgb led strip using ws2812) 5 | * NeoPixel examples generally use delay() which precludes simultaneous effects 6 | * this library two classes: 7 | * NeoStrip provides an abstraction for a daisy chain of NeoPixels, 8 | * allowing multiple effects to share memory buffer and 9 | * write only once per loop(), if needed 10 | * NeoWindow defines a window (range of pixels) within a strip 11 | * on which an effect will be produced 12 | * windows can be distinct or overlap 13 | * a base set of effect functions is included in the library 14 | * additional effects can be implemented via subclassing NeoWindow 15 | * CAVEAT: latest NeoPixel can support RGBW strips. This library does NOT. 16 | */ 17 | 18 | #ifndef NEOEFFECTS_LIBRARY 19 | #define NEOEFFECTS_LIBRARY 20 | 21 | #if ARDUINO >= 100 22 | #include 23 | #else 24 | #include 25 | #include 26 | #endif 27 | 28 | // We are based on the Adafruit library: 29 | // https://github.com/adafruit/Adafruit_NeoPixel 30 | #include 31 | 32 | // we add two classes in these headers 33 | #include 34 | #include 35 | 36 | #endif 37 | 38 | -------------------------------------------------------------------------------- /NeoStrip.cpp: -------------------------------------------------------------------------------- 1 | // NeoStrip.cpp 2 | // a wrapper/dervied class of Adafruit_NeoPixel to add some functionality 3 | // most everything passes on to the parent class 4 | 5 | #include 6 | #include "NeoStrip.h" 7 | 8 | 9 | int NeoStrip::s_nIDGenerator = 1; 10 | const uint32_t NeoStrip::White = Adafruit_NeoPixel::Color(255,255,255); 11 | 12 | // wrapper on Adafruit_NeoPixel constructor 13 | NeoStrip::NeoStrip(uint16_t n, uint8_t p, uint8_t t) 14 | : Adafruit_NeoPixel(n, p, t) 15 | { 16 | stripChanged = false; 17 | myId = s_nIDGenerator++; 18 | // allocate and initialize array of active flags 19 | // have this at Strip level vs Window to reduce #dynamic memory alloc 20 | pixelActive = new boolean[n]; 21 | for (int i=0; i 19 | 20 | class NeoStrip: public Adafruit_NeoPixel { 21 | private: 22 | boolean stripChanged; /*!< marked TRUE by any effect that changes a pixel */ 23 | static int s_nIDGenerator; /*! class level counter for next instance id */ 24 | int myId; /*!< id of this strip; autogenerated by constructor */ 25 | boolean *pixelActive; /*!< array of booleans to define if each pixel is in use by Effects */ 26 | 27 | public: 28 | 29 | NeoStrip(uint16_t n, uint8_t p=6, uint8_t t=NEO_GRB + NEO_KHZ800); 30 | 31 | void setStripChanged(); /*!< marks the strip as Changed */ 32 | void clearStripChanged(); /*!< clears changed flag; strip shown only if changed */ 33 | boolean getStripChanged(); /*!< access internal flag */ 34 | 35 | // some simple functions to effect whole strip 36 | void clearStrip(); /*!< clears whole strip to black */ 37 | void fillStrip(uint32_t c); /*!< fills whole strip with Adafruit_NeoPixel::Color */ 38 | 39 | void printId(); /*!< uses Serial.println to emit strip number */ 40 | 41 | void show(void); /*!< if strip changed, invoke parent show, and clear stripChanged */ 42 | 43 | 44 | ////// 45 | /** 46 | * Active Pixel booleans can be used by NeoWindows to determine if a particular pixel 47 | * is active or not at any time. Useful for sparkles, random fades, etc. 48 | */ 49 | void clearActive(); /*!< clears the active pixel array */ 50 | void setPixelActive(int idx); /*!< sets active bit for given pixel index */ 51 | void setPixelInactive(int idx); /*!< clears active bit for given pixel index */ 52 | boolean isPixelActive(int idx); /*!< returns whether current pixel is active */ 53 | 54 | ////// 55 | // helper function to create random Color (unit32_t of r, g,b) 56 | /** 57 | * helper functions dealing with Adafruit_NeoPixel::Color (32 bit color) 58 | */ 59 | static uint32_t randomColor(void) { return Adafruit_NeoPixel::Color(random(0,255),random(0,255),random(0,255));} 60 | static uint32_t randomWheelColor(void); 61 | static uint32_t randomColor(uint32_t c1, uint32_t c2); 62 | static uint8_t getRed(uint32_t c) { return (uint8_t)(c >> 16);} 63 | static uint8_t getGreen(uint32_t c) { return (uint8_t)(c >> 8);} 64 | static uint8_t getBlue(uint32_t c) { return (uint8_t)c;} 65 | 66 | static const uint32_t White; /*!< quick common reference for full white color */ 67 | static uint32_t colorWheel(byte WheelPos); /*!< colorWheel defines 255 colors of full intensity */ 68 | 69 | }; 70 | 71 | #endif // NEOSTRIP 72 | -------------------------------------------------------------------------------- /NeoWindow.cpp: -------------------------------------------------------------------------------- 1 | // NeoWindow 2 | /** @file NeoWindow.cpp 3 | @brief Implements the NeoWindow class of NeoEfx library - providing concurrent effects on NeoPixels 4 | @author jerry isdale 5 | */ 6 | 7 | #include "NeoStrip.h" 8 | #include "NeoWindow.h" 9 | 10 | ////// 11 | // to invoke the member function pointer... 12 | //#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) 13 | 14 | // Class Variable definitions: 15 | 16 | uint32_t NeoWindow::currTime = 0; // current Millis 17 | int NeoWindow::s_nIDGenerator = 1; 18 | 19 | ///////////////// 20 | // Constructor 21 | NeoWindow::NeoWindow(NeoStrip *strip, int startPixel, int len) 22 | { 23 | myId = s_nIDGenerator++; 24 | myStrip = strip; 25 | myStartPixel = startPixel; 26 | myPixelCount = len; 27 | myEndPixel = myStartPixel + myPixelCount-1; 28 | 29 | setNoEfx(); // this does rest of setup 30 | } 31 | 32 | void NeoWindow::printId(void) 33 | { 34 | Serial.print("NeoWindow ");Serial.print(myId); Serial.print(" "); 35 | } 36 | 37 | void NeoWindow::printData(void) 38 | { 39 | printId(); 40 | Serial.print(" myStartPixel: ");Serial.println(myStartPixel); 41 | Serial.print(" myPixelCount: ");Serial.println(myPixelCount); 42 | Serial.print(" myEndPixel: ");Serial.println(myEndPixel); 43 | Serial.print(" efxDone: ");Serial.println(efxDone); 44 | Serial.print(" effectDelay: ");Serial.println(effectDelay); 45 | // Serial.print(" updateFunc: ");Serial.println((void *)curUpdateFunc); 46 | 47 | } 48 | 49 | void NeoWindow::updateWindow(void) 50 | { 51 | if (!curUpdateFunc) { 52 | // printId(); Serial.println(" No updateFunc"); 53 | return; // no effect defined. quick return 54 | } 55 | 56 | // determine if the current Effect time has passed 57 | 58 | if (NeoWindow::currTime - lastTime < effectDelay) { 59 | // printId(); Serial.println(" Not yet time"); 60 | return; 61 | } 62 | lastTime = NeoWindow::currTime; 63 | 64 | // printId(); Serial.println(" invoke current effect function update"); 65 | // invoke current effect function update 66 | (this->*curUpdateFunc)(); 67 | 68 | myStrip->setStripChanged(); // mark the strip changed 69 | } 70 | 71 | void NeoWindow::fillColor(uint32_t color) 72 | { 73 | 74 | for (int i=myStartPixel; i <= myEndPixel; i++) 75 | myStrip->setPixelColor(i, color); //set rest of window to black 76 | 77 | myStrip->setStripChanged(); // mark the strip changed 78 | 79 | } 80 | 81 | void NeoWindow::fillBlack() 82 | { 83 | fillColor(0); 84 | } 85 | 86 | //////////////////////////////// 87 | // Effects here 88 | void NeoWindow::setNoEfx() 89 | { 90 | efxDone = false; 91 | effectDelay = 0; 92 | curUpdateFunc = NULL; 93 | effectCount = 0; 94 | lastTime = 0; 95 | } 96 | 97 | void NeoWindow::setHoldEfx(int delayTime) 98 | { 99 | // printId(); Serial.println(" set to use hold effect"); 100 | setNoEfx(); 101 | effectDelay = delayTime; 102 | curUpdateFunc = &NeoWindow::holdUpdateEfx; 103 | } 104 | 105 | void NeoWindow::holdUpdateEfx(void) 106 | { 107 | // once we are called the hold time has passed so mark us as done 108 | efxDone = true; 109 | effectCount++; 110 | } 111 | 112 | /////////////// 113 | void NeoWindow::setCircleEfx(uint32_t color, uint32_t delayTime) 114 | { 115 | // printId(); Serial.println(" set to use circle effect"); 116 | setNoEfx(); // reset values 117 | effectDelay = delayTime; 118 | curUpdateFunc = &NeoWindow::circleUpdateEfx; 119 | 120 | // starting a Circle Effect using color and time 121 | circle_color = color; 122 | circle_cursor = myStartPixel; 123 | 124 | // setup the initial frame 125 | myStrip->setPixelColor(circle_cursor, circle_color); 126 | for (int i=circle_cursor+1; i< myEndPixel; i++) 127 | myStrip->setPixelColor(i, 0); //set rest of window to black 128 | 129 | myStrip->setStripChanged(); // mark the strip changed 130 | } 131 | 132 | void NeoWindow::circleUpdateEfx(void) 133 | { 134 | // we assume the update function has determined if it is time to call me 135 | 136 | // printData(); 137 | // Serial.println("Updating Circle Effect"); 138 | // Serial.print(" circle_cursor: ");Serial.println(circle_cursor); 139 | 140 | // circle moves a single pixel of circle_color around the virtual circle of the window 141 | // clear the currentPixel 142 | myStrip->setPixelColor(circle_cursor, 0); 143 | circle_cursor++; 144 | if (circle_cursor > myEndPixel) { 145 | circle_cursor = myStartPixel; 146 | efxDone = true; // if we dont check, it just continues 147 | effectCount++; 148 | // Serial.println(" wrapped circle"); 149 | } 150 | myStrip->setPixelColor(circle_cursor, circle_color); 151 | } 152 | 153 | void NeoWindow::setWipeEfx(uint32_t color, uint32_t delayTime) // Wipe color once around window 154 | { 155 | // printId(); Serial.println(" set to use wipe effect"); 156 | setNoEfx(); // reset values 157 | 158 | effectDelay = delayTime; 159 | curUpdateFunc = &NeoWindow::wipeUpdateEfx; 160 | 161 | // starting a Circle Effect using color and time 162 | wipe_color = color; 163 | wipe_cursor = myStartPixel; 164 | 165 | myStrip->setPixelColor(wipe_cursor, wipe_color); 166 | // dont change rest of colors 167 | // for (int i=circle_cursor+1; i< myEndPixel; i++) 168 | // myStrip->setPixelColor(i, 0); //set rest of window to black 169 | 170 | myStrip->setStripChanged(); // mark the strip changed 171 | } 172 | 173 | void NeoWindow::wipeUpdateEfx(void) 174 | { 175 | // wipe fills the window one pixel each update, then sets Done 176 | 177 | myStrip->setPixelColor(wipe_cursor, wipe_color); 178 | wipe_cursor++; 179 | 180 | if (wipe_cursor > myEndPixel) { 181 | efxDone = true; 182 | wipe_cursor = myStartPixel; 183 | 184 | } 185 | } 186 | 187 | //static uint32_t randomColor(uint32_t fromColor, uint32_t toColor) 188 | //{ 189 | // uint8_t fromR, toR; 190 | // uint8_t fromG, toG; 191 | // uint8_t fromB, toB; 192 | // fromR = NeoStrip::getRed(fromColor); 193 | // fromG = NeoStrip::getGreen(fromColor); 194 | // fromB = NeoStrip::getBlue(fromColor); 195 | // 196 | // toR = NeoStrip::getRed(toColor); 197 | // toG = NeoStrip::getGreen(toColor); 198 | // toB = NeoStrip::getBlue(toColor); 199 | // 200 | // return Adafruit_NeoPixel::Color(random(fromR,toR), random(fromG,toG),random(fromB,toB)); 201 | //} 202 | 203 | void NeoWindow::setRandomWipeEfx(uint32_t color1, uint32_t color2, uint32_t delayTime) // Wipe color once around window 204 | { 205 | // printId(); Serial.println(" set to use wipe effect"); 206 | setNoEfx(); // reset values 207 | 208 | effectDelay = delayTime; 209 | curUpdateFunc = &NeoWindow::randomWipeUpdateEfx; 210 | 211 | // starting a Circle Effect using color and time 212 | randomWipeColor1 = color1; 213 | randomWipeColor2 = color2; 214 | wipe_color = NeoStrip::randomColor(color1, color2); 215 | wipe_cursor = myStartPixel; 216 | 217 | myStrip->setPixelColor(wipe_cursor, wipe_color); 218 | // dont change rest of colors 219 | // for (int i=circle_cursor+1; i< myEndPixel; i++) 220 | // myStrip->setPixelColor(i, 0); //set rest of window to black 221 | 222 | myStrip->setStripChanged(); // mark the strip changed 223 | } 224 | 225 | 226 | void NeoWindow::randomWipeUpdateEfx(void) 227 | { 228 | // wipe fills the window one pixel each update, then sets Done 229 | 230 | myStrip->setPixelColor(wipe_cursor, wipe_color); 231 | wipe_cursor++; 232 | 233 | if (wipe_cursor > myEndPixel) { 234 | wipe_cursor = myStartPixel; 235 | wipe_color = NeoStrip::randomColor(randomWipeColor1, randomWipeColor2); 236 | efxDone = true; 237 | } 238 | } 239 | 240 | void NeoWindow::setBlinkEfx(uint32_t color, uint32_t delayTime, int count) 241 | { 242 | // set the instance stuff 243 | setNoEfx(); // reset values 244 | 245 | effectDelay = delayTime; 246 | curUpdateFunc = &NeoWindow::blinkUpdateEfx; 247 | 248 | // effect specific stuff 249 | blink_color = color; 250 | blink_state = false; 251 | blink_maxCount = count; 252 | effectCount++; 253 | 254 | blinkUpdateEfx(); 255 | 256 | } 257 | 258 | void NeoWindow::blinkUpdateEfx() 259 | { 260 | if (blink_state) 261 | { 262 | fillColor(blink_color); 263 | blink_state = false; 264 | } else { 265 | fillBlack(); 266 | blink_state = true; 267 | effectCount++; 268 | } 269 | 270 | if (blink_maxCount > 0 && effectCount > blink_maxCount) 271 | efxDone = true; 272 | } 273 | 274 | // couple flags for the state 275 | static const int sparkleFLASH = 1; 276 | static const int sparkleTWEEN = 0; 277 | 278 | void NeoWindow::setSparkleEfx(uint32_t color, int flashTime, int tweenTime, int count) 279 | { 280 | setNoEfx(); // reset values 281 | 282 | effectDelay = flashTime; 283 | curUpdateFunc = &NeoWindow::sparkleEfxUpdate; 284 | 285 | sparkleColor = color; 286 | sparkleFlashTime = flashTime; 287 | sparkleTweenTime = tweenTime; 288 | sparkleMaxCount = count; 289 | sparkleState = sparkleFLASH; 290 | sparkleCurPixel= random(myStartPixel, myEndPixel); 291 | fillBlack(); // clear it 292 | 293 | // now turn on just that pixel 294 | myStrip->setPixelColor(sparkleCurPixel,sparkleColor); 295 | myStrip->setStripChanged(); // mark the strip changed 296 | } 297 | 298 | void NeoWindow::sparkleEfxUpdate(void) 299 | { 300 | if (sparkleState == sparkleFLASH) { 301 | // it is on, turn off and set to sparkleTWEEN 302 | myStrip->setPixelColor(sparkleCurPixel, 0); 303 | sparkleState = sparkleTWEEN; 304 | effectDelay = sparkleTweenTime; 305 | } else { 306 | // it is in TWEEN, so turn to FLASH: select new pixel and turn it on 307 | sparkleCurPixel= random(myStartPixel, myEndPixel); 308 | myStrip->setPixelColor(sparkleCurPixel, sparkleColor); 309 | sparkleState = sparkleFLASH; 310 | effectDelay = sparkleFlashTime; 311 | } 312 | 313 | effectCount++; 314 | if (sparkleMaxCount > 0 && effectCount > sparkleMaxCount) 315 | { 316 | efxDone = true; 317 | } 318 | } 319 | //////////////////////////////// 320 | void NeoWindow::clearActive(void) 321 | { 322 | for (int i= myStartPixel; i <= myEndPixel; i++) 323 | myStrip->setPixelInactive(i); 324 | } 325 | 326 | /*! \brief setMultiSparkEfx: N randomly selected pixels in window flash on/off in selected color 327 | * flashTime is time pixels are ON; Tween Time is time the are off 328 | * when tweenTime is up, new pixels are chosen 329 | * when there have been count flashes, the effect is set to Done. 330 | * 331 | */ 332 | void NeoWindow::setMultiSparkleEfx(uint32_t color, int flashTime, int tweenTime, int numActive, int count) 333 | { 334 | setNoEfx(); // reset values 335 | 336 | effectDelay = flashTime; 337 | curUpdateFunc = &NeoWindow::multiSparkleEfxUpdate; 338 | 339 | multiSparkleColor = color; 340 | multiSparkleFlashTime = flashTime; 341 | multiSparkleTweenTime = tweenTime; 342 | multiSparkleMaxCount = count; 343 | multiSparkleNumActive = numActive; 344 | multiSparkleState = sparkleFLASH; 345 | 346 | if (numActive <= 0 || numActive > myPixelCount) 347 | numActive = myPixelCount; 348 | multiSparkleNumActive = numActive; 349 | 350 | 351 | clearActive(); 352 | fillBlack(); // clear it 353 | 354 | // Select N pixels, make them Active and set them to the color 355 | multiSparkleEfxSelectPixels(); 356 | 357 | myStrip->setStripChanged(); // mark the strip changed 358 | } 359 | 360 | void NeoWindow::multiSparkleEfxSelectPixels() 361 | { 362 | // Serial.println("multiSparkleEfxSelectPixels"); 363 | 364 | if (multiSparkleNumActive == 0 || multiSparkleNumActive == myPixelCount) { 365 | // do all pixels in window; skip random choice so it runs fast 366 | for (int idx=myStartPixel; idx<= myEndPixel; idx++) { 367 | myStrip->setPixelActive(idx); 368 | myStrip->setPixelColor(idx,multiSparkleColor); 369 | } 370 | } else { 371 | for (int i = 0; i < multiSparkleNumActive; i++){ 372 | int idx = random(myStartPixel,myEndPixel); 373 | while (myStrip->isPixelActive(idx)) 374 | // if it is already active, pick another; note this could take a while to fill large number 375 | idx = random(myStartPixel,myEndPixel); 376 | // Serial.print("Set Pixel Active: "); Serial.print(idx);Serial.println(); 377 | myStrip->setPixelActive(idx); 378 | myStrip->setPixelColor(idx,multiSparkleColor); 379 | } 380 | } 381 | } 382 | 383 | void NeoWindow::multiSparkleEfxUpdate(void) 384 | { 385 | // printId(); Serial.print("multiSparkle Update state:"); Serial.print(multiSparkleState); Serial.println(); 386 | 387 | if (multiSparkleState == sparkleFLASH) { 388 | // Serial.println(" clear and set to TWEEN"); 389 | // it is on, turn off and set to multiSparkleTWEEN 390 | for (int idx = myStartPixel; idx <= myEndPixel;idx++) { 391 | if (myStrip->isPixelActive(idx)) 392 | myStrip->setPixelColor(idx, 0); 393 | } 394 | clearActive(); 395 | multiSparkleState = sparkleTWEEN; 396 | effectDelay = multiSparkleTweenTime; 397 | } else { 398 | // it is in TWEEN, so turn to FLASH: select new pixels 399 | multiSparkleEfxSelectPixels(); 400 | 401 | multiSparkleState = sparkleFLASH; 402 | effectDelay = multiSparkleFlashTime; 403 | } 404 | 405 | effectCount++; 406 | if (multiSparkleMaxCount > 0 && effectCount > multiSparkleMaxCount) 407 | { 408 | efxDone = true; 409 | } 410 | 411 | // Serial.println("Bottom sparkle update"); 412 | // printData(); 413 | // delay(2000); 414 | 415 | } 416 | 417 | //////////////////// 418 | // Fade = linear fade between two colors, cycle makes if fade back 419 | // linear fade in rgb space looks odd if not to black 420 | // better to fade in hsv or hcl 421 | // http://www.alanzucconi.com/2016/01/06/colour-interpolation/ 422 | // but compute is expensive. might be better to precompute 423 | // 424 | static const int fadeFadeIn = 0; 425 | static const int fadeFadeOut = 1; 426 | 427 | void NeoWindow::setFadeEfx(uint32_t fromColor, uint32_t toColor, int fadeTime, int type, int count) 428 | { 429 | setNoEfx(); // reset values 430 | 431 | effectDelay = fadeTime; 432 | curUpdateFunc = &NeoWindow::fadeEfxUpdate; 433 | 434 | fadeFromColor = fromColor; 435 | fadeToColor = toColor; 436 | fadeType = type; 437 | fadeMaxCount = count; 438 | 439 | // internally we use seperate RGB values 440 | fadeFromR = myStrip->getRed(fromColor); 441 | fadeFromG = myStrip->getGreen(fromColor); 442 | fadeFromB = myStrip->getBlue(fromColor); 443 | 444 | fadeToR = myStrip->getRed(toColor); 445 | fadeToG = myStrip->getGreen(toColor); 446 | fadeToB = myStrip->getBlue(toColor); 447 | 448 | fadeCurR = fadeFromR; 449 | fadeCurG = fadeFromG; 450 | fadeCurB = fadeFromB; 451 | 452 | fadePhase = fadeFadeIn; 453 | fillColor(fromColor); 454 | 455 | myStrip->setStripChanged(); // mark the strip changed 456 | } 457 | 458 | 459 | void NeoWindow::fadeEfxUpdate(void) 460 | { 461 | // uses ternary operator to handle incr/decr direction 462 | if (fadePhase == fadeFadeIn){ 463 | // fade in, fancy way to linearly ramp each of RGB, regardless of whether from>to or from fadeCurR) ? (fadeCurR+1) : ((fadeToR != fadeCurR) ? fadeCurR-1 : fadeCurR)); 465 | fadeCurG = ((fadeToG > fadeCurG) ? (fadeCurG+1) : ((fadeToG != fadeCurG) ? fadeCurG-1 : fadeCurG)); 466 | fadeCurB = ((fadeToB > fadeCurB) ? (fadeCurB+1) : ((fadeToB != fadeCurB) ? fadeCurB-1 : fadeCurB)); 467 | 468 | // faded all the way in? are we cycling? 469 | if (fadeCurR == fadeToR && fadeCurG == fadeToG && fadeCurB == fadeToB) { 470 | switch (fadeType) { 471 | case fadeTypeCycle: 472 | printId(); Serial.println("FadeEfx: cycled all the way in; fade out"); 473 | // faded all in, cycle out 474 | fadePhase = fadeFadeOut; 475 | break; 476 | case fadeTypeJumpBack: 477 | printId(); Serial.println("FadeEfx: cycled all the way in; not cycle, jump back"); 478 | fadeEfxEndCheck(); 479 | fillColor(fadeFromColor); 480 | fadeCurR = fadeFromR; 481 | fadeCurG = fadeFromG; 482 | fadeCurB = fadeFromB; 483 | case fadeTypeOnce: 484 | default: 485 | //thats all 486 | break; 487 | } 488 | } 489 | } else { // fade out 490 | // fade in, fancy way to linearly ramp each of RGB, regardless of whether from>to or from fadeCurR) ? (fadeCurR+1) : ((fadeFromR != fadeCurR) ? fadeCurR-1 : fadeCurR)); 492 | fadeCurG = ((fadeFromG > fadeCurG) ? (fadeCurG+1) : ((fadeFromG != fadeCurG) ? fadeCurG-1 : fadeCurG)); 493 | fadeCurB = ((fadeFromB > fadeCurB) ? (fadeCurB+1) : ((fadeFromB != fadeCurB) ? fadeCurB-1 : fadeCurB)); 494 | 495 | // faded all the way out? 496 | if (fadeCurR == fadeFromR && fadeCurG == fadeFromG && fadeCurB == fadeFromB) { 497 | printId(); Serial.println("FadeEfx: cycled all the way out; fade in"); 498 | fadePhase = fadeFadeIn; 499 | fadeEfxEndCheck(); 500 | } 501 | } 502 | fillColor(myStrip->Color(fadeCurR, fadeCurG, fadeCurB)); 503 | 504 | } 505 | 506 | void NeoWindow::fadeEfxEndCheck() 507 | { 508 | effectCount++; 509 | if (effectCount > fadeMaxCount) 510 | { 511 | efxDone = true; 512 | } 513 | } 514 | 515 | 516 | 517 | void NeoWindow:: setRainbowEfx(uint16_t waitTime, int type) 518 | { 519 | // members common to all effects 520 | setNoEfx();// reset counters 521 | effectDelay = waitTime; 522 | // effect specfic members 523 | curColor = 0; 524 | rainbowType = type; 525 | 526 | // and set the update function - magic of function poiners 527 | curUpdateFunc = &NeoWindow::rainbowEfxUpdate; 528 | } 529 | 530 | void NeoWindow::rainbowEfxUpdate(void) 531 | { 532 | // put a color in each pixel of window, depending on type 533 | for (int i=0; i < myPixelCount; i++) 534 | { 535 | // colorWheel has 255 colors, from Adafruit NeoPixel strandtest example 536 | if (rainbowType == 0) { 537 | myStrip->setPixelColor(i+myStartPixel, NeoStrip::colorWheel((i+curColor) & 255)); 538 | } else { 539 | myStrip->setPixelColor(i+myStartPixel, NeoStrip::colorWheel(((i*256/myPixelCount)+curColor) & 255)); 540 | } 541 | } 542 | 543 | curColor++; 544 | if (curColor > 255) 545 | { 546 | // reached end of colors, mark effect done 547 | effectCount++; 548 | efxDone = true; 549 | // and set color index back to start so we can keep cycling 550 | curColor = 0; 551 | } 552 | } 553 | 554 | -------------------------------------------------------------------------------- /NeoWindow.h: -------------------------------------------------------------------------------- 1 | // NeoWindow 2 | /** @file NeoWindow.h 3 | * @brief NeoWindow class of NeoEfx library - providing concurrent effects on NeoPixels 4 | * 5 | * NeoWindow defines a Window (region) of a NeoPixel strip and concurrent effects to be performed. 6 | * Effects defined in different NeoWindows can be run concurrently, that is without use of delay() 7 | * A NeoWindow is defined on a NeoStrip (also of NeoEfx library). 8 | * Windows in a strip can be overlapping, although this can cause odd issues. Use SetNoEfx() 9 | * 10 | * Various effects are implemented by a couple functions: setXXXEfx(); updateXXXEfx() 11 | * the Set Efx function sets up the window to run the effect, variations will take various parameters 12 | * the update efx function is internal to the libary, called when an object's updateWindow() is called. 13 | * 14 | * @author jerry isdale 15 | */ 16 | 17 | #ifndef _NEOWINDOW_ 18 | #define _NEOWINDOW_ 19 | 20 | // all based on the NeoPixel library from Adafruit 21 | #include 22 | 23 | // and our NeoStrip object that encapsulates the Pixel 24 | #include "NeoStrip.h" 25 | 26 | class NeoWindow 27 | { 28 | protected: 29 | // class variables 30 | // for use herein, and by derived classes 31 | typedef void (NeoWindow::*NeoWindowUpdateFunc)(void); /*!< function that runs effect each cycle */ 32 | static uint32_t currTime; /*!< current Millis */ 33 | static int s_nIDGenerator; /*!< used to generate uniqueID for each window */ 34 | 35 | public: 36 | // Instance Constructor: 37 | NeoWindow(NeoStrip *strip, int startPixel, int len); /*!< creates window on strip given start index & length */ 38 | 39 | // Class functions 40 | static void updateTime() {NeoWindow::currTime = millis();} /*!< class method to be called at top of loop() */ 41 | static uint32_t currentTime() {return NeoWindow::currTime;} /*!< access time recorded at top of loop() */ 42 | 43 | ///////////////////////// 44 | // instance functions 45 | 46 | void updateWindow(void); /*!< invoke the current effect update function */ 47 | boolean effectDone(void) {return efxDone;} /*