├── .gitignore ├── .travis.yml ├── README.md ├── lib ├── WS2812FX │ ├── .gitignore │ ├── .library.json │ ├── LICENSE │ ├── README.md │ ├── WS2812FX.cpp │ ├── WS2812FX.h │ ├── WS2812FX_logo.png │ ├── keywords.txt │ └── library.json ├── WebUSB │ ├── WebUSB.cpp │ ├── WebUSB.h │ ├── keywords.txt │ └── library.properties └── readme.txt ├── platformio.ini ├── schematic ├── PhysicalLedRingWebUSB.fzz └── PhysicalLedRingWebUSB.png ├── src └── main.cpp └── webapp ├── .gitignore ├── package.json ├── public ├── favicon.ico ├── index.html └── manifest.json ├── src ├── App.css ├── App.js ├── LedRing.js ├── Serial.js ├── index.js ├── logo.svg └── registerServiceWorker.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | .piolibdeps 3 | .vscode 4 | .vscode/c_cpp_properties.json 5 | .vscode/launch.json 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < http://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < http://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < http://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choice one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # install: 32 | # - pip install -U platformio 33 | # 34 | # script: 35 | # - platformio run 36 | 37 | 38 | # 39 | # Template #2: The project is intended to by used as a library with examples 40 | # 41 | 42 | # language: python 43 | # python: 44 | # - "2.7" 45 | # 46 | # env: 47 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 48 | # - PLATFORMIO_CI_SRC=examples/file.ino 49 | # - PLATFORMIO_CI_SRC=path/to/test/directory 50 | # 51 | # install: 52 | # - pip install -U platformio 53 | # 54 | # script: 55 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Physical Led Ring controlled via a Browser - A WebUSB and Arduino experiment. 2 | 3 | ## Overview 4 | 5 | IoT Project that shows how to connect a microcontroller directly to the Browser. This project uses WebUSB specification, a Arduino Micro/Leonardo and a NeoPixel Ring that is controlled by the web interface made with ReactJS. 6 | 7 | WebApp: https://alvarowolfx.github.io/physical-led-ring-webusb-arduino 8 | 9 | ### Upload firmware to Arduino 10 | 11 | I used Platform.io to write this project. I recommend to use it with the Visual Studio Code IDE. 12 | 13 | * [Visual Studio Code](https://code.visualstudio.com/) 14 | * [Platform.io](https://platformio.org) 15 | * [Platform.io VSCode Plugin](http://docs.platformio.org/en/latest/ide/vscode.html) 16 | 17 | ### BOM 18 | 19 | * An Arduino board with a ATMega32u4 microcontroller. 20 | * It's needed because this chip has native USB support. 21 | * 16 Leds Neopixel Ring. 22 | * Jumpers 23 | 24 | ### Schematic 25 | 26 | ![schematic](https://raw.githubusercontent.com/alvarowolfx/physical-led-ring-webusb-arduino/master/schematic/PhysicalLedRingWebUSB.png) 27 | 28 | ## References 29 | 30 | * https://github.com/webusb/arduino 31 | * https://developers.google.com/web/updates/2016/03/access-usb-devices-on-the-web 32 | 33 | This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app). 34 | -------------------------------------------------------------------------------- /lib/WS2812FX/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/c_cpp_properties.json 2 | .vscode/arduino.json 3 | -------------------------------------------------------------------------------- /lib/WS2812FX/.library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WS2812FX", 3 | "repository": { 4 | "url": "https://github.com/kitesurfer1404/WS2812FX.git", 5 | "type": "git" 6 | }, 7 | "platforms": [ 8 | "espressif8266" 9 | ], 10 | "downloadUrl": "https://github.com/kitesurfer1404/WS2812FX/archive/master.zip", 11 | "frameworks": [ 12 | "arduino" 13 | ], 14 | "version": "1.0.1", 15 | "export": { 16 | "include": "WS2812FX-master" 17 | }, 18 | "dependencies": [ 19 | { 20 | "version": "~1.1.2", 21 | "name": "Adafruit NeoPixel" 22 | } 23 | ], 24 | "authors": [ 25 | { 26 | "url": "https://github.com/kitesurfer1404/WS2812FX", 27 | "maintainer": false, 28 | "email": null, 29 | "name": "Harm Aldick" 30 | } 31 | ], 32 | "keywords": [ 33 | "esp8266", 34 | "ws2812" 35 | ], 36 | "id": 1647, 37 | "description": "WS2812 FX Library for Arduino and ESP8266" 38 | } -------------------------------------------------------------------------------- /lib/WS2812FX/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Harm Aldick 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/WS2812FX/README.md: -------------------------------------------------------------------------------- 1 | ![WS2812FX library](https://raw.githubusercontent.com/kitesurfer1404/WS2812FX/master/WS2812FX_logo.png) 2 | 3 | WS2812FX - More Blinken for your LEDs! 4 | ====================================== 5 | 6 | This library features a variety of blinken effects for the WS2811/WS2812/NeoPixel LEDs. It is meant to be a drop-in replacement for the Adafruit NeoPixel library with additional features. 7 | 8 | Features 9 | -------- 10 | 11 | * 53 different effects. And counting. 12 | * Free of any delay() 13 | * Tested on Arduino Nano, Uno, Micro and ESP8266. 14 | * All effects with printable names - easy to use in user interfaces. 15 | * FX, speed and brightness controllable on the fly. 16 | * Ready for sound-to-light (see external trigger example) 17 | 18 | 19 | Download, Install and Example 20 | ----------------------------- 21 | 22 | * Install the famous [Adafruit NeoPixel library](https://github.com/adafruit/Adafruit_NeoPixel) 23 | * Download this repository. 24 | * Extract to your Arduino libraries directory. 25 | * Open Arduino IDE. 26 | * Now you can choose File > Examples > WS2812FX > ... 27 | 28 | See examples for basic usage. 29 | 30 | In it's most simple form, here's the code to get you started! 31 | 32 | ```cpp 33 | #include 34 | 35 | #define LED_COUNT 30 36 | #define LED_PIN 12 37 | 38 | WS2812FX ws2812fx = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800); 39 | 40 | void setup() { 41 | ws2812fx.init(); 42 | ws2812fx.setBrightness(100); 43 | ws2812fx.setSpeed(200); 44 | ws2812fx.setMode(FX_MODE_RAINBOW_CYCLE); 45 | ws2812fx.start(); 46 | } 47 | 48 | void loop() { 49 | ws2812fx.service(); 50 | } 51 | ``` 52 | 53 | 54 | Effects 55 | ------- 56 | 57 | * **Static** - No blinking. Just plain old static light. 58 | * **Blink** - Normal blinking. 50% on/off time. 59 | * **Breath** - Does the "standby-breathing" of well known i-Devices. Fixed Speed. 60 | * **Color Wipe** - Lights all LEDs after each other up. Then turns them in that order off. Repeat. 61 | * **Color Wipe Random** - Turns all LEDs after each other to a random color. Then starts over with another color. 62 | * **Random Color** - Lights all LEDs in one random color up. Then switches them to the next random color. 63 | * **Single Dynamic** - Lights every LED in a random color. Changes one random LED after the other to another random color. 64 | * **Multi Dynamic** - Lights every LED in a random color. Changes all LED at the same time to new random colors. 65 | * **Rainbow** - Cycles all LEDs at once through a rainbow. 66 | * **Rainbow Cycle** - Cycles a rainbow over the entire string of LEDs. 67 | * **Scan** - Runs a single pixel back and forth. 68 | * **Dual Scan** - Runs two pixel back and forth in opposite directions. 69 | * **Fade** - Fades the LEDs on and (almost) off again. 70 | * **Theater Chase** - Theatre-style crawling lights. Inspired by the Adafruit examples. 71 | * **Theater Chase Rainbow** - Theatre-style crawling lights with rainbow effect. Inspired by the Adafruit examples. 72 | * **Running Lights** - Running lights effect with smooth sine transition. 73 | * **Twinkle** - Blink several LEDs on, reset, repeat. 74 | * **Twinkle Random** - Blink several LEDs in random colors on, reset, repeat. 75 | * **Twinkle Fade** - Blink several LEDs on, fading out. 76 | * **Twinkle Fade Random** - Blink several LEDs in random colors on, fading out. 77 | * **Sparkle** - Blinks one LED at a time. 78 | * **Flash Sparkle** - Lights all LEDs in the selected color. Flashes single white pixels randomly. 79 | * **Hyper Sparkle** - Like flash sparkle. With more flash. 80 | * **Strobe** - Classic Strobe effect. 81 | * **Strobe Rainbow** - Classic Strobe effect. Cycling through the rainbow. 82 | * **Multi Strobe** - Strobe effect with different strobe count and pause, controlled by speed setting. 83 | * **Blink Rainbow** - Classic Blink effect. Cycling through the rainbow. 84 | * **Chase White** - Color running on white. 85 | * **Chase Color** - White running on color. 86 | * **Chase Random** - White running followed by random color. 87 | * **Chase Rainbow** - White running on rainbow. 88 | * **Chase Flash** - White flashes running on color. 89 | * **Chase Flash Random** - White flashes running, followed by random color. 90 | * **Chase Rainbow White** - Rainbow running on white. 91 | * **Chase Blackout** - Black running on color. 92 | * **Chase Blackout Rainbow** - Black running on rainbow. 93 | * **Color Sweep Random** - Random color introduced alternating from start and end of strip. 94 | * **Running Color** - Alternating color/white pixels running. 95 | * **Running Red Blue** - Alternating red/blue pixels running. 96 | * **Running Random** - Random colored pixels running. 97 | * **Larson Scanner** - K.I.T.T. 98 | * **Comet** - Firing comets from one end. 99 | * **Fireworks** - Firework sparks. 100 | * **Fireworks Random** - Random colored firework sparks. 101 | * **Merry Christmas** - Alternating green/red pixels running. 102 | * **Fire Flicker** - Fire flickering effect. Like in harsh wind. 103 | * **Fire Flicker (soft)** - Fire flickering effect. Runs slower/softer. 104 | * **Fire Flicker (intense)** - Fire flickering effect. More range of color. 105 | * **Dual Color Wipe In/Out** - Light from edges in to middle, then turn off in reverse. 106 | * **Dual Color Wipe In/In** - Light from edges in to middle, then turn off in same order. 107 | * **Dual Color Wipe Out/Out** - Light from middle to edges, then turn off in same order. 108 | * **Dual Color Wipe Out/In** - Light from middle to edges, then turn off in reverse. 109 | * **Circus Combustus** - Alternating white/red/black pixels running. 110 | * **Halloween** - Alternating orange/purple pixels running. 111 | 112 | Projects using WS2812FX 113 | ----------------------- 114 | 115 | * [Smart Home project by renat2985](https://github.com/renat2985/rgb) using the ESP8266. Including a nice webinterface in the demo video! 116 | * [WiFi LED Star by kitesurfer1404](http://www.kitesurfer1404.de/tech/led-star/en) 117 | * [McLighting by toblum](https://github.com/toblum/McLighting) is a multi-client lighting gadget for ESP8266 118 | -------------------------------------------------------------------------------- /lib/WS2812FX/WS2812FX.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | WS2812FX.cpp - Library for WS2812 LED effects. 3 | 4 | Harm Aldick - 2016 5 | www.aldick.org 6 | 7 | 8 | FEATURES 9 | * A lot of blinken modes and counting 10 | * WS2812FX can be used as drop-in replacement for Adafruit Neopixel Library 11 | 12 | NOTES 13 | * Uses the Adafruit Neopixel library. Get it here: 14 | https://github.com/adafruit/Adafruit_NeoPixel 15 | 16 | 17 | 18 | LICENSE 19 | 20 | The MIT License (MIT) 21 | 22 | Copyright (c) 2016 Harm Aldick 23 | 24 | Permission is hereby granted, free of charge, to any person obtaining a copy 25 | of this software and associated documentation files (the "Software"), to deal 26 | in the Software without restriction, including without limitation the rights 27 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 28 | copies of the Software, and to permit persons to whom the Software is 29 | furnished to do so, subject to the following conditions: 30 | 31 | The above copyright notice and this permission notice shall be included in 32 | all copies or substantial portions of the Software. 33 | 34 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 35 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 36 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 37 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 38 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 39 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 40 | THE SOFTWARE. 41 | 42 | 43 | CHANGELOG 44 | 45 | 2016-05-28 Initial beta release 46 | 2016-06-03 Code cleanup, minor improvements, new modes 47 | 2016-06-04 2 new fx, fixed setColor (now also resets _mode_color) 48 | 2017-02-02 added external trigger functionality (e.g. for sound-to-light) 49 | 2017-02-02 removed "blackout" on mode, speed or color-change 50 | 2017-09-26 implemented segment and reverse features 51 | */ 52 | 53 | #include "Arduino.h" 54 | #include "WS2812FX.h" 55 | 56 | //#define CALL_MODE(n) (this->*_mode[n])(); 57 | 58 | void WS2812FX::init() { 59 | RESET_RUNTIME; 60 | Adafruit_NeoPixel::begin(); 61 | setBrightness(_brightness); 62 | Adafruit_NeoPixel::show(); 63 | } 64 | 65 | void WS2812FX::service() { 66 | if(_running || _triggered) { 67 | unsigned long now = millis(); // Be aware, millis() rolls over every 49 days 68 | bool doShow = false; 69 | for(uint8_t i=0; i < _num_segments; i++) { 70 | _segment_index = i; 71 | if(now > SEGMENT_RUNTIME.next_time || _triggered) { 72 | doShow = true; 73 | uint16_t delay = (this->*_mode[SEGMENT.mode])(); 74 | SEGMENT_RUNTIME.next_time = now + max(delay, 20); 75 | SEGMENT_RUNTIME.counter_mode_call++; 76 | } 77 | } 78 | if(doShow) { 79 | delay(1); // for ESP32 (see https://forums.adafruit.com/viewtopic.php?f=47&t=117327) 80 | Adafruit_NeoPixel::show(); 81 | } 82 | _triggered = false; 83 | } 84 | } 85 | 86 | void WS2812FX::start() { 87 | RESET_RUNTIME; 88 | _running = true; 89 | } 90 | 91 | void WS2812FX::stop() { 92 | _running = false; 93 | strip_off(); 94 | } 95 | 96 | void WS2812FX::trigger() { 97 | _triggered = true; 98 | } 99 | 100 | void WS2812FX::setMode(uint8_t m) { 101 | RESET_RUNTIME; 102 | _segments[0].mode = constrain(m, 0, MODE_COUNT - 1); 103 | setBrightness(_brightness); 104 | //strip_off(); 105 | } 106 | 107 | void WS2812FX::setSpeed(uint16_t s) { 108 | RESET_RUNTIME; 109 | _segments[0].speed = constrain(s, SPEED_MIN, SPEED_MAX); 110 | //strip_off(); 111 | } 112 | 113 | void WS2812FX::increaseSpeed(uint8_t s) { 114 | s = constrain(SEGMENT.speed + s, SPEED_MIN, SPEED_MAX); 115 | setSpeed(s); 116 | } 117 | 118 | void WS2812FX::decreaseSpeed(uint8_t s) { 119 | s = constrain(SEGMENT.speed - s, SPEED_MIN, SPEED_MAX); 120 | setSpeed(s); 121 | } 122 | 123 | void WS2812FX::setColor(uint8_t r, uint8_t g, uint8_t b) { 124 | setColor(((uint32_t)r << 16) | ((uint32_t)g << 8) | b); 125 | } 126 | 127 | void WS2812FX::setColor(uint32_t c) { 128 | RESET_RUNTIME; 129 | _segments[0].colors[0] = c; 130 | setBrightness(_brightness); 131 | //strip_off(); 132 | } 133 | 134 | void WS2812FX::setBrightness(uint8_t b) { 135 | _brightness = constrain(b, BRIGHTNESS_MIN, BRIGHTNESS_MAX); 136 | Adafruit_NeoPixel::setBrightness(_brightness); 137 | Adafruit_NeoPixel::show(); 138 | delay(1); 139 | } 140 | 141 | void WS2812FX::increaseBrightness(uint8_t s) { 142 | s = constrain(_brightness + s, BRIGHTNESS_MIN, BRIGHTNESS_MAX); 143 | setBrightness(s); 144 | } 145 | 146 | void WS2812FX::decreaseBrightness(uint8_t s) { 147 | s = constrain(_brightness - s, BRIGHTNESS_MIN, BRIGHTNESS_MAX); 148 | setBrightness(s); 149 | } 150 | 151 | void WS2812FX::setLength(uint16_t b) { 152 | RESET_RUNTIME; 153 | if (b < 1) b = 1; 154 | 155 | // Decrease numLEDs to maximum available memory 156 | do { 157 | Adafruit_NeoPixel::updateLength(b); 158 | b--; 159 | } while(!Adafruit_NeoPixel::numLEDs && b > 1); 160 | 161 | _segments[0].start = 0; 162 | _segments[0].stop = Adafruit_NeoPixel::numLEDs - 1; 163 | } 164 | 165 | void WS2812FX::increaseLength(uint16_t s) { 166 | s = _segments[0].stop - _segments[0].start + 1 + s; 167 | setLength(s); 168 | } 169 | 170 | void WS2812FX::decreaseLength(uint16_t s) { 171 | if (s > _segments[0].stop - _segments[0].start + 1) s = 1; 172 | s = _segments[0].stop - _segments[0].start + 1 - s; 173 | 174 | for(uint16_t i=_segments[0].start + s; i <= (_segments[0].stop - _segments[0].start + 1); i++) { 175 | Adafruit_NeoPixel::setPixelColor(i, 0); 176 | } 177 | Adafruit_NeoPixel::show(); 178 | 179 | setLength(s); 180 | } 181 | 182 | boolean WS2812FX::isRunning() { 183 | return _running; 184 | } 185 | 186 | uint8_t WS2812FX::getMode(void) { 187 | return _segments[0].mode; 188 | } 189 | 190 | uint16_t WS2812FX::getSpeed(void) { 191 | return _segments[0].speed; 192 | } 193 | 194 | uint8_t WS2812FX::getBrightness(void) { 195 | return _brightness; 196 | } 197 | 198 | uint16_t WS2812FX::getLength(void) { 199 | return _segments[0].stop - _segments[0].start + 1; 200 | } 201 | 202 | uint8_t WS2812FX::getModeCount(void) { 203 | return MODE_COUNT; 204 | } 205 | 206 | uint8_t WS2812FX::getNumSegments(void) { 207 | return _num_segments; 208 | } 209 | 210 | void WS2812FX::setNumSegments(uint8_t n) { 211 | _num_segments = n; 212 | } 213 | 214 | uint32_t WS2812FX::getColor(void) { 215 | return _segments[0].colors[0]; 216 | } 217 | 218 | WS2812FX::segment* WS2812FX::getSegments(void) { 219 | return _segments; 220 | } 221 | 222 | const __FlashStringHelper* WS2812FX::getModeName(uint8_t m) { 223 | if(m < MODE_COUNT) { 224 | return _name[m]; 225 | } else { 226 | return F(""); 227 | } 228 | } 229 | 230 | void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, bool reverse) { 231 | if(n < MAX_NUM_SEGMENTS) { 232 | if(n + 1 > _num_segments) _num_segments = n + 1; 233 | _segments[n].start = start; 234 | _segments[n].stop = stop; 235 | _segments[n].mode = mode; 236 | _segments[n].speed = speed; 237 | _segments[n].reverse = reverse; 238 | _segments[n].colors[0] = color; 239 | } 240 | } 241 | 242 | void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint16_t speed, bool reverse) { 243 | if(n < MAX_NUM_SEGMENTS) { 244 | if(n + 1 > _num_segments) _num_segments = n + 1; 245 | _segments[n].start = start; 246 | _segments[n].stop = stop; 247 | _segments[n].mode = mode; 248 | _segments[n].speed = speed; 249 | _segments[n].reverse = reverse; 250 | 251 | for(uint8_t i=0; i g -> b -> back to r 275 | * Inspired by the Adafruit examples. 276 | */ 277 | uint32_t WS2812FX::color_wheel(uint8_t pos) { 278 | pos = 255 - pos; 279 | if(pos < 85) { 280 | return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3); 281 | } else if(pos < 170) { 282 | pos -= 85; 283 | return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3); 284 | } else { 285 | pos -= 170; 286 | return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0); 287 | } 288 | } 289 | 290 | 291 | /* 292 | * Returns a new, random wheel index with a minimum distance of 42 from pos. 293 | */ 294 | uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) { 295 | uint8_t r = 0; 296 | uint8_t x = 0; 297 | uint8_t y = 0; 298 | uint8_t d = 0; 299 | 300 | while(d < 42) { 301 | r = random(256); 302 | x = abs(pos - r); 303 | y = 255 - x; 304 | d = min(x, y); 305 | } 306 | 307 | return r; 308 | } 309 | 310 | 311 | /* 312 | * No blinking. Just plain old static light. 313 | */ 314 | uint16_t WS2812FX::mode_static(void) { 315 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 316 | Adafruit_NeoPixel::setPixelColor(i, SEGMENT.colors[0]); 317 | } 318 | return 200; 319 | } 320 | 321 | 322 | /* 323 | * Normal blinking. 50% on/off time. 324 | */ 325 | uint16_t WS2812FX::mode_blink(void) { 326 | uint32_t color = SEGMENT_RUNTIME.counter_mode_call % 2 == 1 ? 0 : SEGMENT.colors[0]; 327 | if(SEGMENT.reverse) color = color == 0 ? SEGMENT.colors[0] : 0; 328 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 329 | Adafruit_NeoPixel::setPixelColor(i, color); 330 | } 331 | //return (SEGMENT.speed / 2); 332 | return 100 + ((1986 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 333 | } 334 | 335 | 336 | /* 337 | * Color wipe function 338 | */ 339 | uint16_t WS2812FX::color_wipe(uint32_t color1, uint32_t color2) { 340 | uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step; 341 | uint32_t color = color1; 342 | if(SEGMENT_RUNTIME.counter_mode_step >= SEGMENT_LENGTH) { 343 | led_offset = SEGMENT_RUNTIME.counter_mode_step - SEGMENT_LENGTH; 344 | color = color2; 345 | } 346 | if(SEGMENT.reverse) { 347 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - led_offset, color); 348 | } else { 349 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + led_offset, color); 350 | } 351 | 352 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % (SEGMENT_LENGTH * 2); 353 | //return (SEGMENT.speed / (SEGMENT_LENGTH * 2)); 354 | return 5 + ((50 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 355 | } 356 | 357 | /* 358 | * Lights all LEDs after each other up. Then turns them in 359 | * that order off. Repeat. 360 | */ 361 | uint16_t WS2812FX::mode_color_wipe(void) { 362 | return color_wipe(SEGMENT.colors[0], 0); 363 | } 364 | 365 | uint16_t WS2812FX::mode_color_wipe_inverse(void) { 366 | return color_wipe(0, SEGMENT.colors[0]); 367 | } 368 | 369 | /* 370 | * Turns all LEDs after each other to a random color. 371 | * Then starts over with another color. 372 | */ 373 | uint16_t WS2812FX::mode_color_wipe_random(void) { 374 | if(SEGMENT_RUNTIME.counter_mode_step == 0) { // aux_param will store our random color wheel index 375 | SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); 376 | } 377 | 378 | if(SEGMENT.reverse) { 379 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, color_wheel(SEGMENT_RUNTIME.aux_param)); 380 | } else { 381 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, color_wheel(SEGMENT_RUNTIME.aux_param)); 382 | } 383 | 384 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 385 | //return (SEGMENT.speed / SEGMENT_LENGTH); 386 | return 5 + ((50 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 387 | } 388 | 389 | 390 | /* 391 | * Lights all LEDs in one random color up. Then switches them 392 | * to the next random color. 393 | */ 394 | uint16_t WS2812FX::mode_random_color(void) { 395 | SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); // aux_param will store our random color wheel index 396 | 397 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 398 | Adafruit_NeoPixel::setPixelColor(i, color_wheel(SEGMENT_RUNTIME.aux_param)); 399 | } 400 | //return (SEGMENT.speed); 401 | return 100 + ((5000 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 402 | } 403 | 404 | 405 | /* 406 | * Lights every LED in a random color. Changes one random LED after the other 407 | * to another random color. 408 | */ 409 | uint16_t WS2812FX::mode_single_dynamic(void) { 410 | if(SEGMENT_RUNTIME.counter_mode_call == 0) { 411 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 412 | Adafruit_NeoPixel::setPixelColor(i, color_wheel(random(256))); 413 | } 414 | } 415 | 416 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start+random(SEGMENT_LENGTH), color_wheel(random(256))); 417 | //return (SEGMENT.speed); 418 | return 10 + ((5000 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 419 | } 420 | 421 | 422 | /* 423 | * Lights every LED in a random color. Changes all LED at the same time 424 | * to new random colors. 425 | */ 426 | uint16_t WS2812FX::mode_multi_dynamic(void) { 427 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 428 | Adafruit_NeoPixel::setPixelColor(i, color_wheel(random(256))); 429 | } 430 | //return (SEGMENT.speed); 431 | return 100 + ((5000 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 432 | } 433 | 434 | 435 | /* 436 | * Does the "standby-breathing" of well known i-Devices. Fixed Speed. 437 | * Use mode "fade" if you like to have something similar with a different speed. 438 | */ 439 | uint16_t WS2812FX::mode_breath(void) { 440 | // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // step 441 | uint16_t breath_delay_steps[] = { 7, 9, 13, 15, 16, 17, 18, 930, 19, 18, 15, 13, 9, 7, 4, 5, 10 }; // magic numbers for breathing LED 442 | uint8_t breath_brightness_steps[] = { 150, 125, 100, 75, 50, 25, 16, 15, 16, 25, 50, 75, 100, 125, 150, 220, 255 }; // even more magic numbers! 443 | 444 | if(SEGMENT_RUNTIME.counter_mode_call == 0) { 445 | SEGMENT_RUNTIME.aux_param = breath_brightness_steps[0] + 1; // we use aux_param to store the brightness 446 | } 447 | 448 | uint8_t breath_brightness = SEGMENT_RUNTIME.aux_param; 449 | 450 | if(SEGMENT_RUNTIME.counter_mode_step < 8) { 451 | breath_brightness--; 452 | } else { 453 | breath_brightness++; 454 | } 455 | 456 | // update index of current delay when target brightness is reached, start over after the last step 457 | if(breath_brightness == breath_brightness_steps[SEGMENT_RUNTIME.counter_mode_step]) { 458 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % (sizeof(breath_brightness_steps)/sizeof(uint8_t)); 459 | } 460 | 461 | int b = map(breath_brightness, 0, 255, 0, _brightness); // keep brightness below brightness set by user 462 | uint8_t red = (SEGMENT.colors[0] >> 16 & 0xFF) * b / _brightness; // modify RGB colors with brightness info 463 | uint8_t green = (SEGMENT.colors[0] >> 8 & 0xFF) * b / _brightness; 464 | uint8_t blue = (SEGMENT.colors[0] & 0xFF) * b / _brightness; 465 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 466 | Adafruit_NeoPixel::setPixelColor(i, red, green, blue); // set all LEDs to selected color 467 | } 468 | 469 | SEGMENT_RUNTIME.aux_param = breath_brightness; 470 | //return (SEGMENT.speed / 550); // another magic number :) 471 | return breath_delay_steps[SEGMENT_RUNTIME.counter_mode_step]; 472 | } 473 | 474 | 475 | /* 476 | * Fades the LEDs on and (almost) off again. 477 | */ 478 | uint16_t WS2812FX::mode_fade(void) { 479 | int b = SEGMENT_RUNTIME.counter_mode_step - 31; 480 | b = 63 - (abs(b) * 2); 481 | b = map(b, 0, 64, min(25, _brightness), _brightness); 482 | 483 | uint8_t red = (SEGMENT.colors[0] >> 16 & 0xFF) * b / _brightness; // modify RGB colors with brightness info 484 | uint8_t green = (SEGMENT.colors[0] >> 8 & 0xFF) * b / _brightness; 485 | uint8_t blue = (SEGMENT.colors[0] & 0xFF) * b / _brightness; 486 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 487 | Adafruit_NeoPixel::setPixelColor(i, red, green, blue); 488 | } 489 | 490 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % 64; 491 | //return (SEGMENT.speed / 64); 492 | return 5 + ((15 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 493 | } 494 | 495 | 496 | /* 497 | * Runs a single pixel back and forth. 498 | */ 499 | uint16_t WS2812FX::mode_scan(void) { 500 | if(SEGMENT_RUNTIME.counter_mode_step > (SEGMENT_LENGTH * 2) - 3) { 501 | SEGMENT_RUNTIME.counter_mode_step = 0; 502 | } 503 | 504 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 505 | Adafruit_NeoPixel::setPixelColor(i, 0); 506 | } 507 | 508 | int led_offset = SEGMENT_RUNTIME.counter_mode_step - (SEGMENT_LENGTH - 1); 509 | led_offset = abs(led_offset); 510 | 511 | if(SEGMENT.reverse) { 512 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + led_offset, SEGMENT.colors[0]); 513 | } else { 514 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - led_offset, SEGMENT.colors[0]); 515 | } 516 | 517 | SEGMENT_RUNTIME.counter_mode_step++; 518 | //return (SEGMENT.speed / ((SEGMENT_LENGTH - 1) * 2)); 519 | return 10 + ((30 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 520 | } 521 | 522 | 523 | /* 524 | * Runs two pixel back and forth in opposite directions. 525 | */ 526 | uint16_t WS2812FX::mode_dual_scan(void) { 527 | if(SEGMENT_RUNTIME.counter_mode_step > (SEGMENT_LENGTH*2) - 3) { 528 | SEGMENT_RUNTIME.counter_mode_step = 0; 529 | } 530 | 531 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 532 | Adafruit_NeoPixel::setPixelColor(i, 0); 533 | } 534 | 535 | int led_offset = SEGMENT_RUNTIME.counter_mode_step - (SEGMENT_LENGTH - 1); 536 | led_offset = abs(led_offset); 537 | 538 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + led_offset, SEGMENT.colors[0]); 539 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_LENGTH - led_offset - 1, SEGMENT.colors[0]); 540 | 541 | SEGMENT_RUNTIME.counter_mode_step++; 542 | //return (SEGMENT.speed / ((SEGMENT_LENGTH - 1) * 2)); 543 | return 10 + ((30 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 544 | } 545 | 546 | 547 | /* 548 | * Cycles all LEDs at once through a rainbow. 549 | */ 550 | uint16_t WS2812FX::mode_rainbow(void) { 551 | uint32_t color = color_wheel(SEGMENT_RUNTIME.counter_mode_step); 552 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 553 | Adafruit_NeoPixel::setPixelColor(i, color); 554 | } 555 | 556 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % 256; 557 | //return (SEGMENT.speed / 256); 558 | return 1 + ((50 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 559 | } 560 | 561 | 562 | /* 563 | * Cycles a rainbow over the entire string of LEDs. 564 | */ 565 | uint16_t WS2812FX::mode_rainbow_cycle(void) { 566 | for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { 567 | uint32_t color = color_wheel(((i * 256 / SEGMENT_LENGTH) + SEGMENT_RUNTIME.counter_mode_step) % 256); 568 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color); 569 | } 570 | 571 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % 256; 572 | //return (SEGMENT.speed / 256); 573 | return 1 + ((50 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 574 | } 575 | 576 | 577 | /* 578 | * Theatre-style crawling lights. 579 | * Inspired by the Adafruit examples. 580 | */ 581 | uint16_t WS2812FX::mode_theater_chase(void) { 582 | SEGMENT_RUNTIME.counter_mode_call = SEGMENT_RUNTIME.counter_mode_call % 3; 583 | for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { 584 | if((i % 3) == SEGMENT_RUNTIME.counter_mode_call) { 585 | if(SEGMENT.reverse) { 586 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, SEGMENT.colors[0]); 587 | } else { 588 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, SEGMENT.colors[0]); 589 | } 590 | } else { 591 | if(SEGMENT.reverse) { 592 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, 0); 593 | } else { 594 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, 0); 595 | } 596 | } 597 | } 598 | 599 | //return (SEGMENT.speed / 3); 600 | return 50 + ((500 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 601 | } 602 | 603 | 604 | /* 605 | * Theatre-style crawling lights with rainbow effect. 606 | * Inspired by the Adafruit examples. 607 | */ 608 | uint16_t WS2812FX::mode_theater_chase_rainbow(void) { 609 | SEGMENT_RUNTIME.counter_mode_call = SEGMENT_RUNTIME.counter_mode_call % 3; 610 | for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { 611 | if((i % 3) == SEGMENT_RUNTIME.counter_mode_call) { 612 | if(SEGMENT.reverse) { 613 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, color_wheel((i + SEGMENT_RUNTIME.counter_mode_step) % 256)); 614 | } else { 615 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color_wheel((i + SEGMENT_RUNTIME.counter_mode_step) % 256)); 616 | } 617 | } else { 618 | if(SEGMENT.reverse) { 619 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, 0); 620 | } else { 621 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, 0); 622 | } 623 | } 624 | } 625 | 626 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % 256; 627 | //return (SEGMENT.speed / 3); 628 | return 50 + ((500 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 629 | } 630 | 631 | 632 | /* 633 | * Running lights effect with smooth sine transition. 634 | */ 635 | uint16_t WS2812FX::mode_running_lights(void) { 636 | uint8_t r = ((SEGMENT.colors[0] >> 16) & 0xFF); 637 | uint8_t g = ((SEGMENT.colors[0] >> 8) & 0xFF); 638 | uint8_t b = (SEGMENT.colors[0] & 0xFF); 639 | 640 | for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { 641 | int s = (sin(i + SEGMENT_RUNTIME.counter_mode_call) * 127) + 128; 642 | if(SEGMENT.reverse) { 643 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, (((uint32_t)(r * s)) / 255), (((uint32_t)(g * s)) / 255), (((uint32_t)(b * s)) / 255)); 644 | } else { 645 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, (((uint32_t)(r * s)) / 255), (((uint32_t)(g * s)) / 255), (((uint32_t)(b * s)) / 255)); 646 | } 647 | } 648 | //return (SEGMENT.speed / (SEGMENT_LENGTH / 2)); 649 | return 35 + ((350 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 650 | } 651 | 652 | 653 | /* 654 | * twinkle function 655 | */ 656 | uint16_t WS2812FX::twinkle(uint32_t color) { 657 | if(SEGMENT_RUNTIME.counter_mode_step == 0) { 658 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 659 | Adafruit_NeoPixel::setPixelColor(i, 0); 660 | } 661 | uint16_t min_leds = max(1, SEGMENT_LENGTH / 5); // make sure, at least one LED is on 662 | uint16_t max_leds = max(1, SEGMENT_LENGTH / 2); // make sure, at least one LED is on 663 | SEGMENT_RUNTIME.counter_mode_step = random(min_leds, max_leds); 664 | } 665 | 666 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + random(SEGMENT_LENGTH), color); 667 | 668 | SEGMENT_RUNTIME.counter_mode_step--; 669 | //return (SEGMENT.speed); 670 | return 50 + ((1986 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 671 | } 672 | 673 | /* 674 | * Blink several LEDs on, reset, repeat. 675 | * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ 676 | */ 677 | uint16_t WS2812FX::mode_twinkle(void) { 678 | uint32_t color = SEGMENT.colors[0]; 679 | return twinkle(color); 680 | } 681 | 682 | /* 683 | * Blink several LEDs in random colors on, reset, repeat. 684 | * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ 685 | */ 686 | uint16_t WS2812FX::mode_twinkle_random(void) { 687 | uint32_t color = color_wheel(random(256)); 688 | return twinkle(color); 689 | } 690 | 691 | 692 | /* 693 | * twinkle_fade function 694 | */ 695 | uint16_t WS2812FX::twinkle_fade(uint32_t color) { 696 | 697 | for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { 698 | uint32_t px_rgb = Adafruit_NeoPixel::getPixelColor(SEGMENT.start+i); 699 | 700 | byte px_r = (px_rgb & 0x00FF0000) >> 16; 701 | byte px_g = (px_rgb & 0x0000FF00) >> 8; 702 | byte px_b = (px_rgb & 0x000000FF) >> 0; 703 | 704 | // fade out (divide by 2) 705 | px_r = px_r >> 1; 706 | px_g = px_g >> 1; 707 | px_b = px_b >> 1; 708 | 709 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, px_r, px_g, px_b); 710 | } 711 | 712 | if(random(3) == 0) { 713 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + random(SEGMENT_LENGTH), color); 714 | } 715 | //return (SEGMENT.speed / 8); 716 | return 100 + ((100 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 717 | } 718 | 719 | 720 | /* 721 | * Blink several LEDs on, fading out. 722 | */ 723 | uint16_t WS2812FX::mode_twinkle_fade(void) { 724 | uint32_t color = SEGMENT.colors[0]; 725 | return twinkle_fade(color); 726 | } 727 | 728 | 729 | /* 730 | * Blink several LEDs in random colors on, fading out. 731 | */ 732 | uint16_t WS2812FX::mode_twinkle_fade_random(void) { 733 | uint32_t color = color_wheel(random(256)); 734 | return twinkle_fade(color); 735 | } 736 | 737 | 738 | /* 739 | * Blinks one LED at a time. 740 | * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ 741 | */ 742 | uint16_t WS2812FX::mode_sparkle(void) { 743 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 744 | Adafruit_NeoPixel::setPixelColor(i, 0); 745 | } 746 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + random(SEGMENT_LENGTH), SEGMENT.colors[0]); 747 | //return (SEGMENT.speed); 748 | return 10 + ((200 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 749 | } 750 | 751 | 752 | /* 753 | * Lights all LEDs in the color. Flashes single white pixels randomly. 754 | * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ 755 | */ 756 | uint16_t WS2812FX::mode_flash_sparkle(void) { 757 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 758 | Adafruit_NeoPixel::setPixelColor(i, SEGMENT.colors[0]); 759 | } 760 | 761 | //uint16_t delay = SEGMENT.speed; 762 | uint16_t delay = 20 + ((200 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 763 | if(random(10) < 2) { 764 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + random(SEGMENT_LENGTH), 255, 255, 255); 765 | delay = 20; 766 | } 767 | return delay; 768 | } 769 | 770 | 771 | /* 772 | * Like flash sparkle. With more flash. 773 | * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ 774 | */ 775 | uint16_t WS2812FX::mode_hyper_sparkle(void) { 776 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 777 | Adafruit_NeoPixel::setPixelColor(i, SEGMENT.colors[0]); 778 | } 779 | 780 | //uint16_t delay = SEGMENT.speed; 781 | uint16_t delay = 15 + ((120 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 782 | if(random(10) < 4) { 783 | for(uint16_t i=0; i < max(1, SEGMENT_LENGTH/3); i++) { 784 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + random(SEGMENT_LENGTH), 255, 255, 255); 785 | } 786 | delay = 20; 787 | } 788 | return delay; 789 | } 790 | 791 | 792 | /* 793 | * Classic Strobe effect. 794 | */ 795 | uint16_t WS2812FX::mode_strobe(void) { 796 | //uint16_t delay = SEGMENT.speed - 20; 797 | uint16_t delay = 50 + ((1986 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 798 | if(SEGMENT_RUNTIME.counter_mode_call % 2 == 0) { 799 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 800 | Adafruit_NeoPixel::setPixelColor(i, SEGMENT.colors[0]); 801 | } 802 | delay = 20; 803 | } else { 804 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 805 | Adafruit_NeoPixel::setPixelColor(i, 0); 806 | } 807 | } 808 | return delay; 809 | } 810 | 811 | 812 | /* 813 | * Strobe effect with different strobe count and pause, controlled by speed. 814 | */ 815 | uint16_t WS2812FX::mode_multi_strobe(void) { 816 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 817 | Adafruit_NeoPixel::setPixelColor(i, 0); 818 | } 819 | 820 | //uint16_t delay = SEGMENT.speed / (2 * ((SEGMENT.speed / 10) + 1)); 821 | uint16_t delay = 100 + ((9 - (SEGMENT.speed % 10)) * 125); 822 | if(SEGMENT_RUNTIME.counter_mode_step < (2 * ((SEGMENT.speed / 10) + 1))) { 823 | if(SEGMENT_RUNTIME.counter_mode_step % 2 == 0) { 824 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 825 | Adafruit_NeoPixel::setPixelColor(i, SEGMENT.colors[0]); 826 | } 827 | delay = 20; 828 | } else { 829 | delay = 50; 830 | } 831 | } 832 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % ((2 * ((SEGMENT.speed / 10) + 1)) + 1); 833 | return delay; 834 | } 835 | 836 | 837 | /* 838 | * Classic Strobe effect. Cycling through the rainbow. 839 | */ 840 | uint16_t WS2812FX::mode_strobe_rainbow(void) { 841 | //uint16_t delay = SEGMENT.speed - 20; 842 | uint16_t delay = 50 + ((1986 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 843 | if(SEGMENT_RUNTIME.counter_mode_call % 2 == 0) { 844 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 845 | Adafruit_NeoPixel::setPixelColor(i, color_wheel(SEGMENT_RUNTIME.counter_mode_call % 256)); 846 | } 847 | delay = 20; 848 | } else { 849 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 850 | Adafruit_NeoPixel::setPixelColor(i, 0); 851 | } 852 | } 853 | return delay; 854 | } 855 | 856 | 857 | /* 858 | * Classic Blink effect. Cycling through the rainbow. 859 | */ 860 | uint16_t WS2812FX::mode_blink_rainbow(void) { 861 | if(SEGMENT_RUNTIME.counter_mode_call % 2 == 1) { 862 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 863 | Adafruit_NeoPixel::setPixelColor(i, color_wheel(SEGMENT_RUNTIME.counter_mode_call % 256)); 864 | } 865 | } else { 866 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 867 | Adafruit_NeoPixel::setPixelColor(i, 0); 868 | } 869 | } 870 | //return (SEGMENT.speed / 2); 871 | return 100 + ((1986 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 872 | } 873 | 874 | 875 | /* 876 | * _color running on white. 877 | */ 878 | uint16_t WS2812FX::mode_chase_white(void) { 879 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 880 | Adafruit_NeoPixel::setPixelColor(i, 255, 255, 255); 881 | } 882 | 883 | uint16_t n = SEGMENT_RUNTIME.counter_mode_step; 884 | uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 885 | if(SEGMENT.reverse) { 886 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - n, SEGMENT.colors[0]); 887 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - m, SEGMENT.colors[0]); 888 | } else { 889 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + n, SEGMENT.colors[0]); 890 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + m, SEGMENT.colors[0]); 891 | } 892 | 893 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 894 | //return (SEGMENT.speed / SEGMENT_LENGTH); 895 | return 10 + ((30 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 896 | } 897 | 898 | 899 | /* 900 | * White running on _color. 901 | */ 902 | uint16_t WS2812FX::mode_chase_color(void) { 903 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 904 | Adafruit_NeoPixel::setPixelColor(i, SEGMENT.colors[0]); 905 | } 906 | 907 | uint16_t n = SEGMENT_RUNTIME.counter_mode_step; 908 | uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 909 | if(SEGMENT.reverse) { 910 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - n, 255, 255, 255); 911 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - m, 255, 255, 255); 912 | } else { 913 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + n, 255, 255, 255); 914 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + m, 255, 255, 255); 915 | } 916 | 917 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 918 | //return (SEGMENT.speed / SEGMENT_LENGTH); 919 | return 10 + ((30 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 920 | } 921 | 922 | 923 | /* 924 | * White running followed by random color. 925 | */ 926 | uint16_t WS2812FX::mode_chase_random(void) { 927 | if(SEGMENT_RUNTIME.counter_mode_step == 0) { 928 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop, color_wheel(SEGMENT_RUNTIME.aux_param)); 929 | SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); 930 | } 931 | 932 | for(uint16_t i=0; i < SEGMENT_RUNTIME.counter_mode_step; i++) { 933 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color_wheel(SEGMENT_RUNTIME.aux_param)); 934 | } 935 | 936 | uint16_t n = SEGMENT_RUNTIME.counter_mode_step; 937 | uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 938 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + n, 255, 255, 255); 939 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + m, 255, 255, 255); 940 | 941 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 942 | //return (SEGMENT.speed / SEGMENT_LENGTH); 943 | return 10 + ((30 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 944 | } 945 | 946 | 947 | /* 948 | * White running on rainbow. 949 | */ 950 | uint16_t WS2812FX::mode_chase_rainbow(void) { 951 | uint8_t color_sep = 256 / SEGMENT_LENGTH; 952 | uint8_t color_index = SEGMENT_RUNTIME.counter_mode_call & 0xFF; 953 | for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { 954 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color_wheel(((i * color_sep) + color_index) & 0xFF)); 955 | } 956 | 957 | uint16_t n = SEGMENT_RUNTIME.counter_mode_step; 958 | uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 959 | if(SEGMENT.reverse) { 960 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - n, 255, 255, 255); 961 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - m, 255, 255, 255); 962 | } else { 963 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + n, 255, 255, 255); 964 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + m, 255, 255, 255); 965 | } 966 | 967 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 968 | //return (SEGMENT.speed / SEGMENT_LENGTH); 969 | return 10 + ((30 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 970 | } 971 | 972 | 973 | /* 974 | * White flashes running on _color. 975 | */ 976 | uint16_t WS2812FX::mode_chase_flash(void) { 977 | const static uint8_t flash_count = 4; 978 | uint8_t flash_step = SEGMENT_RUNTIME.counter_mode_call % ((flash_count * 2) + 1); 979 | 980 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 981 | Adafruit_NeoPixel::setPixelColor(i, SEGMENT.colors[0]); 982 | } 983 | 984 | //uint16_t delay = (SEGMENT.speed / SEGMENT_LENGTH); 985 | uint16_t delay = 10 + ((30 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 986 | if(flash_step < (flash_count * 2)) { 987 | if(flash_step % 2 == 0) { 988 | uint16_t n = SEGMENT_RUNTIME.counter_mode_step; 989 | uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 990 | if(SEGMENT.reverse) { 991 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - n, 255, 255, 255); 992 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - m, 255, 255, 255); 993 | } else { 994 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + n, 255, 255, 255); 995 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + m, 255, 255, 255); 996 | } 997 | delay = 20; 998 | } else { 999 | delay = 30; 1000 | } 1001 | } else { 1002 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 1003 | } 1004 | return delay; 1005 | } 1006 | 1007 | 1008 | /* 1009 | * White flashes running, followed by random color. 1010 | */ 1011 | uint16_t WS2812FX::mode_chase_flash_random(void) { 1012 | const static uint8_t flash_count = 4; 1013 | uint8_t flash_step = SEGMENT_RUNTIME.counter_mode_call % ((flash_count * 2) + 1); 1014 | 1015 | for(uint16_t i=0; i < SEGMENT_RUNTIME.counter_mode_step; i++) { 1016 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color_wheel(SEGMENT_RUNTIME.aux_param)); 1017 | } 1018 | 1019 | //uint16_t delay = (SEGMENT.speed / SEGMENT_LENGTH); 1020 | uint16_t delay = 1 + ((10 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1021 | if(flash_step < (flash_count * 2)) { 1022 | uint16_t n = SEGMENT_RUNTIME.counter_mode_step; 1023 | uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 1024 | if(flash_step % 2 == 0) { 1025 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + n, 255, 255, 255); 1026 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + m, 255, 255, 255); 1027 | delay = 20; 1028 | } else { 1029 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + n, color_wheel(SEGMENT_RUNTIME.aux_param)); 1030 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + m, 0, 0, 0); 1031 | delay = 30; 1032 | } 1033 | } else { 1034 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 1035 | 1036 | if(SEGMENT_RUNTIME.counter_mode_step == 0) { 1037 | SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); 1038 | } 1039 | } 1040 | return delay; 1041 | } 1042 | 1043 | 1044 | /* 1045 | * color chase function. 1046 | * color1 = background color 1047 | * color2 and color3 = colors of two adjacent leds 1048 | */ 1049 | uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3) { 1050 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 1051 | Adafruit_NeoPixel::setPixelColor(i, color1); 1052 | } 1053 | 1054 | uint16_t n = SEGMENT_RUNTIME.counter_mode_step; 1055 | uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 1056 | if(SEGMENT.reverse) { 1057 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - n, color2); 1058 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - m, color3); 1059 | } else { 1060 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + n, color2); 1061 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + m, color3); 1062 | } 1063 | 1064 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 1065 | //return (SEGMENT.speed / SEGMENT_LENGTH); 1066 | return 10 + ((30 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1067 | } 1068 | 1069 | 1070 | /* 1071 | * Rainbow running on white. 1072 | */ 1073 | uint16_t WS2812FX::mode_chase_rainbow_white(void) { 1074 | uint32_t color1 = 0xFFFFFF; 1075 | uint16_t n = SEGMENT_RUNTIME.counter_mode_step; 1076 | uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 1077 | uint32_t color2 = color_wheel(((n * 256 / SEGMENT_LENGTH) + (SEGMENT_RUNTIME.counter_mode_call & 0xFF)) & 0xFF); 1078 | uint32_t color3 = color_wheel(((m * 256 / SEGMENT_LENGTH) + (SEGMENT_RUNTIME.counter_mode_call & 0xFF)) & 0xFF); 1079 | 1080 | return chase(color1, color2, color3); 1081 | } 1082 | 1083 | 1084 | /* 1085 | * Black running on _color. 1086 | */ 1087 | uint16_t WS2812FX::mode_chase_blackout(void) { 1088 | return chase(SEGMENT.colors[0], 0, 0); 1089 | } 1090 | 1091 | 1092 | /* 1093 | * Black running on rainbow. 1094 | */ 1095 | uint16_t WS2812FX::mode_chase_blackout_rainbow(void) { 1096 | for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { 1097 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color_wheel(((i * 256 / SEGMENT_LENGTH) + (SEGMENT_RUNTIME.counter_mode_call % 256)) % 256)); 1098 | } 1099 | 1100 | uint16_t n = SEGMENT_RUNTIME.counter_mode_step; 1101 | uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 1102 | if(SEGMENT.reverse) { 1103 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - n, 0, 0, 0); 1104 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - m, 0, 0, 0); 1105 | } else { 1106 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + n, 0, 0, 0); 1107 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + m, 0, 0, 0); 1108 | } 1109 | 1110 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 1111 | //return (SEGMENT.speed / SEGMENT_LENGTH); 1112 | return 10 + ((30 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1113 | } 1114 | 1115 | 1116 | /* 1117 | * Random color intruduced alternating from start and end of strip. 1118 | */ 1119 | uint16_t WS2812FX::mode_color_sweep_random(void) { 1120 | if(SEGMENT_RUNTIME.counter_mode_step == 0 || SEGMENT_RUNTIME.counter_mode_step == SEGMENT_LENGTH) { 1121 | SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); 1122 | } 1123 | 1124 | if(SEGMENT_RUNTIME.counter_mode_step < SEGMENT_LENGTH) { 1125 | if(SEGMENT.reverse) { 1126 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, color_wheel(SEGMENT_RUNTIME.aux_param)); 1127 | } else { 1128 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, color_wheel(SEGMENT_RUNTIME.aux_param)); 1129 | } 1130 | } else { 1131 | if(SEGMENT.reverse) { 1132 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - ((SEGMENT_LENGTH * 2) - SEGMENT_RUNTIME.counter_mode_step) + 1, color_wheel(SEGMENT_RUNTIME.aux_param)); 1133 | } else { 1134 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + ((SEGMENT_LENGTH * 2) - SEGMENT_RUNTIME.counter_mode_step) - 1, color_wheel(SEGMENT_RUNTIME.aux_param)); 1135 | } 1136 | } 1137 | 1138 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % (SEGMENT_LENGTH * 2); 1139 | //return (SEGMENT.speed / (SEGMENT_LENGTH * 2)); 1140 | return 5 + ((50 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1141 | } 1142 | 1143 | 1144 | /* 1145 | * Alternating pixels running function. 1146 | */ 1147 | uint16_t WS2812FX::running(uint32_t color1, uint32_t color2) { 1148 | for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { 1149 | if((i + SEGMENT_RUNTIME.counter_mode_step) % 4 < 2) { 1150 | if(SEGMENT.reverse) { 1151 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color1); 1152 | } else { 1153 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, color1); 1154 | } 1155 | } else { 1156 | if(SEGMENT.reverse) { 1157 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color2); 1158 | } else { 1159 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, color2); 1160 | } 1161 | } 1162 | } 1163 | 1164 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % 4; 1165 | //return (SEGMENT.speed / 4); 1166 | return 10 + ((30 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1167 | } 1168 | 1169 | /* 1170 | * Alternating color/white pixels running. 1171 | */ 1172 | uint16_t WS2812FX::mode_running_color(void) { 1173 | return running(SEGMENT.colors[0], 0xFFFFFF); 1174 | } 1175 | 1176 | 1177 | /* 1178 | * Alternating red/blue pixels running. 1179 | */ 1180 | uint16_t WS2812FX::mode_running_red_blue(void) { 1181 | return running(0xFF0000, 0x0000FF); 1182 | } 1183 | 1184 | 1185 | /* 1186 | * Random colored pixels running. 1187 | */ 1188 | uint16_t WS2812FX::mode_running_random(void) { 1189 | for(uint16_t i=SEGMENT_LENGTH-1; i > 0; i--) { 1190 | if(SEGMENT.reverse) { 1191 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, Adafruit_NeoPixel::getPixelColor(SEGMENT.stop - i + 1)); 1192 | } else { 1193 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, Adafruit_NeoPixel::getPixelColor(SEGMENT.start + i - 1)); 1194 | } 1195 | } 1196 | 1197 | if(SEGMENT_RUNTIME.counter_mode_step == 0) { 1198 | SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); 1199 | if(SEGMENT.reverse) { 1200 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop, color_wheel(SEGMENT_RUNTIME.aux_param)); 1201 | } else { 1202 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start, color_wheel(SEGMENT_RUNTIME.aux_param)); 1203 | } 1204 | } 1205 | 1206 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % 2; 1207 | //return (SEGMENT.speed / SEGMENT_LENGTH); 1208 | return 50 + ((50 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1209 | } 1210 | 1211 | 1212 | /* 1213 | * K.I.T.T. 1214 | */ 1215 | uint16_t WS2812FX::mode_larson_scanner(void) { 1216 | 1217 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 1218 | uint32_t px_rgb = Adafruit_NeoPixel::getPixelColor(i); 1219 | 1220 | byte px_r = (px_rgb & 0xFF0000) >> 16; 1221 | byte px_g = (px_rgb & 0x00FF00) >> 8; 1222 | byte px_b = (px_rgb & 0x0000FF); 1223 | 1224 | px_r = px_r >> 1; // fade out (divide by 2) 1225 | px_g = px_g >> 1; 1226 | px_b = px_b >> 1; 1227 | 1228 | Adafruit_NeoPixel::setPixelColor(i, px_r, px_g, px_b); 1229 | } 1230 | 1231 | if(SEGMENT_RUNTIME.counter_mode_step < SEGMENT_LENGTH) { 1232 | if(SEGMENT.reverse) { 1233 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1234 | } else { 1235 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1236 | } 1237 | } else { 1238 | if(SEGMENT.reverse) { 1239 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - ((SEGMENT_LENGTH * 2) - SEGMENT_RUNTIME.counter_mode_step) + 2, SEGMENT.colors[0]); 1240 | } else { 1241 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + ((SEGMENT_LENGTH * 2) - SEGMENT_RUNTIME.counter_mode_step) - 2, SEGMENT.colors[0]); 1242 | } 1243 | } 1244 | 1245 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % ((SEGMENT_LENGTH * 2) - 2); 1246 | //return (SEGMENT.speed / (SEGMENT_LENGTH * 2)); 1247 | return 10 + ((10 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1248 | } 1249 | 1250 | 1251 | /* 1252 | * Firing comets from one end. 1253 | */ 1254 | uint16_t WS2812FX::mode_comet(void) { 1255 | 1256 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 1257 | uint32_t px_rgb = Adafruit_NeoPixel::getPixelColor(i); 1258 | 1259 | byte px_r = (px_rgb & 0xFF0000) >> 16; 1260 | byte px_g = (px_rgb & 0x00FF00) >> 8; 1261 | byte px_b = (px_rgb & 0x0000FF); 1262 | 1263 | // fade out (divide by 2) 1264 | px_r = px_r >> 1; 1265 | px_g = px_g >> 1; 1266 | px_b = px_b >> 1; 1267 | 1268 | Adafruit_NeoPixel::setPixelColor(i, px_r, px_g, px_b); 1269 | } 1270 | 1271 | if(SEGMENT.reverse) { 1272 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1273 | } else { 1274 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1275 | } 1276 | 1277 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; 1278 | //return (SEGMENT.speed / SEGMENT_LENGTH); 1279 | return 10 + ((10 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1280 | } 1281 | 1282 | 1283 | /* 1284 | * Fireworks function. 1285 | */ 1286 | uint16_t WS2812FX::fireworks(uint32_t color) { 1287 | uint32_t px_rgb = 0; 1288 | byte px_r = 0; 1289 | byte px_g = 0; 1290 | byte px_b = 0; 1291 | 1292 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 1293 | px_rgb = Adafruit_NeoPixel::getPixelColor(i); 1294 | 1295 | px_r = (px_rgb & 0x00FF0000) >> 16; 1296 | px_g = (px_rgb & 0x0000FF00) >> 8; 1297 | px_b = (px_rgb & 0x000000FF); 1298 | 1299 | // fade out (divide by 2) 1300 | px_r = px_r >> 1; 1301 | px_g = px_g >> 1; 1302 | px_b = px_b >> 1; 1303 | 1304 | Adafruit_NeoPixel::setPixelColor(i, px_r, px_g, px_b); 1305 | } 1306 | 1307 | // first LED has only one neighbour 1308 | px_r = (((Adafruit_NeoPixel::getPixelColor(SEGMENT.start+1) & 0xFF0000) >> 16) >> 1) + ((Adafruit_NeoPixel::getPixelColor(SEGMENT.start) & 0xFF0000) >> 16); 1309 | px_g = (((Adafruit_NeoPixel::getPixelColor(SEGMENT.start+1) & 0x00FF00) >> 8) >> 1) + ((Adafruit_NeoPixel::getPixelColor(SEGMENT.start) & 0x00FF00) >> 8); 1310 | px_b = (((Adafruit_NeoPixel::getPixelColor(SEGMENT.start+1) & 0x0000FF) ) >> 1) + ((Adafruit_NeoPixel::getPixelColor(SEGMENT.start) & 0x0000FF)); 1311 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start, px_r, px_g, px_b); 1312 | 1313 | // set brightness(i) = ((brightness(i-1)/2 + brightness(i+1)) / 2) + brightness(i) 1314 | for(uint16_t i=SEGMENT.start+1; i <= SEGMENT.stop-1; i++) { 1315 | px_r = (( 1316 | (((Adafruit_NeoPixel::getPixelColor(i-1) & 0xFF0000) >> 16) >> 1) + 1317 | (((Adafruit_NeoPixel::getPixelColor(i+1) & 0xFF0000) >> 16) ) ) >> 1) + 1318 | (((Adafruit_NeoPixel::getPixelColor(i ) & 0xFF0000) >> 16) ); 1319 | 1320 | px_g = (( 1321 | (((Adafruit_NeoPixel::getPixelColor(i-1) & 0x00FF00) >> 8) >> 1) + 1322 | (((Adafruit_NeoPixel::getPixelColor(i+1) & 0x00FF00) >> 8) ) ) >> 1) + 1323 | (((Adafruit_NeoPixel::getPixelColor(i ) & 0x00FF00) >> 8) ); 1324 | 1325 | px_b = (( 1326 | (((Adafruit_NeoPixel::getPixelColor(i-1) & 0x0000FF) ) >> 1) + 1327 | (((Adafruit_NeoPixel::getPixelColor(i+1) & 0x0000FF) ) ) ) >> 1) + 1328 | (((Adafruit_NeoPixel::getPixelColor(i ) & 0x0000FF) ) ); 1329 | 1330 | Adafruit_NeoPixel::setPixelColor(i, px_r, px_g, px_b); 1331 | } 1332 | 1333 | // last LED has only one neighbour 1334 | px_r = (((Adafruit_NeoPixel::getPixelColor(SEGMENT.stop-1) & 0xFF0000) >> 16) >> 2) + ((Adafruit_NeoPixel::getPixelColor(SEGMENT.stop) & 0xFF0000) >> 16); 1335 | px_g = (((Adafruit_NeoPixel::getPixelColor(SEGMENT.stop-1) & 0x00FF00) >> 8) >> 2) + ((Adafruit_NeoPixel::getPixelColor(SEGMENT.stop) & 0x00FF00) >> 8); 1336 | px_b = (((Adafruit_NeoPixel::getPixelColor(SEGMENT.stop-1) & 0x0000FF) ) >> 2) + ((Adafruit_NeoPixel::getPixelColor(SEGMENT.stop) & 0x0000FF)); 1337 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop, px_r, px_g, px_b); 1338 | 1339 | if(!_triggered) { 1340 | for(uint16_t i=0; i> 16; 1415 | byte p_g = (SEGMENT.colors[0] & 0x00FF00) >> 8; 1416 | byte p_b = (SEGMENT.colors[0] & 0x0000FF); 1417 | byte flicker_val = max(p_r, max(p_g, p_b)) / rev_intensity; 1418 | for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { 1419 | int flicker = random(0, flicker_val); 1420 | int r1 = p_r - flicker; 1421 | int g1 = p_g - flicker; 1422 | int b1 = p_b - flicker; 1423 | if(g1<0) g1 = 0; 1424 | if(r1<0) r1 = 0; 1425 | if(b1<0) b1 = 0; 1426 | Adafruit_NeoPixel::setPixelColor(i, r1, g1, b1); 1427 | } 1428 | //return (SEGMENT.speed); 1429 | return 10 + ((500 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SPEED_MAX); 1430 | } 1431 | 1432 | 1433 | 1434 | /* 1435 | * Lights all LEDs after each other up starting from the outer edges and 1436 | * finishing in the middle. Then turns them in reverse order off. Repeat. 1437 | */ 1438 | uint16_t WS2812FX::mode_dual_color_wipe_in_out(void) { 1439 | int end = SEGMENT_LENGTH - SEGMENT_RUNTIME.counter_mode_step - 1; 1440 | bool odd = (SEGMENT_LENGTH % 2) == 1; 1441 | int mid = odd ? ((SEGMENT_LENGTH / 2) + 1) : (SEGMENT_LENGTH / 2); 1442 | if (SEGMENT_RUNTIME.counter_mode_step < mid) { 1443 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1444 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + end, SEGMENT.colors[0]); 1445 | } else { 1446 | if (odd) { 1447 | // If odd, we need to 'double count' the center LED (once to turn it on, 1448 | // once to turn it off). So trail one behind after the middle LED. 1449 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step - 1, 0); 1450 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + end + 1, 0); 1451 | } else { 1452 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, 0); 1453 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + end, 0); 1454 | } 1455 | } 1456 | 1457 | SEGMENT_RUNTIME.counter_mode_step++; 1458 | if (odd) { 1459 | if (SEGMENT_RUNTIME.counter_mode_step > SEGMENT_LENGTH) { 1460 | SEGMENT_RUNTIME.counter_mode_step = 0; 1461 | } 1462 | } else { 1463 | if (SEGMENT_RUNTIME.counter_mode_step >= SEGMENT_LENGTH) { 1464 | SEGMENT_RUNTIME.counter_mode_step = 0; 1465 | } 1466 | } 1467 | //return (SEGMENT.speed / SEGMENT_LENGTH); 1468 | return 5 + ((50 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1469 | } 1470 | 1471 | /* 1472 | * Lights all LEDs after each other up starting from the outer edges and 1473 | * finishing in the middle. Then turns them in that order off. Repeat. 1474 | */ 1475 | uint16_t WS2812FX::mode_dual_color_wipe_in_in(void) { 1476 | bool odd = (SEGMENT_LENGTH % 2) == 1; 1477 | int mid = SEGMENT_LENGTH / 2; 1478 | if (odd) { 1479 | if (SEGMENT_RUNTIME.counter_mode_step <= mid) { 1480 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1481 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_LENGTH - SEGMENT_RUNTIME.counter_mode_step - 1, SEGMENT.colors[0]); 1482 | } else { 1483 | int i = SEGMENT_RUNTIME.counter_mode_step - mid; 1484 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i - 1, 0); 1485 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i, 0); 1486 | } 1487 | } else { 1488 | if (SEGMENT_RUNTIME.counter_mode_step < mid) { 1489 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1490 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_LENGTH - SEGMENT_RUNTIME.counter_mode_step - 1, SEGMENT.colors[0]); 1491 | } else { 1492 | int i = SEGMENT_RUNTIME.counter_mode_step - mid; 1493 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, 0); 1494 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i - 1, 0); 1495 | } 1496 | } 1497 | 1498 | SEGMENT_RUNTIME.counter_mode_step++; 1499 | if (odd) { 1500 | if (SEGMENT_RUNTIME.counter_mode_step > SEGMENT_LENGTH) { 1501 | SEGMENT_RUNTIME.counter_mode_step = 0; 1502 | } 1503 | } else { 1504 | if (SEGMENT_RUNTIME.counter_mode_step >= SEGMENT_LENGTH) { 1505 | SEGMENT_RUNTIME.counter_mode_step = 0; 1506 | } 1507 | } 1508 | //return (SEGMENT.speed / SEGMENT_LENGTH); 1509 | return 5 + ((50 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1510 | } 1511 | 1512 | /* 1513 | * Lights all LEDs after each other up starting from the middle and 1514 | * finishing at the edges. Then turns them off in that order. Repeat. 1515 | */ 1516 | uint16_t WS2812FX::mode_dual_color_wipe_out_out(void) { 1517 | int end = SEGMENT_LENGTH - SEGMENT_RUNTIME.counter_mode_step - 1; 1518 | bool odd = (SEGMENT_LENGTH % 2) == 1; 1519 | int mid = SEGMENT_LENGTH / 2; 1520 | 1521 | if (odd) { 1522 | if (SEGMENT_RUNTIME.counter_mode_step <= mid) { 1523 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1524 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1525 | } else { 1526 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step - 1, 0); 1527 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + end + 1, 0); 1528 | } 1529 | } else { 1530 | if (SEGMENT_RUNTIME.counter_mode_step < mid) { 1531 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step - 1, SEGMENT.colors[0]); 1532 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1533 | } else { 1534 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, 0); 1535 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + end, 0); 1536 | } 1537 | } 1538 | 1539 | SEGMENT_RUNTIME.counter_mode_step++; 1540 | if (odd) { 1541 | if (SEGMENT_RUNTIME.counter_mode_step > SEGMENT_LENGTH) { 1542 | SEGMENT_RUNTIME.counter_mode_step = 0; 1543 | } 1544 | } else { 1545 | if (SEGMENT_RUNTIME.counter_mode_step >= SEGMENT_LENGTH) { 1546 | SEGMENT_RUNTIME.counter_mode_step = 0; 1547 | } 1548 | } 1549 | //return (SEGMENT.speed / SEGMENT_LENGTH); 1550 | return 5 + ((50 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1551 | } 1552 | 1553 | /* 1554 | * Lights all LEDs after each other up starting from the middle and 1555 | * finishing at the edges. Then turns them off in reverse order. Repeat. 1556 | */ 1557 | uint16_t WS2812FX::mode_dual_color_wipe_out_in(void) { 1558 | bool odd = (SEGMENT_LENGTH % 2) == 1; 1559 | int mid = SEGMENT_LENGTH / 2; 1560 | 1561 | if (odd) { 1562 | if (SEGMENT_RUNTIME.counter_mode_step <= mid) { 1563 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1564 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1565 | } else { 1566 | int i = SEGMENT_RUNTIME.counter_mode_step - mid; 1567 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i - 1, 0); 1568 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i, 0); 1569 | } 1570 | } else { 1571 | if (SEGMENT_RUNTIME.counter_mode_step < mid) { 1572 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step - 1, SEGMENT.colors[0]); 1573 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); 1574 | } else { 1575 | int i = SEGMENT_RUNTIME.counter_mode_step - mid; 1576 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, 0); 1577 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i - 1, 0); 1578 | } 1579 | } 1580 | 1581 | SEGMENT_RUNTIME.counter_mode_step++; 1582 | if (odd) { 1583 | if (SEGMENT_RUNTIME.counter_mode_step > SEGMENT_LENGTH) { 1584 | SEGMENT_RUNTIME.counter_mode_step = 0; 1585 | } 1586 | } else { 1587 | if (SEGMENT_RUNTIME.counter_mode_step >= SEGMENT_LENGTH) { 1588 | SEGMENT_RUNTIME.counter_mode_step = 0; 1589 | } 1590 | } 1591 | //return (SEGMENT.speed / SEGMENT_LENGTH); 1592 | return 5 + ((50 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1593 | } 1594 | 1595 | 1596 | /* 1597 | * Alternating white/red/black pixels running. 1598 | */ 1599 | uint16_t WS2812FX::mode_circus_combustus(void) { 1600 | return tricolor_chase(0xFF0000, 0xFFFFFF, 0); 1601 | } 1602 | 1603 | 1604 | /* 1605 | * Tricolor chase function 1606 | */ 1607 | uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2, uint32_t color3) { 1608 | for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { 1609 | if((i + SEGMENT_RUNTIME.counter_mode_step) % 6 < 2) { 1610 | if(SEGMENT.reverse) { 1611 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color1); 1612 | } else { 1613 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, color1); 1614 | } 1615 | } else if((i + SEGMENT_RUNTIME.counter_mode_step) % 6 < 4) { 1616 | if(SEGMENT.reverse) { 1617 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color2); 1618 | } else { 1619 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, color2); 1620 | } 1621 | } else { 1622 | if(SEGMENT.reverse) { 1623 | Adafruit_NeoPixel::setPixelColor(SEGMENT.start + i, color3); 1624 | } else { 1625 | Adafruit_NeoPixel::setPixelColor(SEGMENT.stop - i, color3); 1626 | } 1627 | } 1628 | } 1629 | 1630 | SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % 6; 1631 | //return (SEGMENT.speed / 6); 1632 | return 100 + ((100 * (uint32_t)(SPEED_MAX - SEGMENT.speed)) / SEGMENT_LENGTH); 1633 | } 1634 | 1635 | /* 1636 | * Bicolor chase mode 1637 | */ 1638 | uint16_t WS2812FX::mode_bicolor_chase(void) { 1639 | return chase(SEGMENT.colors[0], SEGMENT.colors[1], SEGMENT.colors[2]); 1640 | } 1641 | 1642 | 1643 | /* 1644 | * Tricolor chase mode 1645 | */ 1646 | uint16_t WS2812FX::mode_tricolor_chase(void) { 1647 | return tricolor_chase(SEGMENT.colors[0], SEGMENT.colors[1], SEGMENT.colors[2]); 1648 | } 1649 | -------------------------------------------------------------------------------- /lib/WS2812FX/WS2812FX.h: -------------------------------------------------------------------------------- 1 | /* 2 | WS2812FX.h - Library for WS2812 LED effects. 3 | 4 | Harm Aldick - 2016 5 | www.aldick.org 6 | FEATURES 7 | * A lot of blinken modes and counting 8 | * WS2812FX can be used as drop-in replacement for Adafruit Neopixel Library 9 | NOTES 10 | * Uses the Adafruit Neopixel library. Get it here: 11 | https://github.com/adafruit/Adafruit_NeoPixel 12 | LICENSE 13 | The MIT License (MIT) 14 | Copyright (c) 2016 Harm Aldick 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | The above copyright notice and this permission notice shall be included in 22 | all copies or substantial portions of the Software. 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | THE SOFTWARE. 30 | CHANGELOG 31 | 2016-05-28 Initial beta release 32 | 2016-06-03 Code cleanup, minor improvements, new modes 33 | 2016-06-04 2 new fx, fixed setColor (now also resets _mode_color) 34 | 2017-02-02 added external trigger functionality (e.g. for sound-to-light) 35 | */ 36 | 37 | #ifndef WS2812FX_h 38 | #define WS2812FX_h 39 | 40 | #include "Arduino.h" 41 | #include 42 | 43 | #define DEFAULT_BRIGHTNESS 50 44 | #define DEFAULT_MODE 0 45 | #define DEFAULT_SPEED 150 46 | #define DEFAULT_COLOR 0xFF0000 47 | 48 | #define SPEED_MIN 0 49 | #define SPEED_MAX 255 50 | 51 | #define BRIGHTNESS_MIN 0 52 | #define BRIGHTNESS_MAX 255 53 | 54 | #define MAX_NUM_SEGMENTS 10 55 | #define NUM_COLORS 3 /* number of colors per segment */ 56 | #define SEGMENT _segments[_segment_index] 57 | #define SEGMENT_RUNTIME _segment_runtimes[_segment_index] 58 | #define SEGMENT_LENGTH (SEGMENT.stop - SEGMENT.start + 1) 59 | #define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes)) 60 | 61 | #define MODE_COUNT 57 62 | 63 | #define FX_MODE_STATIC 0 64 | #define FX_MODE_BLINK 1 65 | #define FX_MODE_BREATH 2 66 | #define FX_MODE_COLOR_WIPE 3 67 | #define FX_MODE_COLOR_WIPE_RANDOM 4 68 | #define FX_MODE_RANDOM_COLOR 5 69 | #define FX_MODE_SINGLE_DYNAMIC 6 70 | #define FX_MODE_MULTI_DYNAMIC 7 71 | #define FX_MODE_RAINBOW 8 72 | #define FX_MODE_RAINBOW_CYCLE 9 73 | #define FX_MODE_SCAN 10 74 | #define FX_MODE_DUAL_SCAN 11 75 | #define FX_MODE_FADE 12 76 | #define FX_MODE_THEATER_CHASE 13 77 | #define FX_MODE_THEATER_CHASE_RAINBOW 14 78 | #define FX_MODE_RUNNING_LIGHTS 15 79 | #define FX_MODE_TWINKLE 16 80 | #define FX_MODE_TWINKLE_RANDOM 17 81 | #define FX_MODE_TWINKLE_FADE 18 82 | #define FX_MODE_TWINKLE_FADE_RANDOM 19 83 | #define FX_MODE_SPARKLE 20 84 | #define FX_MODE_FLASH_SPARKLE 21 85 | #define FX_MODE_HYPER_SPARKLE 22 86 | #define FX_MODE_STROBE 23 87 | #define FX_MODE_STROBE_RAINBOW 24 88 | #define FX_MODE_MULTI_STROBE 25 89 | #define FX_MODE_BLINK_RAINBOW 26 90 | #define FX_MODE_CHASE_WHITE 27 91 | #define FX_MODE_CHASE_COLOR 28 92 | #define FX_MODE_CHASE_RANDOM 29 93 | #define FX_MODE_CHASE_RAINBOW 30 94 | #define FX_MODE_CHASE_FLASH 31 95 | #define FX_MODE_CHASE_FLASH_RANDOM 32 96 | #define FX_MODE_CHASE_RAINBOW_WHITE 33 97 | #define FX_MODE_CHASE_BLACKOUT 34 98 | #define FX_MODE_CHASE_BLACKOUT_RAINBOW 35 99 | #define FX_MODE_COLOR_SWEEP_RANDOM 36 100 | #define FX_MODE_RUNNING_COLOR 37 101 | #define FX_MODE_RUNNING_RED_BLUE 38 102 | #define FX_MODE_RUNNING_RANDOM 39 103 | #define FX_MODE_LARSON_SCANNER 40 104 | #define FX_MODE_COMET 41 105 | #define FX_MODE_FIREWORKS 42 106 | #define FX_MODE_FIREWORKS_RANDOM 43 107 | #define FX_MODE_MERRY_CHRISTMAS 44 108 | #define FX_MODE_FIRE_FLICKER 45 109 | #define FX_MODE_FIRE_FLICKER_SOFT 46 110 | #define FX_MODE_FIRE_FLICKER_INTENSE 47 111 | #define FX_MODE_DUAL_COLOR_WIPE_IN_OUT 48 112 | #define FX_MODE_DUAL_COLOR_WIPE_IN_IN 49 113 | #define FX_MODE_DUAL_COLOR_WIPE_OUT_OUT 50 114 | #define FX_MODE_DUAL_COLOR_WIPE_OUT_IN 51 115 | #define FX_MODE_CIRCUS_COMBUSTUS 52 116 | #define FX_MODE_HALLOWEEN 53 117 | #define FX_MODE_COLOR_WIPE_INVERSE 54 118 | #define FX_MODE_BICOLOR_CHASE 55 119 | #define FX_MODE_TRICOLOR_CHASE 56 120 | 121 | class WS2812FX : public Adafruit_NeoPixel 122 | { 123 | 124 | typedef uint16_t (WS2812FX::*mode_ptr)(void); 125 | 126 | // segment parameters 127 | public: 128 | typedef struct segment 129 | { 130 | uint8_t mode; 131 | uint32_t colors[NUM_COLORS]; 132 | uint16_t speed; 133 | uint16_t start; 134 | uint16_t stop; 135 | bool reverse; 136 | } segment; 137 | 138 | // segment runtime parameters 139 | typedef struct segment_runtime 140 | { 141 | uint32_t counter_mode_step; 142 | uint32_t counter_mode_call; 143 | unsigned long next_time; 144 | uint8_t aux_param; 145 | } segment_runtime; 146 | 147 | public: 148 | WS2812FX(uint16_t n, uint8_t p, neoPixelType t) : Adafruit_NeoPixel(n, p, t) 149 | { 150 | _mode[FX_MODE_STATIC] = &WS2812FX::mode_static; 151 | _mode[FX_MODE_BLINK] = &WS2812FX::mode_blink; 152 | //_mode[FX_MODE_BREATH] = &WS2812FX::mode_breath; 153 | _mode[FX_MODE_COLOR_WIPE] = &WS2812FX::mode_color_wipe; 154 | _mode[FX_MODE_COLOR_WIPE_INVERSE] = &WS2812FX::mode_color_wipe_inverse; 155 | _mode[FX_MODE_COLOR_WIPE_RANDOM] = &WS2812FX::mode_color_wipe_random; 156 | _mode[FX_MODE_RANDOM_COLOR] = &WS2812FX::mode_random_color; 157 | _mode[FX_MODE_SINGLE_DYNAMIC] = &WS2812FX::mode_single_dynamic; 158 | _mode[FX_MODE_MULTI_DYNAMIC] = &WS2812FX::mode_multi_dynamic; 159 | _mode[FX_MODE_RAINBOW] = &WS2812FX::mode_rainbow; 160 | _mode[FX_MODE_RAINBOW_CYCLE] = &WS2812FX::mode_rainbow_cycle; 161 | _mode[FX_MODE_SCAN] = &WS2812FX::mode_scan; 162 | _mode[FX_MODE_DUAL_SCAN] = &WS2812FX::mode_dual_scan; 163 | _mode[FX_MODE_FADE] = &WS2812FX::mode_fade; 164 | _mode[FX_MODE_THEATER_CHASE] = &WS2812FX::mode_theater_chase; 165 | _mode[FX_MODE_THEATER_CHASE_RAINBOW] = &WS2812FX::mode_theater_chase_rainbow; 166 | //_mode[FX_MODE_RUNNING_LIGHTS] = &WS2812FX::mode_running_lights; 167 | //_mode[FX_MODE_TWINKLE] = &WS2812FX::mode_twinkle; 168 | _mode[FX_MODE_TWINKLE_RANDOM] = &WS2812FX::mode_twinkle_random; 169 | _mode[FX_MODE_TWINKLE_FADE] = &WS2812FX::mode_twinkle_fade; 170 | _mode[FX_MODE_TWINKLE_FADE_RANDOM] = &WS2812FX::mode_twinkle_fade_random; 171 | _mode[FX_MODE_SPARKLE] = &WS2812FX::mode_sparkle; 172 | _mode[FX_MODE_FLASH_SPARKLE] = &WS2812FX::mode_flash_sparkle; 173 | _mode[FX_MODE_HYPER_SPARKLE] = &WS2812FX::mode_hyper_sparkle; 174 | _mode[FX_MODE_STROBE] = &WS2812FX::mode_strobe; 175 | _mode[FX_MODE_STROBE_RAINBOW] = &WS2812FX::mode_strobe_rainbow; 176 | _mode[FX_MODE_MULTI_STROBE] = &WS2812FX::mode_multi_strobe; 177 | _mode[FX_MODE_BLINK_RAINBOW] = &WS2812FX::mode_blink_rainbow; 178 | _mode[FX_MODE_CHASE_WHITE] = &WS2812FX::mode_chase_white; 179 | _mode[FX_MODE_CHASE_COLOR] = &WS2812FX::mode_chase_color; 180 | _mode[FX_MODE_CHASE_RANDOM] = &WS2812FX::mode_chase_random; 181 | _mode[FX_MODE_CHASE_RAINBOW] = &WS2812FX::mode_chase_rainbow; 182 | _mode[FX_MODE_CHASE_FLASH] = &WS2812FX::mode_chase_flash; 183 | _mode[FX_MODE_CHASE_FLASH_RANDOM] = &WS2812FX::mode_chase_flash_random; 184 | _mode[FX_MODE_CHASE_RAINBOW_WHITE] = &WS2812FX::mode_chase_rainbow_white; 185 | _mode[FX_MODE_CHASE_BLACKOUT] = &WS2812FX::mode_chase_blackout; 186 | _mode[FX_MODE_CHASE_BLACKOUT_RAINBOW] = &WS2812FX::mode_chase_blackout_rainbow; 187 | _mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random; 188 | _mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color; 189 | _mode[FX_MODE_RUNNING_RED_BLUE] = &WS2812FX::mode_running_red_blue; 190 | _mode[FX_MODE_RUNNING_RANDOM] = &WS2812FX::mode_running_random; 191 | //_mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner; 192 | _mode[FX_MODE_COMET] = &WS2812FX::mode_comet; 193 | _mode[FX_MODE_FIREWORKS] = &WS2812FX::mode_fireworks; 194 | //_mode[FX_MODE_FIREWORKS_RANDOM] = &WS2812FX::mode_fireworks_random; 195 | _mode[FX_MODE_MERRY_CHRISTMAS] = &WS2812FX::mode_merry_christmas; 196 | _mode[FX_MODE_HALLOWEEN] = &WS2812FX::mode_halloween; 197 | _mode[FX_MODE_FIRE_FLICKER] = &WS2812FX::mode_fire_flicker; 198 | _mode[FX_MODE_FIRE_FLICKER_SOFT] = &WS2812FX::mode_fire_flicker_soft; 199 | _mode[FX_MODE_FIRE_FLICKER_INTENSE] = &WS2812FX::mode_fire_flicker_intense; 200 | /* 201 | _mode[FX_MODE_DUAL_COLOR_WIPE_IN_OUT] = &WS2812FX::mode_dual_color_wipe_in_out; 202 | _mode[FX_MODE_DUAL_COLOR_WIPE_IN_IN] = &WS2812FX::mode_dual_color_wipe_in_in; 203 | _mode[FX_MODE_DUAL_COLOR_WIPE_OUT_OUT] = &WS2812FX::mode_dual_color_wipe_out_out; 204 | _mode[FX_MODE_DUAL_COLOR_WIPE_OUT_IN] = &WS2812FX::mode_dual_color_wipe_out_in; 205 | _mode[FX_MODE_CIRCUS_COMBUSTUS] = &WS2812FX::mode_circus_combustus; 206 | _mode[FX_MODE_BICOLOR_CHASE] = &WS2812FX::mode_bicolor_chase; 207 | _mode[FX_MODE_TRICOLOR_CHASE] = &WS2812FX::mode_tricolor_chase; 208 | */ 209 | 210 | _name[FX_MODE_STATIC] = F("Static"); 211 | _name[FX_MODE_BLINK] = F("Blink"); 212 | //_name[FX_MODE_BREATH] = F("Breath"); 213 | _name[FX_MODE_COLOR_WIPE] = F("Color Wipe"); 214 | _name[FX_MODE_COLOR_WIPE_INVERSE] = F("Color Wipe Inverse"); 215 | _name[FX_MODE_COLOR_WIPE_RANDOM] = F("Color Wipe Random"); 216 | _name[FX_MODE_RANDOM_COLOR] = F("Random Color"); 217 | _name[FX_MODE_SINGLE_DYNAMIC] = F("Single Dynamic"); 218 | _name[FX_MODE_MULTI_DYNAMIC] = F("Multi Dynamic"); 219 | _name[FX_MODE_RAINBOW] = F("Rainbow"); 220 | _name[FX_MODE_RAINBOW_CYCLE] = F("Rainbow Cycle"); 221 | _name[FX_MODE_SCAN] = F("Scan"); 222 | _name[FX_MODE_DUAL_SCAN] = F("Dual Scan"); 223 | _name[FX_MODE_FADE] = F("Fade"); 224 | _name[FX_MODE_THEATER_CHASE] = F("Theater Chase"); 225 | _name[FX_MODE_THEATER_CHASE_RAINBOW] = F("Theater Chase Rainbow"); 226 | //_name[FX_MODE_RUNNING_LIGHTS] = F("Running Lights"); 227 | //_name[FX_MODE_TWINKLE] = F("Twinkle"); 228 | _name[FX_MODE_TWINKLE_RANDOM] = F("Twinkle Random"); 229 | _name[FX_MODE_TWINKLE_FADE] = F("Twinkle Fade"); 230 | _name[FX_MODE_TWINKLE_FADE_RANDOM] = F("Twinkle Fade Random"); 231 | _name[FX_MODE_SPARKLE] = F("Sparkle"); 232 | _name[FX_MODE_FLASH_SPARKLE] = F("Flash Sparkle"); 233 | _name[FX_MODE_HYPER_SPARKLE] = F("Hyper Sparkle"); 234 | _name[FX_MODE_STROBE] = F("Strobe"); 235 | _name[FX_MODE_STROBE_RAINBOW] = F("Strobe Rainbow"); 236 | _name[FX_MODE_MULTI_STROBE] = F("Multi Strobe"); 237 | _name[FX_MODE_BLINK_RAINBOW] = F("Blink Rainbow"); 238 | _name[FX_MODE_CHASE_WHITE] = F("Chase White"); 239 | _name[FX_MODE_CHASE_COLOR] = F("Chase Color"); 240 | _name[FX_MODE_CHASE_RANDOM] = F("Chase Random"); 241 | _name[FX_MODE_CHASE_RAINBOW] = F("Chase Rainbow"); 242 | _name[FX_MODE_CHASE_FLASH] = F("Chase Flash"); 243 | _name[FX_MODE_CHASE_FLASH_RANDOM] = F("Chase Flash Random"); 244 | _name[FX_MODE_CHASE_RAINBOW_WHITE] = F("Chase Rainbow White"); 245 | _name[FX_MODE_CHASE_BLACKOUT] = F("Chase Blackout"); 246 | _name[FX_MODE_CHASE_BLACKOUT_RAINBOW] = F("Chase Blackout Rainbow"); 247 | _name[FX_MODE_COLOR_SWEEP_RANDOM] = F("Color Sweep Random"); 248 | _name[FX_MODE_RUNNING_COLOR] = F("Running Color"); 249 | _name[FX_MODE_RUNNING_RED_BLUE] = F("Running Red Blue"); 250 | _name[FX_MODE_RUNNING_RANDOM] = F("Running Random"); 251 | //_name[FX_MODE_LARSON_SCANNER] = F("Larson Scanner"); 252 | _name[FX_MODE_COMET] = F("Comet"); 253 | _name[FX_MODE_FIREWORKS] = F("Fireworks"); 254 | //_name[FX_MODE_FIREWORKS_RANDOM] = F("Fireworks Random"); 255 | _name[FX_MODE_MERRY_CHRISTMAS] = F("Merry Christmas"); 256 | _name[FX_MODE_HALLOWEEN] = F("Halloween"); 257 | _name[FX_MODE_FIRE_FLICKER] = F("Fire Flicker"); 258 | _name[FX_MODE_FIRE_FLICKER_SOFT] = F("Fire Flicker (soft)"); 259 | _name[FX_MODE_FIRE_FLICKER_INTENSE] = F("Fire Flicker (intense)"); 260 | /* 261 | _name[FX_MODE_DUAL_COLOR_WIPE_IN_OUT] = F("Dual Color Wipe In to Out"); 262 | _name[FX_MODE_DUAL_COLOR_WIPE_IN_IN] = F("Dual Color Wipe In to In"); 263 | _name[FX_MODE_DUAL_COLOR_WIPE_OUT_OUT] = F("Dual Color Wipe Out to Out"); 264 | _name[FX_MODE_DUAL_COLOR_WIPE_OUT_IN] = F("Dual Color Wipe Out to In"); 265 | _name[FX_MODE_CIRCUS_COMBUSTUS] = F("Circus Combustus"); 266 | _name[FX_MODE_BICOLOR_CHASE] = F("Bicolor Chase"); 267 | _name[FX_MODE_TRICOLOR_CHASE] = F("Tricolor Chase"); 268 | */ 269 | 270 | // _mode_index = DEFAULT_MODE; 271 | // _speed = DEFAULT_SPEED; 272 | _brightness = DEFAULT_BRIGHTNESS; 273 | _running = false; 274 | // _led_count = n; 275 | // _mode_last_call_time = 0; 276 | // _mode_delay = 50; 277 | // _color = DEFAULT_COLOR; 278 | // _mode_color = DEFAULT_COLOR; 279 | // _counter_mode_call = 0; 280 | // _counter_mode_step = 0; 281 | RESET_RUNTIME; 282 | _num_segments = 1; 283 | _segments[0].mode = DEFAULT_MODE; 284 | _segments[0].colors[0] = DEFAULT_COLOR; 285 | _segments[0].start = 0; 286 | _segments[0].stop = n - 1; 287 | _segments[0].speed = DEFAULT_SPEED; 288 | } 289 | 290 | void 291 | init(void), 292 | service(void), 293 | start(void), 294 | stop(void), 295 | setMode(uint8_t m), 296 | setSpeed(uint16_t s), 297 | increaseSpeed(uint8_t s), 298 | decreaseSpeed(uint8_t s), 299 | setColor(uint8_t r, uint8_t g, uint8_t b), 300 | setColor(uint32_t c), 301 | setBrightness(uint8_t b), 302 | increaseBrightness(uint8_t s), 303 | decreaseBrightness(uint8_t s), 304 | setLength(uint16_t b), 305 | increaseLength(uint16_t s), 306 | decreaseLength(uint16_t s), 307 | trigger(void), 308 | setNumSegments(uint8_t n), 309 | setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, bool reverse), 310 | setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint16_t speed, bool reverse); 311 | 312 | boolean 313 | isRunning(void); 314 | 315 | uint8_t 316 | getMode(void), 317 | getBrightness(void), 318 | getModeCount(void), 319 | getNumSegments(void); 320 | 321 | uint16_t 322 | getSpeed(void), 323 | getLength(void); 324 | 325 | uint32_t 326 | color_wheel(uint8_t), 327 | getColor(void); 328 | 329 | const __FlashStringHelper * 330 | getModeName(uint8_t m); 331 | 332 | WS2812FX::segment * 333 | getSegments(void); 334 | 335 | private: 336 | void 337 | strip_off(void); 338 | 339 | uint16_t 340 | mode_static(void), 341 | mode_blink(void), 342 | color_wipe(uint32_t, uint32_t), 343 | mode_color_wipe(void), 344 | mode_color_wipe_inverse(void), 345 | mode_color_wipe_random(void), 346 | mode_random_color(void), 347 | mode_single_dynamic(void), 348 | mode_multi_dynamic(void), 349 | mode_breath(void), 350 | mode_fade(void), 351 | mode_scan(void), 352 | mode_dual_scan(void), 353 | mode_theater_chase(void), 354 | mode_theater_chase_rainbow(void), 355 | mode_rainbow(void), 356 | mode_rainbow_cycle(void), 357 | mode_running_lights(void), 358 | twinkle(uint32_t), 359 | mode_twinkle(void), 360 | mode_twinkle_random(void), 361 | twinkle_fade(uint32_t), 362 | mode_twinkle_fade(void), 363 | mode_twinkle_fade_random(void), 364 | mode_sparkle(void), 365 | mode_flash_sparkle(void), 366 | mode_hyper_sparkle(void), 367 | mode_strobe(void), 368 | mode_strobe_rainbow(void), 369 | mode_multi_strobe(void), 370 | mode_blink_rainbow(void), 371 | chase(uint32_t, uint32_t, uint32_t), 372 | mode_chase_white(void), 373 | mode_chase_color(void), 374 | mode_chase_random(void), 375 | mode_chase_rainbow(void), 376 | mode_chase_flash(void), 377 | mode_chase_flash_random(void), 378 | mode_chase_rainbow_white(void), 379 | mode_chase_blackout(void), 380 | mode_chase_blackout_rainbow(void), 381 | mode_color_sweep_random(void), 382 | running(uint32_t, uint32_t), 383 | mode_running_color(void), 384 | mode_running_red_blue(void), 385 | mode_running_random(void), 386 | mode_larson_scanner(void), 387 | mode_comet(void), 388 | fireworks(uint32_t), 389 | mode_fireworks(void), 390 | mode_fireworks_random(void), 391 | mode_merry_christmas(void), 392 | mode_halloween(void), 393 | mode_fire_flicker(void), 394 | mode_fire_flicker_soft(void), 395 | mode_fire_flicker_intense(void), 396 | fire_flicker(int), 397 | mode_dual_color_wipe_in_out(void), 398 | mode_dual_color_wipe_in_in(void), 399 | mode_dual_color_wipe_out_out(void), 400 | mode_dual_color_wipe_out_in(void), 401 | mode_circus_combustus(void), 402 | tricolor_chase(uint32_t, uint32_t, uint32_t), 403 | mode_bicolor_chase(void), 404 | mode_tricolor_chase(void); 405 | 406 | boolean 407 | _running, 408 | _triggered; 409 | 410 | uint8_t 411 | get_random_wheel_index(uint8_t), 412 | // _mode_index, 413 | // _speed, 414 | _brightness; 415 | 416 | // uint16_t 417 | // _led_count; 418 | 419 | // uint32_t 420 | // _color, 421 | // _counter_mode_call, 422 | // _counter_mode_step, 423 | // _mode_color, 424 | // _mode_delay; 425 | 426 | // unsigned long 427 | // _mode_last_call_time; 428 | 429 | const __FlashStringHelper * 430 | _name[MODE_COUNT]; 431 | 432 | mode_ptr 433 | _mode[MODE_COUNT]; 434 | 435 | uint8_t _segment_index = 0; 436 | uint8_t _num_segments = 1; 437 | segment _segments[MAX_NUM_SEGMENTS] = {// must explicitly set array size 438 | // mode, color[], speed, start, stop, reverse 439 | {FX_MODE_STATIC, {DEFAULT_COLOR}, DEFAULT_SPEED, 0, 9, false}}; 440 | segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; 441 | }; 442 | 443 | #endif 444 | -------------------------------------------------------------------------------- /lib/WS2812FX/WS2812FX_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alvarowolfx/physical-led-ring-webusb-arduino/9466b685d4a731b21aedef5529790303bd04511c/lib/WS2812FX/WS2812FX_logo.png -------------------------------------------------------------------------------- /lib/WS2812FX/keywords.txt: -------------------------------------------------------------------------------- 1 | WS2812FX KEYWORD1 2 | init KEYWORD2 3 | service KEYWORD2 4 | start KEYWORD2 5 | stop KEYWORD2 6 | trigger KEYWORD2 7 | setMode KEYWORD2 8 | setSpeed KEYWORD2 9 | increaseSpeed KEYWORD2 10 | decreaseSpeed KEYWORD2 11 | setColor KEYWORD2 12 | setBrightness KEYWORD2 13 | setSegment KEYWORD2 14 | increaseBrightness KEYWORD2 15 | decreaseBrightness KEYWORD2 16 | isRunning KEYWORD2 17 | getMode KEYWORD2 18 | getSpeed KEYWORD2 19 | getBrightness KEYWORD2 20 | getModeCount KEYWORD2 21 | getModeName KEYWORD2 22 | getColor KEYWORD2 23 | getNumSegments KEYWORD2 24 | getSegments KEYWORD2 25 | FX_MODE_STATIC KEYWORD2 26 | FX_MODE_BLINK KEYWORD2 27 | FX_MODE_BREATH KEYWORD2 28 | FX_MODE_COLOR_WIPE KEYWORD2 29 | FX_MODE_COLOR_WIPE_INVERSE KEYWORD2 30 | FX_MODE_COLOR_WIPE_RANDOM KEYWORD2 31 | FX_MODE_RANDOM_COLOR KEYWORD2 32 | FX_MODE_SINGLE_DYNAMIC KEYWORD2 33 | FX_MODE_MULTI_DYNAMIC KEYWORD2 34 | FX_MODE_RAINBOW KEYWORD2 35 | FX_MODE_RAINBOW_CYCLE KEYWORD2 36 | FX_MODE_SCAN KEYWORD2 37 | FX_MODE_DUAL_SCAN KEYWORD2 38 | FX_MODE_FADE KEYWORD2 39 | FX_MODE_THEATER_CHASE KEYWORD2 40 | FX_MODE_THEATER_CHASE_RAINBOW KEYWORD2 41 | FX_MODE_RUNNING_LIGHTS KEYWORD2 42 | FX_MODE_TWINKLE KEYWORD2 43 | FX_MODE_TWINKLE_RANDOM KEYWORD2 44 | FX_MODE_TWINKLE_FADE KEYWORD2 45 | FX_MODE_TWINKLE_FADE_RANDOM KEYWORD2 46 | FX_MODE_SPARKLE KEYWORD2 47 | FX_MODE_FLASH_SPARKLE KEYWORD2 48 | FX_MODE_HYPER_SPARKLE KEYWORD2 49 | FX_MODE_STROBE KEYWORD2 50 | FX_MODE_STROBE_RAINBOW KEYWORD2 51 | FX_MODE_MULTI_STROBE KEYWORD2 52 | FX_MODE_BLINK_RAINBOW KEYWORD2 53 | FX_MODE_CHASE_WHITE KEYWORD2 54 | FX_MODE_CHASE_COLOR KEYWORD2 55 | FX_MODE_CHASE_RANDOM KEYWORD2 56 | FX_MODE_CHASE_RAINBOW KEYWORD2 57 | FX_MODE_CHASE_FLASH KEYWORD2 58 | FX_MODE_CHASE_FLASH_RANDOM KEYWORD2 59 | FX_MODE_CHASE_RAINBOW_WHITE KEYWORD2 60 | FX_MODE_CHASE_BLACKOUT KEYWORD2 61 | FX_MODE_CHASE_BLACKOUT_RAINBOW KEYWORD2 62 | FX_MODE_COLOR_SWEEP_RANDOM KEYWORD2 63 | FX_MODE_RUNNING_COLOR KEYWORD2 64 | FX_MODE_RUNNING_RED_BLUE KEYWORD2 65 | FX_MODE_RUNNING_RANDOM KEYWORD2 66 | FX_MODE_LARSON_SCANNER KEYWORD2 67 | FX_MODE_COMET KEYWORD2 68 | FX_MODE_FIREWORKS KEYWORD2 69 | FX_MODE_FIREWORKS_RANDOM KEYWORD2 70 | FX_MODE_MERRY_CHRISTMAS KEYWORD2 71 | FX_MODE_HALLOWEEN KEYWORD2 72 | FX_MODE_FIRE_FLICKER KEYWORD2 73 | FX_MODE_FIRE_FLICKER_SOFT KEYWORD2 74 | FX_MODE_FIRE_FLICKER_INTENSE KEYWORD2 75 | FX_MODE_DUAL_COLOR_WIPE_IN_OUT KEYWORD2 76 | FX_MODE_DUAL_COLOR_WIPE_IN_IN KEYWORD2 77 | FX_MODE_DUAL_COLOR_WIPE_OUT_OUT KEYWORD2 78 | FX_MODE_DUAL_COLOR_WIPE_OUT_IN KEYWORD2 79 | FX_MODE_CIRCUS_COMBUSTUS KEYWORD2 80 | FX_MODE_BICOLOR_CHASE KEYWORD2 81 | FX_MODE_TRICOLOR_CHASE KEYWORD2 82 | -------------------------------------------------------------------------------- /lib/WS2812FX/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WS2812FX", 3 | "description": "WS2812 FX Library for Arduino and ESP8266", 4 | "keywords": "ws2812, esp8266", 5 | "authors": { 6 | "name": "Harm Aldick", 7 | "url": "https://github.com/kitesurfer1404/WS2812FX" 8 | }, 9 | "version": "1.0.1", 10 | "downloadUrl": "https://github.com/kitesurfer1404/WS2812FX/archive/master.zip", 11 | "export": { 12 | "include": "WS2812FX-master" 13 | }, 14 | "frameworks": "arduino", 15 | "platforms": "espressif8266", 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/kitesurfer1404/WS2812FX.git" 19 | }, 20 | "dependencies": [ 21 | { 22 | "name": "Adafruit NeoPixel", 23 | "version": "~1.1.2" 24 | } 25 | ] 26 | } 27 | 28 | -------------------------------------------------------------------------------- /lib/WebUSB/WebUSB.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Arduino LLC 3 | Original code (pre-library): Copyright (c) 2011, Peter Barrett 4 | 5 | Permission to use, copy, modify, and/or distribute this software for 6 | any purpose with or without fee is hereby granted, provided that the 7 | above copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 12 | BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES 13 | OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 14 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 15 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 16 | SOFTWARE. 17 | */ 18 | 19 | #define MS_OS_20_SET_HEADER_DESCRIPTOR 0x00 20 | #define MS_OS_20_SUBSET_HEADER_CONFIGURATION 0x01 21 | #define MS_OS_20_SUBSET_HEADER_FUNCTION 0x02 22 | #define MS_OS_20_FEATURE_COMPATIBLE_ID 0x03 23 | #define MS_OS_20_FEATURE_REG_PROPERTY 0x04 24 | #define MS_OS_20_DESCRIPTOR_LENGTH 0xb2 25 | 26 | #include "WebUSB.h" 27 | 28 | #ifdef ARDUINO_ARCH_SAMD 29 | 30 | #define USB_SendControl USBDevice.sendControl 31 | #define USB_RecvControl USBDevice.recvControl 32 | #define USB_Available USBDevice.available 33 | #define USB_Recv USBDevice.recv 34 | #define USB_Send USBDevice.send 35 | #define USB_SendSpace(ep) (EPX_SIZE - 1) 36 | #define USB_Flush USBDevice.flush 37 | 38 | #define TRANSFER_PGM 0 39 | 40 | #define EP_TYPE_BULK_IN_WEBUSB USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN(0); 41 | #define EP_TYPE_BULK_OUT_WEBUSB USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_OUT(0); 42 | 43 | #else 44 | 45 | #define EP_TYPE_BULK_IN_WEBUSB EP_TYPE_BULK_IN 46 | #define EP_TYPE_BULK_OUT_WEBUSB EP_TYPE_BULK_OUT 47 | 48 | #endif 49 | 50 | const uint8_t BOS_DESCRIPTOR_PREFIX[] PROGMEM = { 51 | 0x05, // Length 52 | 0x0F, // Binary Object Store descriptor 53 | 0x39, 0x00, // Total length 54 | 0x02, // Number of device capabilities 55 | 56 | // WebUSB Platform Capability descriptor (bVendorCode == 0x01). 57 | 0x18, // Length 58 | 0x10, // Device Capability descriptor 59 | 0x05, // Platform Capability descriptor 60 | 0x00, // Reserved 61 | 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 62 | 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65, // WebUSB GUID 63 | 0x00, 0x01, // Version 1.0 64 | 0x01, // Vendor request code 65 | }; 66 | 67 | // Landing page (1 byte) sent in the middle. 68 | 69 | const uint8_t BOS_DESCRIPTOR_SUFFIX[] PROGMEM { 70 | // Microsoft OS 2.0 Platform Capability Descriptor (MS_VendorCode == 0x02) 71 | 0x1C, // Length 72 | 0x10, // Device Capability descriptor 73 | 0x05, // Platform Capability descriptor 74 | 0x00, // Reserved 75 | 0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 76 | 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F, // MS OS 2.0 GUID 77 | 0x00, 0x00, 0x03, 0x06, // Windows version 78 | MS_OS_20_DESCRIPTOR_LENGTH, 0x00, // Descriptor set length 79 | 0x02, // Vendor request code 80 | 0x00 // Alternate enumeration code 81 | }; 82 | 83 | const uint8_t MS_OS_20_DESCRIPTOR_PREFIX[] PROGMEM = { 84 | // Microsoft OS 2.0 descriptor set header (table 10) 85 | 0x0A, 0x00, // Descriptor size (10 bytes) 86 | MS_OS_20_SET_HEADER_DESCRIPTOR, 0x00, // MS OS 2.0 descriptor set header 87 | 0x00, 0x00, 0x03, 0x06, // Windows version (8.1) (0x06030000) 88 | MS_OS_20_DESCRIPTOR_LENGTH, 0x00, // Size, MS OS 2.0 descriptor set 89 | 90 | // Microsoft OS 2.0 configuration subset header 91 | 0x08, 0x00, // Descriptor size (8 bytes) 92 | MS_OS_20_SUBSET_HEADER_CONFIGURATION, 0x00, // MS OS 2.0 configuration subset header 93 | 0x00, // bConfigurationValue 94 | 0x00, // Reserved 95 | 0xA8, 0x00, // Size, MS OS 2.0 configuration subset 96 | 97 | // Microsoft OS 2.0 function subset header 98 | 0x08, 0x00, // Descriptor size (8 bytes) 99 | MS_OS_20_SUBSET_HEADER_FUNCTION, 0x00, // MS OS 2.0 function subset header 100 | }; 101 | 102 | // First interface number (1 byte) sent here. 103 | 104 | const uint8_t MS_OS_20_DESCRIPTOR_SUFFIX[] PROGMEM = { 105 | 0x00, // Reserved 106 | 0xA0, 0x00, // Size, MS OS 2.0 function subset 107 | 108 | // Microsoft OS 2.0 compatible ID descriptor (table 13) 109 | 0x14, 0x00, // wLength 110 | MS_OS_20_FEATURE_COMPATIBLE_ID, 0x00, // MS_OS_20_FEATURE_COMPATIBLE_ID 111 | 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, 112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 113 | }; 114 | 115 | 116 | const uint8_t MS_OS_20_CUSTOM_PROPERTY[] PROGMEM = { 117 | 0x84, 0x00, //wLength: 118 | MS_OS_20_FEATURE_REG_PROPERTY, 0x00, // wDescriptorType: MS_OS_20_FEATURE_REG_PROPERTY: 0x04 (Table 9) 119 | 0x07, 0x00, //wPropertyDataType: REG_MULTI_SZ (Table 15) 120 | 0x2a, 0x00, //wPropertyNameLength: 121 | //bPropertyName: “DeviceInterfaceGUID” 122 | 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, 123 | 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 124 | 0x00, 0x00, 125 | 0x50, 0x00, // wPropertyDataLength 126 | //bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”. 127 | '{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00, 128 | '0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00, 129 | '8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00, 130 | '8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 131 | }; 132 | 133 | typedef struct 134 | { 135 | uint32_t dwDTERate; 136 | uint8_t bCharFormat; 137 | uint8_t bParityType; 138 | uint8_t bDataBits; 139 | uint8_t lineState; 140 | } LineInfo; 141 | 142 | static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; 143 | static volatile int32_t breakValue = -1; 144 | 145 | int WebUSB::getInterface(uint8_t* interfaceCount) 146 | { 147 | *interfaceCount += 1; // uses 1 interface 148 | WebUSBDescriptor webUSBInterface = { 149 | D_INTERFACE(pluggedInterface, 2, 0xff, 0, 0), 150 | D_ENDPOINT(USB_ENDPOINT_OUT(pluggedEndpoint),USB_ENDPOINT_TYPE_BULK,0x40,0), 151 | D_ENDPOINT(USB_ENDPOINT_IN (pluggedEndpoint+1),USB_ENDPOINT_TYPE_BULK,0x40,0) 152 | }; 153 | return USB_SendControl(0, &webUSBInterface, sizeof(webUSBInterface)); 154 | } 155 | 156 | int WebUSB::getDescriptor(USBSetup& setup) 157 | { 158 | if (USB_BOS_DESCRIPTOR_TYPE == setup.wValueH) 159 | { 160 | if (setup.wValueL == 0 && setup.wIndex == 0) { 161 | if (USB_SendControl(TRANSFER_PGM, &BOS_DESCRIPTOR_PREFIX, sizeof(BOS_DESCRIPTOR_PREFIX)) < 0) 162 | return -1; 163 | uint8_t landingPage = landingPageUrl ? 1 : 0; 164 | if (USB_SendControl(0, &landingPage, 1) < 0) 165 | return -1; 166 | if (USB_SendControl(TRANSFER_PGM, &BOS_DESCRIPTOR_SUFFIX, sizeof(BOS_DESCRIPTOR_SUFFIX)) < 0) 167 | return -1; 168 | return sizeof(BOS_DESCRIPTOR_PREFIX) + 1 + sizeof(BOS_DESCRIPTOR_SUFFIX); 169 | } 170 | } 171 | return 0; 172 | } 173 | 174 | uint8_t WebUSB::getShortName(char* name) 175 | { 176 | memcpy(name, "WUART", 5); 177 | return 5; 178 | } 179 | 180 | bool WebUSB::VendorControlRequest(USBSetup& setup) 181 | { 182 | if (setup.bmRequestType == (REQUEST_DEVICETOHOST | REQUEST_VENDOR | REQUEST_DEVICE)) { 183 | if (setup.bRequest == 0x01 && setup.wIndex == WEBUSB_REQUEST_GET_URL && landingPageUrl) 184 | { 185 | if (setup.wValueL != 1) 186 | return false; 187 | uint8_t urlLength = strlen(landingPageUrl); 188 | uint8_t descriptorLength = urlLength + 3; 189 | if (USB_SendControl(0, &descriptorLength, 1) < 0) 190 | return false; 191 | uint8_t descriptorType = 3; 192 | if (USB_SendControl(0, &descriptorType, 1) < 0) 193 | return false; 194 | if (USB_SendControl(0, &landingPageScheme, 1) < 0) 195 | return false; 196 | return USB_SendControl(0, landingPageUrl, urlLength) >= 0; 197 | } 198 | else if (setup.bRequest == 0x02 && setup.wIndex == MS_OS_20_REQUEST_DESCRIPTOR) 199 | { 200 | if (USB_SendControl(TRANSFER_PGM, &MS_OS_20_DESCRIPTOR_PREFIX, sizeof(MS_OS_20_DESCRIPTOR_PREFIX)) < 0) 201 | return false; 202 | if (USB_SendControl(0, &pluggedInterface, 1) < 0) 203 | return false; 204 | if (USB_SendControl(TRANSFER_PGM, &MS_OS_20_DESCRIPTOR_SUFFIX, sizeof(MS_OS_20_DESCRIPTOR_SUFFIX)) < 0) 205 | return false; 206 | if (USB_SendControl(TRANSFER_PGM, &MS_OS_20_CUSTOM_PROPERTY, sizeof(MS_OS_20_CUSTOM_PROPERTY)) < 0) 207 | return false; 208 | return true; 209 | } 210 | } 211 | return false; 212 | } 213 | 214 | 215 | bool WebUSB::setup(USBSetup& setup) 216 | { 217 | uint8_t r = setup.bRequest; 218 | uint8_t requestType = setup.bmRequestType; 219 | 220 | if (REQUEST_CLASS == (requestType & REQUEST_TYPE) && (pluggedInterface == setup.wIndex)) { 221 | if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) 222 | { 223 | if (CDC_GET_LINE_CODING == r) 224 | { 225 | return USB_SendControl(0,(void*)&_usbLineInfo,7) >= 0; 226 | } 227 | } 228 | 229 | if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) 230 | { 231 | if (CDC_SEND_BREAK == r) 232 | { 233 | breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; 234 | } 235 | 236 | if (CDC_SET_LINE_CODING == r) 237 | { 238 | USB_RecvControl((void*)&_usbLineInfo,7); 239 | } 240 | 241 | if (CDC_SET_CONTROL_LINE_STATE == r) 242 | { 243 | _usbLineInfo.lineState = setup.wValueL; 244 | } 245 | return true; 246 | } 247 | } else if (REQUEST_VENDOR == (requestType & REQUEST_TYPE)) { 248 | return VendorControlRequest(setup); 249 | } 250 | return false; 251 | } 252 | 253 | WebUSB::WebUSB(uint8_t landingPageScheme, const char* landingPageUrl) 254 | : PluggableUSBModule(2, 1, epType), 255 | landingPageScheme(landingPageScheme), landingPageUrl(landingPageUrl) 256 | { 257 | // one interface, 2 endpoints 258 | epType[0] = EP_TYPE_BULK_OUT_WEBUSB; 259 | epType[1] = EP_TYPE_BULK_IN_WEBUSB; 260 | PluggableUSB().plug(this); 261 | } 262 | 263 | void WebUSB::begin(unsigned long /* baud_count */) 264 | { 265 | peek_buffer = -1; 266 | } 267 | 268 | void WebUSB::begin(unsigned long /* baud_count */, byte /* config */) 269 | { 270 | peek_buffer = -1; 271 | } 272 | 273 | void WebUSB::end(void) 274 | { 275 | } 276 | 277 | int WebUSB::available(void) 278 | { 279 | if (peek_buffer >= 0) { 280 | return 1 + USB_Available(pluggedEndpoint); 281 | } 282 | return USB_Available(pluggedEndpoint); 283 | } 284 | 285 | int WebUSB::peek(void) 286 | { 287 | if (peek_buffer < 0) 288 | peek_buffer = USB_Recv(pluggedEndpoint); 289 | return peek_buffer; 290 | } 291 | 292 | int WebUSB::read(void) 293 | { 294 | if (peek_buffer >= 0) { 295 | int c = peek_buffer; 296 | peek_buffer = -1; 297 | return c; 298 | } 299 | return USB_Recv(pluggedEndpoint); 300 | } 301 | 302 | int WebUSB::availableForWrite(void) 303 | { 304 | return USB_SendSpace(pluggedEndpoint+1); 305 | } 306 | 307 | void WebUSB::flush(void) 308 | { 309 | USB_Flush(pluggedEndpoint+1); 310 | } 311 | 312 | size_t WebUSB::write(uint8_t c) 313 | { 314 | return write(&c, 1); 315 | } 316 | 317 | size_t WebUSB::write(const uint8_t *buffer, size_t size) 318 | { 319 | /* only try to send bytes if the high-level CDC connection itself 320 | is open (not just the pipe) - the OS should set lineState when the port 321 | is opened and clear lineState when the port is closed. 322 | bytes sent before the user opens the connection or after 323 | the connection is closed are lost - just like with a UART. */ 324 | 325 | // TODO - ZE - check behavior on different OSes and test what happens if an 326 | // open connection isn't broken cleanly (cable is yanked out, host dies 327 | // or locks up, or host virtual serial port hangs) 328 | if (_usbLineInfo.lineState > 0) { 329 | int r = USB_Send(pluggedEndpoint+1,buffer,size); 330 | if (r > 0) { 331 | return r; 332 | } else { 333 | setWriteError(); 334 | return 0; 335 | } 336 | } 337 | setWriteError(); 338 | return 0; 339 | } 340 | 341 | // This operator is a convenient way for a sketch to check whether the 342 | // port has actually been configured and opened by the host (as opposed 343 | // to just being connected to the host). It can be used, for example, in 344 | // setup() before printing to ensure that an application on the host is 345 | // actually ready to receive and display the data. 346 | // We add a short delay before returning to fix a bug observed by Federico 347 | // where the port is configured (lineState != 0) but not quite opened. 348 | WebUSB::operator bool() { 349 | bool result = false; 350 | if (_usbLineInfo.lineState > 0) 351 | result = true; 352 | delay(10); 353 | return result; 354 | } 355 | 356 | unsigned long WebUSB::baud() { 357 | // Disable interrupts while reading a multi-byte value 358 | uint32_t baudrate; 359 | #ifdef ARDUINO_ARCH_SAMD 360 | // nothing needed 361 | #else 362 | // Disable IRQs while reading and clearing breakValue to make 363 | // sure we don't overwrite a value just set by the ISR. 364 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 365 | #endif 366 | baudrate = _usbLineInfo.dwDTERate; 367 | #ifdef ARDUINO_ARCH_SAMD 368 | // nothing needed 369 | #else 370 | } 371 | #endif 372 | return baudrate; 373 | } 374 | 375 | uint8_t WebUSB::stopbits() { 376 | return _usbLineInfo.bCharFormat; 377 | } 378 | 379 | uint8_t WebUSB::paritytype() { 380 | return _usbLineInfo.bParityType; 381 | } 382 | 383 | uint8_t WebUSB::numbits() { 384 | return _usbLineInfo.bDataBits; 385 | } 386 | 387 | bool WebUSB::dtr() { 388 | return _usbLineInfo.lineState & 0x1; 389 | } 390 | 391 | bool WebUSB::rts() { 392 | return _usbLineInfo.lineState & 0x2; 393 | } 394 | 395 | int32_t WebUSB::readBreak() { 396 | int32_t ret; 397 | #ifdef ARDUINO_ARCH_SAMD 398 | uint8_t enableInterrupts = ((__get_PRIMASK() & 0x1) == 0); 399 | 400 | // disable interrupts, 401 | // to avoid clearing a breakValue that might occur 402 | // while processing the current break value 403 | __disable_irq(); 404 | #else 405 | // Disable IRQs while reading and clearing breakValue to make 406 | // sure we don't overwrite a value just set by the ISR. 407 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 408 | #endif 409 | ret = breakValue; 410 | breakValue = -1; 411 | #ifdef ARDUINO_ARCH_SAMD 412 | if (enableInterrupts) { 413 | // re-enable the interrupts 414 | __enable_irq(); 415 | } 416 | #else 417 | } 418 | #endif 419 | return ret; 420 | } 421 | -------------------------------------------------------------------------------- /lib/WebUSB/WebUSB.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, Arduino LLC 3 | Original code (pre-library): Copyright (c) 2011, Peter Barrett 4 | 5 | Permission to use, copy, modify, and/or distribute this software for 6 | any purpose with or without fee is hereby granted, provided that the 7 | above copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 12 | BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES 13 | OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 14 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 15 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 16 | SOFTWARE. 17 | */ 18 | 19 | #ifndef WebUSB_h 20 | #define WebUSB_h 21 | 22 | #include 23 | #include 24 | #ifdef ARDUINO_ARCH_SAMD 25 | #include "USB/PluggableUSB.h" 26 | #else 27 | #include "PluggableUSB.h" 28 | #include 29 | #include 30 | #endif 31 | 32 | #ifndef USBCON 33 | #error "WebUSB requires a board that supports USB client device mode." 34 | #endif 35 | 36 | #define USB_BOS_DESCRIPTOR_TYPE 15 37 | #define WEBUSB_REQUEST_GET_URL 0x02 38 | 39 | #define MS_OS_20_REQUEST_DESCRIPTOR 0x07 40 | 41 | typedef struct 42 | { 43 | InterfaceDescriptor dif; 44 | EndpointDescriptor in; 45 | EndpointDescriptor out; 46 | } WebUSBDescriptor; 47 | 48 | class WebUSB : public PluggableUSBModule, public Stream 49 | { 50 | public: 51 | WebUSB(uint8_t landingPageScheme, const char* landingPageUrl); 52 | void begin(unsigned long); 53 | void begin(unsigned long, uint8_t); 54 | void end(void); 55 | 56 | virtual int available(void); 57 | virtual int peek(void); 58 | virtual int read(void); 59 | int availableForWrite(void); 60 | virtual void flush(void); 61 | virtual size_t write(uint8_t); 62 | virtual size_t write(const uint8_t*, size_t); 63 | using Print::write; // pull in write(str) and write(buf, size) from Print 64 | operator bool(); 65 | 66 | volatile uint8_t _rx_buffer_head; 67 | volatile uint8_t _rx_buffer_tail; 68 | unsigned char _rx_buffer[SERIAL_BUFFER_SIZE]; 69 | 70 | int32_t readBreak(); 71 | 72 | uint32_t baud(); 73 | uint8_t stopbits(); 74 | uint8_t paritytype(); 75 | uint8_t numbits(); 76 | bool dtr(); 77 | bool rts(); 78 | enum { 79 | ONE_STOP_BIT = 0, 80 | ONE_AND_HALF_STOP_BIT = 1, 81 | TWO_STOP_BITS = 2, 82 | }; 83 | enum { 84 | NO_PARITY = 0, 85 | ODD_PARITY = 1, 86 | EVEN_PARITY = 2, 87 | MARK_PARITY = 3, 88 | SPACE_PARITY = 4, 89 | }; 90 | 91 | protected: 92 | // Implementation of the PluggableUSBModule 93 | int getInterface(uint8_t* interfaceCount); 94 | int getDescriptor(USBSetup& setup); 95 | bool setup(USBSetup& setup); 96 | uint8_t getShortName(char* name); 97 | 98 | private: 99 | bool VendorControlRequest(USBSetup& setup); 100 | 101 | #ifdef ARDUINO_ARCH_SAMD 102 | uint32_t epType[2]; 103 | #else 104 | uint8_t epType[2]; 105 | #endif 106 | uint16_t descriptorSize; 107 | uint8_t protocol; 108 | uint8_t idle; 109 | int peek_buffer; 110 | uint8_t landingPageScheme; 111 | const char* landingPageUrl; 112 | }; 113 | 114 | #endif // WebUSB_h 115 | -------------------------------------------------------------------------------- /lib/WebUSB/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map HID 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | HID KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | begin KEYWORD2 15 | SendReport KEYWORD2 16 | AppendDescriptor KEYWORD2 17 | 18 | ####################################### 19 | # Constants (LITERAL1) 20 | ####################################### 21 | HID_TX LITERAL1 -------------------------------------------------------------------------------- /lib/WebUSB/library.properties: -------------------------------------------------------------------------------- 1 | name=WebUSB 2 | version=1.0 3 | author=Arduino 4 | maintainer=Arduino 5 | sentence=Module for PluggableUSB infrastructure. Exposes an API for WebUSB API 6 | paragraph= 7 | category=Communication 8 | url=http://www.arduino.cc/en/Reference/HID 9 | architectures=avr,samd 10 | -------------------------------------------------------------------------------- /lib/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for the project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link to executable file. 4 | 5 | The source code of each library should be placed in separate directory, like 6 | "lib/private_lib/[here are source files]". 7 | 8 | For example, see how can be organized `Foo` and `Bar` libraries: 9 | 10 | |--lib 11 | | |--Bar 12 | | | |--docs 13 | | | |--examples 14 | | | |--src 15 | | | |- Bar.c 16 | | | |- Bar.h 17 | | |--Foo 18 | | | |- Foo.c 19 | | | |- Foo.h 20 | | |- readme.txt --> THIS FILE 21 | |- platformio.ini 22 | |--src 23 | |- main.c 24 | 25 | Then in `src/main.c` you should use: 26 | 27 | #include 28 | #include 29 | 30 | // rest H/C/CPP code 31 | 32 | PlatformIO will find your libraries automatically, configure preprocessor's 33 | include paths and build them. 34 | 35 | More information about PlatformIO Library Dependency Finder 36 | - http://docs.platformio.org/page/librarymanager/ldf.html 37 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; http://docs.platformio.org/page/projectconf.html 10 | 11 | [env:micro] 12 | platform = atmelavr 13 | board = micro 14 | framework = arduino 15 | 16 | #"-DUSB_VERSION=0x210" 17 | 18 | lib_deps = 19 | # Using a library name 20 | #MAX30100lib 21 | #WS2812FX 22 | Adafruit NeoPixel -------------------------------------------------------------------------------- /schematic/PhysicalLedRingWebUSB.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alvarowolfx/physical-led-ring-webusb-arduino/9466b685d4a731b21aedef5529790303bd04511c/schematic/PhysicalLedRingWebUSB.fzz -------------------------------------------------------------------------------- /schematic/PhysicalLedRingWebUSB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alvarowolfx/physical-led-ring-webusb-arduino/9466b685d4a731b21aedef5529790303bd04511c/schematic/PhysicalLedRingWebUSB.png -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #define USB_VERSION 0x210 2 | #include 3 | #include 4 | #include 5 | 6 | #define PIN 6 7 | #define NUMPIXELS 16 8 | #define FX_SPEED 220 9 | #define FX_BRIGHTNESS 100 10 | //Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); 11 | WS2812FX ws2812fx = WS2812FX(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); 12 | 13 | //WebUSB WebUSBSerial(1, "localhost:3000"); 14 | WebUSB WebUSBSerial(1, "alvarowolfx.github.io/physical-led-ring-webusb-arduino"); 15 | 16 | //#define Serial WebUSBSerial 17 | 18 | int color[4]; 19 | int index; 20 | 21 | void setup() 22 | { 23 | /*while (!Serial) 24 | { 25 | ; 26 | }*/ 27 | WebUSBSerial.begin(9600); 28 | WebUSBSerial.write("Sketch begins.\r\n"); 29 | WebUSBSerial.flush(); 30 | 31 | ws2812fx.init(); 32 | ws2812fx.setBrightness(FX_BRIGHTNESS); 33 | ws2812fx.setSpeed(FX_SPEED); 34 | ws2812fx.setColor(0x007BFF); 35 | ws2812fx.setMode(FX_MODE_STATIC); 36 | ws2812fx.start(); 37 | /* 38 | pixels.begin(); 39 | pixels.setBrightness(100); 40 | */ 41 | index = 0; 42 | } 43 | 44 | void loop() 45 | { 46 | ws2812fx.service(); 47 | 48 | if (WebUSBSerial && WebUSBSerial.available()) 49 | { 50 | color[index++] = WebUSBSerial.read(); 51 | if (index == 4) 52 | { 53 | int ledIndex = color[0]; 54 | int red = color[1]; 55 | int green = color[2]; 56 | int blue = color[3]; 57 | 58 | // Turn all leds if receives 255 59 | if (ledIndex == 255) 60 | { 61 | /* 62 | for (int i = 0; i < NUMPIXELS; i++) 63 | { 64 | pixels.setPixelColor(i, pixels.Color(red, green, blue)); 65 | } 66 | */ 67 | ws2812fx.setColor(red, green, blue); 68 | } 69 | else if (ledIndex == 254) 70 | { 71 | //SET MODE 72 | ws2812fx.setMode(red); 73 | } 74 | else if (ledIndex == 253) 75 | { 76 | //SET Speed 77 | ws2812fx.setSpeed(red); 78 | } 79 | else if (ledIndex < NUMPIXELS) 80 | { 81 | //pixels.setPixelColor(ledIndex, pixels.Color(red, green, blue)); 82 | } 83 | //pixels.show(); 84 | 85 | WebUSBSerial.print("Set LED at position "); 86 | WebUSBSerial.print(ledIndex); 87 | WebUSBSerial.print(" to "); 88 | WebUSBSerial.print(color[1]); 89 | WebUSBSerial.print(", "); 90 | WebUSBSerial.print(color[2]); 91 | WebUSBSerial.print(", "); 92 | WebUSBSerial.print(color[3]); 93 | WebUSBSerial.print(".\r\n"); 94 | WebUSBSerial.flush(); 95 | index = 0; 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /webapp/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /webapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webapp", 3 | "version": "0.1.0", 4 | "private": true, 5 | "homepage": "https://alvarowolfx.github.io/physical-led-ring-webusb-arduino", 6 | "dependencies": { 7 | "gh-pages": "^1.1.0", 8 | "react": "^16.2.0", 9 | "react-color": "^2.13.8", 10 | "react-dom": "^16.2.0", 11 | "react-throttle": "^0.3.0" 12 | }, 13 | "devDependencies": { 14 | "react-scripts": "1.1.0" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test --env=jsdom", 20 | "eject": "react-scripts eject", 21 | "predeploy": "npm run build", 22 | "deploy": "gh-pages -d build" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /webapp/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alvarowolfx/physical-led-ring-webusb-arduino/9466b685d4a731b21aedef5529790303bd04511c/webapp/public/favicon.ico -------------------------------------------------------------------------------- /webapp/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 23 | React + WebUSB 24 | 25 | 26 | 27 | 30 |
31 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /webapp/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /webapp/src/App.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | background-color: #d4d4d4; 6 | } 7 | 8 | .app { 9 | text-align: center; 10 | } 11 | 12 | .logo { 13 | animation: app-logo-spin infinite 20s linear; 14 | height: 80px; 15 | } 16 | 17 | header { 18 | display: flex; 19 | flex-direction: row; 20 | align-items: center; 21 | align-content: center; 22 | align-self: center; 23 | background-color: #222; 24 | height: 60px; 25 | padding: 20px; 26 | color: white; 27 | } 28 | 29 | .title { 30 | font-size: 1.5em; 31 | } 32 | 33 | .container { 34 | margin: 0; 35 | display: flex; 36 | flex-direction: column; 37 | align-items: center; 38 | background-color: #d4d4d4; 39 | } 40 | 41 | .led-control { 42 | display: flex; 43 | flex-direction: row; 44 | align-items: center; 45 | } 46 | 47 | @media screen and (max-width: 480px) { 48 | .led-control { 49 | flex-direction: column; 50 | } 51 | } 52 | 53 | @keyframes app-logo-spin { 54 | from { 55 | transform: rotate(0deg); 56 | } 57 | to { 58 | transform: rotate(360deg); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /webapp/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | import { SketchPicker } from 'react-color'; 4 | import { Throttle } from 'react-throttle'; 5 | import './App.css'; 6 | import { getPorts, requestPort } from './Serial'; 7 | import LedRing from './LedRing'; 8 | 9 | const numberLeds = 16; 10 | 11 | const MODES = { 12 | MODE_STATIC: 0, 13 | MODE_BLINK: 1, 14 | //MODE_BREATH: 2, 15 | MODE_COLOR_WIPE: 3, 16 | MODE_COLOR_WIPE_RANDOM: 4, 17 | MODE_RANDOM_COLOR: 5, 18 | MODE_SINGLE_DYNAMIC: 6, 19 | MODE_MULTI_DYNAMIC: 7, 20 | MODE_RAINBOW: 8, 21 | MODE_RAINBOW_CYCLE: 9, 22 | MODE_SCAN: 10, 23 | MODE_DUAL_SCAN: 11, 24 | MODE_FADE: 12, 25 | MODE_THEATER_CHASE: 13, 26 | MODE_THEATER_CHASE_RAINBOW: 14, 27 | //MODE_RUNNING_LIGHTS: 15, 28 | //MODE_TWINKLE: 16, 29 | MODE_TWINKLE_RANDOM: 17, 30 | MODE_TWINKLE_FADE: 18, 31 | MODE_TWINKLE_FADE_RANDOM: 19, 32 | MODE_SPARKLE: 20, 33 | MODE_FLASH_SPARKLE: 21, 34 | MODE_HYPER_SPARKLE: 22, 35 | MODE_STROBE: 23, 36 | MODE_STROBE_RAINBOW: 24, 37 | MODE_MULTI_STROBE: 25, 38 | MODE_BLINK_RAINBOW: 26, 39 | MODE_CHASE_WHITE: 27, 40 | MODE_CHASE_COLOR: 28, 41 | MODE_CHASE_RANDOM: 29, 42 | MODE_CHASE_RAINBOW: 30, 43 | MODE_CHASE_FLASH: 31, 44 | MODE_CHASE_FLASH_RANDOM: 32, 45 | MODE_CHASE_RAINBOW_WHITE: 33, 46 | MODE_CHASE_BLACKOUT: 34, 47 | MODE_CHASE_BLACKOUT_RAINBOW: 35, 48 | MODE_COLOR_SWEEP_RANDOM: 36, 49 | MODE_RUNNING_COLOR: 37, 50 | MODE_RUNNING_RED_BLUE: 38, 51 | MODE_RUNNING_RANDOM: 39, 52 | //MODE_LARSON_SCANNER: 40, 53 | MODE_COMET: 41, 54 | MODE_FIREWORKS: 42, 55 | //MODE_FIREWORKS_RANDOM: 43, 56 | MODE_MERRY_CHRISTMAS: 44, 57 | MODE_FIRE_FLICKER: 45, 58 | MODE_FIRE_FLICKER_SOFT: 46, 59 | MODE_FIRE_FLICKER_INTENSE: 47 60 | /* 61 | MODE_DUAL_COLOR_WIPE_IN_OUT: 48, 62 | MODE_DUAL_COLOR_WIPE_IN_IN: 49, 63 | MODE_DUAL_COLOR_WIPE_OUT_OUT: 50, 64 | MODE_DUAL_COLOR_WIPE_OUT_IN: 51, 65 | MODE_CIRCUS_COMBUSTUS: 52, 66 | MODE_HALLOWEEN: 53, 67 | MODE_COLOR_WIPE_INVERSE: 54, 68 | MODE_BICOLOR_CHASE: 55, 69 | MODE_TRICOLOR_CHASE: 56 70 | */ 71 | }; 72 | 73 | class App extends Component { 74 | state = { 75 | port: null, 76 | searchingPorts: false, 77 | connected: false, 78 | selectedLed: 'all', 79 | colors: new Array(numberLeds).fill({ r: 0, g: 200, b: 0 }), 80 | speed: 230, 81 | mode: 0 82 | }; 83 | 84 | componentDidMount() { 85 | this.setState({ 86 | searchingPorts: true 87 | }); 88 | getPorts().then(ports => { 89 | this.onPortsFound(ports); 90 | }); 91 | } 92 | 93 | onPortsFound(ports) { 94 | if (ports.length === 0) { 95 | this.setState({ 96 | port: null, 97 | searchingPorts: false 98 | }); 99 | } else { 100 | const port = ports[0]; 101 | this.setState( 102 | { 103 | port, 104 | searchingPorts: false 105 | }, 106 | this.connect 107 | ); 108 | } 109 | } 110 | 111 | connect = () => { 112 | const { port } = this.state; 113 | if (!port) { 114 | return; 115 | } 116 | port.connect().then( 117 | () => { 118 | this.setState( 119 | { 120 | connected: true 121 | }, 122 | this.sync 123 | ); 124 | 125 | port.onReceive = data => { 126 | /* 127 | let textDecoder = new TextDecoder(); 128 | console.log(textDecoder.decode(data)); 129 | */ 130 | }; 131 | 132 | port.onReceiveError = error => { 133 | console.error(error); 134 | this.onConnectClick(); 135 | }; 136 | }, 137 | error => { 138 | console.error(error); 139 | this.onConnectClick(); 140 | } 141 | ); 142 | }; 143 | 144 | onConnectClick = () => { 145 | const { port } = this.state; 146 | if (port) { 147 | port.disconnect(); 148 | this.setState({ 149 | connected: false, 150 | port: null 151 | }); 152 | } else { 153 | requestPort() 154 | .then(port => { 155 | this.onPortsFound([port]); 156 | }) 157 | .catch(error => { 158 | console.log('Request Port: ', error); 159 | }); 160 | } 161 | }; 162 | 163 | sendData(code, { r, g, b }) { 164 | const { port } = this.state; 165 | if (!port) { 166 | return; 167 | } 168 | let view = new Uint8Array(4); 169 | view[0] = code; 170 | view[1] = r; 171 | view[2] = g; 172 | view[3] = b; 173 | port.send(view); 174 | } 175 | 176 | sendMode(mode) { 177 | this.sendData(254, { r: mode, g: 0, b: 0 }); 178 | } 179 | 180 | sendSpeed(speed) { 181 | this.sendData(253, { r: speed, g: 0, b: 0 }); 182 | } 183 | 184 | sync = () => { 185 | const { colors, selectedLed, mode, speed } = this.state; 186 | if (selectedLed === 'all') { 187 | this.sendData(255, colors[0]); 188 | } else { 189 | for (let i = 0; i < colors.length; i++) { 190 | this.sendData(i, colors[i]); 191 | } 192 | } 193 | this.sendMode(mode); 194 | this.sendSpeed(speed); 195 | }; 196 | 197 | onAllOff = () => { 198 | this.setState( 199 | { 200 | colors: new Array(numberLeds).fill({ r: 0, g: 0, b: 0 }), 201 | selectedLed: 'all' 202 | }, 203 | this.sync 204 | ); 205 | }; 206 | 207 | onToggleAll = () => { 208 | this.setState({ 209 | selectedLed: 'all' 210 | }); 211 | }; 212 | 213 | handleColorChange = ({ rgb }) => { 214 | const { selectedLed } = this.state; 215 | 216 | const index = selectedLed === 'all' ? 255 : selectedLed; 217 | this.sendData(index, rgb); 218 | 219 | if (selectedLed === 'all') { 220 | const colors = new Array(numberLeds).fill(rgb); 221 | this.setState({ 222 | colors 223 | }); 224 | } else { 225 | const colors = [ 226 | ...this.state.colors.slice(0, selectedLed), 227 | rgb, 228 | ...this.state.colors.slice(selectedLed + 1) 229 | ]; 230 | this.setState({ 231 | colors 232 | }); 233 | } 234 | }; 235 | 236 | onModeChange = e => { 237 | const mode = e.target.value; 238 | this.setState({ mode }); 239 | this.sendMode(mode); 240 | }; 241 | 242 | onSpeedChange = e => { 243 | const speed = e.target.value; 244 | this.setState({ speed }); 245 | this.sendSpeed(speed); 246 | }; 247 | 248 | onLedClickWithIndex = (e, index) => { 249 | /* DO NOTHING FOR NOW 250 | this.setState({ 251 | selectedLed: index 252 | }); 253 | */ 254 | }; 255 | 256 | render() { 257 | const { connected, selectedLed, colors, speed, mode } = this.state; 258 | let selectedColor = null; 259 | if (selectedLed === 'all') { 260 | selectedColor = colors[0]; 261 | } else { 262 | selectedColor = colors[selectedLed]; 263 | } 264 | return ( 265 |
266 |
267 | logo 268 |

Welcome to React + WebUSB Demo

269 |
270 |
271 |
272 |
273 | 276 | 277 | {selectedLed !== 'all' && ( 278 | 279 | )} 280 |
281 | 282 | 291 |
292 | 293 | 300 | 301 |
302 | {selectedLed === 'all' &&

All leds selected

} 303 | {selectedLed !== 'all' &&

Led {selectedLed} selected

} 304 |
305 | 311 |
312 | 313 | 317 | 318 |
319 |
320 |
321 | ); 322 | } 323 | } 324 | 325 | export default App; 326 | -------------------------------------------------------------------------------- /webapp/src/LedRing.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Led = ({ 4 | index, 5 | selected, 6 | color, 7 | onClick, 8 | ringMiddle, 9 | ringWidth, 10 | size, 11 | angle, 12 | distance 13 | }) => { 14 | const rot = (index + 4) * angle; 15 | const transform = `rotate(${rot}deg) translate(${distance + 16 | ringWidth / 2}em)`; 17 | const cssColor = `rgb(${color.r},${color.g},${color.b}`; 18 | return ( 19 |
  • 35 | ); 36 | }; 37 | 38 | const LedRing = ({ colors, selectedLed, circleSize, onLedClickWithIndex }) => { 39 | const angle = 360 / colors.length; 40 | const ledSize = circleSize / 8; 41 | const distance = circleSize / 2; 42 | const ringMiddle = distance - ledSize / 2; 43 | const ringWidth = circleSize / 6; 44 | return ( 45 |
      57 | {colors.map((color, idx) => { 58 | return ( 59 | onLedClickWithIndex(e, idx)} 70 | /> 71 | ); 72 | })} 73 |

      74 | NeoPixel Ring
      75 | with 16 RGB
      76 | addressable LEDs 77 |

      78 |
    79 | ); 80 | }; 81 | 82 | export default LedRing; 83 | -------------------------------------------------------------------------------- /webapp/src/Serial.js: -------------------------------------------------------------------------------- 1 | export function getPorts() { 2 | return navigator.usb.getDevices().then(devices => { 3 | return devices.map(device => new Port(device)); 4 | }); 5 | } 6 | 7 | export function requestPort() { 8 | const filters = [ 9 | { vendorId: 0x2341, productId: 0x0037 }, 10 | { vendorId: 0x2341, productId: 0x8036 }, 11 | { vendorId: 0x2341, productId: 0x8037 }, 12 | { vendorId: 0x2341, productId: 0x804d }, 13 | { vendorId: 0x2341, productId: 0x804e }, 14 | { vendorId: 0x2341, productId: 0x804f }, 15 | { vendorId: 0x2341, productId: 0x8050 } 16 | ]; 17 | return navigator.usb 18 | .requestDevice({ filters: filters }) 19 | .then(device => new Port(device)); 20 | } 21 | 22 | export default class Port { 23 | constructor(device) { 24 | this.device_ = device; 25 | } 26 | 27 | connect() { 28 | let readLoop = () => { 29 | this.device_.transferIn(5, 64).then( 30 | result => { 31 | this.onReceive(result.data); 32 | readLoop(); 33 | }, 34 | error => { 35 | this.onReceiveError(error); 36 | } 37 | ); 38 | }; 39 | 40 | return this.device_ 41 | .open() 42 | .then(() => { 43 | if (this.device_.configuration === null) { 44 | return this.device_.selectConfiguration(1); 45 | } 46 | }) 47 | .then(() => this.device_.claimInterface(2)) 48 | .then(() => this.device_.selectAlternateInterface(2, 0)) 49 | .then(() => 50 | this.device_.controlTransferOut({ 51 | requestType: 'class', 52 | recipient: 'interface', 53 | request: 0x22, 54 | value: 0x01, 55 | index: 0x02 56 | }) 57 | ) 58 | .then(() => { 59 | readLoop(); 60 | }); 61 | } 62 | 63 | disconnect() { 64 | return this.device_ 65 | .controlTransferOut({ 66 | requestType: 'class', 67 | recipient: 'interface', 68 | request: 0x22, 69 | value: 0x00, 70 | index: 0x02 71 | }) 72 | .then(() => this.device_.close()); 73 | } 74 | 75 | send(data) { 76 | return this.device_.transferOut(4, data); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /webapp/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import registerServiceWorker from './registerServiceWorker'; 5 | 6 | ReactDOM.render(, document.getElementById('root')); 7 | registerServiceWorker(); 8 | -------------------------------------------------------------------------------- /webapp/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /webapp/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (isLocalhost) { 36 | // This is running on localhost. Lets check if a service worker still exists or not. 37 | checkValidServiceWorker(swUrl); 38 | 39 | // Add some additional logging to localhost, pointing developers to the 40 | // service worker/PWA documentation. 41 | navigator.serviceWorker.ready.then(() => { 42 | console.log( 43 | 'This web app is being served cache-first by a service ' + 44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ' 45 | ); 46 | }); 47 | } else { 48 | // Is not local host. Just register service worker 49 | registerValidSW(swUrl); 50 | } 51 | }); 52 | } 53 | } 54 | 55 | function registerValidSW(swUrl) { 56 | navigator.serviceWorker 57 | .register(swUrl) 58 | .then(registration => { 59 | registration.onupdatefound = () => { 60 | const installingWorker = registration.installing; 61 | installingWorker.onstatechange = () => { 62 | if (installingWorker.state === 'installed') { 63 | if (navigator.serviceWorker.controller) { 64 | // At this point, the old content will have been purged and 65 | // the fresh content will have been added to the cache. 66 | // It's the perfect time to display a "New content is 67 | // available; please refresh." message in your web app. 68 | console.log('New content is available; please refresh.'); 69 | } else { 70 | // At this point, everything has been precached. 71 | // It's the perfect time to display a 72 | // "Content is cached for offline use." message. 73 | console.log('Content is cached for offline use.'); 74 | } 75 | } 76 | }; 77 | }; 78 | }) 79 | .catch(error => { 80 | console.error('Error during service worker registration:', error); 81 | }); 82 | } 83 | 84 | function checkValidServiceWorker(swUrl) { 85 | // Check if the service worker can be found. If it can't reload the page. 86 | fetch(swUrl) 87 | .then(response => { 88 | // Ensure service worker exists, and that we really are getting a JS file. 89 | if ( 90 | response.status === 404 || 91 | response.headers.get('content-type').indexOf('javascript') === -1 92 | ) { 93 | // No service worker found. Probably a different app. Reload the page. 94 | navigator.serviceWorker.ready.then(registration => { 95 | registration.unregister().then(() => { 96 | window.location.reload(); 97 | }); 98 | }); 99 | } else { 100 | // Service worker found. Proceed as normal. 101 | registerValidSW(swUrl); 102 | } 103 | }) 104 | .catch(() => { 105 | console.log( 106 | 'No internet connection found. App is running in offline mode.' 107 | ); 108 | }); 109 | } 110 | 111 | export function unregister() { 112 | if ('serviceWorker' in navigator) { 113 | navigator.serviceWorker.ready.then(registration => { 114 | registration.unregister(); 115 | }); 116 | } 117 | } 118 | --------------------------------------------------------------------------------