diff --git a/.gitignore b/.gitignore index 249fd4d6..f5850d48 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ build/ buildcache/ arduino.json c_cpp_properties.json -.vscode \ No newline at end of file +.vscode + +/platformio-override.ini +/release/ diff --git a/esp8266-fastled-webserver/ColorWavesPlayground.h b/esp8266-fastled-webserver/ColorWavesPlayground.cpp similarity index 83% rename from esp8266-fastled-webserver/ColorWavesPlayground.h rename to esp8266-fastled-webserver/ColorWavesPlayground.cpp index 12411f54..a0de53ce 100644 --- a/esp8266-fastled-webserver/ColorWavesPlayground.h +++ b/esp8266-fastled-webserver/ColorWavesPlayground.cpp @@ -1,10 +1,12 @@ +#include "common.h" + // ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb // This function draws color waves with an ever-changing, // widely-varying set of parameters, using a color palette. // Modified by Jason Coon to replace "magic numbers" with customizable inputs via sliders in the web app. -void colorwavesPlayground( CRGB* ledarray, uint16_t numleds, CRGBPalette16& palette) +void colorwavesPlayground( CRGB* ledarray, uint16_t numleds, CRGBPalette16& palette, bool useFibonacciOrder) { static uint16_t sPseudotime = 0; static uint16_t sLastMillis = 0; @@ -50,6 +52,13 @@ void colorwavesPlayground( CRGB* ledarray, uint16_t numleds, CRGBPalette16& pale CRGB newcolor = ColorFromPalette( palette, index, bri8); uint16_t pixelnumber = i; + +#if IS_FIBONACCI + if (useFibonacciOrder) pixelnumber = fibonacciToPhysical[i]; +#else + (void)useFibonacciOrder; +#endif + pixelnumber = (numleds - 1) - pixelnumber; nblend( ledarray[pixelnumber], newcolor, 128); @@ -58,5 +67,14 @@ void colorwavesPlayground( CRGB* ledarray, uint16_t numleds, CRGBPalette16& pale void colorWavesPlayground() { - colorwavesPlayground(leds, NUM_LEDS, gCurrentPalette); + colorwavesPlayground(leds, NUM_PIXELS, gCurrentPalette, false); +} + + +#if IS_FIBONACCI +void colorWavesPlaygroundFibonacci() +{ + colorwavesPlayground(leds, NUM_PIXELS, gCurrentPalette, true); } +#endif + diff --git a/esp8266-fastled-webserver/FSBrowser.h b/esp8266-fastled-webserver/FSBrowser.cpp similarity index 77% rename from esp8266-fastled-webserver/FSBrowser.h rename to esp8266-fastled-webserver/FSBrowser.cpp index 08fa4f7d..3400004e 100644 --- a/esp8266-fastled-webserver/FSBrowser.h +++ b/esp8266-fastled-webserver/FSBrowser.cpp @@ -1,3 +1,4 @@ +#include "common.h" //holds the current upload File fsUploadFile; @@ -34,12 +35,15 @@ String getContentType(String filename){ bool handleFileRead(String path){ Serial.println("handleFileRead: " + path); - if(path.endsWith("/")) path += "index.htm"; + if (path.endsWith("/")) { + path += "index.htm"; + } String contentType = getContentType(path); String pathWithGz = path + ".gz"; - if(MYFS.exists(pathWithGz) || MYFS.exists(path)){ - if(MYFS.exists(pathWithGz)) - path += ".gz"; + if (MYFS.exists(pathWithGz) || MYFS.exists(path)) { + if (MYFS.exists(pathWithGz)) { + path = pathWithGz; + } File file = MYFS.open(path, "r"); (void)webServer.streamFile(file, contentType); file.close(); @@ -50,58 +54,75 @@ bool handleFileRead(String path){ } void handleFileUpload(){ - if(webServer.uri() != "/edit") return; + if (webServer.uri() != "/edit") return; + HTTPUpload& upload = webServer.upload(); - if(upload.status == UPLOAD_FILE_START){ + if (upload.status == UPLOAD_FILE_START) { String filename = upload.filename; - if(!filename.startsWith("/")) filename = "/"+filename; + if (!filename.startsWith("/")) { + filename = "/" + filename; + } Serial.print("handleFileUpload Name: "); Serial.println(filename); fsUploadFile = MYFS.open(filename, "w"); filename = String(); - } else if(upload.status == UPLOAD_FILE_WRITE){ + } else if (upload.status == UPLOAD_FILE_WRITE) { //Serial.print("handleFileUpload Data: "); Serial.println(upload.currentSize); - if(fsUploadFile) + if (fsUploadFile) { fsUploadFile.write(upload.buf, upload.currentSize); - } else if(upload.status == UPLOAD_FILE_END){ - if(fsUploadFile) + } + } else if (upload.status == UPLOAD_FILE_END) { + if (fsUploadFile) { fsUploadFile.close(); + } Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); } } void handleFileDelete(){ - if(webServer.args() == 0) return webServer.send(500, "text/plain", "BAD ARGS"); + if (webServer.args() == 0) { + return webServer.send(500, "text/plain", "BAD ARGS"); + } + String path = webServer.arg(0); Serial.println("handleFileDelete: " + path); - if(path == "/") + if (path == "/") { return webServer.send(500, "text/plain", "BAD PATH"); - if(!MYFS.exists(path)) + } + if (!MYFS.exists(path)) { return webServer.send(404, "text/plain", "FileNotFound"); + } MYFS.remove(path); webServer.send(200, "text/plain", ""); path = String(); } void handleFileCreate(){ - if(webServer.args() == 0) + if (webServer.args() == 0) { return webServer.send(500, "text/plain", "BAD ARGS"); + } String path = webServer.arg(0); Serial.println("handleFileCreate: " + path); - if(path == "/") + if (path == "/") { return webServer.send(500, "text/plain", "BAD PATH"); - if(MYFS.exists(path)) + } + if (MYFS.exists(path)) { return webServer.send(500, "text/plain", "FILE EXISTS"); + } File file = MYFS.open(path, "w"); - if(file) + if (file) { file.close(); - else + } else { return webServer.send(500, "text/plain", "CREATE FAILED"); + } webServer.send(200, "text/plain", ""); path = String(); } void handleFileList() { - if(!webServer.hasArg("dir")) {webServer.send(500, "text/plain", "BAD ARGS"); return;} + if (!webServer.hasArg("dir")) { + webServer.send(500, "text/plain", "BAD ARGS"); + return; + } String path = webServer.arg("dir"); Serial.println("handleFileList: " + path); @@ -109,9 +130,11 @@ void handleFileList() { path = String(); String output = "["; - while(dir.next()){ + while (dir.next()) { File entry = dir.openFile("r"); - if (output != "[") output += ','; + if (output != "[") { + output += ','; + } bool isDir = false; //bool isDir = entry.isDirectory(); diff --git a/esp8266-fastled-webserver/Field.h b/esp8266-fastled-webserver/Field.h deleted file mode 100644 index c3a04ce9..00000000 --- a/esp8266-fastled-webserver/Field.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - ESP8266 + FastLED + IR Remote: https://github.com/jasoncoon/esp8266-fastled-webserver - Copyright (C) 2016 Jason Coon - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -typedef String (*FieldSetter)(String); -typedef String (*FieldGetter)(); - -const String NumberFieldType = "Number"; -const String BooleanFieldType = "Boolean"; -const String SelectFieldType = "Select"; -const String ColorFieldType = "Color"; -const String SectionFieldType = "Section"; -const String StringFieldType = "String"; -const String LabelFieldType = "Label"; - -struct Field { - String name; - String label; - String type; - uint8_t min; - uint8_t max; - FieldGetter getValue; - FieldGetter getOptions; - FieldSetter setValue; -}; - -typedef Field FieldList[]; - -Field getField(String name, FieldList fields, uint8_t count) { - for (uint8_t i = 0; i < count; i++) { - Field field = fields[i]; - if (field.name == name) { - return field; - } - } - return Field(); -} - -String getFieldValue(String name, FieldList fields, uint8_t count) { - Field field = getField(name, fields, count); - if (field.getValue) { - return field.getValue(); - } - return String(); -} - -String setFieldValue(String name, String value, FieldList fields, uint8_t count) { - Field field = getField(name, fields, count); - if (field.setValue) { - return field.setValue(value); - } - return String(); -} - -String getFieldsJson(FieldList fields, uint8_t count) { - String json = "["; - - for (uint8_t i = 0; i < count; i++) { - Field field = fields[i]; - - json += "{\"name\":\"" + field.name + "\",\"label\":\"" + field.label + "\",\"type\":\"" + field.type + "\""; - - if(field.getValue) { - if (field.type == ColorFieldType || field.type == StringFieldType || field.type == LabelFieldType) { - json += ",\"value\":\"" + field.getValue() + "\""; - } - else { - json += ",\"value\":" + field.getValue(); - } - } - - if (field.type == NumberFieldType) { - json += ",\"min\":" + String(field.min); - json += ",\"max\":" + String(field.max); - } - - if (field.getOptions) { - json += ",\"options\":["; - json += field.getOptions(); - json += "]"; - } - - json += "}"; - - if (i < count - 1) - json += ","; - } - - json += "]"; - - return json; -} - -/* - String json = "["; - - json += "{\"name\":\"power\",\"label\":\"Power\",\"type\":\"Boolean\",\"value\":" + String(power) + "},"; - json += "{\"name\":\"brightness\",\"label\":\"Brightness\",\"type\":\"Number\",\"value\":" + String(brightness) + "},"; - - json += "{\"name\":\"pattern\",\"label\":\"Pattern\",\"type\":\"Select\",\"value\":" + String(currentPatternIndex) + ",\"options\":["; - for (uint8_t i = 0; i < patternCount; i++) - { - json += "\"" + patterns[i].name + "\""; - if (i < patternCount - 1) - json += ","; - } - json += "]},"; - - json += "{\"name\":\"autoplay\",\"label\":\"Autoplay\",\"type\":\"Boolean\",\"value\":" + String(autoplay) + "},"; - json += "{\"name\":\"autoplayDuration\",\"label\":\"Autoplay Duration\",\"type\":\"Number\",\"value\":" + String(autoplayDuration) + "},"; - - json += "{\"name\":\"solidColor\",\"label\":\"Color\",\"type\":\"Color\",\"value\":\"" + String(solidColor.r) + "," + String(solidColor.g) + "," + String(solidColor.b) +"\"},"; - - json += "{\"name\":\"cooling\",\"label\":\"Cooling\",\"type\":\"Number\",\"value\":" + String(cooling) + "},"; - json += "{\"name\":\"sparking\",\"label\":\"Sparking\",\"type\":\"Number\",\"value\":" + String(sparking) + "}"; - - json += "]"; -*/ diff --git a/esp8266-fastled-webserver/Fields.h b/esp8266-fastled-webserver/Fields.cpp similarity index 51% rename from esp8266-fastled-webserver/Fields.h rename to esp8266-fastled-webserver/Fields.cpp index b324c1d3..f20af72a 100644 --- a/esp8266-fastled-webserver/Fields.h +++ b/esp8266-fastled-webserver/Fields.cpp @@ -15,10 +15,21 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "common.h" + +const String NumberFieldType = "Number"; +const String BooleanFieldType = "Boolean"; +const String SelectFieldType = "Select"; +const String ColorFieldType = "Color"; +const String SectionFieldType = "Section"; +const String StringFieldType = "String"; +const String LabelFieldType = "Label"; uint8_t power = 1; uint8_t brightness = brightnessMap[brightnessIndex]; + + //String setPower(String value) { // power = value.toInt(); // if(power < 0) power = 0; @@ -37,6 +48,12 @@ String getPower() { // return String(brightness); //} +// TODO: wrapper class for EEPROM settings, to help ensure clear understanding +// of all locations that can cause settings committed / EEPROM write. +// Also simplifies reading prior value before writing new value (extend EEPROM life) +// Also simplifies later extending CRC, transactional updates, bypassing "dead" +// areas of EEPROM, etc. + String getBrightness() { return String(brightness); } @@ -81,6 +98,28 @@ String getAutoplayDuration() { return String(autoplayDuration); } +String getShowClock() { + return String(showClock); +} + +String getClockBackgroundFade() { + return String(clockBackgroundFade); +} + +void setShowClock(uint8_t value) +{ + showClock = value == 0 ? 0 : 1; + writeAndCommitSettings(); + broadcastInt("showClock", showClock); +} + +void setClockBackgroundFade(uint8_t value) +{ + clockBackgroundFade = value; + writeAndCommitSettings(); + broadcastInt("clockBackgroundFade", clockBackgroundFade); +} + String getSolidColor() { return String(solidColor.r) + "," + String(solidColor.g) + "," + String(solidColor.b); } @@ -120,130 +159,232 @@ String getSaturationBpm() { } String setSaturationBpm(String value) { - saturationBpm = value.toInt(); return value; + saturationBpm = value.toInt(); + return value; } String getSaturationMin() { return String(saturationMin); } String setSaturationMin(String value) { - saturationMin = value.toInt(); return value; + saturationMin = value.toInt(); + return value; } String getSaturationMax() { return String(saturationMax); } String setSaturationMax(String value) { - saturationMax = value.toInt(); return value; + saturationMax = value.toInt(); + return value; } String getBrightDepthBpm() { return String(brightDepthBpm); } String setBrightDepthBpm(String value) { - brightDepthBpm = value.toInt(); return value; + brightDepthBpm = value.toInt(); + return value; } String getBrightDepthMin() { return String(brightDepthMin); } String setBrightDepthMin(String value) { - brightDepthMin = value.toInt(); return value; + brightDepthMin = value.toInt(); + return value; } String getBrightDepthMax() { return String(brightDepthMax); } String setBrightDepthMax(String value) { - brightDepthMax = value.toInt(); return value; + brightDepthMax = value.toInt(); + return value; } String getBrightThetaIncBpm() { return String(brightThetaIncBpm); } String setBrightThetaIncBpm(String value) { - brightThetaIncBpm = value.toInt(); return value; + brightThetaIncBpm = value.toInt(); + return value; } String getBrightThetaIncMin() { return String(brightThetaIncMin); } String setBrightThetaIncMin(String value) { - brightThetaIncMin = value.toInt(); return value; + brightThetaIncMin = value.toInt(); + return value; } String getBrightThetaIncMax() { return String(brightThetaIncMax); } String setBrightThetaIncMax(String value) { - brightThetaIncMax = value.toInt(); return value; + brightThetaIncMax = value.toInt(); + return value; } String getMsMultiplierBpm() { return String(msMultiplierBpm); } String setMsMultiplierBpm(String value) { - msMultiplierBpm = value.toInt(); return value; + msMultiplierBpm = value.toInt(); + return value; } String getMsMultiplierMin() { return String(msMultiplierMin); } String setMsMultiplierMin(String value) { - msMultiplierMin = value.toInt(); return value; + msMultiplierMin = value.toInt(); + return value; } String getMsMultiplierMax() { return String(msMultiplierMax); } String setMsMultiplierMax(String value) { - msMultiplierMax = value.toInt(); return value; + msMultiplierMax = value.toInt(); + return value; } String getHueIncBpm() { return String(hueIncBpm); } String setHueIncBpm(String value) { - hueIncBpm = value.toInt(); return value; + hueIncBpm = value.toInt(); + return value; } String getHueIncMin() { return String(hueIncMin); } String setHueIncMin(String value) { - hueIncMin = value.toInt(); return value; + hueIncMin = value.toInt(); + return value; } String getHueIncMax() { return String(hueIncMax); } String setHueIncMax(String value) { - hueIncMax = value.toInt(); return value; + hueIncMax = value.toInt(); + return value; } String getSHueBpm() { return String(sHueBpm); } String setSHueBpm(String value) { - sHueBpm = value.toInt(); return value; + sHueBpm = value.toInt(); + return value; } String getSHueMin() { return String(sHueMin); } String setSHueMin(String value) { - sHueMin = value.toInt(); return value; + sHueMin = value.toInt(); + return value; } String getSHueMax() { return String(sHueMax); } String setSHueMax(String value) { - sHueMax = value.toInt(); return value; + sHueMax = value.toInt(); + return value; +} + + +typedef String (*FieldSetter)(String); +typedef String (*FieldGetter)(); +struct Field { + String name; + String label; + String type; + uint8_t min; + uint8_t max; + FieldGetter getValue; + FieldGetter getOptions; + FieldSetter setValue; +}; + +// passing array reference works fine, but need to make the function a template +// to capture the array size... on the positive side, no need to pass `count` parameter +template +Field getField(String name, const Field (&fields)[N]) { + for (uint8_t i = 0; i < N; i++) { + Field field = fields[i]; + if (field.name == name) { + return field; + } + } + return Field(); +} +template +String getFieldValue(String name, const Field (&fields)[N]) { + Field field = getField(name, fields); + if (field.getValue) { + return field.getValue(); + } + return String(); +} +template +String setFieldValue(String name, String value, const Field (&fields)[N]) { + Field field = getField(name, fields); + if (field.setValue) { + return field.setValue(value); + } + return String(); +} +template +String getFieldsJson(const Field (&fields)[N]) { + String json = "["; + + for (uint8_t i = 0; i < N; i++) { + Field field = fields[i]; + + json += "{\"name\":\"" + field.name + "\",\"label\":\"" + field.label + "\",\"type\":\"" + field.type + "\""; + + if(field.getValue) { + if (field.type == ColorFieldType || field.type == StringFieldType || field.type == LabelFieldType) { + json += ",\"value\":\"" + field.getValue() + "\""; + } + else { + json += ",\"value\":" + field.getValue(); + } + } + + if (field.type == NumberFieldType) { + json += ",\"min\":" + String(field.min); + json += ",\"max\":" + String(field.max); + } + + if (field.getOptions) { + json += ",\"options\":["; + json += field.getOptions(); + json += "]"; + } + + json += "}"; + + if (i < N - 1) + json += ","; + } + + json += "]"; + + return json; } // name, label, type, min, max, getValue, getOptions, setValue -FieldList fields = { +// only items that use the 'getOptions': patterns and palettes +// only items that support 'setValue': options used for pridePlayground +const Field fields[] = { {"name", "Name", LabelFieldType, 0, 0, getName, nullptr, nullptr}, {"power", "Power", BooleanFieldType, 0, 1, getPower, nullptr, nullptr}, @@ -257,6 +398,11 @@ FieldList fields = { {"autoplay", "Autoplay", BooleanFieldType, 0, 1, getAutoplay, nullptr, nullptr}, {"autoplayDuration", "Autoplay Duration", NumberFieldType, 0, 255, getAutoplayDuration, nullptr, nullptr}, + //-------------------------------------------------------------------------------------------------------- + {"clock", "Clock", SectionFieldType, 0, 0, nullptr, nullptr, nullptr}, + {"showClock", "Show Clock", BooleanFieldType, 0, 1, getShowClock, nullptr, nullptr}, + {"clockBackgroundFade", "Background Fade", NumberFieldType, 0, 255, getClockBackgroundFade, nullptr, nullptr}, + //-------------------------------------------------------------------------------------------------------- {"solidColorSection", "Solid Color", SectionFieldType, 0, 0, nullptr, nullptr, nullptr}, {"solidColor", "Color", ColorFieldType, 0, 255, getSolidColor, nullptr, nullptr}, @@ -274,31 +420,46 @@ FieldList fields = { //-------------------------------------------------------------------------------------------------------- - {"prideSection", "Pride", SectionFieldType, 0, 0, nullptr, nullptr, nullptr}, + {"prideSection", "Pride Playground", SectionFieldType, 0, 0, nullptr, nullptr, nullptr}, - {"saturationBpm", "Saturation BPM", NumberFieldType, 0, 255, getSaturationBpm, nullptr, setSaturationBpm}, - {"saturationMin", "Saturation Min", NumberFieldType, 0, 255, getSaturationMin, nullptr, setSaturationMin}, - {"saturationMax", "Saturation Max", NumberFieldType, 0, 255, getSaturationMax, nullptr, setSaturationMax}, + {"saturationBpm", "Saturation BPM", NumberFieldType, 0, 255, getSaturationBpm, nullptr, setSaturationBpm}, + {"saturationMin", "Saturation Min", NumberFieldType, 0, 255, getSaturationMin, nullptr, setSaturationMin}, + {"saturationMax", "Saturation Max", NumberFieldType, 0, 255, getSaturationMax, nullptr, setSaturationMax}, - {"brightDepthBpm", "Brightness Depth BPM", NumberFieldType, 0, 255, getBrightDepthBpm, nullptr, setBrightDepthBpm}, - {"brightDepthMin", "Brightness Depth Min", NumberFieldType, 0, 255, getBrightDepthMin, nullptr, setBrightDepthMin}, - {"brightDepthMax", "Brightness Depth Max", NumberFieldType, 0, 255, getBrightDepthMax, nullptr, setBrightDepthMax}, + {"brightDepthBpm", "Brightness Depth BPM", NumberFieldType, 0, 255, getBrightDepthBpm, nullptr, setBrightDepthBpm}, + {"brightDepthMin", "Brightness Depth Min", NumberFieldType, 0, 255, getBrightDepthMin, nullptr, setBrightDepthMin}, + {"brightDepthMax", "Brightness Depth Max", NumberFieldType, 0, 255, getBrightDepthMax, nullptr, setBrightDepthMax}, {"brightThetaIncBpm", "Bright Theta Inc BPM", NumberFieldType, 0, 255, getBrightThetaIncBpm, nullptr, setBrightThetaIncBpm}, {"brightThetaIncMin", "Bright Theta Inc Min", NumberFieldType, 0, 255, getBrightThetaIncMin, nullptr, setBrightThetaIncMin}, {"brightThetaIncMax", "Bright Theta Inc Max", NumberFieldType, 0, 255, getBrightThetaIncMax, nullptr, setBrightThetaIncMax}, - {"msMultiplierBpm", "Time Multiplier BPM", NumberFieldType, 0, 255, getMsMultiplierBpm, nullptr, setMsMultiplierBpm}, - {"msMultiplierMin", "Time Multiplier Min", NumberFieldType, 0, 255, getMsMultiplierMin, nullptr, setMsMultiplierMin}, - {"msMultiplierMax", "Time Multiplier Max", NumberFieldType, 0, 255, getMsMultiplierMax, nullptr, setMsMultiplierMax}, + {"msMultiplierBpm", "Time Multiplier BPM", NumberFieldType, 0, 255, getMsMultiplierBpm, nullptr, setMsMultiplierBpm}, + {"msMultiplierMin", "Time Multiplier Min", NumberFieldType, 0, 255, getMsMultiplierMin, nullptr, setMsMultiplierMin}, + {"msMultiplierMax", "Time Multiplier Max", NumberFieldType, 0, 255, getMsMultiplierMax, nullptr, setMsMultiplierMax}, - {"hueIncBpm", "Hue Inc BPM", NumberFieldType, 0, 255, getHueIncBpm, nullptr, setHueIncBpm}, - {"hueIncMin", "Hue Inc Min", NumberFieldType, 0, 255, getHueIncMin, nullptr, setHueIncMin}, - {"hueIncMax", "Hue Inc Max", NumberFieldType, 0, 255, getHueIncMax, nullptr, setHueIncMax}, + {"hueIncBpm", "Hue Inc BPM", NumberFieldType, 0, 255, getHueIncBpm, nullptr, setHueIncBpm}, + {"hueIncMin", "Hue Inc Min", NumberFieldType, 0, 255, getHueIncMin, nullptr, setHueIncMin}, + {"hueIncMax", "Hue Inc Max", NumberFieldType, 0, 255, getHueIncMax, nullptr, setHueIncMax}, - {"sHueBpm", "S Hue BPM", NumberFieldType, 0, 255, getSHueBpm, nullptr, setSHueBpm}, - {"sHueMin", "S Hue Min", NumberFieldType, 0, 255, getSHueMin, nullptr, setSHueMin}, - {"sHueMax", "S Hue Max", NumberFieldType, 0, 255, getSHueMax, nullptr, setSHueMax}, + {"sHueBpm", "S Hue BPM", NumberFieldType, 0, 255, getSHueBpm, nullptr, setSHueBpm}, + {"sHueMin", "S Hue Min", NumberFieldType, 0, 255, getSHueMin, nullptr, setSHueMin}, + {"sHueMax", "S Hue Max", NumberFieldType, 0, 255, getSHueMax, nullptr, setSHueMax}, }; -uint8_t fieldCount = ARRAY_SIZE(fields); +const uint8_t fieldCount = ARRAY_SIZE2(fields); +// TODO: consider using ArduinoJSON ... pre-allocated buffer, simpler usage, tested code + +Field getField(String name) { + return getField(name, fields); +} +String getFieldValue(String name) { + return getFieldValue(name, fields); +} +String setFieldValue(String name, String value) { + return setFieldValue(name, value, fields); +} +String getFieldsJson() { + return getFieldsJson(fields); +} + diff --git a/esp8266-fastled-webserver/GradientPalettes.h b/esp8266-fastled-webserver/GradientPalettes.cpp similarity index 99% rename from esp8266-fastled-webserver/GradientPalettes.h rename to esp8266-fastled-webserver/GradientPalettes.cpp index 9928500c..219c9424 100644 --- a/esp8266-fastled-webserver/GradientPalettes.h +++ b/esp8266-fastled-webserver/GradientPalettes.cpp @@ -1,3 +1,5 @@ +#include "common.h" + // From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb // Gradient Color Palette definitions for 33 different cpt-city color palettes. @@ -513,6 +515,5 @@ const TProgmemRGBGradientPalettePtr gGradientPalettes[] = { // Count of how many cpt-city gradients are defined: -const uint8_t gGradientPaletteCount = - sizeof( gGradientPalettes) / sizeof( TProgmemRGBGradientPalettePtr ); +const uint8_t gGradientPaletteCount = ARRAY_SIZE2(gGradientPalettes); diff --git a/esp8266-fastled-webserver/Info.cpp b/esp8266-fastled-webserver/Info.cpp new file mode 100644 index 00000000..badab026 --- /dev/null +++ b/esp8266-fastled-webserver/Info.cpp @@ -0,0 +1,49 @@ +#include "common.h" + +String WiFi_SSID(bool persistent) { + struct station_config conf; + if(persistent) wifi_station_get_config_default(&conf); + else wifi_station_get_config(&conf); + + const size_t buffer_len = sizeof(conf.ssid)+1; //ssid can be up to 32chars, => plus null term + char tmp[buffer_len]; + memcpy(tmp, conf.ssid, sizeof(conf.ssid)); + tmp[buffer_len-1] = 0; //nullterm in case of 32 char ssid + return String(reinterpret_cast(tmp)); +} + +String getInfoJson() +{ + String json = "{"; + json += "\"millis\":" + (String)millis() + ","; + json += "\"vcc\":" + (String)ESP.getVcc() + ","; + json += "\"wiFiChipId\":\"" + String(WIFI_getChipId(), HEX) + "\","; + json += "\"flashChipId\":\"" + String(ESP.getFlashChipId(), HEX) + "\","; + json += "\"flashChipSize\":" + (String)ESP.getFlashChipSize() + ","; + json += "\"flashChipRealSize\":" + (String)ESP.getFlashChipRealSize() + ","; + json += "\"sdkVersion\":\"" + (String)system_get_sdk_version() + "\","; + json += "\"coreVersion\":\"" + (String)ESP.getCoreVersion() + "\","; + json += "\"bootVersion\":" + (String)system_get_boot_version() + ","; + json += "\"cpuFreqMHz\":" + (String)ESP.getCpuFreqMHz() + ","; + json += "\"freeHeap\":" + (String)ESP.getFreeHeap() + ","; + json += "\"sketchSize\":" + (String)ESP.getSketchSize() + ","; + json += "\"freeSketchSpace\":" + (String)ESP.getFreeSketchSpace() + ","; + json += "\"resetReason\":\"" + (String)ESP.getResetReason() + "\","; + json += "\"isConnected\":" + (WiFi.isConnected() ? String("true") : String("false")) + ","; + json += "\"wiFiSsidDefault\":\"" + (String)WiFi_SSID(true) + "\","; + json += "\"wiFiSSID\":\"" + (String)WiFi_SSID(false) + "\","; + json += "\"localIP\":\"" + WiFi.localIP().toString() + "\","; + json += "\"gatewayIP\":\"" + WiFi.gatewayIP().toString() + "\","; + json += "\"subnetMask\":\"" + WiFi.subnetMask().toString() + "\","; + json += "\"dnsIP\":\"" + WiFi.dnsIP().toString() + "\","; + json += "\"hostname\":\"" + WiFi.hostname() + "\","; + json += "\"macAddress\":\"" + WiFi.macAddress() + "\","; + json += "\"autoConnect\":" + (WiFi.getAutoConnect() ? String("true") : String("false")) + ","; + json += "\"softAPSSID\":\"" + WiFi.softAPSSID() + "\","; + json += "\"softAPIP\":\"" + WiFi.softAPIP().toString() + "\","; + json += "\"BSSID\":\"" + (String)WiFi.BSSIDstr() + "\","; + json += "\"softAPmacAddress\":\"" + (String)WiFi.softAPmacAddress() + "\""; + json += "}"; + + return json; +} diff --git a/esp8266-fastled-webserver/Map.cpp b/esp8266-fastled-webserver/Map.cpp new file mode 100644 index 00000000..da95218b --- /dev/null +++ b/esp8266-fastled-webserver/Map.cpp @@ -0,0 +1,544 @@ +#include "common.h" + +#if HAS_COORDINATE_MAP // IS_FIBONACCI and HAS_POLAR_COORDS each imply HAS_COORDINATE_MAP + +// Each Fibonacci board must define the following arrays: +// +// physicalToFibonacci[] === given physical pixel number, get it's order if sorted by distance from center (radius, aka the vogel spiral order) +// fibonacciToPhysical[] === given index to pixel in radial order (vogel spiral order), get physical pixel index +// angles[] === angle, using units where 256 units == 360 degrees +// coordsX[] / coordsY[] === uint8_t coordinates for transformed spiral +// +// All boards appear to use the vogel model, with offset to first point == 0. +// [[ This can be confirmed by first element of angles[] === 0, +// i.e., the first point is the center of the spiral at origin (x=0, y=0) +// ]] +// +// 1. Using radial coordinates, the Nth pixel's position is defined as: +// ``` +// r = sqrt(n) +// theta = n * GOLDEN_ANGLE +// ``` +// +// 2. Calculate all coordinates, giving Vogel's model centered at the origin +// +// 3. Store theta in `angles[]` (after converting to units where 256 units == 360 degrees) +// +// 4. Convert the radial coordinates to cartesian (x/y) coordinates +// +// 5. Transform the coordinates, such as via following psuedo-code: +// +// ```C++ +// // first, translate from origin == center so left side and bottom aligned with X/Y axis +// double shiftX := min(originalCoordinatesX[]); +// double shiftY := min(originalCoordinatesY[]); +// double translatedX[] <== originalCoordinatesX[] - shiftX; // shifts right to align left side with X=0 +// double translatedY[] = originalCoordinatesY[] - shiftY; // shifts upward to align bottom with Y=0 +// // next, scale so that values lie entirely within the range [ 0.0 ... 256.0 ] +// double maxXY = max(max(translatedX[]), max(translatedY[]); +// double scaleFactor = 256.0 / maxXY; +// double scaledX[] = translatedX[] * scaleFactor; +// double scaledY[] = translatedY[] * scaleFactor; +// // finally, convert to integer values in the range [ 0 ... 255 ] +// uint8_t coordsX[] = (uint8_t)(scaledX[] - 0.5); // subtract 0.5 to avoid bias +// uint8_t coordsY[] = (uint8_t)(scaledY[] - 0.5); // subtract 0.5 to avoid bias +// ``` +// +// There appears to have been a concious decision to store the X/Y +// values as 8-bit values. Perhaps this was to allow for faster +// (8-bit) math operations on lower-power MCUs? +// +// Of course, the supported boards are ESP8266 or ESP32 (or SAMD21E), +// each of which are 32-bit native processors. If this was on AVR, +// the continued use of 8-bit algorithms would be more critical. +// + +#if defined(PRODUCT_FIBONACCI512) + const uint16_t physicalToFibonacci[NUM_PIXELS] { 510, 476, 442, 408, 374, 340, 306, 272, 238, 204, 170, 136, 102, 68, 34, 0, 13, 47, 81, 115, 149, 183, 217, 251, 285, 319, 353, 387, 421, 455, 489, 502, 468, 434, 400, 366, 332, 298, 264, 230, 196, 162, 128, 94, 60, 26, 5, 39, 73, 107, 141, 175, 209, 243, 277, 311, 345, 379, 413, 447, 481, 494, 460, 426, 392, 358, 324, 290, 256, 222, 188, 154, 120, 86, 52, 18, 31, 65, 99, 133, 167, 201, 235, 269, 303, 337, 371, 405, 439, 473, 507, 486, 452, 418, 384, 350, 316, 282, 248, 214, 180, 146, 112, 78, 44, 10, 23, 57, 91, 125, 159, 193, 227, 261, 295, 329, 363, 397, 431, 465, 499, 478, 444, 410, 376, 342, 308, 274, 240, 206, 172, 138, 104, 70, 36, 2, 15, 49, 83, 117, 151, 185, 219, 253, 287, 321, 355, 389, 423, 457, 491, 504, 470, 436, 402, 368, 334, 300, 266, 232, 198, 164, 130, 96, 62, 28, 7, 41, 75, 109, 143, 177, 211, 245, 279, 313, 347, 381, 415, 449, 483, 496, 462, 428, 394, 360, 326, 292, 258, 224, 190, 156, 122, 88, 54, 20, 33, 67, 101, 135, 169, 203, 237, 271, 305, 339, 373, 407, 441, 475, 509, 488, 454, 420, 386, 352, 318, 284, 250, 216, 182, 148, 114, 80, 46, 12, 25, 59, 93, 127, 161, 195, 229, 263, 297, 331, 365, 399, 433, 467, 501, 480, 446, 412, 378, 344, 310, 276, 242, 208, 174, 140, 106, 72, 38, 4, 17, 51, 85, 119, 153, 187, 221, 255, 289, 323, 357, 391, 425, 459, 493, 506, 472, 438, 404, 370, 336, 302, 268, 234, 200, 166, 132, 98, 64, 30, 9, 43, 77, 111, 145, 179, 213, 247, 281, 315, 349, 383, 417, 451, 485, 498, 464, 430, 396, 362, 328, 294, 260, 226, 192, 158, 124, 90, 56, 22, 1, 35, 69, 103, 137, 171, 205, 239, 273, 307, 341, 375, 409, 443, 477, 511, 490, 456, 422, 388, 354, 320, 286, 252, 218, 184, 150, 116, 82, 48, 14, 27, 61, 95, 129, 163, 197, 231, 265, 299, 333, 367, 401, 435, 469, 503, 482, 448, 414, 380, 346, 312, 278, 244, 210, 176, 142, 108, 74, 40, 6, 19, 53, 87, 121, 155, 189, 223, 257, 291, 325, 359, 393, 427, 461, 495, 508, 474, 440, 406, 372, 338, 304, 270, 236, 202, 168, 134, 100, 66, 32, 11, 45, 79, 113, 147, 181, 215, 249, 283, 317, 351, 385, 419, 453, 487, 500, 466, 432, 398, 364, 330, 296, 262, 228, 194, 160, 126, 92, 58, 24, 3, 37, 71, 105, 139, 173, 207, 241, 275, 309, 343, 377, 411, 445, 479, 492, 458, 424, 390, 356, 322, 288, 254, 220, 186, 152, 118, 84, 50, 16, 29, 63, 97, 131, 165, 199, 233, 267, 301, 335, 369, 403, 437, 471, 505, 484, 450, 416, 382, 348, 314, 280, 246, 212, 178, 144, 110, 76, 42, 8, 21, 55, 89, 123, 157, 191, 225, 259, 293, 327, 361, 395, 429, 463, 497 }; + const uint16_t fibonacciToPhysical[NUM_PIXELS] { 15, 316, 135, 437, 255, 46, 376, 166, 496, 286, 105, 407, 225, 16, 346, 136, 466, 256, 75, 377, 195, 497, 315, 106, 436, 226, 45, 347, 165, 467, 285, 76, 406, 196, 14, 317, 134, 438, 254, 47, 375, 167, 495, 287, 104, 408, 224, 17, 345, 137, 465, 257, 74, 378, 194, 498, 314, 107, 435, 227, 44, 348, 164, 468, 284, 77, 405, 197, 13, 318, 133, 439, 253, 48, 374, 168, 494, 288, 103, 409, 223, 18, 344, 138, 464, 258, 73, 379, 193, 499, 313, 108, 434, 228, 43, 349, 163, 469, 283, 78, 404, 198, 12, 319, 132, 440, 252, 49, 373, 169, 493, 289, 102, 410, 222, 19, 343, 139, 463, 259, 72, 380, 192, 500, 312, 109, 433, 229, 42, 350, 162, 470, 282, 79, 403, 199, 11, 320, 131, 441, 251, 50, 372, 170, 492, 290, 101, 411, 221, 20, 342, 140, 462, 260, 71, 381, 191, 501, 311, 110, 432, 230, 41, 351, 161, 471, 281, 80, 402, 200, 10, 321, 130, 442, 250, 51, 371, 171, 491, 291, 100, 412, 220, 21, 341, 141, 461, 261, 70, 382, 190, 502, 310, 111, 431, 231, 40, 352, 160, 472, 280, 81, 401, 201, 9, 322, 129, 443, 249, 52, 370, 172, 490, 292, 99, 413, 219, 22, 340, 142, 460, 262, 69, 383, 189, 503, 309, 112, 430, 232, 39, 353, 159, 473, 279, 82, 400, 202, 8, 323, 128, 444, 248, 53, 369, 173, 489, 293, 98, 414, 218, 23, 339, 143, 459, 263, 68, 384, 188, 504, 308, 113, 429, 233, 38, 354, 158, 474, 278, 83, 399, 203, 7, 324, 127, 445, 247, 54, 368, 174, 488, 294, 97, 415, 217, 24, 338, 144, 458, 264, 67, 385, 187, 505, 307, 114, 428, 234, 37, 355, 157, 475, 277, 84, 398, 204, 6, 325, 126, 446, 246, 55, 367, 175, 487, 295, 96, 416, 216, 25, 337, 145, 457, 265, 66, 386, 186, 506, 306, 115, 427, 235, 36, 356, 156, 476, 276, 85, 397, 205, 5, 326, 125, 447, 245, 56, 366, 176, 486, 296, 95, 417, 215, 26, 336, 146, 456, 266, 65, 387, 185, 507, 305, 116, 426, 236, 35, 357, 155, 477, 275, 86, 396, 206, 4, 327, 124, 448, 244, 57, 365, 177, 485, 297, 94, 418, 214, 27, 335, 147, 455, 267, 64, 388, 184, 508, 304, 117, 425, 237, 34, 358, 154, 478, 274, 87, 395, 207, 3, 328, 123, 449, 243, 58, 364, 178, 484, 298, 93, 419, 213, 28, 334, 148, 454, 268, 63, 389, 183, 509, 303, 118, 424, 238, 33, 359, 153, 479, 273, 88, 394, 208, 2, 329, 122, 450, 242, 59, 363, 179, 483, 299, 92, 420, 212, 29, 333, 149, 453, 269, 62, 390, 182, 510, 302, 119, 423, 239, 32, 360, 152, 480, 272, 89, 393, 209, 1, 330, 121, 451, 241, 60, 362, 180, 482, 300, 91, 421, 211, 30, 332, 150, 452, 270, 61, 391, 181, 511, 301, 120, 422, 240, 31, 361, 151, 481, 271, 90, 392, 210, 0, 331 }; + const uint8_t coordsX[NUM_PIXELS] { 170, 178, 185, 191, 196, 199, 202, 202, 202, 200, 196, 191, 184, 175, 161, 132, 148, 166, 176, 183, 188, 190, 192, 191, 190, 186, 182, 176, 170, 162, 153, 125, 136, 145, 154, 161, 168, 173, 177, 180, 181, 181, 178, 174, 167, 155, 139, 157, 164, 169, 170, 170, 168, 165, 160, 154, 147, 139, 129, 119, 109, 82, 93, 104, 114, 124, 132, 140, 147, 152, 157, 159, 160, 159, 155, 145, 145, 150, 150, 149, 146, 141, 135, 127, 119, 110, 100, 90, 79, 68, 57, 45, 56, 66, 77, 87, 97, 107, 115, 123, 130, 135, 139, 142, 141, 136, 134, 134, 131, 126, 120, 113, 105, 96, 86, 76, 66, 56, 45, 35, 25, 18, 27, 37, 47, 57, 67, 77, 86, 95, 104, 112, 119, 124, 128, 129, 125, 120, 113, 105, 97, 88, 78, 69, 59, 50, 40, 31, 22, 14, 6, 0, 6, 12, 19, 27, 35, 44, 54, 63, 73, 82, 91, 101, 109, 118, 121, 108, 98, 88, 78, 69, 59, 50, 41, 33, 25, 18, 12, 7, 3, 6, 8, 11, 15, 20, 26, 33, 40, 48, 57, 67, 77, 87, 98, 111, 102, 89, 77, 67, 58, 49, 41, 34, 28, 23, 19, 16, 15, 14, 15, 26, 24, 23, 24, 26, 28, 33, 38, 44, 51, 60, 69, 80, 93, 111, 100, 85, 73, 64, 55, 49, 43, 39, 36, 34, 33, 34, 36, 39, 43, 58, 53, 49, 45, 44, 43, 44, 46, 50, 55, 61, 69, 79, 93, 116, 104, 87, 76, 68, 62, 58, 55, 54, 54, 55, 58, 62, 68, 74, 82, 108, 99, 90, 83, 77, 72, 68, 65, 64, 65, 67, 70, 76, 85, 97, 112, 94, 85, 80, 76, 75, 75, 77, 81, 85, 91, 98, 106, 115, 125, 153, 142, 131, 122, 113, 105, 99, 93, 89, 87, 85, 86, 89, 95, 106, 123, 105, 99, 96, 96, 98, 101, 106, 112, 119, 128, 137, 147, 157, 168, 180, 193, 182, 171, 161, 151, 141, 133, 125, 118, 113, 108, 106, 106, 108, 115, 116, 114, 115, 118, 123, 129, 137, 145, 154, 164, 174, 184, 195, 206, 216, 226, 216, 205, 195, 185, 175, 165, 156, 147, 139, 133, 127, 123, 121, 124, 127, 129, 134, 141, 148, 156, 165, 174, 184, 194, 204, 214, 224, 233, 242, 253, 246, 238, 229, 221, 211, 202, 192, 182, 173, 164, 155, 147, 140, 133, 134, 142, 151, 160, 169, 179, 188, 198, 207, 216, 225, 233, 241, 247, 253, 255, 251, 247, 241, 234, 227, 219, 210, 201, 192, 182, 173, 163, 153, 142, 134, 151, 163, 174, 184, 194, 203, 212, 220, 227, 233, 239, 243, 247, 249, 242, 242, 241, 238, 235, 230, 225, 218, 211, 203, 194, 184, 173, 161, 146, 155, 170, 182, 192, 201, 208, 215, 221, 226, 229, 231, 232, 232, 231, 228, 215, 219, 221, 223, 223, 221, 219, 215, 210, 204, 197, 188, 177, 164, 144, 154, 170, 182, 191, 198, 204, 208, 211, 212, 213, 212, 209, 205, 200, 194 }; + const uint8_t coordsY[NUM_PIXELS] { 6, 14, 22, 31, 41, 50, 60, 70, 80, 89, 98, 106, 114, 120, 125, 128, 124, 116, 109, 101, 92, 82, 73, 63, 54, 44, 35, 27, 18, 11, 4, 0, 5, 10, 17, 24, 32, 40, 49, 59, 68, 78, 87, 97, 106, 116, 121, 106, 95, 85, 75, 65, 56, 47, 38, 31, 24, 17, 12, 7, 4, 10, 10, 13, 16, 20, 25, 31, 39, 46, 55, 64, 74, 85, 96, 111, 101, 87, 76, 65, 56, 48, 41, 34, 29, 25, 21, 20, 19, 19, 21, 33, 30, 29, 28, 29, 31, 34, 39, 45, 51, 59, 69, 79, 92, 111, 101, 85, 73, 64, 56, 50, 45, 41, 39, 38, 38, 40, 43, 47, 52, 68, 62, 56, 53, 50, 49, 49, 50, 53, 57, 63, 70, 80, 94, 119, 106, 89, 78, 70, 65, 61, 59, 59, 60, 62, 66, 71, 77, 84, 92, 119, 109, 100, 92, 85, 80, 75, 72, 70, 70, 71, 74, 79, 87, 99, 114, 97, 88, 83, 81, 80, 81, 84, 88, 94, 100, 108, 116, 126, 136, 163, 152, 142, 132, 123, 114, 107, 101, 96, 93, 91, 91, 93, 98, 108, 108, 102, 101, 101, 104, 108, 114, 120, 128, 137, 146, 157, 167, 178, 190, 203, 192, 181, 170, 160, 150, 141, 133, 126, 119, 115, 111, 110, 111, 118, 119, 118, 120, 124, 130, 136, 144, 153, 162, 172, 182, 193, 203, 214, 224, 232, 223, 213, 202, 192, 182, 172, 163, 154, 146, 139, 132, 128, 125, 126, 129, 133, 139, 146, 154, 162, 172, 181, 191, 201, 210, 220, 229, 238, 246, 255, 249, 242, 234, 225, 216, 207, 197, 188, 178, 169, 160, 151, 143, 136, 135, 145, 155, 164, 174, 183, 193, 202, 211, 220, 228, 236, 243, 249, 254, 253, 250, 246, 242, 236, 229, 222, 213, 205, 196, 186, 176, 166, 155, 143, 133, 153, 166, 177, 187, 196, 205, 214, 221, 228, 234, 238, 242, 245, 246, 246, 236, 237, 237, 236, 233, 229, 225, 219, 212, 204, 195, 186, 175, 162, 146, 156, 171, 182, 192, 201, 208, 214, 220, 223, 226, 228, 228, 227, 224, 221, 207, 211, 215, 217, 218, 218, 216, 213, 209, 203, 196, 187, 177, 164, 142, 153, 170, 181, 190, 196, 201, 205, 207, 208, 207, 205, 202, 197, 191, 184, 159, 168, 176, 182, 188, 192, 195, 197, 197, 196, 193, 189, 182, 173, 160, 146, 164, 173, 180, 184, 186, 186, 185, 183, 179, 174, 167, 160, 151, 142, 114, 125, 135, 144, 152, 159, 165, 170, 173, 175, 176, 174, 171, 164, 153, 136, 154, 161, 164, 165, 164, 162, 157, 152, 145, 138, 129, 119, 109, 98, 72, 83, 94, 105, 114, 124, 132, 139, 145, 150, 153, 155, 155, 152, 143, 142, 146, 146, 143, 139, 134, 127, 119, 110, 101, 91, 81, 70, 59, 48, 37, 48, 58, 69, 79, 89, 99, 108, 116, 123, 129, 134, 137, 138, 134, 132, 130, 126, 121, 114, 106, 98, 88, 79, 69, 59, 48, 38, 29, 19 }; + const uint8_t angles[NUM_PIXELS] { 205, 208, 211, 215, 218, 221, 225, 228, 231, 235, 238, 242, 245, 248, 252, 255, 246, 243, 239, 236, 233, 229, 226, 223, 219, 216, 213, 209, 206, 203, 199, 190, 194, 197, 200, 204, 207, 211, 214, 217, 221, 224, 227, 231, 234, 237, 232, 229, 225, 222, 219, 215, 212, 208, 205, 202, 198, 195, 192, 188, 185, 176, 180, 183, 186, 190, 193, 196, 200, 203, 206, 210, 213, 216, 220, 223, 214, 211, 208, 204, 201, 198, 194, 191, 188, 184, 181, 177, 174, 171, 167, 162, 165, 169, 172, 175, 179, 182, 185, 189, 192, 196, 199, 202, 206, 209, 200, 197, 193, 190, 187, 183, 180, 177, 173, 170, 167, 163, 160, 157, 153, 148, 151, 154, 158, 161, 165, 168, 171, 175, 178, 181, 185, 188, 191, 195, 186, 183, 179, 176, 173, 169, 166, 162, 159, 156, 152, 149, 146, 142, 139, 130, 133, 137, 140, 144, 147, 150, 154, 157, 160, 164, 167, 170, 174, 177, 172, 168, 165, 162, 158, 155, 152, 148, 145, 141, 138, 135, 131, 128, 125, 116, 119, 123, 126, 129, 133, 136, 139, 143, 146, 149, 153, 156, 160, 163, 154, 151, 147, 144, 141, 137, 134, 131, 127, 124, 121, 117, 114, 110, 107, 102, 105, 108, 112, 115, 118, 122, 125, 129, 132, 135, 139, 142, 145, 149, 140, 137, 133, 130, 126, 123, 120, 116, 113, 110, 106, 103, 100, 96, 93, 87, 91, 94, 98, 101, 104, 108, 111, 114, 118, 121, 124, 128, 131, 134, 126, 122, 119, 116, 112, 109, 106, 102, 99, 95, 92, 89, 85, 82, 79, 70, 73, 77, 80, 83, 87, 90, 93, 97, 100, 103, 107, 110, 114, 117, 111, 108, 105, 101, 98, 95, 91, 88, 85, 81, 78, 74, 71, 68, 64, 56, 59, 62, 66, 69, 72, 76, 79, 82, 86, 89, 93, 96, 99, 103, 97, 94, 90, 87, 84, 80, 77, 74, 70, 67, 64, 60, 57, 54, 50, 47, 41, 45, 48, 51, 55, 58, 62, 65, 68, 72, 75, 78, 82, 85, 88, 80, 76, 73, 70, 66, 63, 59, 56, 53, 49, 46, 43, 39, 36, 33, 27, 31, 34, 37, 41, 44, 47, 51, 54, 57, 61, 64, 67, 71, 74, 65, 62, 59, 55, 52, 49, 45, 42, 39, 35, 32, 28, 25, 22, 18, 10, 13, 16, 20, 23, 26, 30, 33, 36, 40, 43, 47, 50, 53, 57, 51, 48, 44, 41, 38, 34, 31, 28, 24, 21, 18, 14, 11, 8, 4, 251, 254, 2, 5, 9, 12, 16, 19, 22, 26, 29, 32, 36, 39, 42, 37, 34, 30, 27, 24, 20, 17, 13, 10, 7, 3, 0, 252, 249, 245, 236, 240, 243, 247, 250, 253, 1, 5, 8, 11, 15, 18, 21, 25, 28, 19, 16, 13, 9, 6, 3, 255, 251, 248, 244, 241, 238, 234, 231, 228, 222, 226, 229, 232, 236, 239, 242, 246, 249, 252, 0, 4, 7, 11, 14, 5, 2, 254, 250, 247, 244, 240, 237, 234, 230, 227, 223, 220, 217, 213 }; + static const auto (&radiusProxy)[NUM_PIXELS] = physicalToFibonacci; + static const uint8_t RADII_SCALE_DIVISOR { 2 }; + static const uint8_t RADII_SCALE_MULTIPLIER { 1 }; +#elif defined(PRODUCT_FIBONACCI256) + const uint8_t physicalToFibonacci[NUM_PIXELS] { 0, 13, 26, 39, 52, 65, 78, 91, 104, 117, 130, 143, 156, 169, 182, 195, 208, 221, 234, 247, 252, 239, 226, 213, 200, 187, 174, 161, 148, 135, 122, 109, 96, 83, 70, 57, 44, 31, 18, 5, 10, 23, 36, 49, 62, 75, 88, 101, 114, 127, 140, 153, 166, 179, 192, 205, 218, 231, 244, 249, 236, 223, 210, 197, 184, 171, 158, 145, 132, 119, 106, 93, 80, 67, 54, 41, 28, 15, 2, 7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176, 189, 202, 215, 228, 241, 254, 246, 233, 220, 207, 194, 181, 168, 155, 142, 129, 116, 103, 90, 77, 64, 51, 38, 25, 12, 4, 17, 30, 43, 56, 69, 82, 95, 108, 121, 134, 147, 160, 173, 186, 199, 212, 225, 238, 251, 243, 230, 217, 204, 191, 178, 165, 152, 139, 126, 113, 100, 87, 74, 61, 48, 35, 22, 9, 1, 14, 27, 40, 53, 66, 79, 92, 105, 118, 131, 144, 157, 170, 183, 196, 209, 222, 235, 248, 253, 240, 227, 214, 201, 188, 175, 162, 149, 136, 123, 110, 97, 84, 71, 58, 45, 32, 19, 6, 11, 24, 37, 50, 63, 76, 89, 102, 115, 128, 141, 154, 167, 180, 193, 206, 219, 232, 245, 250, 237, 224, 211, 198, 185, 172, 159, 146, 133, 120, 107, 94, 81, 68, 55, 42, 29, 16, 3, 8, 21, 34, 47, 60, 73, 86, 99, 112, 125, 138, 151, 164, 177, 190, 203, 216, 229, 242, 255 }; + const uint8_t fibonacciToPhysical[NUM_PIXELS] { 0, 157, 78, 235, 118, 39, 196, 79, 236, 156, 40, 197, 117, 1, 158, 77, 234, 119, 38, 195, 80, 237, 155, 41, 198, 116, 2, 159, 76, 233, 120, 37, 194, 81, 238, 154, 42, 199, 115, 3, 160, 75, 232, 121, 36, 193, 82, 239, 153, 43, 200, 114, 4, 161, 74, 231, 122, 35, 192, 83, 240, 152, 44, 201, 113, 5, 162, 73, 230, 123, 34, 191, 84, 241, 151, 45, 202, 112, 6, 163, 72, 229, 124, 33, 190, 85, 242, 150, 46, 203, 111, 7, 164, 71, 228, 125, 32, 189, 86, 243, 149, 47, 204, 110, 8, 165, 70, 227, 126, 31, 188, 87, 244, 148, 48, 205, 109, 9, 166, 69, 226, 127, 30, 187, 88, 245, 147, 49, 206, 108, 10, 167, 68, 225, 128, 29, 186, 89, 246, 146, 50, 207, 107, 11, 168, 67, 224, 129, 28, 185, 90, 247, 145, 51, 208, 106, 12, 169, 66, 223, 130, 27, 184, 91, 248, 144, 52, 209, 105, 13, 170, 65, 222, 131, 26, 183, 92, 249, 143, 53, 210, 104, 14, 171, 64, 221, 132, 25, 182, 93, 250, 142, 54, 211, 103, 15, 172, 63, 220, 133, 24, 181, 94, 251, 141, 55, 212, 102, 16, 173, 62, 219, 134, 23, 180, 95, 252, 140, 56, 213, 101, 17, 174, 61, 218, 135, 22, 179, 96, 253, 139, 57, 214, 100, 18, 175, 60, 217, 136, 21, 178, 97, 254, 138, 58, 215, 99, 19, 176, 59, 216, 137, 20, 177, 98, 255 }; + const uint8_t coordsX[NUM_PIXELS] { 133, 156, 165, 168, 165, 158, 147, 132, 114, 95, 76, 57, 41, 28, 19, 15, 17, 24, 37, 56, 123, 96, 73, 53, 38, 28, 24, 25, 31, 41, 55, 71, 89, 106, 122, 136, 146, 152, 152, 143, 138, 136, 128, 115, 101, 85, 70, 56, 44, 37, 33, 34, 41, 53, 69, 90, 114, 140, 167, 226, 204, 180, 154, 129, 106, 85, 67, 54, 46, 43, 44, 50, 60, 72, 86, 100, 113, 123, 128, 117, 104, 90, 78, 67, 59, 54, 54, 59, 68, 82, 100, 121, 143, 167, 191, 212, 231, 246, 255, 251, 251, 245, 233, 218, 199, 178, 156, 134, 114, 96, 82, 73, 67, 66, 70, 78, 89, 103, 111, 94, 84, 80, 81, 86, 96, 109, 126, 145, 165, 185, 204, 220, 233, 241, 244, 241, 232, 217, 179, 201, 217, 229, 235, 235, 230, 220, 207, 190, 172, 154, 136, 121, 108, 99, 95, 96, 104, 120, 110, 111, 118, 130, 144, 160, 176, 192, 206, 217, 224, 227, 224, 216, 202, 184, 162, 137, 110, 44, 68, 94, 120, 145, 168, 187, 202, 212, 216, 216, 212, 203, 191, 177, 162, 148, 135, 126, 122, 136, 147, 161, 174, 186, 197, 204, 206, 205, 198, 187, 172, 152, 130, 106, 81, 58, 36, 17, 0, 5, 15, 30, 49, 71, 93, 116, 138, 157, 173, 185, 192, 195, 193, 187, 178, 166, 152, 137, 149, 164, 175, 180, 182, 179, 171, 159, 143, 125, 105, 83, 63, 44, 28, 16, 9, 7, 12, 23 }; + const uint8_t coordsY[NUM_PIXELS] { 126, 120, 109, 96, 82, 69, 57, 49, 45, 45, 50, 59, 74, 92, 114, 138, 163, 188, 211, 231, 255, 248, 235, 218, 198, 175, 152, 129, 107, 89, 74, 63, 57, 56, 59, 66, 76, 88, 102, 116, 103, 88, 77, 71, 68, 70, 77, 88, 103, 121, 141, 163, 184, 205, 222, 236, 245, 249, 247, 208, 224, 235, 241, 240, 234, 223, 209, 191, 172, 152, 132, 115, 101, 90, 84, 82, 86, 95, 114, 107, 98, 98, 103, 112, 126, 142, 159, 177, 195, 210, 222, 230, 233, 230, 223, 209, 191, 168, 142, 98, 125, 151, 174, 194, 209, 219, 223, 223, 218, 208, 195, 180, 164, 148, 134, 122, 114, 112, 123, 128, 138, 151, 165, 180, 193, 203, 211, 214, 212, 206, 194, 178, 158, 134, 109, 83, 58, 35, 11, 28, 48, 71, 95, 120, 142, 163, 179, 192, 200, 203, 202, 196, 187, 175, 162, 148, 136, 133, 152, 166, 177, 186, 190, 191, 187, 178, 165, 148, 128, 107, 84, 62, 41, 24, 11, 2, 0, 28, 16, 9, 8, 13, 23, 37, 55, 75, 96, 116, 135, 151, 164, 173, 177, 177, 172, 162, 146, 153, 161, 163, 160, 152, 139, 124, 106, 87, 69, 51, 36, 25, 18, 16, 20, 29, 44, 64, 133, 106, 81, 60, 44, 32, 26, 25, 29, 38, 50, 65, 82, 99, 115, 129, 140, 147, 148, 138, 134, 131, 122, 110, 95, 80, 65, 52, 42, 36, 34, 37, 45, 59, 77, 98, 123, 149, 176, 202 }; + const uint8_t angles[NUM_PIXELS] { 0, 247, 238, 229, 220, 211, 203, 194, 185, 176, 167, 159, 150, 141, 132, 123, 115, 106, 97, 88, 65, 74, 83, 92, 100, 109, 118, 127, 136, 144, 153, 162, 171, 180, 188, 197, 206, 215, 224, 232, 209, 201, 192, 183, 174, 165, 157, 148, 139, 130, 121, 113, 104, 95, 86, 77, 69, 60, 51, 28, 37, 46, 54, 63, 72, 81, 90, 98, 107, 116, 125, 134, 142, 151, 160, 169, 178, 186, 195, 172, 163, 155, 146, 137, 128, 119, 111, 102, 93, 84, 75, 67, 58, 49, 40, 31, 23, 14, 5, 246, 255, 8, 17, 26, 35, 44, 52, 61, 70, 79, 88, 96, 105, 114, 123, 132, 140, 149, 135, 126, 117, 108, 100, 91, 82, 73, 64, 56, 47, 38, 29, 20, 12, 3, 250, 241, 232, 223, 209, 218, 227, 235, 244, 253, 6, 15, 24, 33, 41, 50, 59, 68, 77, 85, 94, 103, 112, 98, 89, 80, 71, 62, 54, 45, 36, 27, 18, 10, 1, 247, 239, 230, 221, 212, 203, 195, 186, 163, 172, 180, 189, 198, 207, 216, 224, 233, 242, 251, 4, 13, 22, 31, 39, 48, 57, 66, 75, 52, 43, 34, 25, 16, 8, 254, 245, 237, 228, 219, 210, 201, 193, 184, 175, 166, 157, 149, 126, 134, 143, 152, 161, 170, 178, 187, 196, 205, 214, 222, 231, 240, 249, 2, 11, 20, 28, 37, 14, 5, 252, 243, 235, 226, 217, 208, 199, 191, 182, 173, 164, 155, 147, 138, 129, 120, 111, 103 }; + static const auto (&radiusProxy)[NUM_PIXELS] = physicalToFibonacci; + static const uint8_t RADII_SCALE_DIVISOR { 1 }; + static const uint8_t RADII_SCALE_MULTIPLIER { 1 }; +#elif defined(PRODUCT_FIBONACCI128) + const uint8_t physicalToFibonacci[NUM_PIXELS] { 0, 13, 26, 39, 52, 65, 78, 91, 104, 117, 122, 109, 96, 83, 70, 57, 44, 31, 18, 5, 10, 23, 36, 49, 62, 75, 88, 101, 114, 127, 119, 106, 93, 80, 67, 54, 41, 28, 15, 2, 7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 116, 103, 90, 77, 64, 51, 38, 25, 12, 4, 17, 30, 43, 56, 69, 82, 95, 108, 121, 126, 113, 100, 87, 74, 61, 48, 35, 22, 9, 1, 14, 27, 40, 53, 66, 79, 92, 105, 118, 123, 110, 97, 84, 71, 58, 45, 32, 19, 6, 11, 24, 37, 50, 63, 76, 89, 102, 115, 120, 107, 94, 81, 68, 55, 42, 29, 16, 3, 8, 21, 34, 47, 60, 73, 86, 99, 112, 125 }; + const uint8_t fibonacciToPhysical[NUM_PIXELS] { 0, 79, 39, 117, 59, 19, 98, 40, 118, 78, 20, 99, 58, 1, 80, 38, 116, 60, 18, 97, 41, 119, 77, 21, 100, 57, 2, 81, 37, 115, 61, 17, 96, 42, 120, 76, 22, 101, 56, 3, 82, 36, 114, 62, 16, 95, 43, 121, 75, 23, 102, 55, 4, 83, 35, 113, 63, 15, 94, 44, 122, 74, 24, 103, 54, 5, 84, 34, 112, 64, 14, 93, 45, 123, 73, 25, 104, 53, 6, 85, 33, 111, 65, 13, 92, 46, 124, 72, 26, 105, 52, 7, 86, 32, 110, 66, 12, 91, 47, 125, 71, 27, 106, 51, 8, 87, 31, 109, 67, 11, 90, 48, 126, 70, 28, 107, 50, 9, 88, 30, 108, 68, 10, 89, 49, 127, 69, 29 }; + const uint8_t coordsX[NUM_PIXELS] { 137, 170, 182, 186, 182, 172, 156, 135, 110, 83, 26, 49, 74, 99, 121, 141, 155, 164, 164, 151, 145, 141, 129, 112, 91, 69, 47, 27, 11, 0, 9, 11, 19, 33, 50, 70, 90, 108, 123, 130, 114, 96, 77, 58, 43, 32, 25, 25, 32, 45, 85, 65, 51, 43, 42, 47, 58, 74, 94, 105, 81, 68, 62, 63, 70, 84, 103, 127, 154, 218, 193, 167, 142, 119, 101, 89, 83, 84, 96, 118, 104, 106, 116, 132, 152, 175, 198, 221, 241, 255, 248, 236, 219, 199, 178, 158, 140, 126, 121, 140, 157, 176, 195, 213, 227, 237, 241, 239, 193, 210, 221, 225, 222, 214, 201, 184, 164, 142, 160, 181, 196, 204, 206, 202, 191, 174, 152, 125 }; + const uint8_t coordsY[NUM_PIXELS] { 130, 121, 105, 86, 66, 47, 31, 19, 13, 13, 55, 39, 30, 28, 33, 43, 57, 75, 95, 115, 96, 75, 60, 50, 46, 49, 59, 74, 96, 122, 166, 139, 114, 93, 78, 69, 67, 72, 85, 112, 102, 90, 89, 96, 110, 129, 152, 177, 203, 227, 247, 228, 207, 184, 161, 140, 123, 112, 109, 126, 132, 146, 165, 185, 206, 225, 240, 251, 255, 224, 235, 240, 237, 229, 216, 199, 181, 161, 143, 139, 166, 186, 202, 215, 221, 222, 216, 204, 185, 115, 142, 166, 184, 197, 203, 202, 195, 181, 158, 167, 180, 182, 178, 166, 148, 126, 101, 74, 21, 42, 66, 91, 114, 134, 150, 159, 160, 147, 141, 137, 124, 106, 85, 63, 42, 24, 9, 0 }; + const uint8_t angles[NUM_PIXELS] { 0, 247, 239, 230, 221, 212, 203, 194, 186, 177, 154, 163, 171, 180, 189, 198, 207, 216, 224, 233, 210, 201, 192, 184, 175, 166, 157, 148, 139, 131, 116, 125, 134, 143, 152, 160, 169, 178, 187, 196, 173, 164, 155, 146, 137, 129, 120, 111, 102, 93, 79, 88, 97, 105, 114, 123, 132, 141, 150, 135, 126, 118, 109, 100, 91, 82, 73, 65, 56, 33, 42, 50, 59, 68, 77, 86, 95, 103, 112, 98, 89, 80, 71, 63, 54, 45, 36, 27, 18, 252, 4, 13, 22, 31, 39, 48, 57, 66, 75, 52, 43, 34, 25, 16, 8, 255, 246, 237, 214, 223, 232, 241, 250, 2, 11, 20, 29, 37, 14, 5, 253, 244, 235, 226, 218, 209, 200, 191 }; + static const auto (&radiusProxy)[NUM_PIXELS] = physicalToFibonacci; + static const uint8_t RADII_SCALE_DIVISOR { 1 }; + static const uint8_t RADII_SCALE_MULTIPLIER { 2 }; +#elif defined(PRODUCT_FIBONACCI64_FULL) || defined(PRODUCT_FIBONACCI64_MINI) + const uint8_t physicalToFibonacci[NUM_PIXELS] { 0, 13, 26, 39, 52, 57, 44, 31, 18, 5, 10, 23, 36, 49, 62, 54, 41, 28, 15, 2, 7, 20, 33, 46, 59, 51, 38, 25, 12, 4, 17, 30, 43, 56, 61, 48, 35, 22, 9, 1, 14, 27, 40, 53, 58, 45, 32, 19, 6, 11, 24, 37, 50, 63, 55, 42, 29, 16, 3, 8, 21, 34, 47, 60 }; + const uint8_t fibonacciToPhysical[NUM_PIXELS] { 0, 39, 19, 58, 29, 9, 48, 20, 59, 38, 10, 49, 28, 1, 40, 18, 57, 30, 8, 47, 21, 60, 37, 11, 50, 27, 2, 41, 17, 56, 31, 7, 46, 22, 61, 36, 12, 51, 26, 3, 42, 16, 55, 32, 6, 45, 23, 62, 35, 13, 52, 25, 4, 43, 15, 54, 33, 5, 44, 24, 63, 34, 14, 53 }; + const uint8_t coordsX[NUM_PIXELS] { 140, 189, 208, 214, 208, 146, 168, 180, 180, 162, 152, 146, 129, 103, 72, 40, 70, 97, 120, 131, 107, 79, 50, 23, 0, 7, 23, 46, 76, 93, 57, 37, 28, 29, 87, 68, 59, 62, 80, 113, 91, 94, 109, 133, 202, 172, 145, 125, 117, 145, 170, 198, 227, 253, 255, 235, 210, 181, 148, 175, 207, 228, 240, 244 }; + const uint8_t coordsY[NUM_PIXELS] { 128, 114, 91, 63, 34, 0, 21, 48, 76, 106, 78, 47, 25, 11, 5, 38, 35, 42, 61, 101, 87, 69, 68, 78, 98, 143, 118, 102, 98, 122, 131, 152, 179, 209, 255, 230, 202, 174, 148, 142, 181, 210, 235, 252, 235, 234, 224, 203, 170, 183, 201, 205, 198, 181, 134, 157, 171, 173, 153, 145, 138, 120, 93, 63 }; + const uint8_t angles[NUM_PIXELS] { 0, 249, 241, 232, 223, 200, 208, 217, 226, 235, 212, 203, 194, 185, 176, 162, 171, 180, 188, 197, 174, 165, 156, 147, 139, 124, 133, 142, 151, 136, 128, 119, 110, 101, 78, 86, 95, 104, 113, 99, 90, 81, 72, 63, 40, 49, 58, 67, 75, 52, 43, 34, 25, 17, 2, 11, 20, 29, 38, 14, 6, 255, 246, 237 }; + static const auto (&radiusProxy)[NUM_PIXELS] = physicalToFibonacci; + static const uint8_t RADII_SCALE_DIVISOR { 1 }; + static const uint8_t RADII_SCALE_MULTIPLIER { 4 }; +#elif defined(PRODUCT_FIBONACCI32) + const uint8_t physicalToFibonacci[NUM_PIXELS] { 0, 13, 26, 31, 18, 5, 10, 23, 28, 15, 2, 7, 20, 33, 25, 12, 4, 17, 30, 22, 9, 1, 14, 27, 32, 19, 6, 11, 24, 29, 16, 3, 8, 21 }; + const uint8_t fibonacciToPhysical[NUM_PIXELS] { 0, 21, 10, 31, 16, 5, 26, 11, 32, 20, 6, 27, 15, 1, 22, 9, 30, 17, 4, 25, 12, 33, 19, 7, 28, 14, 2, 23, 8, 29, 18, 3, 24, 13 }; + const uint8_t coordsX[NUM_PIXELS] { 152, 224, 252, 210, 211, 184, 169, 161, 89, 121, 138, 102, 61, 19, 13, 57, 82, 29, 0, 36, 63, 111, 79, 83, 158, 129, 118, 160, 196, 255, 212, 163, 203, 250 }; + const uint8_t coordsY[NUM_PIXELS] { 120, 101, 69, 7, 48, 90, 50, 7, 0, 27, 83, 62, 37, 35, 84, 78, 112, 125, 154, 185, 149, 140, 195, 236, 255, 226, 179, 198, 223, 181, 183, 156, 144, 135 }; + const uint8_t angles[NUM_PIXELS] { 255, 246, 237, 214, 223, 232, 208, 199, 176, 185, 193, 170, 161, 152, 138, 147, 132, 123, 114, 100, 108, 94, 85, 76, 53, 62, 70, 47, 38, 15, 23, 32, 9, 0 }; + static const auto (&radiusProxy)[NUM_PIXELS] = physicalToFibonacci; + static const uint8_t RADII_SCALE_DIVISOR { 1 }; + static const uint8_t RADII_SCALE_MULTIPLIER { 8 }; +#elif defined(PRODUCT_KRAKEN64) + const uint8_t coordsX[NUM_PIXELS] { 151, 188, 199, 199, 171, 147, 131, 119, 124, 179, 200, 217, 237, 249, 242, 234, 255, 148, 175, 177, 150, 143, 171, 153, 155, 106, 110, 102, 75, 86, 106, 108, 88, 90, 84, 78, 107, 98, 121, 128, 80, 69, 134, 159, 192, 202, 195, 218, 61, 32, 18, 26, 39, 20, 3, 0, 48, 52, 61, 54, 33, 20, 7, 8 }; + const uint8_t coordsY[NUM_PIXELS] { 190, 204, 225, 252, 255, 236, 216, 191, 166, 147, 154, 170, 173, 156, 131, 107, 106, 148, 121, 86, 81, 63, 56, 36, 17, 145, 120, 96, 55, 23, 18, 0, 2, 112, 77, 31, 35, 49, 51, 30, 124, 103, 101, 98, 80, 58, 40, 69, 134, 124, 107, 81, 56, 43, 50, 70, 156, 180, 202, 219, 213, 195, 197, 215 }; + const uint8_t angles[NUM_PIXELS] { 0, 249, 241, 232, 223, 200, 208, 217, 226, 235, 212, 203, 194, 185, 176, 162, 171, 180, 188, 197, 174, 165, 156, 147, 139, 124, 133, 142, 151, 136, 128, 119, 110, 101, 78, 86, 95, 104, 113, 99, 90, 81, 72, 63, 40, 49, 58, 67, 75, 52, 43, 34, 25, 17, 2, 11, 20, 29, 38, 14, 6, 255, 246, 237 }; + const uint8_t body[NUM_PIXELS] { 0, 16, 32, 48, 64, 80, 96, 112, 128, 143, 159, 175, 191, 207, 223, 239, 255, 143, 159, 175, 191, 207, 223, 239, 255, 143, 159, 175, 191, 207, 223, 239, 255, 143, 159, 175, 191, 207, 223, 239, 143, 159, 175, 191, 207, 223, 239, 255, 143, 159, 175, 191, 207, 223, 239, 255, 143, 159, 175, 191, 207, 223, 239, 255 }; + static_assert(NUM_PIXELS == ARRAY_SIZE2(body), ""); + static const auto (&radiusProxy)[NUM_PIXELS] = body; + static const uint8_t RADII_SCALE_DIVISOR { 1 }; // body[] values are already in range [0..255] + static const uint8_t RADII_SCALE_MULTIPLIER { 1 }; // body[] values are already in range [0..255] + // For reference purposes... + // const uint8_t head[9] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + // const uint8_t tentacle0[8] { 9, 10, 11, 12, 13, 14, 15, 16 }; + // const uint8_t tentacle1[8] { 17, 18, 19, 20, 21, 22, 23, 24 }; + // const uint8_t tentacle2[8] { 25, 26, 27, 28, 29, 30, 31, 32 }; + // const uint8_t tentacle3[8] { 33, 34, 35, 36, 37, 38, 39 }; + // const uint8_t tentacle4[8] { 40, 41, 42, 43, 44, 45, 46, 47 }; + // const uint8_t tentacle5[8] { 48, 49, 50, 51, 52, 53, 54, 55 }; + // const uint8_t tentacle6[8] { 56, 57, 58, 59, 60, 61, 62, 63 }; +#elif defined(PRODUCT_1628_RINGS) + // Yes, this is 1628 pixels ... all driven by one ESP8266 + // 20 concentric rings of pixel goodness! + const uint8_t coordsX[NUM_PIXELS] { 134, 128, 121, 128, 140, 139, 134, 128, 121, 116, 115, 116, 121, 128, 134, 139, 147, 146, 143, 139, 134, 129, 123, 118, 113, 110, 109, 109, 110, 113, 118, 123, 129, 134, 139, 143, 146, 153, 152, 151, 148, 144, 139, 134, 129, 123, 118, 113, 109, 106, 103, 102, 102, 103, 106, 109, 113, 118, 123, 129, 134, 139, 144, 148, 151, 152, 159, 159, 158, 155, 152, 149, 144, 139, 134, 129, 123, 118, 113, 109, 104, 101, 98, 97, 96, 96, 97, 98, 101, 104, 109, 113, 118, 123, 129, 134, 139, 144, 149, 152, 155, 158, 159, 166, 165, 164, 162, 160, 157, 153, 149, 144, 139, 134, 129, 124, 118, 113, 108, 104, 100, 97, 94, 92, 90, 89, 89, 90, 92, 94, 97, 100, 104, 108, 113, 118, 124, 129, 134, 139, 144, 149, 153, 157, 160, 162, 164, 165, 172, 172, 171, 169, 167, 165, 161, 158, 154, 149, 144, 139, 134, 129, 124, 118, 113, 108, 104, 99, 95, 92, 89, 87, 85, 84, 83, 83, 84, 85, 87, 89, 92, 95, 99, 104, 108, 113, 118, 124, 129, 134, 139, 144, 149, 154, 158, 161, 165, 167, 169, 171, 172, 179, 178, 177, 176, 174, 172, 169, 166, 163, 159, 154, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 101, 96, 92, 89, 86, 83, 81, 79, 78, 77, 77, 77, 78, 79, 81, 83, 86, 89, 92, 96, 101, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 154, 159, 163, 166, 169, 172, 174, 176, 177, 178, 185, 185, 184, 183, 181, 179, 177, 174, 171, 167, 163, 159, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 100, 96, 92, 88, 84, 81, 78, 76, 74, 72, 71, 70, 70, 70, 71, 72, 74, 76, 78, 81, 84, 88, 92, 96, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 159, 163, 167, 171, 174, 177, 179, 181, 183, 184, 185, 191, 191, 190, 189, 188, 186, 184, 181, 178, 175, 172, 168, 164, 159, 155, 150, 145, 140, + 135, 130, 125, 120, 115, 110, 105, 100, 96, 91, 87, 83, 80, 77, 74, 71, 69, 67, 66, 65, 64, 64, 64, 65, 66, 67, 69, 71, 74, 77, 80, 83, 87, 91, 96, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 159, 164, 168, 172, 175, 178, 181, 184, 186, 188, 189, 190, 191, 198, 197, 197, 196, 195, 193, 191, 189, 186, 183, 180, 176, 172, 168, 164, 160, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 100, 95, 91, 87, 83, 79, 75, 72, 69, 66, 64, 62, 60, 59, 58, 58, 57, 58, 58, 59, 60, 62, 64, 66, 69, 72, 75, 79, 83, 87, 91, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 164, 168, 172, 176, 180, 183, 186, 189, 191, 193, 195, 196, 197, 197, 204, 204, 203, 202, 201, 200, 198, 196, 193, 191, 188, 184, 181, 177, 173, 169, 164, 160, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 100, 95, 91, 86, 82, 78, 74, 71, 67, 64, 62, 59, 57, 55, 54, 53, 52, 51, 51, 51, 52, 53, 54, 55, 57, 59, 62, 64, 67, 71, 74, 78, 82, 86, 91, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 164, 169, 173, 177, 181, 184, 188, 191, 193, 196, 198, 200, 201, 202, 203, 204, 210, 210, 210, 209, 208, 206, 205, 203, 201, 198, 195, 192, 189, 185, 181, 177, 173, 169, 164, 160, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 100, 95, 91, 86, 82, 78, 74, 70, 66, 63, 60, 57, 54, 52, 50, 49, 47, 46, 45, 45, 45, 45, 45, 46, 47, 49, 50, 52, 54, 57, 60, 63, 66, 70, 74, 78, 82, 86, 91, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 164, 169, 173, 177, 181, 185, 189, 192, 195, 198, 201, 203, 205, 206, 208, 209, 210, 210, 217, 217, 216, 215, 214, 213, 212, 210, 208, 205, 203, 200, 197, 193, 190, 186, 182, 178, 174, + 169, 165, 160, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 100, 95, 90, 86, 81, 77, 73, 69, 65, 62, 58, 55, 52, 50, 47, 45, 43, 42, 41, 40, 39, 38, 38, 38, 39, 40, 41, 42, 43, 45, 47, 50, 52, 55, 58, 62, 65, 69, 73, 77, 81, 86, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 169, 174, 178, 182, 186, 190, 193, 197, 200, 203, 205, 208, 210, 212, 213, 214, 215, 216, 217, 223, 223, 223, 222, 221, 220, 218, 217, 215, 212, 210, 207, 204, 201, 198, 194, 190, 187, 182, 178, 174, 169, 165, 160, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 100, 95, 90, 86, 81, 77, 73, 68, 65, 61, 57, 54, 51, 48, 45, 43, 40, 38, 37, 35, 34, 33, 32, 32, 32, 32, 32, 33, 34, 35, 37, 38, 40, 43, 45, 48, 51, 54, 57, 61, 65, 68, 73, 77, 81, 86, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 169, 174, 178, 182, 187, 190, 194, 198, 201, 204, 207, 210, 212, 215, 217, 218, 220, 221, 222, 223, 223, 230, 229, 229, 228, 227, 226, 225, 223, 221, 219, 217, 214, 212, 208, 205, 202, 198, 194, 191, 186, 182, 178, 173, 169, 164, 159, 154, 149, 144, 139, 134, 129, 124, 119, 113, 108, 103, 98, 94, 89, 84, 79, 75, 71, 67, 62, 59, 55, 51, 48, 45, 42, 39, 37, 35, 33, 31, 29, 28, 27, 26, 26, 26, 26, 26, 26, 27, 28, 29, 31, 33, 35, 37, 39, 42, 45, 48, 51, 55, 59, 62, 67, 71, 75, 79, 84, 89, 94, 98, 103, 108, 113, 119, 124, 129, 134, 139, 144, 149, 154, 159, 164, 169, 173, 178, 182, 186, 191, 194, 198, 202, 205, 208, 212, 214, 217, 219, 221, 223, 225, 226, 227, 228, 229, 229, 236, 236, 235, 235, 234, 233, 232, 230, 228, 227, 224, 222, 219, 217, 214, 211, 207, 204, 200, 196, 192, 188, 184, 179, 175, 170, 166, 161, 156, 151, + 146, 141, 136, 131, 126, 121, 116, 111, 106, 101, 96, 92, 87, 82, 78, 73, 69, 65, 61, 57, 53, 50, 46, 43, 40, 37, 34, 32, 30, 27, 26, 24, 23, 21, 21, 20, 19, 19, 19, 19, 20, 21, 21, 23, 24, 26, 27, 30, 32, 34, 37, 40, 43, 46, 50, 53, 57, 61, 65, 69, 73, 78, 82, 87, 92, 96, 101, 106, 111, 116, 121, 126, 131, 136, 141, 146, 151, 156, 161, 166, 170, 175, 179, 184, 188, 192, 196, 200, 204, 207, 211, 214, 217, 219, 222, 224, 227, 228, 230, 232, 233, 234, 235, 235, 236, 242, 242, 242, 241, 240, 239, 238, 237, 235, 233, 231, 229, 226, 224, 221, 218, 215, 211, 208, 204, 200, 196, 192, 188, 183, 179, 174, 170, 165, 160, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 100, 95, 90, 85, 81, 76, 72, 67, 63, 59, 55, 51, 47, 44, 40, 37, 34, 31, 29, 26, 24, 22, 20, 18, 17, 16, 15, 14, 13, 13, 13, 13, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 29, 31, 34, 37, 40, 44, 47, 51, 55, 59, 63, 67, 72, 76, 81, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 174, 179, 183, 188, 192, 196, 200, 204, 208, 211, 215, 218, 221, 224, 226, 229, 231, 233, 235, 237, 238, 239, 240, 241, 242, 242, 249, 249, 248, 248, 247, 246, 245, 243, 241, 240, 237, 235, 233, 230, 227, 224, 221, 217, 214, 210, 206, 202, 198, 193, 189, 184, 180, 175, 170, 165, 160, 155, 150, 145, 139, 134, 129, 124, 118, 113, 108, 103, 98, 93, 88, 83, 78, 73, 68, 64, 60, 55, 51, 47, 43, 40, 36, 33, 30, 27, 24, 21, 19, 16, 14, 13, 11, 10, 9, 8, 7, 7, 6, 6, 7, 7, 8, 9, 10, 11, 13, 14, 16, 19, 21, 24, 27, 30, 33, 36, 40, 43, 47, 51, 55, 60, 64, 68, 73, 78, 83, 88, 93, 98, 103, 108, 113, 118, 124, 129, 134, 139, 145, 150, 155, 160, 165, 170, 175, 180, 184, 189, 193, 198, 202, 206, + 210, 214, 217, 221, 224, 227, 230, 233, 235, 237, 240, 241, 243, 245, 246, 247, 248, 248, 249, 255, 255, 255, 254, 253, 253, 251, 250, 249, 247, 245, 243, 241, 239, 236, 234, 231, 228, 224, 221, 218, 214, 210, 206, 202, 198, 194, 190, 185, 181, 176, 172, 167, 162, 157, 152, 147, 142, 138, 133, 128, 122, 117, 113, 108, 103, 98, 93, 88, 83, 79, 74, 70, 65, 61, 57, 53, 49, 45, 41, 37, 34, 31, 27, 24, 21, 19, 16, 14, 12, 10, 8, 6, 5, 4, 2, 2, 1, 0, 0, 0, 0, 0, 1, 2, 2, 4, 5, 6, 8, 10, 12, 14, 16, 19, 21, 24, 27, 31, 34, 37, 41, 45, 49, 53, 57, 61, 65, 70, 74, 79, 83, 88, 93, 98, 103, 108, 113, 117, 122, 127, 133, 138, 142, 147, 152, 157, 162, 167, 172, 176, 181, 185, 190, 194, 198, 202, 206, 210, 214, 218, 221, 224, 228, 231, 234, 236, 239, 241, 243, 245, 247, 249, 250, 251, 253, 253, 254, 255, 255 }; + const uint8_t coordsY[NUM_PIXELS] { 128, 134, 128, 121, 128, 134, 139, 140, 139, 134, 128, 121, 116, 115, 116, 121, 128, 133, 138, 142, 145, 147, 146, 144, 141, 136, 130, 125, 119, 114, 111, 109, 108, 110, 113, 117, 122, 128, 133, 138, 143, 147, 150, 152, 153, 153, 151, 149, 145, 141, 136, 130, 125, 119, 114, 110, 106, 104, 102, 102, 103, 105, 108, 112, 117, 122, 128, 133, 138, 143, 148, 151, 155, 157, 159, 159, 159, 158, 156, 153, 150, 145, 141, 136, 130, 125, 119, 114, 110, 105, 102, 99, 97, 96, 96, 96, 98, 100, 104, 107, 112, 117, 122, 128, 133, 138, 143, 148, 152, 156, 159, 162, 164, 165, 166, 166, 165, 163, 161, 158, 154, 150, 145, 141, 135, 130, 125, 120, 114, 110, 105, 101, 97, 94, 92, 90, 89, 89, 90, 91, 93, 96, 99, 103, 107, 112, 117, 122, 128, 133, 138, 143, 148, 152, 157, 160, 164, 167, 169, 171, 172, 172, 172, 171, 170, 168, 165, 162, 159, 155, 150, 145, 141, 135, 130, 125, 120, 114, 110, 105, 100, 96, 93, 90, 87, 85, 84, 83, 83, 83, 84, 86, 88, 91, 95, 98, 103, 107, 112, 117, 122, 128, 133, 138, 143, 148, 152, 157, 161, 164, 168, 171, 173, 175, 177, 178, 178, 178, 178, 177, 175, 173, 171, 168, 164, 161, 157, 152, 148, 143, 138, 133, 128, 122, 117, 112, 107, 103, 98, 94, 91, 87, 84, 82, 80, 78, 77, 77, 77, 77, 78, 80, 82, 84, 87, 91, 94, 98, 103, 107, 112, 117, 122, 128, 133, 138, 143, 148, 152, 157, 161, 165, 169, 172, 175, 178, 180, 182, 183, 184, 185, 185, 184, 183, 182, 180, 178, 175, 172, 169, 165, 161, 157, 152, 148, 143, 138, 133, 128, 122, 117, 112, 107, 103, 98, 94, 90, 86, 83, 80, 77, 75, 73, 72, 71, 70, 70, 71, 72, 73, 75, 77, 80, 83, 86, 90, 94, 98, 103, 107, 112, 117, 122, 128, 133, 138, 143, 148, 152, 157, 162, 166, 170, 173, 177, 180, 183, 185, 187, 189, 190, + 191, 191, 191, 191, 190, 189, 187, 185, 183, 180, 177, 173, 170, 166, 162, 157, 152, 148, 143, 138, 133, 128, 122, 117, 112, 107, 103, 98, 93, 89, 85, 82, 78, 75, 72, 70, 68, 66, 65, 64, 64, 64, 64, 65, 66, 68, 70, 72, 75, 78, 82, 85, 89, 93, 98, 103, 107, 112, 117, 122, 128, 133, 138, 143, 148, 153, 157, 162, 166, 170, 174, 178, 181, 185, 187, 190, 192, 194, 195, 196, 197, 198, 198, 197, 196, 195, 194, 192, 190, 187, 185, 181, 178, 174, 170, 166, 162, 157, 153, 148, 143, 138, 133, 128, 122, 117, 112, 107, 102, 98, 93, 89, 85, 81, 77, 74, 70, 68, 65, 63, 61, 60, 59, 58, 57, 57, 58, 59, 60, 61, 63, 65, 68, 70, 74, 77, 81, 85, 89, 93, 98, 102, 107, 112, 117, 122, 128, 133, 138, 143, 148, 153, 157, 162, 166, 171, 175, 179, 182, 186, 189, 192, 195, 197, 199, 201, 202, 203, 204, 204, 204, 204, 203, 202, 201, 199, 197, 195, 192, 189, 186, 182, 179, 175, 171, 166, 162, 157, 153, 148, 143, 138, 133, 128, 122, 117, 112, 107, 102, 98, 93, 89, 84, 80, 76, 73, 69, 66, 63, 60, 58, 56, 54, 53, 52, 51, 51, 51, 51, 52, 53, 54, 56, 58, 60, 63, 66, 69, 73, 76, 80, 84, 89, 93, 98, 102, 107, 112, 117, 122, 128, 133, 138, 143, 148, 153, 157, 162, 167, 171, 175, 179, 183, 187, 190, 194, 197, 199, 202, 204, 206, 207, 208, 209, 210, 210, 210, 210, 209, 208, 207, 206, 204, 202, 199, 197, 194, 190, 187, 183, 179, 175, 171, 167, 162, 157, 153, 148, 143, 138, 133, 128, 122, 117, 112, 107, 102, 98, 93, 88, 84, 80, 76, 72, 68, 65, 61, 58, 56, 53, 51, 49, 48, 47, 46, 45, 45, 45, 45, 46, 47, 48, 49, 51, 53, 56, 58, 61, 65, 68, 72, 76, 80, 84, 88, 93, 98, 102, 107, 112, 117, 122, 128, 133, 138, 143, 148, 153, 157, 162, 167, 171, 176, 180, 184, 188, 192, 195, 198, 201, 204, 206, 209, + 211, 212, 214, 215, 216, 216, 217, 217, 216, 216, 215, 214, 212, 211, 209, 206, 204, 201, 198, 195, 192, 188, 184, 180, 176, 171, 167, 162, 157, 153, 148, 143, 138, 133, 128, 122, 117, 112, 107, 102, 98, 93, 88, 84, 79, 75, 71, 67, 63, 60, 57, 54, 51, 49, 46, 44, 43, 41, 40, 39, 39, 38, 38, 39, 39, 40, 41, 43, 44, 46, 49, 51, 54, 57, 60, 63, 67, 71, 75, 79, 84, 88, 93, 98, 102, 107, 112, 117, 122, 128, 133, 138, 143, 148, 153, 158, 162, 167, 172, 176, 180, 185, 189, 192, 196, 199, 203, 206, 209, 211, 213, 216, 217, 219, 220, 221, 222, 223, 223, 223, 223, 222, 221, 220, 219, 217, 216, 213, 211, 209, 206, 203, 199, 196, 192, 189, 185, 180, 176, 172, 167, 162, 158, 153, 148, 143, 138, 133, 128, 122, 117, 112, 107, 102, 97, 93, 88, 83, 79, 75, 70, 66, 63, 59, 56, 52, 49, 46, 44, 42, 39, 38, 36, 35, 34, 33, 32, 32, 32, 32, 33, 34, 35, 36, 38, 39, 42, 44, 46, 49, 52, 56, 59, 63, 66, 70, 75, 79, 83, 88, 93, 97, 102, 107, 112, 117, 122, 128, 133, 138, 143, 148, 153, 158, 163, 167, 172, 177, 181, 185, 190, 193, 197, 201, 204, 208, 211, 214, 216, 219, 221, 223, 225, 226, 227, 228, 229, 229, 229, 229, 229, 229, 228, 227, 225, 224, 222, 220, 217, 215, 212, 209, 206, 203, 199, 195, 192, 187, 183, 179, 174, 170, 165, 160, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 100, 95, 90, 85, 81, 76, 72, 68, 63, 60, 56, 52, 49, 46, 43, 40, 38, 35, 33, 31, 30, 28, 27, 26, 26, 26, 26, 26, 26, 27, 28, 29, 30, 32, 34, 36, 39, 41, 44, 47, 51, 54, 58, 62, 65, 70, 74, 78, 83, 88, 92, 97, 102, 107, 112, 117, 122, 128, 133, 138, 143, 148, 152, 157, 162, 167, 172, 176, 181, 185, 189, 193, 197, 201, 205, 208, 211, 214, 217, 220, 223, 225, 227, 229, 231, 232, 233, 234, 235, 236, + 236, 236, 236, 235, 235, 234, 233, 231, 230, 228, 226, 224, 221, 219, 216, 213, 210, 206, 203, 199, 195, 191, 187, 183, 178, 174, 169, 165, 160, 155, 150, 145, 140, 135, 130, 125, 120, 115, 110, 105, 100, 95, 90, 86, 81, 77, 72, 68, 64, 60, 56, 52, 49, 45, 42, 39, 36, 34, 31, 29, 27, 25, 24, 22, 21, 20, 20, 19, 19, 19, 19, 20, 21, 22, 23, 24, 26, 28, 30, 32, 35, 38, 41, 44, 47, 50, 54, 58, 62, 66, 70, 74, 79, 83, 88, 93, 98, 103, 107, 112, 117, 122, 128, 133, 138, 143, 148, 153, 158, 162, 167, 172, 177, 181, 186, 190, 194, 198, 202, 206, 210, 213, 216, 219, 222, 225, 228, 230, 232, 234, 236, 238, 239, 240, 241, 242, 242, 242, 242, 242, 242, 241, 240, 239, 238, 236, 234, 232, 230, 228, 225, 222, 219, 216, 213, 210, 206, 202, 198, 194, 190, 186, 181, 177, 172, 167, 162, 158, 153, 148, 143, 138, 133, 128, 122, 117, 112, 107, 102, 97, 93, 88, 83, 78, 74, 69, 65, 61, 57, 53, 49, 45, 42, 39, 36, 33, 30, 27, 25, 23, 21, 19, 17, 16, 15, 14, 13, 13, 13, 13, 13, 13, 14, 15, 16, 17, 19, 21, 23, 25, 27, 30, 33, 36, 39, 42, 45, 49, 53, 57, 61, 65, 69, 74, 78, 83, 88, 93, 97, 102, 107, 112, 117, 122, 128, 133, 138, 143, 148, 154, 159, 164, 169, 174, 178, 183, 188, 192, 197, 201, 205, 209, 213, 216, 220, 223, 226, 229, 232, 235, 237, 239, 241, 243, 244, 246, 247, 247, 248, 248, 249, 249, 248, 248, 247, 246, 245, 243, 242, 240, 238, 236, 233, 231, 228, 225, 221, 218, 215, 211, 207, 203, 199, 194, 190, 185, 181, 176, 171, 166, 161, 156, 151, 146, 141, 135, 130, 125, 120, 114, 109, 104, 99, 94, 89, 84, 79, 74, 70, 65, 61, 56, 52, 48, 44, 40, 37, 34, 30, 27, 24, 22, 19, 17, 15, 13, 12, 10, 9, 8, 7, 7, 6, 6, 7, 7, 8, 8, 9, 11, 12, 14, 16, 18, 20, 23, 26, 29, 32, 35, + 39, 42, 46, 50, 54, 58, 63, 67, 72, 77, 81, 86, 91, 96, 101, 107, 112, 117, 122, 128, 133, 138, 142, 147, 152, 157, 162, 167, 172, 176, 181, 185, 190, 194, 198, 202, 206, 210, 214, 218, 221, 224, 228, 231, 234, 236, 239, 241, 243, 245, 247, 249, 250, 251, 253, 253, 254, 255, 255, 255, 255, 255, 254, 253, 253, 251, 250, 249, 247, 245, 243, 241, 239, 236, 234, 231, 228, 224, 221, 218, 214, 210, 206, 202, 198, 194, 190, 185, 181, 176, 172, 167, 162, 157, 152, 147, 142, 138, 133, 128, 122, 117, 113, 108, 103, 98, 93, 88, 83, 79, 74, 70, 65, 61, 57, 53, 49, 45, 41, 37, 34, 31, 27, 24, 21, 19, 16, 14, 12, 10, 8, 6, 5, 4, 2, 2, 1, 0, 0, 0, 0, 0, 1, 2, 2, 4, 5, 6, 8, 10, 12, 14, 16, 19, 21, 24, 27, 31, 34, 37, 41, 45, 49, 53, 57, 61, 65, 70, 74, 79, 83, 88, 93, 98, 103, 108, 113, 117, 122 }; + const uint8_t angles[NUM_PIXELS] { 0, 64, 128, 191, 0, 21, 43, 64, 85, 106, 128, 149, 170, 191, 213, 234, 0, 12, 24, 36, 49, 61, 73, 85, 97, 109, 121, 134, 146, 158, 170, 182, 194, 206, 219, 231, 243, 0, 9, 18, 26, 35, 44, 53, 62, 70, 79, 88, 97, 106, 114, 123, 132, 141, 149, 158, 167, 176, 185, 193, 202, 211, 220, 229, 237, 246, 0, 7, 14, 21, 28, 34, 41, 48, 55, 62, 69, 76, 83, 90, 96, 103, 110, 117, 124, 131, 138, 145, 152, 159, 165, 172, 179, 186, 193, 200, 207, 214, 221, 227, 234, 241, 248, 0, 6, 11, 17, 23, 28, 34, 40, 45, 51, 57, 62, 68, 74, 79, 85, 91, 96, 102, 108, 113, 119, 125, 130, 136, 142, 147, 153, 159, 164, 170, 176, 181, 187, 193, 198, 204, 210, 215, 221, 227, 232, 238, 244, 249, 0, 5, 10, 14, 19, 24, 29, 34, 38, 43, 48, 53, 58, 63, 67, 72, 77, 82, 87, 91, 96, 101, 106, 111, 115, 120, 125, 130, 135, 140, 144, 149, 154, 159, 164, 168, 173, 178, 183, 188, 192, 197, 202, 207, 212, 217, 221, 226, 231, 236, 241, 245, 250, 0, 4, 8, 12, 16, 21, 25, 29, 33, 37, 41, 45, 49, 53, 58, 62, 66, 70, 74, 78, 82, 86, 90, 95, 99, 103, 107, 111, 115, 119, 123, 128, 132, 136, 140, 144, 148, 152, 156, 160, 165, 169, 173, 177, 181, 185, 189, 193, 197, 202, 206, 210, 214, 218, 222, 226, 230, 234, 239, 243, 247, 251, 0, 4, 7, 11, 15, 18, 22, 26, 29, 33, 36, 40, 44, 47, 51, 55, 58, 62, 66, 69, 73, 77, 80, 84, 87, 91, 95, 98, 102, 106, 109, 113, 117, 120, 124, 128, 131, 135, 138, 142, 146, 149, 153, 157, 160, 164, 168, 171, 175, 179, 182, 186, 189, 193, 197, 200, 204, 208, 211, 215, 219, 222, 226, 230, 233, 237, 240, 244, 248, 251, 0, 3, 7, 10, 13, 16, 20, 23, 26, 29, 33, 36, 39, 43, 46, 49, 52, 56, 59, 62, 65, 69, 72, 75, 78, 82, 85, 88, 92, 95, 98, 101, 105, 108, 111, 114, 118, 121, 124, 127, + 131, 134, 137, 141, 144, 147, 150, 154, 157, 160, 163, 167, 170, 173, 177, 180, 183, 186, 190, 193, 196, 199, 203, 206, 209, 213, 216, 219, 222, 226, 229, 232, 235, 239, 242, 245, 248, 252, 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98, 101, 104, 107, 110, 113, 116, 119, 122, 125, 128, 130, 133, 136, 139, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 172, 175, 178, 181, 184, 187, 190, 193, 196, 199, 202, 205, 208, 211, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240, 243, 246, 249, 252, 0, 3, 5, 8, 11, 14, 16, 19, 22, 24, 27, 30, 33, 35, 38, 41, 43, 46, 49, 52, 54, 57, 60, 62, 65, 68, 71, 73, 76, 79, 81, 84, 87, 90, 92, 95, 98, 100, 103, 106, 109, 111, 114, 117, 119, 122, 125, 128, 130, 133, 136, 138, 141, 144, 146, 149, 152, 155, 157, 160, 163, 165, 168, 171, 174, 176, 179, 182, 184, 187, 190, 193, 195, 198, 201, 203, 206, 209, 212, 214, 217, 220, 222, 225, 228, 231, 233, 236, 239, 241, 244, 247, 250, 252, 0, 3, 5, 8, 10, 13, 15, 17, 20, 23, 25, 27, 30, 33, 35, 37, 40, 43, 45, 48, 50, 53, 55, 57, 60, 63, 65, 68, 70, 73, 75, 78, 80, 83, 85, 88, 90, 93, 95, 98, 100, 102, 105, 107, 110, 113, 115, 118, 120, 123, 125, 128, 130, 133, 135, 138, 140, 142, 145, 147, 150, 153, 155, 158, 160, 163, 165, 168, 170, 173, 175, 178, 180, 182, 185, 187, 190, 193, 195, 198, 200, 203, 205, 208, 210, 213, 215, 218, 220, 223, 225, 228, 230, 233, 235, 238, 240, 243, 245, 247, 250, 252, 0, 2, 5, 7, 9, 12, 14, 16, 19, 21, 23, 26, 28, 30, 32, 35, 37, 39, 42, 44, 46, 49, 51, 53, 56, 58, 60, 63, 65, 67, 70, 72, 74, 77, 79, 81, 83, 86, 88, 90, 93, 95, 97, 100, 102, 104, 107, 109, 111, 114, + 116, 118, 121, 123, 125, 128, 130, 132, 134, 137, 139, 141, 144, 146, 148, 151, 153, 155, 158, 160, 162, 165, 167, 169, 172, 174, 176, 179, 181, 183, 185, 188, 190, 192, 195, 197, 199, 202, 204, 206, 209, 211, 213, 216, 218, 220, 223, 225, 227, 230, 232, 234, 236, 239, 241, 243, 246, 248, 250, 253, 0, 2, 4, 6, 9, 11, 13, 15, 17, 19, 22, 24, 26, 28, 30, 32, 35, 37, 39, 41, 43, 45, 48, 50, 52, 54, 56, 58, 61, 63, 65, 67, 69, 71, 73, 76, 78, 80, 82, 84, 86, 89, 91, 93, 95, 97, 99, 102, 104, 106, 108, 110, 112, 115, 117, 119, 121, 123, 125, 128, 130, 132, 134, 136, 138, 140, 143, 145, 147, 149, 151, 153, 156, 158, 160, 162, 164, 166, 169, 171, 173, 175, 177, 179, 182, 184, 186, 188, 190, 192, 194, 197, 199, 201, 203, 205, 207, 210, 212, 214, 216, 218, 220, 223, 225, 227, 229, 231, 233, 236, 238, 240, 242, 244, 246, 249, 251, 253, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 0, 2, 4, 6, 8, 9, 11, 13, 15, 17, 19, 21, 23, 25, 26, 28, 30, 32, 34, 36, 38, 40, 42, 43, 45, 47, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, 68, 70, 72, 74, 76, 77, 79, 81, 83, 85, 87, 89, 91, 93, 94, 96, 98, 100, 102, 104, 106, 108, 110, 111, 113, 115, 117, 119, 121, 123, + 125, 127, 128, 130, 132, 134, 136, 138, 140, 142, 144, 145, 147, 149, 151, 153, 155, 157, 159, 161, 162, 164, 166, 168, 170, 172, 174, 176, 178, 179, 181, 183, 185, 187, 189, 191, 193, 195, 196, 198, 200, 202, 204, 206, 208, 210, 212, 213, 215, 217, 219, 221, 223, 225, 227, 229, 230, 232, 234, 236, 238, 240, 242, 244, 246, 247, 249, 251, 253, 0, 2, 4, 5, 7, 9, 11, 13, 14, 16, 18, 20, 22, 23, 25, 27, 29, 31, 32, 34, 36, 38, 40, 41, 43, 45, 47, 48, 50, 52, 54, 56, 57, 59, 61, 63, 65, 66, 68, 70, 72, 74, 75, 77, 79, 81, 83, 84, 86, 88, 90, 92, 93, 95, 97, 99, 101, 102, 104, 106, 108, 110, 111, 113, 115, 117, 119, 120, 122, 124, 126, 128, 129, 131, 133, 135, 136, 138, 140, 142, 144, 145, 147, 149, 151, 153, 154, 156, 158, 160, 162, 163, 165, 167, 169, 171, 172, 174, 176, 178, 180, 181, 183, 185, 187, 189, 190, 192, 194, 196, 198, 199, 201, 203, 205, 207, 208, 210, 212, 214, 215, 217, 219, 221, 223, 224, 226, 228, 230, 232, 233, 235, 237, 239, 241, 242, 244, 246, 248, 250, 251, 253, 0, 2, 4, 5, 7, 9, 11, 12, 14, 16, 18, 19, 21, 23, 25, 26, 28, 30, 32, 33, 35, 37, 39, 40, 42, 44, 46, 47, 49, 51, 53, 55, 56, 58, 60, 62, 63, 65, 67, 69, 70, 72, 74, 76, 77, 79, 81, 83, 84, 86, 88, 90, 91, 93, 95, 97, 98, 100, 102, 104, 106, 107, 109, 111, 113, 114, 116, 118, 120, 121, 123, 125, 127, 128, 130, 132, 134, 135, 137, 139, 141, 142, 144, 146, 148, 149, 151, 153, 155, 157, 158, 160, 162, 164, 165, 167, 169, 171, 172, 174, 176, 178, 179, 181, 183, 185, 186, 188, 190, 192, 193, 195, 197, 199, 200, 202, 204, 206, 208, 209, 211, 213, 215, 216, 218, 220, 222, 223, 225, 227, 229, 230, 232, 234, 236, 237, 239, 241, 243, 244, 246, 248, 250, 251, 253, 0, 2, 3, 5, 6, 8, 10, + 11, 13, 14, 16, 18, 19, 21, 22, 24, 26, 27, 29, 30, 32, 33, 35, 37, 38, 40, 41, 43, 45, 46, 48, 49, 51, 53, 54, 56, 57, 59, 61, 62, 64, 65, 67, 69, 70, 72, 73, 75, 77, 78, 80, 81, 83, 84, 86, 88, 89, 91, 92, 94, 96, 97, 99, 100, 102, 104, 105, 107, 108, 110, 112, 113, 115, 116, 118, 120, 121, 123, 124, 126, 128, 129, 131, 132, 134, 135, 137, 139, 140, 142, 143, 145, 147, 148, 150, 151, 153, 155, 156, 158, 159, 161, 163, 164, 166, 167, 169, 171, 172, 174, 175, 177, 179, 180, 182, 183, 185, 186, 188, 190, 191, 193, 194, 196, 198, 199, 201, 202, 204, 206, 207, 209, 210, 212, 214, 215, 217, 218, 220, 222, 223, 225, 226, 228, 230, 231, 233, 234, 236, 237, 239, 241, 242, 244, 245, 247, 249, 250, 252, 253 }; + const uint8_t radii[NUM_PIXELS] { 13, 13, 13, 13, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, + 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 217, 217, + 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, + 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; + static const auto (&radiusProxy)[NUM_PIXELS] = radii; + static const uint8_t RADII_SCALE_DIVISOR { 1 }; // radii[] values are already in range [0..255] + static const uint8_t RADII_SCALE_MULTIPLIER { 1 }; // radii[] values are already in range [0..255] + +#else + #error "Unknown / Unsupported product ... no mappings defined" +#endif + +#if IS_FIBONACCI + static_assert(NUM_PIXELS == ARRAY_SIZE2(physicalToFibonacci), ""); + static_assert(NUM_PIXELS == ARRAY_SIZE2(fibonacciToPhysical), ""); +#endif + +// What is HAS_RADIUS_PROXY? It could be the actual radius, or it could be something +// that is used "in place of" the radius during effects processing. +// Use reference to original array; avoids repeating preprocessor checks throughout the code.... +static_assert(RADII_SCALE_DIVISOR >= 1, ""); +static_assert(RADII_SCALE_MULTIPLIER >= 1, ""); +#define HAS_RADIUS_PROXY 1 // functions below wrapped by this ... leave defined for now +static_assert(HAS_COORDINATE_MAP, ""); +static_assert(NUM_PIXELS == ARRAY_SIZE2(coordsX), ""); +static_assert(NUM_PIXELS == ARRAY_SIZE2(coordsY), ""); +static_assert(NUM_PIXELS == ARRAY_SIZE2(angles), ""); + +#if IS_FIBONACCI // drawSpiralLine() uses angles[] and physicalToFibonacci[] +void drawSpiralLine(uint8_t angle, int step, CRGB color) +{ + int startIndex = 0; + int smallestAngleDifference = 255; + + // find the outermost led closest to the desired angle + for (int i = 0; i < NUM_PIXELS; i++) { + int j = physicalToFibonacci[i]; + if (j < step) continue; + if (!(j + step >= NUM_PIXELS)) continue; // not outermost + uint8_t a = angles[i]; + if (a == angle) startIndex = i; + else if (angle - a > 0 && angle - a < smallestAngleDifference) { + smallestAngleDifference = angle - a; + startIndex = i; + } + } + + // draw the starting LED + leds[startIndex] += color; + + // draw to center from outer start + int f = physicalToFibonacci[startIndex]; + while (f - step >= 0 && f - step < NUM_PIXELS) { + leds[fibonacciToPhysical[f]] += color; + f = f - step; + } +} +#endif + +#if HAS_RADIUS_PROXY // setPixelAR() uses radiusProxy[] +// given an angle and radius (and delta for both), set pixels that fall inside that range +void setPixelAR(uint8_t angle, uint8_t dAngle, uint8_t radius, uint8_t dRadius, CRGB color) +{ + uint8_t endRadius = qadd8(radius, dRadius); + uint8_t startRadius = qsub8(radius, dRadius); + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + // TODO: Change from pre-processor defines to `static const bool` values where possible + uint8_t ro = radiusProxy[i]; + // only mess with the pixel when it's radius is within the target radius + if (ro <= endRadius && ro >= startRadius) { + // Get pixel's angle (unit256) + uint8_t ao = angles[i]; + // set adiff to abs(ao - angle) ... relies on unsigned underflow resulting in larger value + uint8_t adiff = min(sub8(ao,angle), sub8(angle, ao)); + // only mess with the pixel when it's angle is within range of target + if (adiff <= dAngle) { + leds[i] = color; + } + } + } +} +#endif + +#if HAS_RADIUS_PROXY // andPixelAR() uses radiusProxy[] +// given an angle and radius (and delta for both), add color to pixels that fall inside that range +void andPixelAR(uint8_t angle, uint8_t dAngle, uint8_t startRadius, uint8_t endRadius, CRGB color) +{ + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint8_t ro = radiusProxy[i]; + // only mess with the pixel when it's radius is within the target radius + if (ro <= endRadius && ro >= startRadius) { + // Get pixel's angle (unit256) + uint8_t ao = angles[i]; + // set adiff to abs(ao - angle) ... relies on unsigned underflow resulting in larger value + uint8_t adiff = min(sub8(ao,angle), sub8(angle, ao)); + // only mess with the pixel when it's angle is within range of target + if (adiff <= dAngle) { + leds[i] += color; + } + } + } +} +#endif + +#if HAS_RADIUS_PROXY // antialiasPixelAR() uses angles[] and radiusProxy[] +// given an angle and radius (and delta for both), set pixels that fall inside that range, +// fading the color from full-color at center, to off (black) at the outer edges. +void antialiasPixelAR(uint8_t angle, uint8_t dAngle, uint8_t startRadius, uint8_t endRadius, CRGB color, CRGB leds[], int _NUM_PIXELS) +{ + // NOTE: + // An earlier version of this routine had significant bugs. + // Do NOT use the version which does qsub8(max(...), min()), + // as it does not handle angle overflow well. + // This version does it properly: + // 1. subtract both ways + // 2. note that unsigned underlow will make the negative result really large instead + // 3. take smaller value + // This is the absolute offset from the target angle + for (uint16_t i = 0; i < _NUM_PIXELS; i++) { + uint8_t ro = radiusProxy[i]; + // only mess with the pixel when it's radius is within the target radius + if (ro <= endRadius && ro >= startRadius) { + // Get pixel's angle (unit256) + uint8_t ao = angles[i]; + // set adiff to abs(ao - angle) ... relies on unsigned underflow resulting in larger value + uint8_t adiff = min(sub8(ao,angle), sub8(angle, ao)); + // only mess with the pixel when it's angle is within range of target + if (adiff <= dAngle) { + // map the intensity of the color so it fades to black at edge of allowed angle + uint8_t fade = map(adiff, 0, dAngle, 0, 255); + CRGB faded = color; + // fade the target color based on how far the angle was from the target + faded.fadeToBlackBy(fade); + // add the faded color (as an overlay) to existing colors + leds[i] += faded; + } + } + } +} +#endif + +// TODO - anglePalette() from Fib32 sets `hues = 256 / NUM_PIXELS' ... which is ZERO(!) +// The other similar functions are hard-coded to `hues = 1` even on Fib32. +// Likely a bug in Fib32 branch for this one function? +// Check if other branches did similar, or set to hard-coded value of 1? +#if HAS_COORDINATE_MAP // anglePalette() uses angles[] +void anglePalette() { + uint16_t hues = 1; + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t x = angles[i]; + + leds[i] = ColorFromPalette(palettes[currentPaletteIndex], beat8(speed) - (x * hues)); + } +} +#endif + +#if HAS_RADIUS_PROXY // radiusPalette() uses radiusProxy[] +void radiusPalette() { + uint16_t hues = 1; + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + + unsigned tmp = ((unsigned)(radiusProxy[i] * RADII_SCALE_MULTIPLIER)) / RADII_SCALE_DIVISOR; +#if ((NUM_PIXELS & (NUM_PIXELS-1)) == 0) // Power-of-two, so no need to check + uint8_t r = tmp; +#else + uint8_t r = tmp > 255 ? 255 : tmp; +#endif + leds[i] = ColorFromPalette(palettes[currentPaletteIndex], beat8(speed) - (r * hues)); + } +} +#endif + +#if HAS_COORDINATE_MAP // xPalette() uses coordsX[] +void xPalette() { + uint16_t hues = 1; + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t x = coordsX[i]; + + leds[i] = ColorFromPalette(palettes[currentPaletteIndex], beat8(speed) - (x * hues)); + } +} +#endif + +#if HAS_COORDINATE_MAP // yPalette() uses coordsY[] +void yPalette() { + uint16_t hues = 1; + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t y = coordsY[i]; + + leds[i] = ColorFromPalette(palettes[currentPaletteIndex], beat8(speed) - (y * hues)); + } +} +#endif + +#if HAS_COORDINATE_MAP // xyPalette() uses coordsX[] and coordsY[] +void xyPalette() { + uint16_t hues = 1; + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t x = coordsX[i]; + uint16_t y = coordsY[i]; + + leds[i] = ColorFromPalette(palettes[currentPaletteIndex], beat8(speed) - ((x + y) * hues)); + } +} +#endif + +#if HAS_COORDINATE_MAP // angleGradientPalette() uses angles[] +void angleGradientPalette() { + uint16_t hues = 1; + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t x = angles[i]; + + leds[i] = ColorFromPalette(gCurrentPalette, beat8(speed) - (x * hues)); + } +} +#endif + +#if HAS_RADIUS_PROXY // radiusGradientPalette() uses radiusProxy[] +void radiusGradientPalette() { + uint16_t hues = 1; + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + unsigned tmp = ((unsigned)(radiusProxy[i] * RADII_SCALE_MULTIPLIER)) / RADII_SCALE_DIVISOR; +#if ((NUM_PIXELS & (NUM_PIXELS-1)) == 0) // Power-of-two, so no need to check + uint8_t r = tmp; +#else + uint8_t r = tmp > 255 ? 255 : tmp; +#endif + + leds[i] = ColorFromPalette(gCurrentPalette, beat8(speed) - (r * hues)); + } +} +#endif + +#if HAS_COORDINATE_MAP // xGradientPalette() uses coordsX[] +void xGradientPalette() { + uint16_t hues = 1; + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t x = coordsX[i]; + + leds[i] = ColorFromPalette(gCurrentPalette, beat8(speed) - (x * hues)); + } +} +#endif + +#if HAS_COORDINATE_MAP // yGradientPalette() uses coordsY[] +void yGradientPalette() { + uint16_t hues = 1; + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t y = coordsY[i]; + + leds[i] = ColorFromPalette(gCurrentPalette, beat8(speed) - (y * hues)); + } +} +#endif + +#if HAS_COORDINATE_MAP // xyGradientPalette() uses coordsX[] and coordsY[] +void xyGradientPalette() { + uint16_t hues = 1; + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t x = coordsX[i]; + uint16_t y = coordsY[i]; + + leds[i] = ColorFromPalette(gCurrentPalette, beat8(speed) - ((x + y) * hues)); + } +} +#endif + +#if IS_FIBONACCI // drawAnalogClock() calls antialiasPixelAR(), which requires physicalToFibonacci[] +void drawAnalogClock() { + + // TODO: Update to use radiusProxy? For now, just divide 512+ by RADII_SCALE_DIVISOR + + static_assert((NUM_PIXELS / RADII_SCALE_DIVISOR) <= 256, ""); + static_assert((NUM_PIXELS / RADII_SCALE_DIVISOR) >= 32, "Update to drawAnalogClock() required to support fewer pixels"); + + const uint8_t hourRadius = (uint8_t)(NUM_PIXELS / RADII_SCALE_DIVISOR / 8u * 3u); // 96 designed for 256 pixels ==> 3/8 + const uint8_t minuteRadius = (uint8_t)(NUM_PIXELS / RADII_SCALE_DIVISOR / 4u * 3u); // 192 designed for 256 pixels ==> 3/4 + const uint8_t secondRadius = (uint8_t)(NUM_PIXELS / RADII_SCALE_DIVISOR - 1); // 255 designed for 256 pixels ==> all pixels + + const uint8_t hourHandWidth = 8; // angle @ unit256 ~= 11.25000 degrees + const uint8_t minuteHandWidth = 7; // angle @ unit256 ~= 9.84375 degrees + const uint8_t secondHandWidth = 6; // angle @ unit256 ~= 8.43750 degrees + + const float degreesPerSecond = 256.0 / 60.0; + const float degreesPerMinute = 256.0 / 60.0; + const float degreesPerHour = 256.0 / 12.0; + + static uint8_t hourAngle = 0; + static uint8_t minuteAngle = 0; + static uint8_t secondAngle = 0; + + EVERY_N_MILLIS(100) { + float second = timeClient.getSeconds(); + float minute = timeClient.getMinutes() + (second / 60.0); + float hour = timeClient.getHours() + (minute / 60.0); + + hourAngle = 256u - hour * degreesPerHour; + minuteAngle = 256u - minute * degreesPerMinute; + secondAngle = 256u - second * degreesPerSecond; + } + + // although can update angles once every 100ms, have to perform fade & overlay with each cycle + fadeToBlackBy(leds, NUM_PIXELS, clockBackgroundFade); + antialiasPixelAR(secondAngle, secondHandWidth, 0, secondRadius, CRGB::Blue ); + antialiasPixelAR(minuteAngle, minuteHandWidth, 0, minuteRadius, CRGB::Green); + antialiasPixelAR(hourAngle, hourHandWidth, 0, hourRadius, CRGB::Red ); + leds[0] = CRGB::Red; +} +#endif + +// TODO: `drawSpiralAnalogClock***()` -- config to disable the seconds hand? + +#if IS_FIBONACCI // drawSpiralAnalogClock*() calls drawSpiralLine(), which requires fibonacci +void drawSpiralAnalogClock(uint8_t step_h, uint8_t step_m, uint8_t step_s) { + static uint8_t hourAngle = 0; + static uint8_t minuteAngle = 0; + static uint8_t secondAngle = 0; + + const float degreesPerSecond = 256.0 / 60.0; + const float degreesPerMinute = 256.0 / 60.0; + const float degreesPerHour = 256.0 / 12.0; + + EVERY_N_MILLIS(100) { + float second = timeClient.getSeconds(); + float minute = timeClient.getMinutes() + (second / 60.0); + float hour = timeClient.getHours() + (minute / 60.0); + + hourAngle = 256u - hour * degreesPerHour; + minuteAngle = 256u - minute * degreesPerMinute; + secondAngle = 256u - second * degreesPerSecond; + } + + drawSpiralLine(secondAngle, step_s, CRGB(0, 0, 2)); + drawSpiralLine(minuteAngle, step_m, CRGB(0, 2, 0)); + drawSpiralLine(hourAngle, step_h, CRGB(2, 0, 0)); +} +void drawSpiralAnalogClock(uint8_t step) { + drawSpiralAnalogClock(step, step, step); +} +void drawSpiralAnalogClock13() { + fadeToBlackBy(leds, NUM_PIXELS, clockBackgroundFade); + drawSpiralAnalogClock(13, 13, 13); +} +void drawSpiralAnalogClock21() { + fadeToBlackBy(leds, NUM_PIXELS, clockBackgroundFade); + drawSpiralAnalogClock(21, 21, 21); +} +void drawSpiralAnalogClock34() { + fadeToBlackBy(leds, NUM_PIXELS, clockBackgroundFade); + drawSpiralAnalogClock(34, 34, 34); +} +void drawSpiralAnalogClock55() { + fadeToBlackBy(leds, NUM_PIXELS, clockBackgroundFade); + drawSpiralAnalogClock(55, 55, 55); +} +void drawSpiralAnalogClock89() { + fadeToBlackBy(leds, NUM_PIXELS, clockBackgroundFade); + drawSpiralAnalogClock(89, 89, 89); +} +void drawSpiralAnalogClock21and34() { + fadeToBlackBy(leds, NUM_PIXELS, clockBackgroundFade); + drawSpiralAnalogClock(21, 21, 21); + drawSpiralAnalogClock(34, 34, 34); +} +void drawSpiralAnalogClock13_21_and_34() { + fadeToBlackBy(leds, NUM_PIXELS, clockBackgroundFade); + drawSpiralAnalogClock(34, 21, 13); +} +void drawSpiralAnalogClock34_21_and_13() { + fadeToBlackBy(leds, NUM_PIXELS, clockBackgroundFade); + drawSpiralAnalogClock(13, 21, 34); +} +#endif + +#if HAS_COORDINATE_MAP // radarSweepPalette() uses angles[] +void radarSweepPalette() { + fadeToBlackBy(leds, NUM_PIXELS, 64); + + uint8_t a = beat8(speed); + uint8_t b = beat88(1); + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint8_t angle = angles[i]; + + if(abs(angle - a) < 3) { + leds[i] = ColorFromPalette(palettes[currentPaletteIndex], beat8(speed)); + } + if(abs(angle - b) < 3) { + leds[i] = ColorFromPalette(palettes[currentPaletteIndex], beat8(speed) + 85); + } + } +} +#endif + + +#endif // IS_FIBONACCI || HAS_COORDINATE_MAP diff --git a/esp8266-fastled-webserver/Noise.cpp b/esp8266-fastled-webserver/Noise.cpp new file mode 100644 index 00000000..69d03772 --- /dev/null +++ b/esp8266-fastled-webserver/Noise.cpp @@ -0,0 +1,418 @@ +/* + ESP8266 + FastLED: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) 2015-2020 Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "common.h" + +#if 0 && defined(PRODUCT_1628_RINGS) + // NOTE: these are entirely unused, and thus commented out entirely. + // however, they are retained in case they would be useful in future. + + // Polar coordinate mapping code for FastLED by Adam Haile, Maniacal Labs: + // http://maniacallabs.com/2015/05/04/review-code-adafruit-dotstar-disk/ + // https://gist.github.com/adammhaile/a769f3ff87ff61f22ace + + const uint8_t ringCount { 20 }; // Total Number of Rings. AdaFruit Disk has 10 + const uint8_t lastRing { ringCount - 1 }; // for convenience + + //Map rings on disk to indicies. + //Each represents one of the concentric rings. + //TODO: change to structure with min/max (inclusive), to clarify meaning of indices + const uint16_t rings[ringCount][2] { + // { first pixel of the ring, last pixel of the ring } // INCLUSIVE indices + { 0, 3 }, + { 4, 15 }, + { 16, 36 }, + { 37, 65 }, + { 66, 102 }, + { 103, 147 }, + { 148, 200 }, + { 201, 262 }, + { 263, 332 }, + { 333, 410 }, + { 411, 496 }, + { 497, 590 }, + { 591, 692 }, + { 693, 802 }, + { 803, 920 }, + { 921, 1045 }, + { 1046, 1180 }, + { 1181, 1322 }, + { 1323, 1467 }, + { 1468, 1627 }, + }; +#endif + +// drawNoise() function uses coordsX / coordsY +#if HAS_COORDINATE_MAP + +// TODO: static assert that the values here correspond to the maximum storable value +// used by the typeof(coordsX) and typeof(coordsY). +const uint8_t matrixWidth = 255; +const uint8_t matrixHeight = 255; + +#define MAX_DIMENSION ((matrixWidth > matrixHeight) ? matrixWidth : matrixHeight) + +// The larger (16-bit) version of our coordinates +static uint16_t noisex; +static uint16_t noisey; +static uint16_t noisez; + +// We're using the x/y dimensions to map to the x/y pixels on the matrix. We'll +// use the z-axis for "time". speed determines how fast time moves forward. Try +// 1 for a very slow moving effect, or 60 for something that ends up looking like +// water. +static int noisespeedx = 0; +static int noisespeedy = 1; +static int noisespeedz = 0; + +// Scale determines how far apart the pixels in our noise matrix are. Try +// changing these values around to see how it affects the motion of the display. The +// higher the value of scale, the more "zoomed out" the noise will be. A value +// of 1 will be so zoomed in, you'll mostly see solid colors. +static uint16_t noisescale = 1; // scale is set dynamically once we've started up + +static uint8_t colorLoop = 0; + + + + +static const CRGBPalette16 blackAndWhiteStripedPalette { + CRGB::White, CRGB::Black, CRGB::Black, CRGB::Black, + CRGB::White, CRGB::Black, CRGB::Black, CRGB::Black, + CRGB::White, CRGB::Black, CRGB::Black, CRGB::Black, + CRGB::White, CRGB::Black, CRGB::Black, CRGB::Black +}; + +static const CRGBPalette16 blackAndBlueStripedPalette { + CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue, + CRGB::Blue, CRGB::Blue, CRGB::Black, CRGB::Black, + CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, + CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black +}; + +// There are several different palettes of colors demonstrated here. +// +// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p, +// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p. +// +// Additionally, you can manually define your own color palettes, or you can write +// code that creates color palettes on the fly. +CRGB noiseXYZ(CRGBPalette16 palette, uint8_t hueReduce, int x, int y, int z) +{ + uint8_t data = inoise8(x, y, z); + // The range of the inoise8 function is roughly 16-238. + // These two operations expand those values out to roughly 0..255 + // You can comment them out if you want the raw noise data. + data = qsub8(data, 16); + data = qadd8(data, scale8(data, 39)); + + if (hueReduce > 0 && data >= hueReduce) { + data -= hueReduce; + } + + return ColorFromPalette(palette, data, 255, LINEARBLEND); +} + +void drawNoise(CRGBPalette16 palette, uint8_t hueReduce = 0) +{ + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint8_t x = coordsX[i]; + uint8_t y = coordsY[i]; + + int xoffset = noisescale * x; + int yoffset = noisescale * y; + + leds[i] = noiseXYZ(palette, hueReduce, x + xoffset + noisex, y + yoffset + noisey, noisez); + } + + noisex += noisespeedx; + noisey += noisespeedy; + noisez += noisespeedz; +} + +#if HAS_POLAR_COORDS // change to "HAS_CONCENTRIC_RINGS" ? +// drawPolarNoise() uses angles[] and rings[][] (may move to using radii[]) +void drawPolarNoise(CRGBPalette16 palette, uint8_t hueReduce = 0) +{ + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint8_t x = angles[i]; + uint8_t y = radii[i] / 2u; // divide by 2 to change range of values from [0..255] to [0..127] + + int xoffset = noisescale * x; + int yoffset = noisescale * y; + leds[i] = noiseXYZ(palette, hueReduce, x + xoffset + noisex, y + yoffset + noisey, noisez); + } + noisex += noisespeedx; + noisey += noisespeedy; + noisez += noisespeedz; +} +#endif // HAS_POLAR_COORDS + +#if HAS_POLAR_COORDS // gradientPalettePolarNoise() uses drawPolarNoise() +// TODO: Check if gradientPalettePolarNoise() is equivalent to angleGradientPalette()? +void gradientPalettePolarNoise() { + noisespeedx = 4; + noisespeedy = 0; + noisespeedz = 0; + noisescale = 1; + colorLoop = 0; + drawPolarNoise(gCurrentPalette); +} +#endif +#if HAS_POLAR_COORDS // palettePolarNoise() uses drawPolarNoise() +void palettePolarNoise() { + noisespeedx = 9; + noisespeedy = 0; + noisespeedz = 0; + noisescale = 1; + colorLoop = 0; + drawPolarNoise(palettes[currentPaletteIndex]); +} +#endif + +void rainbowNoise() { + noisespeedx = 0; + noisespeedy = -1; + noisespeedz = 0; + noisescale = 6; + colorLoop = 0; + drawNoise(RainbowColors_p); +} + +#if HAS_POLAR_COORDS // rainbowPolarNoise() uses drawPolarNoise() +void rainbowPolarNoise() { + noisespeedx = 0; + noisespeedy = 2; + noisespeedz = 0; + noisescale = 0; + colorLoop = 0; + drawPolarNoise(RainbowColors_p); +} +#endif // HAS_POLAR_COORDS + +void rainbowStripeNoise() { + noisespeedx = 0; + noisespeedy = -2; + noisespeedz = 0; + noisescale = 6; + colorLoop = 0; + drawNoise(RainbowStripeColors_p); +} + +#if HAS_POLAR_COORDS // rainbowStripePolarNoise() uses drawPolarNoise() +void rainbowStripePolarNoise() { + noisespeedx = 0; + noisespeedy = 2; + noisespeedz = 0; + noisescale = 0; + colorLoop = 0; + drawPolarNoise(RainbowStripeColors_p); +} +#endif + +void partyNoise() { + noisespeedx = -9; + noisespeedy = 0; + noisespeedz = 0; + noisescale = 8; + colorLoop = 0; + drawNoise(PartyColors_p); +} + +#if HAS_POLAR_COORDS // partyPolarNoise() uses drawPolarNoise() +void partyPolarNoise() { + noisespeedx = 9; + noisespeedy = 0; + noisespeedz = 0; + noisescale = 1; + colorLoop = 0; + drawPolarNoise(PartyColors_p); +} +#endif + +void forestNoise() { + noisespeedx = -9; + noisespeedy = 0; + noisespeedz = 0; + noisescale = 8; + colorLoop = 0; + drawNoise(ForestColors_p); +} + +#if HAS_POLAR_COORDS // forestPolarNoise() uses drawPolarNoise() +void forestPolarNoise() { + noisespeedx = 9; + noisespeedy = 0; + noisespeedz = 0; + noisescale = 1; + colorLoop = 0; + drawPolarNoise(ForestColors_p); +} +#endif + +void cloudNoise() { + noisespeedx = -2; + noisespeedy = 0; + noisespeedz = 0; + noisescale = 6; + colorLoop = 0; + drawNoise(CloudColors_p); +} + +#if HAS_POLAR_COORDS // cloudPolarNoise() uses drawPolarNoise() +void cloudPolarNoise() { + noisespeedx = 2; + noisespeedy = 0; + noisespeedz = 0; + noisescale = 0; + colorLoop = 0; + drawPolarNoise(CloudColors_p); +} +#endif + +void fireNoise() { + noisespeedx = 0; // 24; + noisespeedy = -32; + noisespeedz = 0; + noisescale = 16; + colorLoop = 0; + drawNoise(HeatColors_p, 60); +} + +#if HAS_POLAR_COORDS // firePolarNoise() uses drawPolarNoise() +void firePolarNoise() { +// noisespeedx = 0; // 24; +// noisespeedy = -24; +// noisespeedz = 0; +// noisescale = 4; +// colorLoop = 0; + noisespeedx = 0; // 24; + noisespeedy = -32; + noisespeedz = 0; + noisescale = 4; + colorLoop = 0; + drawPolarNoise(HeatColors_p, 60); +} +#endif + +void fireNoise2() { + noisespeedx = 0; + noisespeedy = -8; + noisespeedz = 3; + noisescale = 8; + colorLoop = 0; + drawNoise(HeatColors_p); +} + +#if HAS_POLAR_COORDS // firePolarNoise2() uses drawPolarNoise() +void firePolarNoise2() { +// noisespeedx = 0; +// noisespeedy = -8; +// noisespeedz = 4; +// noisescale = 1; +// colorLoop = 0; + noisespeedx = 0; + noisespeedy = -4; + noisespeedz = 4; + noisescale = 1; + colorLoop = 0; + drawPolarNoise(HeatColors_p); +} +#endif + +void lavaNoise() { + noisespeedx = 0; + noisespeedy = -1; + noisespeedz = 1; + noisescale = 6; + colorLoop = 0; + drawNoise(LavaColors_p); +} + +#if HAS_POLAR_COORDS // lavaPolarNoise() uses drawPolarNoise() +void lavaPolarNoise() { + noisespeedx = 0; + noisespeedy = -1; + noisespeedz = 1; + noisescale = 1; + colorLoop = 0; + drawPolarNoise(LavaColors_p); +} +#endif + +void oceanNoise() { + noisespeedx = -2; + noisespeedy = 0; + noisespeedz = 4; + noisescale = 6; + colorLoop = 0; + drawNoise(OceanColors_p); +} + +#if HAS_POLAR_COORDS // oceanPolarNoise() uses drawPolarNoise() +void oceanPolarNoise() { + noisespeedx = -1; // beatsin8(6, 0, 2) - 1; + noisespeedy = 0; + noisespeedz = 1; + noisescale = 0; + colorLoop = 0; + drawPolarNoise(OceanColors_p); +} +#endif + +void blackAndWhiteNoise() { + noisespeedx = -12; + noisespeedy = 0; + noisespeedz = 0; + noisescale = 6; + colorLoop = 0; + drawNoise(blackAndWhiteStripedPalette); +} + +#if HAS_POLAR_COORDS // blackAndWhitePolarNoise() uses drawPolarNoise() +void blackAndWhitePolarNoise() { + noisespeedx = -4; // beatsin8(8, 0, 9) - 4; + noisespeedy = 0; + noisespeedz = 0; + noisescale = 0; + colorLoop = 0; + drawPolarNoise(blackAndWhiteStripedPalette); +} +#endif + +void blackAndBlueNoise() { + noisespeedx = 0; + noisespeedy = 8; + noisespeedz = 0; + noisescale = 8; + colorLoop = 0; + drawNoise(blackAndBlueStripedPalette); +} + +#if HAS_POLAR_COORDS // blackAndBluePolarNoise() uses drawPolarNoise() +void blackAndBluePolarNoise() { + noisespeedx = 0; + noisespeedy = -8; // beatsin8(8, 0, 16) - 8; + noisespeedz = 0; + noisescale = 1; + colorLoop = 0; + drawPolarNoise(blackAndBlueStripedPalette); +} +#endif + +#endif // HAS_COORDINATE_MAP \ No newline at end of file diff --git a/esp8266-fastled-webserver/Pacifica.cpp b/esp8266-fastled-webserver/Pacifica.cpp new file mode 100644 index 00000000..1356950a --- /dev/null +++ b/esp8266-fastled-webserver/Pacifica.cpp @@ -0,0 +1,159 @@ +#include "common.h" +// +// "Pacifica" +// Gentle, blue-green ocean waves. +// December 2019, Mark Kriegsman and Mary Corey March. +// For Dan. +// +// https://gist.github.com/kriegsman/36a1e277f5b4084258d9af1eae29bac4 +// + +////////////////////////////////////////////////////////////////////////// +// +// The code for this animation is more complicated than other examples, and +// while it is "ready to run", and documented in general, it is probably not +// the best starting point for learning. Nevertheless, it does illustrate some +// useful techniques. +// +////////////////////////////////////////////////////////////////////////// +// +// In this animation, there are four "layers" of waves of light. +// +// Each layer moves independently, and each is scaled separately. +// +// All four wave layers are added together on top of each other, and then +// another filter is applied that adds "whitecaps" of brightness where the +// waves line up with each other more. Finally, another pass is taken +// over the led array to 'deepen' (dim) the blues and greens. +// +// The speed and scale and motion each layer varies slowly within independent +// hand-chosen ranges, which is why the code has a lot of low-speed 'beatsin8' functions +// with a lot of oddly specific numeric ranges. +// +// These three custom blue-green color palettes were inspired by the colors found in +// the waters off the southern coast of California, https://goo.gl/maps/QQgd97jjHesHZVxQ7 +// +CRGBPalette16 pacifica_palette_1 = + { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, + 0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50 }; +CRGBPalette16 pacifica_palette_2 = + { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, + 0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F }; +CRGBPalette16 pacifica_palette_3 = + { 0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33, + 0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF }; + +// Add one layer of waves into the led array +void pacifica_one_layer( CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff, bool useFibonacciOrder) +{ + uint16_t ci = cistart; + uint16_t waveangle = ioff; + uint16_t wavescale_half = (wavescale / 2) + 20; + for( uint16_t i = 0; i < NUM_PIXELS; i++) { + waveangle += 250; + uint16_t s16 = sin16( waveangle ) + 32768; + uint16_t cs = scale16( s16 , wavescale_half ) + wavescale_half; + ci += cs; + uint16_t sindex16 = sin16( ci) + 32768; + uint8_t sindex8 = scale16( sindex16, 240); + CRGB c = ColorFromPalette( p, sindex8, bri, LINEARBLEND); +#if IS_FIBONACCI + uint16_t idx = useFibonacciOrder ? physicalToFibonacci[i] : i; +#else + (void)useFibonacciOrder; // unused parameter + uint16_t idx = i; +#endif + leds[idx] += c; + } +} + +// Add extra 'white' to areas where the four layers of light have lined up brightly +void pacifica_add_whitecaps(bool useFibonacciOrder) +{ + uint8_t basethreshold = beatsin8( 9, 55, 65); + uint8_t wave = beat8( 7 ); + + for( uint16_t i = 0; i < NUM_PIXELS; i++) { +#if IS_FIBONACCI + uint16_t idx = useFibonacciOrder ? physicalToFibonacci[i] : i; +#else + (void)useFibonacciOrder; // unused parameter + uint16_t idx = i; +#endif + + uint8_t threshold = scale8( sin8( wave), 20) + basethreshold; + wave += 7; + uint8_t l = leds[idx].getAverageLight(); + if( l > threshold) { + uint8_t overage = l - threshold; + uint8_t overage2 = qadd8( overage, overage); + leds[idx] += CRGB( overage, overage2, qadd8( overage2, overage2)); + } + } +} + +// Deepen the blues and greens +void pacifica_deepen_colors(bool useFibonacciOrder) +{ + for( uint16_t i = 0; i < NUM_PIXELS; i++) { +#if IS_FIBONACCI + uint16_t idx = useFibonacciOrder ? physicalToFibonacci[i] : i; +#else + (void)useFibonacciOrder; // unused parameter + uint16_t idx = i; +#endif + + leds[idx].blue = scale8( leds[idx].blue, 145); + leds[idx].green= scale8( leds[idx].green, 200); + leds[idx] |= CRGB( 2, 5, 7); + } +} + +void pacifica_loop_impl(bool useFibonacciOrder) +{ + // Increment the four "color index start" counters, one for each wave layer. + // Each is incremented at a different speed, and the speeds vary over time. + static uint16_t sCIStart1, sCIStart2, sCIStart3, sCIStart4; + static uint32_t sLastms = 0; + uint32_t ms = GET_MILLIS(); + uint32_t deltams = ms - sLastms; + sLastms = ms; + uint16_t speedfactor1 = beatsin16(3, 179, 269); + uint16_t speedfactor2 = beatsin16(4, 179, 269); + uint32_t deltams1 = (deltams * speedfactor1) / 256; + uint32_t deltams2 = (deltams * speedfactor2) / 256; + uint32_t deltams21 = (deltams1 + deltams2) / 2; + sCIStart1 += (deltams1 * beatsin88(1011,10,13)); + sCIStart2 -= (deltams21 * beatsin88(777,8,11)); + sCIStart3 -= (deltams1 * beatsin88(501,5,7)); + sCIStart4 -= (deltams2 * beatsin88(257,4,6)); + + // Clear out the LED array to a dim background blue-green + fill_solid( leds, NUM_PIXELS, CRGB( 2, 6, 10)); + + // Render each of four layers, with different scales and speeds, that vary over time + pacifica_one_layer( pacifica_palette_1, sCIStart1, beatsin16( 3, 11 * 256, 14 * 256), beatsin8( 10, 70, 130), 0-beat16( 301), useFibonacciOrder ); + pacifica_one_layer( pacifica_palette_2, sCIStart2, beatsin16( 4, 6 * 256, 9 * 256), beatsin8( 17, 40, 80), beat16( 401), useFibonacciOrder ); + pacifica_one_layer( pacifica_palette_3, sCIStart3, 6 * 256, beatsin8( 9, 10, 38), 0-beat16(503), useFibonacciOrder ); + pacifica_one_layer( pacifica_palette_3, sCIStart4, 5 * 256, beatsin8( 8, 10, 28), beat16(601), useFibonacciOrder ); + + // Add brighter 'whitecaps' where the waves lines up more + pacifica_add_whitecaps(useFibonacciOrder); + + // Deepen the blues and greens a bit + pacifica_deepen_colors(useFibonacciOrder); +} + +// TODO: Export only these two functions via header file +void pacifica_loop() +{ + return pacifica_loop_impl(false); +} + +#if IS_FIBONACCI +void pacifica_fibonacci_loop() +{ + return pacifica_loop_impl(true); +} +#endif + diff --git a/esp8266-fastled-webserver/Ping.h b/esp8266-fastled-webserver/Ping.cpp similarity index 99% rename from esp8266-fastled-webserver/Ping.h rename to esp8266-fastled-webserver/Ping.cpp index 83fd2ef3..d1adce34 100644 --- a/esp8266-fastled-webserver/Ping.h +++ b/esp8266-fastled-webserver/Ping.cpp @@ -31,6 +31,7 @@ // this data to any 3rd parties, ever. // This was a feature I needed for my own devices, of which there are dozens. :) +#include "common.h" const bool discovery = false; const String serverName = "https://ping.evilgeniuslabs.org"; // address of server to ping diff --git a/esp8266-fastled-webserver/PridePlayground.h b/esp8266-fastled-webserver/PridePlayground.cpp similarity index 82% rename from esp8266-fastled-webserver/PridePlayground.h rename to esp8266-fastled-webserver/PridePlayground.cpp index 609cf665..2831bf76 100644 --- a/esp8266-fastled-webserver/PridePlayground.h +++ b/esp8266-fastled-webserver/PridePlayground.cpp @@ -1,3 +1,5 @@ +#include "common.h" + // Pride2015 by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5 // This function draws rainbows with an ever-changing, // widely-varying set of parameters. @@ -28,7 +30,7 @@ uint8_t sHueBpm = 2; uint8_t sHueMin = 5; uint8_t sHueMax = 9; -void pridePlayground() +void fillWithPridePlayground(bool useFibonacciOrder) { static uint16_t sPseudotime = 0; static uint16_t sLastMillis = 0; @@ -51,7 +53,7 @@ void pridePlayground() sHue16 += deltams * beatsin88(sHueBpm * 256, sHueMin, sHueMax); uint16_t brightnesstheta16 = sPseudotime; - for (uint16_t i = 0; i < NUM_LEDS; i++) + for (uint16_t i = 0; i < NUM_PIXELS; i++) { hue16 += hueinc16; uint8_t hue8 = hue16 / 256; @@ -66,9 +68,24 @@ void pridePlayground() CRGB newcolor = CHSV(hue8, sat8, bri8); uint16_t pixelnumber = i; +#if IS_FIBONACCI + if (useFibonacciOrder) pixelnumber = fibonacciToPhysical[i]; +#else + (void)useFibonacciOrder; +#endif - pixelnumber = (NUM_LEDS - 1) - pixelnumber; + pixelnumber = (NUM_PIXELS - 1) - pixelnumber; nblend(leds[pixelnumber], newcolor, 64); } } + +void pridePlayground() { + fillWithPridePlayground(false); +} + +#if IS_FIBONACCI +void pridePlaygroundFibonacci() { + fillWithPridePlayground(true); +} +#endif diff --git a/esp8266-fastled-webserver/TwinkleFOX.h b/esp8266-fastled-webserver/TwinkleFOX.cpp similarity index 95% rename from esp8266-fastled-webserver/TwinkleFOX.h rename to esp8266-fastled-webserver/TwinkleFOX.cpp index f920910c..7a486d2a 100644 --- a/esp8266-fastled-webserver/TwinkleFOX.h +++ b/esp8266-fastled-webserver/TwinkleFOX.cpp @@ -59,6 +59,7 @@ // smoothly at over 50 updates per seond. // // -Mark Kriegsman, December 2015 +#include "common.h" // Overall twinkle speed. // 0 (VERY slow) to 8 (VERY fast). @@ -194,7 +195,7 @@ void drawTwinkles() uint8_t backgroundBrightness = bg.getAverageLight(); - for(uint16_t i = 0; i < NUM_LEDS; i++) { + for(uint16_t i = 0; i < NUM_PIXELS; i++) { CRGB& pixel = leds[i]; PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number @@ -230,7 +231,7 @@ void drawTwinkles() // A mostly red palette with green accents and white trim. // "CRGB::Gray" is used as white to keep the brightness more uniform. -const TProgmemRGBPalette16 RedGreenWhite_p FL_PROGMEM = +FL_ALIGN_PROGMEM const TProgmemRGBPalette16 RedGreenWhite_p FL_PROGMEM = { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray, @@ -239,7 +240,7 @@ const TProgmemRGBPalette16 RedGreenWhite_p FL_PROGMEM = // A mostly (dark) green palette with red berries. #define Holly_Green 0x00580c #define Holly_Red 0xB00402 -const TProgmemRGBPalette16 Holly_p FL_PROGMEM = +FL_ALIGN_PROGMEM const TProgmemRGBPalette16 Holly_p FL_PROGMEM = { Holly_Green, Holly_Green, Holly_Green, Holly_Green, Holly_Green, Holly_Green, Holly_Green, Holly_Green, Holly_Green, Holly_Green, Holly_Green, Holly_Green, @@ -248,7 +249,7 @@ const TProgmemRGBPalette16 Holly_p FL_PROGMEM = // A red and white striped palette // "CRGB::Gray" is used as white to keep the brightness more uniform. -const TProgmemRGBPalette16 RedWhite_p FL_PROGMEM = +FL_ALIGN_PROGMEM const TProgmemRGBPalette16 RedWhite_p FL_PROGMEM = { CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray, CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray, CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray, @@ -256,7 +257,7 @@ const TProgmemRGBPalette16 RedWhite_p FL_PROGMEM = // A mostly blue palette with white accents. // "CRGB::Gray" is used as white to keep the brightness more uniform. -const TProgmemRGBPalette16 BlueWhite_p FL_PROGMEM = +FL_ALIGN_PROGMEM const TProgmemRGBPalette16 BlueWhite_p FL_PROGMEM = { CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue, @@ -265,14 +266,14 @@ const TProgmemRGBPalette16 BlueWhite_p FL_PROGMEM = // A pure "fairy light" palette with some brightness variations #define HALFFAIRY ((CRGB::FairyLight & 0xFEFEFE) / 2) #define QUARTERFAIRY ((CRGB::FairyLight & 0xFCFCFC) / 4) -const TProgmemRGBPalette16 FairyLight_p FL_PROGMEM = +FL_ALIGN_PROGMEM const TProgmemRGBPalette16 FairyLight_p FL_PROGMEM = { CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, HALFFAIRY, HALFFAIRY, CRGB::FairyLight, CRGB::FairyLight, QUARTERFAIRY, QUARTERFAIRY, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight }; // A palette of soft snowflakes with the occasional bright one -const TProgmemRGBPalette16 Snow_p FL_PROGMEM = +FL_ALIGN_PROGMEM const TProgmemRGBPalette16 Snow_p FL_PROGMEM = { 0x304048, 0x304048, 0x304048, 0x304048, 0x304048, 0x304048, 0x304048, 0x304048, 0x304048, 0x304048, 0x304048, 0x304048, @@ -285,7 +286,7 @@ const TProgmemRGBPalette16 Snow_p FL_PROGMEM = #define C9_Green 0x046002 #define C9_Blue 0x070758 #define C9_White 0x606820 -const TProgmemRGBPalette16 RetroC9_p FL_PROGMEM = +FL_ALIGN_PROGMEM const TProgmemRGBPalette16 RetroC9_p FL_PROGMEM = { C9_Red, C9_Orange, C9_Red, C9_Orange, C9_Orange, C9_Red, C9_Orange, C9_Red, C9_Green, C9_Green, C9_Green, C9_Green, @@ -297,7 +298,7 @@ const TProgmemRGBPalette16 RetroC9_p FL_PROGMEM = #define Ice_Blue1 0x0C1040 #define Ice_Blue2 0x182080 #define Ice_Blue3 0x5080C0 -const TProgmemRGBPalette16 Ice_p FL_PROGMEM = +FL_ALIGN_PROGMEM const TProgmemRGBPalette16 Ice_p FL_PROGMEM = { Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1, diff --git a/esp8266-fastled-webserver/Twinkles.h b/esp8266-fastled-webserver/Twinkles.cpp similarity index 94% rename from esp8266-fastled-webserver/Twinkles.h rename to esp8266-fastled-webserver/Twinkles.cpp index bcc5d6ae..71cb9f21 100644 --- a/esp8266-fastled-webserver/Twinkles.h +++ b/esp8266-fastled-webserver/Twinkles.cpp @@ -1,5 +1,7 @@ // based on ColorTwinkles by Mark Kriegsman: https://gist.github.com/kriegsman/5408ecd397744ba0393e +#include "common.h" + #define STARTING_BRIGHTNESS 64 #define FADE_IN_SPEED 32 #define FADE_OUT_SPEED 20 @@ -26,7 +28,7 @@ CRGB makeDarker( const CRGB& color, fract8 howMuchDarker) // per pixel. This requires a bunch of bit wrangling, // but conserves precious RAM. The cost is a few // cycles and about 100 bytes of flash program memory. -uint8_t directionFlags[ (NUM_LEDS + 7) / 8]; +uint8_t directionFlags[ (NUM_PIXELS + 7) / 8]; bool getPixelDirection( uint16_t i) { @@ -53,7 +55,7 @@ void setPixelDirection( uint16_t i, bool dir) void brightenOrDarkenEachPixel( fract8 fadeUpAmount, fract8 fadeDownAmount) { - for ( uint16_t i = 0; i < NUM_LEDS; i++) { + for ( uint16_t i = 0; i < NUM_PIXELS; i++) { if ( getPixelDirection(i) == GETTING_DARKER) { // This pixel is getting darker leds[i] = makeDarker( leds[i], fadeDownAmount); @@ -79,7 +81,7 @@ void colortwinkles() // Now consider adding a new random twinkle if ( random8() < DENSITY ) { - int pos = random16(NUM_LEDS); + int pos = random16(NUM_PIXELS); if ( !leds[pos]) { leds[pos] = ColorFromPalette( gCurrentPalette, random8(), STARTING_BRIGHTNESS, NOBLEND); setPixelDirection(pos, GETTING_BRIGHTER); diff --git a/esp8266-fastled-webserver/Commands.h b/esp8266-fastled-webserver/commands.cpp similarity index 52% rename from esp8266-fastled-webserver/Commands.h rename to esp8266-fastled-webserver/commands.cpp index bbb7a0f4..ea054190 100644 --- a/esp8266-fastled-webserver/Commands.h +++ b/esp8266-fastled-webserver/commands.cpp @@ -16,6 +16,12 @@ * along with this program. If not, see . */ +#include "common.h" + +#if defined(ENABLE_IR) + +IRrecv irReceiver(RECV_PIN); + enum class InputCommand { None, Up, @@ -75,98 +81,101 @@ enum class InputCommand { LightBlue, }; -// IR Raw Key Codes for SparkFun remote -#define IRCODE_SPARKFUN_POWER 0x10EFD827 // 284153895 -#define IRCODE_SPARKFUN_A 0x10EFF807 // -#define IRCODE_SPARKFUN_B 0x10EF7887 -#define IRCODE_SPARKFUN_C 0x10EF58A7 -#define IRCODE_SPARKFUN_UP 0x10EFA05F // 284139615 -#define IRCODE_SPARKFUN_LEFT 0x10EF10EF -#define IRCODE_SPARKFUN_SELECT 0x10EF20DF -#define IRCODE_SPARKFUN_RIGHT 0x10EF807F -#define IRCODE_SPARKFUN_DOWN 0x10EF00FF -#define IRCODE_SPARKFUN_HELD 0xFFFFFFFF - -// IR Raw Key Codes for Adafruit remote -#define IRCODE_ADAFRUIT_HELD 0x7FFFFFFF // 4294967295 -#define IRCODE_ADAFRUIT_VOLUME_UP 0x00FD40BF // 16597183 -#define IRCODE_ADAFRUIT_PLAY_PAUSE 0x00FD807F // 16613503 -#define IRCODE_ADAFRUIT_VOLUME_DOWN 0x00FD00FF // 16580863 -#define IRCODE_ADAFRUIT_SETUP 0x00FD20DF // 16589023 -#define IRCODE_ADAFRUIT_UP 0x00FDA05F // 16621663 -#define IRCODE_ADAFRUIT_STOP_MODE 0x00FD609F // 16605343 -#define IRCODE_ADAFRUIT_LEFT 0x00FD10EF // 16584943 -#define IRCODE_ADAFRUIT_ENTER_SAVE 0x00FD906F // 16617583 -#define IRCODE_ADAFRUIT_RIGHT 0x00FD50AF // 16601263 -#define IRCODE_ADAFRUIT_0_10_PLUS 0x00FD30CF // 16593103 -#define IRCODE_ADAFRUIT_DOWN 0x00FDB04F // 16625743 -#define IRCODE_ADAFRUIT_BACK 0x00FD708F // 16609423 -#define IRCODE_ADAFRUIT_1 0x00FD08F7 // 16582903 -#define IRCODE_ADAFRUIT_2 0x00FD8877 // 16615543 -#define IRCODE_ADAFRUIT_3 0x00FD48B7 // 16599223 -#define IRCODE_ADAFRUIT_4 0x00FD28D7 // 16591063 -#define IRCODE_ADAFRUIT_5 0x00FDA857 // 16623703 -#define IRCODE_ADAFRUIT_6 0x00FD6897 // 16607383 -#define IRCODE_ADAFRUIT_7 0x00FD18E7 // 16586983 -#define IRCODE_ADAFRUIT_8 0x00FD9867 // 16619623 -#define IRCODE_ADAFRUIT_9 0x00FD58A7 // 16603303 - -// IR Raw Key Codes for eTopxizu 44Key IR Remote Controller for 5050 3528 RGB LED Light Strip -#define IRCODE_ETOPXIZU_HELD 0x7FFFFFFF // 4294967295 -#define IRCODE_ETOPXIZU_POWER 16712445 -#define IRCODE_ETOPXIZU_PLAY_PAUSE 16745085 -#define IRCODE_ETOPXIZU_BRIGHTNESS_UP 16726725 -#define IRCODE_ETOPXIZU_BRIGHTNESS_DOWN 16759365 - -#define IRCODE_ETOPXIZU_DIY1 16724175 -#define IRCODE_ETOPXIZU_DIY2 16756815 -#define IRCODE_ETOPXIZU_DIY3 16740495 -#define IRCODE_ETOPXIZU_DIY4 16716015 -#define IRCODE_ETOPXIZU_DIY5 16748655 -#define IRCODE_ETOPXIZU_DIY6 16732335 - -#define IRCODE_ETOPXIZU_JUMP3 16720095 -#define IRCODE_ETOPXIZU_JUMP7 16752735 -#define IRCODE_ETOPXIZU_FADE3 16736415 -#define IRCODE_ETOPXIZU_FADE7 16769055 -#define IRCODE_ETOPXIZU_FLASH 16764975 -#define IRCODE_ETOPXIZU_AUTO 16773135 - -#define IRCODE_ETOPXIZU_QUICK 16771095 -#define IRCODE_ETOPXIZU_SLOW 16762935 - -#define IRCODE_ETOPXIZU_RED_UP 16722135 -#define IRCODE_ETOPXIZU_RED_DOWN 16713975 - -#define IRCODE_ETOPXIZU_GREEN_UP 16754775 -#define IRCODE_ETOPXIZU_GREEN_DOWN 16746615 - -#define IRCODE_ETOPXIZU_BLUE_UP 16738455 -#define IRCODE_ETOPXIZU_BLUE_DOWN 16730295 - -#define IRCODE_ETOPXIZU_RED 16718565 -#define IRCODE_ETOPXIZU_RED_ORANGE 16722645 -#define IRCODE_ETOPXIZU_ORANGE 16714485 -#define IRCODE_ETOPXIZU_YELLOW_ORANGE 16726215 -#define IRCODE_ETOPXIZU_YELLOW 16718055 - -#define IRCODE_ETOPXIZU_GREEN 16751205 -#define IRCODE_ETOPXIZU_LIME 16755285 -#define IRCODE_ETOPXIZU_AQUA 16747125 -#define IRCODE_ETOPXIZU_TEAL 16758855 -#define IRCODE_ETOPXIZU_NAVY 16750695 - -#define IRCODE_ETOPXIZU_BLUE 16753245 -#define IRCODE_ETOPXIZU_ROYAL_BLUE 16749165 -#define IRCODE_ETOPXIZU_PURPLE 16757325 -#define IRCODE_ETOPXIZU_INDIGO 16742535 -#define IRCODE_ETOPXIZU_MAGENTA 16734375 - -#define IRCODE_ETOPXIZU_WHITE 16720605 -#define IRCODE_ETOPXIZU_PINK 16716525 -#define IRCODE_ETOPXIZU_LIGHT_PINK 16724685 -#define IRCODE_ETOPXIZU_BABY_BLUE 16775175 -#define IRCODE_ETOPXIZU_LIGHT_BLUE 16767015 +#if 1 // collapse IR codes + // IR Raw Key Codes for SparkFun remote + #define IRCODE_SPARKFUN_POWER 0x10EFD827 // 284153895 + #define IRCODE_SPARKFUN_A 0x10EFF807 // + #define IRCODE_SPARKFUN_B 0x10EF7887 + #define IRCODE_SPARKFUN_C 0x10EF58A7 + #define IRCODE_SPARKFUN_UP 0x10EFA05F // 284139615 + #define IRCODE_SPARKFUN_LEFT 0x10EF10EF + #define IRCODE_SPARKFUN_SELECT 0x10EF20DF + #define IRCODE_SPARKFUN_RIGHT 0x10EF807F + #define IRCODE_SPARKFUN_DOWN 0x10EF00FF + #define IRCODE_SPARKFUN_HELD 0xFFFFFFFF + + // IR Raw Key Codes for Adafruit remote + #define IRCODE_ADAFRUIT_HELD 0x7FFFFFFF // 4294967295 + #define IRCODE_ADAFRUIT_VOLUME_UP 0x00FD40BF // 16597183 + #define IRCODE_ADAFRUIT_PLAY_PAUSE 0x00FD807F // 16613503 + #define IRCODE_ADAFRUIT_VOLUME_DOWN 0x00FD00FF // 16580863 + #define IRCODE_ADAFRUIT_SETUP 0x00FD20DF // 16589023 + #define IRCODE_ADAFRUIT_UP 0x00FDA05F // 16621663 + #define IRCODE_ADAFRUIT_STOP_MODE 0x00FD609F // 16605343 + #define IRCODE_ADAFRUIT_LEFT 0x00FD10EF // 16584943 + #define IRCODE_ADAFRUIT_ENTER_SAVE 0x00FD906F // 16617583 + #define IRCODE_ADAFRUIT_RIGHT 0x00FD50AF // 16601263 + #define IRCODE_ADAFRUIT_0_10_PLUS 0x00FD30CF // 16593103 + #define IRCODE_ADAFRUIT_DOWN 0x00FDB04F // 16625743 + #define IRCODE_ADAFRUIT_BACK 0x00FD708F // 16609423 + #define IRCODE_ADAFRUIT_1 0x00FD08F7 // 16582903 + #define IRCODE_ADAFRUIT_2 0x00FD8877 // 16615543 + #define IRCODE_ADAFRUIT_3 0x00FD48B7 // 16599223 + #define IRCODE_ADAFRUIT_4 0x00FD28D7 // 16591063 + #define IRCODE_ADAFRUIT_5 0x00FDA857 // 16623703 + #define IRCODE_ADAFRUIT_6 0x00FD6897 // 16607383 + #define IRCODE_ADAFRUIT_7 0x00FD18E7 // 16586983 + #define IRCODE_ADAFRUIT_8 0x00FD9867 // 16619623 + #define IRCODE_ADAFRUIT_9 0x00FD58A7 // 16603303 + + // IR Raw Key Codes for eTopxizu 44Key IR Remote Controller for 5050 3528 RGB LED Light Strip + #define IRCODE_ETOPXIZU_HELD 0x7FFFFFFF // 4294967295 + #define IRCODE_ETOPXIZU_POWER 16712445 + #define IRCODE_ETOPXIZU_PLAY_PAUSE 16745085 + #define IRCODE_ETOPXIZU_BRIGHTNESS_UP 16726725 + #define IRCODE_ETOPXIZU_BRIGHTNESS_DOWN 16759365 + + #define IRCODE_ETOPXIZU_DIY1 16724175 + #define IRCODE_ETOPXIZU_DIY2 16756815 + #define IRCODE_ETOPXIZU_DIY3 16740495 + #define IRCODE_ETOPXIZU_DIY4 16716015 + #define IRCODE_ETOPXIZU_DIY5 16748655 + #define IRCODE_ETOPXIZU_DIY6 16732335 + + #define IRCODE_ETOPXIZU_JUMP3 16720095 + #define IRCODE_ETOPXIZU_JUMP7 16752735 + #define IRCODE_ETOPXIZU_FADE3 16736415 + #define IRCODE_ETOPXIZU_FADE7 16769055 + #define IRCODE_ETOPXIZU_FLASH 16764975 + #define IRCODE_ETOPXIZU_AUTO 16773135 + + #define IRCODE_ETOPXIZU_QUICK 16771095 + #define IRCODE_ETOPXIZU_SLOW 16762935 + + #define IRCODE_ETOPXIZU_RED_UP 16722135 + #define IRCODE_ETOPXIZU_RED_DOWN 16713975 + + #define IRCODE_ETOPXIZU_GREEN_UP 16754775 + #define IRCODE_ETOPXIZU_GREEN_DOWN 16746615 + + #define IRCODE_ETOPXIZU_BLUE_UP 16738455 + #define IRCODE_ETOPXIZU_BLUE_DOWN 16730295 + + #define IRCODE_ETOPXIZU_RED 16718565 + #define IRCODE_ETOPXIZU_RED_ORANGE 16722645 + #define IRCODE_ETOPXIZU_ORANGE 16714485 + #define IRCODE_ETOPXIZU_YELLOW_ORANGE 16726215 + #define IRCODE_ETOPXIZU_YELLOW 16718055 + + #define IRCODE_ETOPXIZU_GREEN 16751205 + #define IRCODE_ETOPXIZU_LIME 16755285 + #define IRCODE_ETOPXIZU_AQUA 16747125 + #define IRCODE_ETOPXIZU_TEAL 16758855 + #define IRCODE_ETOPXIZU_NAVY 16750695 + + #define IRCODE_ETOPXIZU_BLUE 16753245 + #define IRCODE_ETOPXIZU_ROYAL_BLUE 16749165 + #define IRCODE_ETOPXIZU_PURPLE 16757325 + #define IRCODE_ETOPXIZU_INDIGO 16742535 + #define IRCODE_ETOPXIZU_MAGENTA 16734375 + + #define IRCODE_ETOPXIZU_WHITE 16720605 + #define IRCODE_ETOPXIZU_PINK 16716525 + #define IRCODE_ETOPXIZU_LIGHT_PINK 16724685 + #define IRCODE_ETOPXIZU_BABY_BLUE 16775175 + #define IRCODE_ETOPXIZU_LIGHT_BLUE 16767015 +#endif + bool sparkfunRemoteEnabled = true; bool adafruitRemoteEnabled = true; @@ -216,7 +225,7 @@ unsigned long readIRCode() { unsigned long lastIrCode = 0; unsigned int holdStartTime = 0; -unsigned int defaultHoldDelay = 500; +// unsigned int defaultHoldDelay = 500; bool isHolding = false; unsigned int zeroStartTime = 0; @@ -287,22 +296,6 @@ unsigned long readIRCode(unsigned int holdDelay) { return 0; } -void heldButtonHasBeenHandled() { - lastIrCode = 0; - isHolding = false; - holdStartTime = 0; -} - -unsigned long waitForIRCode() { - - unsigned long irCode = readIRCode(); - while ((irCode == 0) || (irCode == 0xFFFFFFFF)) { - delay(200); - irCode = readIRCode(); - } - return irCode; -} - InputCommand getCommand(unsigned long input) { if (adafruitRemoteEnabled) { switch (input) { @@ -482,3 +475,212 @@ InputCommand readCommand() { InputCommand readCommand(unsigned int holdDelay) { return getCommand(readIRCode(holdDelay)); } + +void handleIrInput() +{ + InputCommand command = readCommand(); + + if (command != InputCommand::None) { + Serial.print("command: "); + Serial.println((int) command); + } + + switch (command) { + case InputCommand::Up: { + adjustPattern(true); + break; + } + case InputCommand::Down: { + adjustPattern(false); + break; + } + case InputCommand::Power: { + setPower(power == 0 ? 1 : 0); + break; + } + case InputCommand::BrightnessUp: { + adjustBrightness(true); + break; + } + case InputCommand::BrightnessDown: { + adjustBrightness(false); + break; + } + case InputCommand::PlayMode: { // toggle pause/play + setAutoplay(!autoplay); + break; + } + + // pattern buttons + + case InputCommand::Pattern1: { + setPattern(0); + break; + } + case InputCommand::Pattern2: { + setPattern(1); + break; + } + case InputCommand::Pattern3: { + setPattern(2); + break; + } + case InputCommand::Pattern4: { + setPattern(3); + break; + } + case InputCommand::Pattern5: { + setPattern(4); + break; + } + case InputCommand::Pattern6: { + setPattern(5); + break; + } + case InputCommand::Pattern7: { + setPattern(6); + break; + } + case InputCommand::Pattern8: { + setPattern(7); + break; + } + case InputCommand::Pattern9: { + setPattern(8); + break; + } + case InputCommand::Pattern10: { + setPattern(9); + break; + } + case InputCommand::Pattern11: { + setPattern(10); + break; + } + case InputCommand::Pattern12: { + setPattern(11); + break; + } + + // custom color adjustment buttons + + case InputCommand::RedUp: { + solidColor.red += 8; + setSolidColor(solidColor); + break; + } + case InputCommand::RedDown: { + solidColor.red -= 8; + setSolidColor(solidColor); + break; + } + case InputCommand::GreenUp: { + solidColor.green += 8; + setSolidColor(solidColor); + break; + } + case InputCommand::GreenDown: { + solidColor.green -= 8; + setSolidColor(solidColor); + break; + } + case InputCommand::BlueUp: { + solidColor.blue += 8; + setSolidColor(solidColor); + break; + } + case InputCommand::BlueDown: { + solidColor.blue -= 8; + setSolidColor(solidColor); + break; + } + + // color buttons + + case InputCommand::Red: { + setSolidColor(CRGB::Red); + break; + } + case InputCommand::RedOrange: { + setSolidColor(CRGB::OrangeRed); + break; + } + case InputCommand::Orange: { + setSolidColor(CRGB::Orange); + break; + } + case InputCommand::YellowOrange: { + setSolidColor(CRGB::Goldenrod); + break; + } + case InputCommand::Yellow: { + setSolidColor(CRGB::Yellow); + break; + } + + case InputCommand::Green: { + setSolidColor(CRGB::Green); + break; + } + case InputCommand::Lime: { + setSolidColor(CRGB::Lime); + break; + } + case InputCommand::Aqua: { + setSolidColor(CRGB::Aqua); + break; + } + case InputCommand::Teal: { + setSolidColor(CRGB::Teal); + break; + } + case InputCommand::Navy: { + setSolidColor(CRGB::Navy); + break; + } + + case InputCommand::Blue: { + setSolidColor(CRGB::Blue); + break; + } + case InputCommand::RoyalBlue: { + setSolidColor(CRGB::RoyalBlue); + break; + } + case InputCommand::Purple: { + setSolidColor(CRGB::Purple); + break; + } + case InputCommand::Indigo: { + setSolidColor(CRGB::Indigo); + break; + } + case InputCommand::Magenta: { + setSolidColor(CRGB::Magenta); + break; + } + + case InputCommand::White: { + setSolidColor(CRGB::White); + break; + } + case InputCommand::Pink: { + setSolidColor(CRGB::Pink); + break; + } + case InputCommand::LightPink: { + setSolidColor(CRGB::LightPink); + break; + } + case InputCommand::BabyBlue: { + setSolidColor(CRGB::CornflowerBlue); + break; + } + case InputCommand::LightBlue: { + setSolidColor(CRGB::LightBlue); + break; + } + } +} + +#endif diff --git a/esp8266-fastled-webserver/common.h b/esp8266-fastled-webserver/common.h new file mode 100644 index 00000000..0bcf7473 --- /dev/null +++ b/esp8266-fastled-webserver/common.h @@ -0,0 +1,336 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#if !defined(ESP8266_FASTLED_WEBSERVER_COMMON_H) +#define ESP8266_FASTLED_WEBSERVER_COMMON_H + +#include "Arduino.h" + +// config.h must be included before FastLED, as it may define FastLED options +// such as whether to disable interrupts, etc. +// config.h defines pre-processor symbols, but does not itself define functions, structs, etc. +#include "config.h" + +#if 1 // external libraries + #define FASTLED_INTERNAL // no other way to suppress build warnings + #include + FASTLED_USING_NAMESPACE + + extern "C" { + #include "user_interface.h" + } + + #include + #define MYFS LittleFS + + #include + #include + #include + #include + #include + #include + #include + //#include + #include + #include // https://github.com/tzapu/WiFiManager/tree/development + + + #include "./include/simplehacks/static_eval.h" + #include "./include/simplehacks/constexpr_strlen.h" + #include "./include/simplehacks/array_size2.h" +#endif // 1 + +void dimAll(byte value); +// info.cpp +String WiFi_SSID(bool persistent); +String getInfoJson(); + + +// Ugly macro-like constexpr, used for FastLED template arguments +template +constexpr int LedOffset() { + static_assert(ONE_BASED_OUTPUT_CHANNEL <= PARALLEL_OUTPUT_CHANNELS, ""); + static_assert(ONE_BASED_OUTPUT_CHANNEL >= 1, ""); + return 0 // this would be much simpler with C++14 + #if PARALLEL_OUTPUT_CHANNELS >= 2 + + ((ONE_BASED_OUTPUT_CHANNEL >= 2) ? PIXELS_ON_DATA_PIN_1 : 0) + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 3 + + ((ONE_BASED_OUTPUT_CHANNEL >= 3) ? PIXELS_ON_DATA_PIN_2 : 0) + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 4 + + ((ONE_BASED_OUTPUT_CHANNEL >= 4) ? PIXELS_ON_DATA_PIN_3 : 0) + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 5 + + ((ONE_BASED_OUTPUT_CHANNEL >= 5) ? PIXELS_ON_DATA_PIN_4 : 0) + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 6 + + ((ONE_BASED_OUTPUT_CHANNEL >= 6) ? PIXELS_ON_DATA_PIN_5 : 0) + #endif + ; +} +template +constexpr int LedCount() { + static_assert(ONE_BASED_OUTPUT_CHANNEL <= PARALLEL_OUTPUT_CHANNELS, ""); + static_assert(ONE_BASED_OUTPUT_CHANNEL >= 1, ""); + #if PARALLEL_OUTPUT_CHANNELS == 1 + return NUM_PIXELS; + #else + return // this would be much simpler with C++14 + #if PARALLEL_OUTPUT_CHANNELS >= 6 + (ONE_BASED_OUTPUT_CHANNEL == 6) ? PIXELS_ON_DATA_PIN_6 : + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 5 + (ONE_BASED_OUTPUT_CHANNEL == 5) ? PIXELS_ON_DATA_PIN_5 : + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 4 + (ONE_BASED_OUTPUT_CHANNEL == 4) ? PIXELS_ON_DATA_PIN_4 : + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 3 + (ONE_BASED_OUTPUT_CHANNEL == 3) ? PIXELS_ON_DATA_PIN_3 : + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 2 + (ONE_BASED_OUTPUT_CHANNEL == 2) ? PIXELS_ON_DATA_PIN_2 : + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 1 + (ONE_BASED_OUTPUT_CHANNEL == 1) ? PIXELS_ON_DATA_PIN_1 : + #endif + 0; + #endif +} + +void writeAndCommitSettings(); +void broadcastInt(String name, uint8_t value); +void broadcastString(String name, String value); + + +#if defined(ESP32) || defined(ESP8266) + // Optional: (LGPL) https://github.com/sinricpro/ESPTrueRandom.git#ed198f459da6d7af65dd13317a4fdc97b23991b4 + // #include "ESPTrueRandom.h" + // Then: + // ESPTrueRandom.useRNG = true; + // int32_t r = ESPTrueRandom.memfill((void*)&r, sizeof(r)); +#else + #error "Currently only ESP32 and ESP8266 are supported" +#endif + + +// Structures +typedef void (*Pattern)(); +typedef Pattern PatternList[]; +typedef struct { + Pattern pattern; + String name; +} PatternAndName; + +typedef struct { + CRGBPalette16 palette; + String name; +} PaletteAndName; + + +// forward-declarations + +// TODO: cleanup to declare minimum necessary variables +// extern const uint8_t brightnessCount; +extern const uint8_t brightnessMap[]; +extern uint8_t brightnessIndex; +extern uint8_t currentPatternIndex; +extern const uint8_t patternCount; +extern const PatternAndName patterns[]; + +extern uint8_t currentPaletteIndex; +extern uint8_t autoplay; +extern uint8_t autoplayDuration; +extern uint8_t showClock; +extern uint8_t clockBackgroundFade; +extern CRGB solidColor; +extern uint8_t cooling; +extern uint8_t sparking; +extern uint8_t speed; +extern uint8_t twinkleSpeed; +extern uint8_t twinkleDensity; +extern uint8_t coolLikeIncandescent; +extern uint8_t saturationBpm; +extern uint8_t saturationMin; +extern uint8_t saturationMax; +extern uint8_t brightDepthBpm; +extern uint8_t brightDepthMin; +extern uint8_t brightDepthMax; +extern uint8_t brightThetaIncBpm; +extern uint8_t brightThetaIncMin; +extern uint8_t brightThetaIncMax; +extern uint8_t msMultiplierBpm; +extern uint8_t msMultiplierMin; +extern uint8_t msMultiplierMax; +extern uint8_t hueIncBpm; +extern uint8_t hueIncMin; +extern uint8_t hueIncMax; +extern uint8_t sHueBpm; +extern uint8_t sHueMin; +extern uint8_t sHueMax; + + + +extern const TProgmemRGBGradientPalettePtr gGradientPalettes[]; +extern const uint8_t gGradientPaletteCount; +extern const CRGBPalette16 palettes[]; +extern const uint8_t paletteCount; +extern const String paletteNames[]; + +extern CRGBPalette16 gCurrentPalette; +extern CRGBPalette16 gTargetPalette; +extern uint8_t gCurrentPaletteNumber; + +extern WiFiManager wifiManager; +extern ESP8266WebServer webServer; +extern NTPClient timeClient; +extern String nameString; + +extern CRGB leds[NUM_PIXELS]; + +#if IS_FIBONACCI // actual data in map.h + #if NUM_PIXELS > 256 // when more than 256 pixels, cannot store index in uint8_t.... + extern const uint16_t physicalToFibonacci [NUM_PIXELS]; + extern const uint16_t fibonacciToPhysical [NUM_PIXELS]; + #else + extern const uint8_t physicalToFibonacci [NUM_PIXELS]; + extern const uint8_t fibonacciToPhysical [NUM_PIXELS]; + #endif +#elif defined(PRODUCT_KRAKEN64) + extern const uint8_t body [NUM_PIXELS]; +#endif + +#if HAS_COORDINATE_MAP + extern const uint8_t coordsX [NUM_PIXELS]; + extern const uint8_t coordsY [NUM_PIXELS]; + extern const uint8_t angles [NUM_PIXELS]; +#endif + +#if HAS_POLAR_COORDS + extern const uint8_t radii[NUM_PIXELS]; // needed in noise.cpp +#endif + +#include "include/GradientPalettes.hpp" +#include "include/Fields.hpp" +#include "include/FSBrowser.hpp" + +// IR (commands.cpp) +#if defined(ENABLE_IR) + #include + extern IRrecv irReceiver; + void handleIrInput(); +#else + inline void handleIrInput() {} +#endif + +// ping.cpp +void checkPingTimer(); + +// effects +// twinkles.cpp +void cloudTwinkles(); +void rainbowTwinkles(); +void snowTwinkles(); +void incandescentTwinkles(); +// twinkleFox.cpp +void redGreenWhiteTwinkles(); +void hollyTwinkles(); +void redWhiteTwinkles(); +void blueWhiteTwinkles(); +void fairyLightTwinkles(); +void snow2Twinkles(); +void iceTwinkles(); +void retroC9Twinkles(); +void partyTwinkles(); +void forestTwinkles(); +void lavaTwinkles(); +void fireTwinkles(); +void cloud2Twinkles(); +void oceanTwinkles(); +// map.h -- only when product defines HAS_COORDINATE_MAP to be true +#if HAS_COORDINATE_MAP +void anglePalette(); +void xPalette(); +void yPalette(); +void xyPalette(); +void xGradientPalette(); +void yGradientPalette(); +void xyGradientPalette(); +void radarSweepPalette(); +void radiusPalette(); +void angleGradientPalette(); +void radiusGradientPalette(); +#endif +// map.h -- only when product defines IS_FIBONACCI to be true +#if IS_FIBONACCI +void drawAnalogClock(); +void drawSpiralAnalogClock13(); +void drawSpiralAnalogClock21(); +void drawSpiralAnalogClock34(); +void drawSpiralAnalogClock55(); +void drawSpiralAnalogClock89(); +void drawSpiralAnalogClock21and34(); +void drawSpiralAnalogClock13_21_and_34(); +void drawSpiralAnalogClock34_21_and_13(); +void antialiasPixelAR(uint8_t angle, uint8_t dAngle, uint8_t startRadius, uint8_t endRadius, CRGB color, CRGB leds[] = leds, int _NUM_PIXELS = NUM_PIXELS); +#endif + +// noise.h -- always defined +void rainbowNoise(); +void rainbowStripeNoise(); +void partyNoise(); +void forestNoise(); +void cloudNoise(); +void fireNoise(); +void fireNoise2(); +void lavaNoise(); +void oceanNoise(); +void blackAndWhiteNoise(); +void blackAndBlueNoise(); + +// noise.h -- only when product defines HAS_POLAR_COORDS to be true +#if HAS_POLAR_COORDS +void palettePolarNoise(); +void gradientPalettePolarNoise(); +void rainbowPolarNoise(); +void rainbowStripePolarNoise(); +void partyPolarNoise(); +void forestPolarNoise(); +void cloudPolarNoise(); +void firePolarNoise(); +void firePolarNoise2(); +void lavaPolarNoise(); +void oceanPolarNoise(); +void blackAndWhitePolarNoise(); +void blackAndBluePolarNoise(); +#endif + +// pacifica.h / prideplayground.h / colorwavesplayground.h +void pacifica_loop(); +void pridePlayground(); +void colorWavesPlayground(); +#if IS_FIBONACCI +void pacifica_fibonacci_loop(); +void pridePlaygroundFibonacci(); +void colorWavesPlaygroundFibonacci(); +#endif + + + +#endif // ESP8266_FASTLED_WEBSERVER_COMMON_H diff --git a/esp8266-fastled-webserver/config.h b/esp8266-fastled-webserver/config.h new file mode 100644 index 00000000..d6f98a7e --- /dev/null +++ b/esp8266-fastled-webserver/config.h @@ -0,0 +1,181 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#if !defined(ESP8266_FASTLED_WEBSERVER_CONFIG_H) +#define ESP8266_FASTLED_WEBSERVER_CONFIG_H + + +// This header file lists (and provides defaults for) the various configurations. +// When compiling from Arduino, you can edit this file. +// When compiling from PlatformIO, this is a reference for compiler flags. + +#define PRODUCT_DEFAULT +// #define PRODUCT_FIBONACCI512 +// #define PRODUCT_FIBONACCI256 +// #define PRODUCT_FIBONACCI128 +// #define PRODUCT_FIBONACCI64_FULL // 86mm, WS2812B-5050, ~60mA/pixel +// #define PRODUCT_FIBONACCI64_MINI // 64mm, WS2812B-3535, ~60mA/pixel +// #define PRODUCT_FIBONACCI64_MICRO // 40mm, WS2812C-2020, ~5mA/pixel +// #define PRODUCT_FIBONACCI64_NANO // 33mm, SK6805-EC15, ~5mA/pixel +// #define PRODUCT_FIBONACCI32 +// #define PRODUCT_KRAKEN64 +// #define PRODUCT_ESP8266_THING // aka parallel (6-output) +// #define PRODUCT_1628_RINGS + +// //////////////////////////////////////////////////////////////////////////////////////////////////// +// Additional configuration options ... defaults shown +// //////////////////////////////////////////////////////////////////////////////////////////////////// +// #define UTC_OFFSET_IN_SECONDS (-6L * 60L * 60L) // UTC-6 (East-coast US ... no DST support) +// #define NTP_UPDATE_THROTTLE_MILLLISECONDS (5UL * 60UL * 60UL * 1000UL) // Ping NTP server no more than every 5 minutes +// +// TODO: add option to disable NTP altogether + +// //////////////////////////////////////////////////////////////////////////////////////////////////// +// Include the configuration files for this build +// //////////////////////////////////////////////////////////////////////////////////////////////////// +#if 1 // just for collapsing + // Product-specific configuration + #if defined(PRODUCT_DEFAULT) + #include "./include/configs/product/default.h" + #elif defined(PRODUCT_1628_RINGS) + #include "./include/configs/product/1628rings.h" + #elif defined(PRODUCT_KRAKEN64) + #include "./include/configs/product/kraken64.h" + #elif defined(PRODUCT_FIBONACCI32) + #include "./include/configs/product/fibonacci32.h" + #elif defined(PRODUCT_FIBONACCI64_FULL) || defined(PRODUCT_FIBONACCI64_MINI) || defined(PRODUCT_FIBONACCI64_MICRO) || defined(PRODUCT_FIBONACCI64_NANO) + #include "./include/configs/product/fibonacci64.h" + #elif defined(PRODUCT_FIBONACCI128) + #include "./include/configs/product/fibonacci128.h" + #elif defined(PRODUCT_FIBONACCI256) + #include "./include/configs/product/fibonacci256.h" + #elif defined(PRODUCT_FIBONACCI512) + #include "./include/configs/product/fibonacci512.h" + #elif defined(PRODUCT_ESP8266_THING) // aka parallel + #include "./include/configs/product/esp8266_thing.h" + #else + #error "Must define product to build against" + #endif + + // Board-specific configuration + #if defined(ARDUINO_ARCH_ESP32) + #include "./include/configs/controller/controller_esp32.h" + #elif defined(ARDUINO_ARCH_ESP8266) + #include "./include/configs/controller/controller_esp8266.h" + #else + #error "Unknown board type ... currently only support ESP8266 and ESP32" + #endif +#endif + + +// //////////////////////////////////////////////////////////////////////////////////////////////////// +// Set defaults for optional values +// //////////////////////////////////////////////////////////////////////////////////////////////////// +#if 1 // just for collapsing + #if !defined(UTC_OFFSET_IN_SECONDS) + #define UTC_OFFSET_IN_SECONDS (-6L * 60L * 60L) // UTC-6 (East-coast US ... no DST support) + #endif + #if !defined(NTP_UPDATE_THROTTLE_MILLLISECONDS) + #define NTP_UPDATE_THROTTLE_MILLLISECONDS (5UL * 60UL * 60UL * 1000UL) // Ping NTP server no more than every 5 minutes + #endif +#endif + +// //////////////////////////////////////////////////////////////////////////////////////////////////// +// Validate configuration options +// //////////////////////////////////////////////////////////////////////////////////////////////////// + +#if 1 // just for collapsing + #if !defined(LED_TYPE) + #error "LED_TYPE must be defined by product" + #endif + #if !defined(COLOR_ORDER) + #error "COLOR_ORDER must be defined by product" + #endif + #if !defined(NUM_PIXELS) + #error "NUM_PIXELS must be defined by product" + #endif + #if !defined(AVAILABLE_MILLI_AMPS) + #error "AVAILABLE_MILLI_AMPS must be defined by product" + #endif + #if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #error "MAX_MILLI_AMPS_PER_PIXEL must be defined by product" + #endif + #if !defined(FRAMES_PER_SECOND) + #error "FRAMES_PER_SECOND must be defined by product" + #endif + #if !defined(DEFAULT_PATTERN_INDEX) + #error "DEFAULT_PATTERN_INDEX must be defined by product" + #endif + #if !defined(DEFAULT_COLOR_CORRECTION) + #error "DEFAULT_COLOR_CORRECTION must be defined by product" + #endif + #if defined(ENABLE_IR) && !defined(IR_RECV_PIN) + #error "IR_RECV_PIN must be defined by product when ENABLE_IR is defined" + #endif + #if !defined(NAME_PREFIX) + #error "NAME_PREFIX must be defined by product" + #endif + #if !defined(PRODUCT_FRIENDLY_NAME) + #error "PRODUCT_FRIENDLY_NAME must be defined by product" + #endif + // IS_FIBONACCI: There does not appear to be a way to check, at compile-time here, if requirements are met + #if !defined(IS_FIBONACCI) || ((IS_FIBONACCI != 0) && (IS_FIBONACCI != 1)) + #error "IS_FIBONACCI must be defined to zero or one" + #endif + #if !defined(HAS_COORDINATE_MAP) || ((HAS_COORDINATE_MAP != 0) && (HAS_COORDINATE_MAP != 1)) + #error "HAS_COORDINATE_MAP must be defined to zero or one" + #endif + #if IS_FIBONACCI && (!HAS_COORDINATE_MAP) + #error "IS_FIBONACCI is true, so HAS_COORDINATE_MAP must also be true (but is not)" + #endif + #if !defined(HAS_POLAR_COORDS) || ((HAS_POLAR_COORDS != 0) && (HAS_POLAR_COORDS != 1)) + #error "HAS_POLAR_COORDS must be defined to zero or one" + #endif + #if HAS_POLAR_COORDS && (!HAS_COORDINATE_MAP) + #error "HAS_POLAR_COORDS is true, so HAS_COORDINATE_MAP must also be true (but is not)" + #endif + #if !defined(PARALLEL_OUTPUT_CHANNELS) + #error "PARALLEL_OUTPUT_CHANNELS must be defined" + #elif (PARALLEL_OUTPUT_CHANNELS == 1) + // nothing to test here + #elif (PARALLEL_OUTPUT_CHANNELS == 4) + static_assert(NUM_PIXELS == (PIXELS_ON_DATA_PIN_1 + PIXELS_ON_DATA_PIN_2 + PIXELS_ON_DATA_PIN_3 + PIXELS_ON_DATA_PIN_4), ""); + #elif (PARALLEL_OUTPUT_CHANNELS == 6) + static_assert(NUM_PIXELS == (PIXELS_ON_DATA_PIN_1 + PIXELS_ON_DATA_PIN_2 + PIXELS_ON_DATA_PIN_3 + PIXELS_ON_DATA_PIN_4 + PIXELS_ON_DATA_PIN_5 + PIXELS_ON_DATA_PIN_6), ""); + #else + #error "PARALLEL_OUTPUT_CHANNELS currently tested only with values 1, 4, or 6." + #endif + #if (UTC_OFFSET_IN_SECONDS < (-14L * 60L * 60L)) + #error "UTC_OFFSET_IN_SECONDS offset does not appear correct (< -14H) ... Note it is defined in seconds." + #elif (UTC_OFFSET_IN_SECONDS > (14L * 60L * 60L)) + #error "UTC_OFFSET_IN_SECONDS offset does not appear correct (> +14H) ... Note it is defined in seconds." + #endif + #if (NTP_UPDATE_THROTTLE_MILLLISECONDS < (15UL * 1000UL)) + #error "NTP_UPDATE_THROTTLE_MILLLISECONDS less than 15 seconds ... may exceed rate limits" + #endif +#endif + + + +#if defined(MILLI_AMPS) + #error "Legacy symbol MILLI_AMPS should be changed to AVAILABLE_MILLI_AMPS" +#endif +#define MAX_MILLI_AMPS (MAX_MILLI_AMPS_PER_PIXEL * NUM_PIXELS) + + +#endif // ESP8266_FASTLED_WEBSERVER_CONFIG_H diff --git a/esp8266-fastled-webserver/data/index.htm b/esp8266-fastled-webserver/data/index.htm index c3c5d531..3400fefd 100644 --- a/esp8266-fastled-webserver/data/index.htm +++ b/esp8266-fastled-webserver/data/index.htm @@ -5,7 +5,7 @@ - ESP8266 + FastLED by Evil Genius Labs +   @@ -36,8 +36,9 @@
diff --git a/esp8266-fastled-webserver/data/info.htm b/esp8266-fastled-webserver/data/info.htm new file mode 100644 index 00000000..b840e9b6 --- /dev/null +++ b/esp8266-fastled-webserver/data/info.htm @@ -0,0 +1,78 @@ + + + + + + + + ESP8266 + FastLED by Evil Genius Labs + + + + + + + + + + + + + + + + +
+ +
+
+ + + +
+ + + + + + + + + + + + + + diff --git a/esp8266-fastled-webserver/data/js/app.js b/esp8266-fastled-webserver/data/js/app.js index 13c5e8ee..02cba8be 100644 --- a/esp8266-fastled-webserver/data/js/app.js +++ b/esp8266-fastled-webserver/data/js/app.js @@ -28,6 +28,16 @@ var allData = {}; $(document).ready(function() { $("#status").html("Connecting, please wait..."); + // info gathers a lot more information ... + // just need product name for main page. + $.get(urlBase + "product", function (data) { + const name = data['productName']; + // Set overall page title + $(document).attr("title", name + " by EvilGenius Labs"); + // Set text of element with id 'product' + $("#product").text(name); + }); + $("#btnTop").click(function () { $([document.documentElement, document.body]).animate( { @@ -460,6 +470,9 @@ function addSectionField(field) { template.attr("id", "form-group-section-" + field.name); template.attr("data-field-type", field.type); + var label = template.find(".section-header-text"); + label.text(field.label); + $("#form").append(template); } diff --git a/esp8266-fastled-webserver/data/js/info.js b/esp8266-fastled-webserver/data/js/info.js new file mode 100644 index 00000000..e901ab74 --- /dev/null +++ b/esp8266-fastled-webserver/data/js/info.js @@ -0,0 +1,81 @@ +// used when hosting the site on the ESP8266 +var address = location.hostname; +var urlBase = ""; + +// used when hosting the site somewhere other than the ESP8266 (handy for testing without waiting forever to upload to SPIFFS) +// var address = "192.168.86.36"; +// var urlBase = "http://" + address + "/"; + +const keyToName = { + millis: "Uptime", + vcc: "VCC", + wiFiChipId: "Wi-Fi Chip ID", + flashChipId: "Flash Chip ID", + flashChipSize: "Flash Chip Size", + flashChipRealSize: "Flash Chip Real Size", + sdkVersion: "SDK Version", + coreVersion: "Core Version", + bootVersion: "Boot Version", + cpuFreqMHz: "CPU Frequency", + freeHeap: "Free Heap Memory", + sketchSize: "Sketch Size", + freeSketchSpace: "Free Sketch Space", + resetReason: "Last Reset Reason", + isConnected: "Wi-Fi Connected", + wiFiSsidDefault: "Wi-Fi SSID (Default)", + wiFiSSID: "Wi-Fi SSID", + localIP: "Local IP Address", + gatewayIP: "Gateway IP Address", + subnetMask: "Subnet Mask", + dnsIP: "DNS IP Address", + hostname: "Hostname", + macAddress: "MAC Address", + autoConnect: "Auto Connect", + softAPSSID: "Soft AP SSID", + softAPIP: "Soft AP IP Address", + BSSID: "BSSID", + softAPmacAddress: "Soft AP MAC Address", +}; + +$(document).ready(function () { + $("#status").html("Connecting, please wait..."); + + $.get(urlBase + "info", function (data) { + $("#status").html("Loading, please wait..."); + + Object.keys(data).forEach((key) => { + var dtTemplate = $("#infoDtTemplate").clone(); + var ddTemplate = $("#infoDdTemplate").clone(); + + const name = keyToName[key] || key; + let value = data[key]; + + switch(key) { + + case 'millis': + value = `${(value / 1000 / 60).toFixed()} minutes, ${((value / 1000) % 60).toFixed()} seconds`; + break; + + case 'flashChipSize': + case 'flashChipRealSize': + case 'freeHeap': + case 'freeSketchSpace': + case 'sketchSize': + value = `${value.toLocaleString()} bytes`; + break; + + case 'cpuFreqMHz': + value = `${value}MHz`; + break; + } + + dtTemplate.html(name); + ddTemplate.html(value); + + $("#infoDl").append(dtTemplate); + $("#infoDl").append(ddTemplate); + }); + }); + + $("#status").html("Ready"); +}); diff --git a/esp8266-fastled-webserver/data/simple.htm b/esp8266-fastled-webserver/data/simple.htm index 5fc86227..3fe8527f 100644 --- a/esp8266-fastled-webserver/data/simple.htm +++ b/esp8266-fastled-webserver/data/simple.htm @@ -47,6 +47,8 @@ + + diff --git a/esp8266-fastled-webserver/esp8266-fastled-webserver.ino b/esp8266-fastled-webserver/esp8266-fastled-webserver.ino index 30f6a85d..2af84642 100644 --- a/esp8266-fastled-webserver/esp8266-fastled-webserver.ino +++ b/esp8266-fastled-webserver/esp8266-fastled-webserver.ino @@ -1,6 +1,6 @@ /* ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver - Copyright (C) 2015-2018 Jason Coon + Copyright (C) Jason Coon This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,67 +16,24 @@ along with this program. If not, see . */ -//#define FASTLED_ALLOW_INTERRUPTS 1 -//#define INTERRUPT_THRESHOLD 1 -#define FASTLED_INTERRUPT_RETRY_COUNT 0 - -#include -FASTLED_USING_NAMESPACE - -extern "C" { -#include "user_interface.h" -} - -// #include -#include -#define MYFS LittleFS - - -#include -#include -#include -#include -#include -//#include - -#include -//#include -#include // https://github.com/tzapu/WiFiManager/tree/development -#include "GradientPalettes.h" - -#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) - -#include "Field.h" - -//#define RECV_PIN D4 -//IRrecv irReceiver(RECV_PIN); - -//#include "Commands.h" +#include "common.h" WiFiManager wifiManager; ESP8266WebServer webServer(80); //WebSocketsServer webSocketsServer = WebSocketsServer(81); ESP8266HTTPUpdateServer httpUpdateServer; -#include "FSBrowser.h" - -#define DATA_PIN D5 -#define LED_TYPE WS2811 -#define COLOR_ORDER RGB -#define NUM_LEDS 200 - -#define MILLI_AMPS 2000 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) -#define FRAMES_PER_SECOND 120 // here you can control the speed. With the Access Point / Web Server the animations run a bit slower. +// Define NTP Client to get time +WiFiUDP ntpUDP; +NTPClient timeClient(ntpUDP, "pool.ntp.org", UTC_OFFSET_IN_SECONDS, NTP_UPDATE_THROTTLE_MILLLISECONDS); String nameString; -#include "Ping.h" - -CRGB leds[NUM_LEDS]; +CRGB leds[NUM_PIXELS]; const uint8_t brightnessCount = 5; -uint8_t brightnessMap[brightnessCount] = { 16, 32, 64, 128, 255 }; -uint8_t brightnessIndex = 3; +const uint8_t brightnessMap[brightnessCount] = { 16, 32, 64, 128, 255 }; +uint8_t brightnessIndex = DEFAULT_BRIGHTNESS_INDEX; // ten seconds per color palette makes a good demo // 20-120 is better for deployment @@ -96,10 +53,6 @@ uint8_t speed = 30; /////////////////////////////////////////////////////////////////////// -// Forward declarations of an array of cpt-city gradient palettes, and -// a count of how many there are. The actual color palette definitions -// are at the bottom of this file. -extern const TProgmemRGBGradientPalettePtr gGradientPalettes[]; uint8_t gCurrentPaletteNumber = 0; @@ -108,12 +61,15 @@ CRGBPalette16 gTargetPalette( gGradientPalettes[0] ); CRGBPalette16 IceColors_p = CRGBPalette16(CRGB::Black, CRGB::Blue, CRGB::Aqua, CRGB::White); -uint8_t currentPatternIndex = 0; // Index number of which pattern is current +uint8_t currentPatternIndex = DEFAULT_PATTERN_INDEX; // Index number of which pattern is current uint8_t autoplay = 0; uint8_t autoplayDuration = 10; unsigned long autoPlayTimeout = 0; +uint8_t showClock = 0; +uint8_t clockBackgroundFade = 240; + uint8_t currentPaletteIndex = 0; uint8_t gHue = 0; // rotating "base color" used by many of the patterns @@ -123,33 +79,136 @@ CRGB solidColor = CRGB::Blue; // scale the brightness of all pixels down void dimAll(byte value) { - for (int i = 0; i < NUM_LEDS; i++) { - leds[i].nscale8(value); + for (auto led : leds) { + led.nscale8(value); } } -typedef void (*Pattern)(); -typedef Pattern PatternList[]; -typedef struct { - Pattern pattern; - String name; -} PatternAndName; -typedef PatternAndName PatternAndNameList[]; - -#include "Twinkles.h" -#include "TwinkleFOX.h" -#include "PridePlayground.h" -#include "ColorWavesPlayground.h" - // List of patterns to cycle through. Each is defined as a separate function below. -PatternAndNameList patterns = { - { pride, "Pride" }, +// NOTE: HAS_POLAR_COORDS implies HAS_COORDINATE_MAP +// IS_FIBONACCI implies HAS_COORDINATE_MAP + +// TODO: Consider patterns listing name and all variants: +// [] original variant +// [] fibonacci variant (or nullptr) +// [] concentric ring variant (or nullptr) +// [] coordinates variant (or nullptr) +// WHY #1: Easier to manage defining the patterns via a macro, +// which discards arguments that do not apply for a given +// board, than this #if/#endif spaghetti mess. +// WHY #2: Easier for users to see correlations between the patterns, +// when switching between them. +// WHY #3: May eventually be able to change mapping for standard +// effects (emulating led array, but using custom mapping), +// which could further reduce code duplication. + +const PatternAndName patterns[] = { + { pride, "Pride" }, +#if IS_FIBONACCI + { prideFibonacci, "Pride Fibonacci" }, +#endif + { colorWaves, "Color Waves" }, +#if HAS_COORDINATE_MAP // really a wrong name... and likely doing way more computation than necessary + { radarSweepPalette, "Radar Sweep Palette" }, +#endif +#if HAS_POLAR_COORDS // really a wrong name... and likely doing way more computation than necessary + // noise patterns (Polar variations) + { gradientPalettePolarNoise, "Gradient Palette Polar Noise" }, + { palettePolarNoise, "Palette Polar Noise" }, + { firePolarNoise, "Fire Polar Noise" }, + { firePolarNoise2, "Fire Polar Noise 2" }, + { lavaPolarNoise, "Lava Polar Noise" }, + { rainbowPolarNoise, "Rainbow Polar Noise" }, + { rainbowStripePolarNoise, "Rainbow Stripe Polar Noise" }, + { partyPolarNoise, "Party Polar Noise" }, + { forestPolarNoise, "Forest Polar Noise" }, + { cloudPolarNoise, "Cloud Polar Noise" }, + { oceanPolarNoise, "Ocean Polar Noise" }, + { blackAndWhitePolarNoise, "Black & White Polar Noise" }, + { blackAndBluePolarNoise, "Black & Blue Polar Noise" }, +#endif + +#if IS_FIBONACCI + { colorWavesFibonacci, "Color Waves Fibonacci" }, + + { pridePlayground, "Pride Playground" }, + { pridePlaygroundFibonacci, "Pride Playground Fibonacci" }, + + { colorWavesPlayground, "Color Waves Playground" }, + { colorWavesPlaygroundFibonacci, "Color Waves Playground Fibonacci" }, +#endif + + { wheel, "Wheel" }, +#if (PARALLEL_OUTPUT_CHANNELS > 1) + { multi_test, "Multi Test" }, +#endif + +#if IS_FIBONACCI + { swirlFibonacci, "Swirl Fibonacci"}, + { fireFibonacci, "Fire Fibonacci" }, + { waterFibonacci, "Water Fibonacci" }, + { emitterFibonacci, "Emitter Fibonacci" }, + + { pacifica_loop, "Pacifica" }, + { pacifica_fibonacci_loop, "Pacifica Fibonacci" }, +#endif + +#if HAS_COORDINATE_MAP + // matrix patterns + { anglePalette, "Angle Palette" }, + { radiusPalette, "Radius Palette" }, + { xPalette, "X Axis Palette" }, + { yPalette, "Y Axis Palette" }, + { xyPalette, "XY Axis Palette" }, + + { angleGradientPalette, "Angle Gradient Palette" }, + { radiusGradientPalette, "Radius Gradient Palette" }, + { xGradientPalette, "X Axis Gradient Palette" }, + { yGradientPalette, "Y Axis Gradient Palette" }, + { xyGradientPalette, "XY Axis Gradient Palette" }, +#endif + +#if HAS_COORDINATE_MAP + // noise patterns + { fireNoise, "Fire Noise" }, + { fireNoise2, "Fire Noise 2" }, + { lavaNoise, "Lava Noise" }, + { rainbowNoise, "Rainbow Noise" }, + { rainbowStripeNoise, "Rainbow Stripe Noise" }, + { partyNoise, "Party Noise" }, + { forestNoise, "Forest Noise" }, + { cloudNoise, "Cloud Noise" }, + { oceanNoise, "Ocean Noise" }, + { blackAndWhiteNoise, "Black & White Noise" }, + { blackAndBlueNoise, "Black & Blue Noise" }, +#endif + +#if IS_FIBONACCI + { drawAnalogClock, "Analog Clock" }, + + { drawSpiralAnalogClock13, "Spiral Analog Clock 13" }, + { drawSpiralAnalogClock21, "Spiral Analog Clock 21" }, + { drawSpiralAnalogClock34, "Spiral Analog Clock 34" }, + { drawSpiralAnalogClock55, "Spiral Analog Clock 55" }, + { drawSpiralAnalogClock89, "Spiral Analog Clock 89" }, + + { drawSpiralAnalogClock21and34, "Spiral Analog Clock 21 & 34"}, + { drawSpiralAnalogClock13_21_and_34, "Spiral Analog Clock 13, 21 & 34"}, + { drawSpiralAnalogClock34_21_and_13, "Spiral Analog Clock 34, 21 & 13"}, +#endif + { pridePlayground, "Pride Playground" }, { colorWavesPlayground, "Color Waves Playground" }, +#if defined(PRODUCT_KRAKEN64) + // Kraken patterns ... these use body[], which is also used as a proxy for radius... + { radiusPalette, "Kraken Palette" }, + { radiusGradientPalette, "Kraken Gradient Palette" }, +#endif + // twinkle patterns { rainbowTwinkles, "Rainbow Twinkles" }, { snowTwinkles, "Snow Twinkles" }, @@ -182,16 +241,12 @@ PatternAndNameList patterns = { { fire, "Fire" }, { water, "Water" }, - { showSolidColor, "Solid Color" } -}; + { strandTest, "Strand Test" }, -const uint8_t patternCount = ARRAY_SIZE(patterns); + { showSolidColor, "Solid Color" } // This *must* be the last pattern +}; -typedef struct { - CRGBPalette16 palette; - String name; -} PaletteAndName; -typedef PaletteAndName PaletteAndNameList[]; +const uint8_t patternCount = ARRAY_SIZE2(patterns); const CRGBPalette16 palettes[] = { RainbowColors_p, @@ -204,7 +259,7 @@ const CRGBPalette16 palettes[] = { HeatColors_p }; -const uint8_t paletteCount = ARRAY_SIZE(palettes); +const uint8_t paletteCount = ARRAY_SIZE2(palettes); const String paletteNames[paletteCount] = { "Rainbow", @@ -217,7 +272,11 @@ const String paletteNames[paletteCount] = { "Heat", }; -#include "Fields.h" +// TODO / BUGBUG -- should this be ESP8266-specific? Is this only for when IR enabled ??? +// FIB128 did not have this... +#if defined(PRODUCT_FIBONACCI256) + ADC_MODE(ADC_VCC); +#endif void setup() { WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP @@ -226,23 +285,50 @@ void setup() { Serial.begin(115200); Serial.setDebugOutput(true); - FastLED.addLeds(leds, NUM_LEDS); // for WS2812 (Neopixel) - //FastLED.addLeds(leds, NUM_LEDS); // for APA102 (Dotstar) + uint16_t milliAmps = (AVAILABLE_MILLI_AMPS < MAX_MILLI_AMPS) ? AVAILABLE_MILLI_AMPS : MAX_MILLI_AMPS; + + #if PARALLEL_OUTPUT_CHANNELS == 1 + FastLED.addLeds(leds, NUM_PIXELS); // for WS2812 (Neopixel) + #else + #if PARALLEL_OUTPUT_CHANNELS >= 2 + FastLED.addLeds(leds, LedOffset<1>(), LedCount<1>()); + FastLED.addLeds(leds, LedOffset<2>(), LedCount<2>()); + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 3 + FastLED.addLeds(leds, LedOffset<3>(), LedCount<3>()); + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 4 + FastLED.addLeds(leds, LedOffset<4>(), LedCount<4>()); + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 5 + FastLED.addLeds(leds, LedOffset<5>(), LedCount<4>()); + #endif + #if PARALLEL_OUTPUT_CHANNELS >= 6 + FastLED.addLeds(leds, LedOffset<6>(), LedCount<4>()); + #endif + #endif // PARALLEL_OUTPUT_CHANNELS + + //FastLED.addLeds(leds, NUM_PIXELS); // for APA102 (Dotstar) + FastLED.setDither(false); FastLED.setCorrection(TypicalLEDStrip); FastLED.setBrightness(brightness); - FastLED.setMaxPowerInVoltsAndMilliamps(5, MILLI_AMPS); - fill_solid(leds, NUM_LEDS, CRGB::Black); + FastLED.setMaxPowerInVoltsAndMilliamps(5, milliAmps); + fill_solid(leds, NUM_PIXELS, CRGB::Black); FastLED.show(); - EEPROM.begin(512); + EEPROM.begin(512); // TODO: move settings (currently EEPROM) to fields.hpp/.cpp readSettings(); FastLED.setBrightness(brightness); - // irReceiver.enableIRIn(); // Start the receiver +#if defined(ENABLE_IR) + irReceiver.enableIRIn(); // Start the receiver +#endif Serial.println(); + Serial.println(F("System Info:")); + Serial.print( F("Max mA: ") ); Serial.println(milliAmps); Serial.print( F("Heap: ") ); Serial.println(system_get_free_heap_size()); Serial.print( F("Boot Vers: ") ); Serial.println(system_get_boot_version()); Serial.print( F("CPU: ") ); Serial.println(system_get_cpu_freq()); @@ -254,6 +340,21 @@ void setup() { Serial.print( F("MAC Address: ") ); Serial.println(WiFi.macAddress()); Serial.println(); + Serial.println(F("Settings: ")); + Serial.print(F("brightness: ")); Serial.println(brightness); + Serial.print(F("currentPatternIndex: ")); Serial.println(currentPatternIndex); + Serial.print(F("solidColor.r: ")); Serial.println(solidColor.r); + Serial.print(F("solidColor.g: ")); Serial.println(solidColor.g); + Serial.print(F("solidColor.b: ")); Serial.println(solidColor.b); + Serial.print(F("power: ")); Serial.println(power); + Serial.print(F("autoplay: ")); Serial.println(autoplay); + Serial.print(F("autoplayDuration: ")); Serial.println(autoplayDuration); + Serial.print(F("currentPaletteIndex: ")); Serial.println(currentPaletteIndex); + Serial.print(F("showClock: ")); Serial.println(showClock); + Serial.print(F("clockBackgroundFade: ")); Serial.println(clockBackgroundFade); + Serial.println(); + + if (!MYFS.begin()) { Serial.println(F("An error occurred when attempting to mount the flash file system")); } else { @@ -268,6 +369,7 @@ void setup() { Serial.printf("\n"); } + // Do a little work to get a unique-ish name. Get the // last two bytes of the MAC (HEX'd)": @@ -283,12 +385,23 @@ void setup() { String macIdString = macID; macIdString.toUpperCase(); - nameString = "ESP8266-" + macIdString; - - char nameChar[nameString.length() + 1]; - memset(nameChar, 0, nameString.length() + 1); - - for (unsigned int i = 0; i < nameString.length(); i++) { + nameString = NAME_PREFIX + macIdString; + + // Allocation of variable-sized arrays on the stack is a GCC extension. + // Converting this to be compile-time evaluated is possible: + // nameString.length() === strlen(NAME_PREFIX) + strlen(maxIdString) + // strlen(NAME_PREFIX) is compile-time constexpr (but changes per NAME_PREFIX) + // strlen(macIdString) is always 4 + // Therefore, can use the following to ensure statically evaluated at compile-time, + // and avoid use of GCC extensions, with no performance loss. + const size_t nameCharCount = static_eval::value; + const size_t nameBufferSize = static_eval::value; + char nameChar[nameBufferSize]; + memset(nameChar, 0, nameBufferSize); + // Technically, this should *NEVER* need to check the nameString length. + // However, I prefer to code defensively, since no static_assert() can detect this. + size_t loopUntil = (nameCharCount <= nameString.length() ? nameCharCount : nameString.length()); + for (size_t i = 0; i < loopUntil; i++) { nameChar[i] = nameString.charAt(i); } @@ -311,14 +424,26 @@ void setup() { httpUpdateServer.setup(&webServer); webServer.on("/all", HTTP_GET, []() { - String json = getFieldsJson(fields, fieldCount); + String json = getFieldsJson(); + webServer.sendHeader("Access-Control-Allow-Origin", "*"); + webServer.send(200, "application/json", json); + }); + + webServer.on("/product", HTTP_GET, []() { + String json = "{\"productName\":\"" PRODUCT_FRIENDLY_NAME "\"}"; + webServer.sendHeader("Access-Control-Allow-Origin", "*"); + webServer.send(200, "application/json", json); + }); + + webServer.on("/info", HTTP_GET, []() { + String json = getInfoJson(); webServer.sendHeader("Access-Control-Allow-Origin", "*"); webServer.send(200, "application/json", json); }); webServer.on("/fieldValue", HTTP_GET, []() { String name = webServer.arg("name"); - String value = getFieldValue(name, fields, fieldCount); + String value = getFieldValue(name); webServer.sendHeader("Access-Control-Allow-Origin", "*"); webServer.send(200, "text/json", value); }); @@ -326,7 +451,7 @@ void setup() { webServer.on("/fieldValue", HTTP_POST, []() { String name = webServer.arg("name"); String value = webServer.arg("value"); - String newValue = setFieldValue(name, value, fields, fieldCount); + String newValue = setFieldValue(name, value); webServer.sendHeader("Access-Control-Allow-Origin", "*"); webServer.send(200, "text/json", newValue); }); @@ -341,7 +466,6 @@ void setup() { webServer.on("/cooling", HTTP_POST, []() { String value = webServer.arg("value"); cooling = value.toInt(); - writeAndCommitSettings(); broadcastInt("cooling", cooling); webServer.sendHeader("Access-Control-Allow-Origin", "*"); sendInt(cooling); @@ -350,7 +474,6 @@ void setup() { webServer.on("/sparking", HTTP_POST, []() { String value = webServer.arg("value"); sparking = value.toInt(); - writeAndCommitSettings(); broadcastInt("sparking", sparking); webServer.sendHeader("Access-Control-Allow-Origin", "*"); sendInt(sparking); @@ -466,6 +589,30 @@ void setup() { sendInt(autoplayDuration); }); + webServer.on("/showClock", HTTP_POST, []() { + String value = webServer.arg("value"); + long tmp = value.toInt(); + if (tmp < 0) { + tmp = 0; + } else if (tmp > 1) { + tmp = 1; + } + setShowClock(tmp); + sendInt(showClock); + }); + + webServer.on("/clockBackgroundFade", HTTP_POST, []() { + String value = webServer.arg("value"); + long tmp = value.toInt(); + if (tmp < 0) { + tmp = 0; + } else if (tmp > 255) { + tmp = 255; + } + setClockBackgroundFade(tmp); + sendInt(clockBackgroundFade); + }); + //list directory webServer.on("/list", HTTP_GET, handleFileList); //load editor @@ -496,6 +643,7 @@ void setup() { // Serial.println("Web socket server started"); autoPlayTimeout = millis() + (autoplayDuration * 1000); + timeClient.begin(); } void sendInt(uint8_t value) @@ -520,8 +668,15 @@ void broadcastString(String name, String value) // webSocketsServer.broadcastTXT(json); } +// TODO: Add board-specific entropy sources +// e.g., using `uint32_t esp_random()`, if exposed in Arduino ESP32 / ESP8266 BSPs +// e.g., directly reading from 0x3FF20E44 on ESP8266 (dangerous! no entropy validation, whitening) +// e.g., directly reading from 0x3FF75144 on ESP32 (dangerous! no entropy validation, whitening) +// e.g., directly reading from RANDOM_REG32 (dangerous! no entropy validation, whitening) +// e.g., using a library, such as https://github.com/marvinroger/ESP8266TrueRandom/blob/master/ESP8266TrueRandom.cpp (less dangerous?) +// e.g., directly reading REG_READ(WDEV_RND_REG) (dangerous! no check for sufficient clock cycles passed for entropy) void loop() { - // Add entropy to random number generator; we use a lot of it. + // Modify random number generator seed; we use a lot of it. (Note: this is still deterministic) random16_add_entropy(random(65535)); // webSocketsServer.loop(); @@ -530,9 +685,8 @@ void loop() { webServer.handleClient(); MDNS.update(); - // timeClient.update(); - static bool hasConnected = false; + EVERY_N_SECONDS(1) { if (WiFi.status() != WL_CONNECTED) { // Serial.printf("Connecting to %s\n", ssid); @@ -549,17 +703,17 @@ void loop() { Serial.print(" or http://"); Serial.print(nameString); Serial.println(".local in your browser"); + } else { + timeClient.update(); // NTPClient has throttling built-in } } checkPingTimer(); - - // handleIrInput(); + handleIrInput(); // empty function when ENABLE_IR is not defined if (power == 0) { - fill_solid(leds, NUM_LEDS, CRGB::Black); - FastLED.show(); - delay(1000 / FRAMES_PER_SECOND); + fill_solid(leds, NUM_PIXELS, CRGB::Black); + FastLED.delay(1000 / FRAMES_PER_SECOND); // this function calls FastLED.show() at least once return; } @@ -587,9 +741,11 @@ void loop() { // Call the current pattern function once, updating the 'leds' array patterns[currentPatternIndex].pattern(); - FastLED.show(); + #if IS_FIBONACCI + if (showClock) drawAnalogClock(); + #endif - // insert a delay to keep the framerate modest + // insert a delay to keep the framerate modest ... this is guaranteed to call FastLED.show() at least once FastLED.delay(1000 / FRAMES_PER_SECOND); } @@ -630,219 +786,15 @@ void loop() { // } //} -//void handleIrInput() -//{ -// InputCommand command = readCommand(); -// -// if (command != InputCommand::None) { -// Serial.print("command: "); -// Serial.println((int) command); -// } -// -// switch (command) { -// case InputCommand::Up: { -// adjustPattern(true); -// break; -// } -// case InputCommand::Down: { -// adjustPattern(false); -// break; -// } -// case InputCommand::Power: { -// setPower(power == 0 ? 1 : 0); -// break; -// } -// case InputCommand::BrightnessUp: { -// adjustBrightness(true); -// break; -// } -// case InputCommand::BrightnessDown: { -// adjustBrightness(false); -// break; -// } -// case InputCommand::PlayMode: { // toggle pause/play -// setAutoplay(!autoplay); -// break; -// } -// -// // pattern buttons -// -// case InputCommand::Pattern1: { -// setPattern(0); -// break; -// } -// case InputCommand::Pattern2: { -// setPattern(1); -// break; -// } -// case InputCommand::Pattern3: { -// setPattern(2); -// break; -// } -// case InputCommand::Pattern4: { -// setPattern(3); -// break; -// } -// case InputCommand::Pattern5: { -// setPattern(4); -// break; -// } -// case InputCommand::Pattern6: { -// setPattern(5); -// break; -// } -// case InputCommand::Pattern7: { -// setPattern(6); -// break; -// } -// case InputCommand::Pattern8: { -// setPattern(7); -// break; -// } -// case InputCommand::Pattern9: { -// setPattern(8); -// break; -// } -// case InputCommand::Pattern10: { -// setPattern(9); -// break; -// } -// case InputCommand::Pattern11: { -// setPattern(10); -// break; -// } -// case InputCommand::Pattern12: { -// setPattern(11); -// break; -// } -// -// // custom color adjustment buttons -// -// case InputCommand::RedUp: { -// solidColor.red += 8; -// setSolidColor(solidColor); -// break; -// } -// case InputCommand::RedDown: { -// solidColor.red -= 8; -// setSolidColor(solidColor); -// break; -// } -// case InputCommand::GreenUp: { -// solidColor.green += 8; -// setSolidColor(solidColor); -// break; -// } -// case InputCommand::GreenDown: { -// solidColor.green -= 8; -// setSolidColor(solidColor); -// break; -// } -// case InputCommand::BlueUp: { -// solidColor.blue += 8; -// setSolidColor(solidColor); -// break; -// } -// case InputCommand::BlueDown: { -// solidColor.blue -= 8; -// setSolidColor(solidColor); -// break; -// } -// -// // color buttons -// -// case InputCommand::Red: { -// setSolidColor(CRGB::Red); -// break; -// } -// case InputCommand::RedOrange: { -// setSolidColor(CRGB::OrangeRed); -// break; -// } -// case InputCommand::Orange: { -// setSolidColor(CRGB::Orange); -// break; -// } -// case InputCommand::YellowOrange: { -// setSolidColor(CRGB::Goldenrod); -// break; -// } -// case InputCommand::Yellow: { -// setSolidColor(CRGB::Yellow); -// break; -// } -// -// case InputCommand::Green: { -// setSolidColor(CRGB::Green); -// break; -// } -// case InputCommand::Lime: { -// setSolidColor(CRGB::Lime); -// break; -// } -// case InputCommand::Aqua: { -// setSolidColor(CRGB::Aqua); -// break; -// } -// case InputCommand::Teal: { -// setSolidColor(CRGB::Teal); -// break; -// } -// case InputCommand::Navy: { -// setSolidColor(CRGB::Navy); -// break; -// } -// -// case InputCommand::Blue: { -// setSolidColor(CRGB::Blue); -// break; -// } -// case InputCommand::RoyalBlue: { -// setSolidColor(CRGB::RoyalBlue); -// break; -// } -// case InputCommand::Purple: { -// setSolidColor(CRGB::Purple); -// break; -// } -// case InputCommand::Indigo: { -// setSolidColor(CRGB::Indigo); -// break; -// } -// case InputCommand::Magenta: { -// setSolidColor(CRGB::Magenta); -// break; -// } -// -// case InputCommand::White: { -// setSolidColor(CRGB::White); -// break; -// } -// case InputCommand::Pink: { -// setSolidColor(CRGB::Pink); -// break; -// } -// case InputCommand::LightPink: { -// setSolidColor(CRGB::LightPink); -// break; -// } -// case InputCommand::BabyBlue: { -// setSolidColor(CRGB::CornflowerBlue); -// break; -// } -// case InputCommand::LightBlue: { -// setSolidColor(CRGB::LightBlue); -// break; -// } -// } -//} +// TODO: Save settings in file system, not EEPROM! +const uint8_t SETTINGS_MAGIC_BYTE = 0x96; void readSettings() { // check for "magic number" so we know settings have been written to EEPROM // and it's not just full of random bytes - if (EEPROM.read(511) != 55) { + if (EEPROM.read(511) != SETTINGS_MAGIC_BYTE) { return; } @@ -882,10 +834,11 @@ void readSettings() sparking = EEPROM.read(12); coolLikeIncandescent = EEPROM.read(13); -} -void writeAndCommitSettings() -{ + showClock = EEPROM.read(14); + clockBackgroundFade = EEPROM.read(15); +} +void writeAndCommitSettings() { EEPROM.write(0, brightness); EEPROM.write(1, currentPatternIndex); EEPROM.write(2, solidColor.r); @@ -899,8 +852,10 @@ void writeAndCommitSettings() EEPROM.write(10, twinkleDensity); EEPROM.write(11, cooling); EEPROM.write(12, sparking); - - EEPROM.write(511, 55); + EEPROM.write(13, coolLikeIncandescent); + EEPROM.write(14, showClock); + EEPROM.write(15, clockBackgroundFade); + EEPROM.write(511, SETTINGS_MAGIC_BYTE); EEPROM.commit(); } @@ -908,9 +863,8 @@ void setPower(uint8_t value) { power = value == 0 ? 0 : 1; writeAndCommitSettings(); - broadcastInt("power", power); + broadcastInt("power", value); } - void setAutoplay(uint8_t value) { autoplay = value == 0 ? 0 : 1; @@ -1030,23 +984,23 @@ void setBrightness(uint8_t value) void strandTest() { - static uint8_t i = 0; + static size_t i = 0; EVERY_N_SECONDS(1) { i++; - if (i >= NUM_LEDS) + if (i >= NUM_PIXELS) i = 0; } - fill_solid(leds, NUM_LEDS, CRGB::Black); + fill_solid(leds, NUM_PIXELS, CRGB::Black); leds[i] = solidColor; } void showSolidColor() { - fill_solid(leds, NUM_LEDS, solidColor); + fill_solid(leds, NUM_PIXELS, solidColor); } // Patterns from FastLED example DemoReel100: https://github.com/FastLED/FastLED/blob/master/examples/DemoReel100/DemoReel100.ino @@ -1054,7 +1008,7 @@ void showSolidColor() void rainbow() { // FastLED's built-in rainbow generator - fill_rainbow( leds, NUM_LEDS, gHue, 255 / NUM_LEDS); + fill_rainbow( leds, NUM_PIXELS, gHue, 255 / NUM_PIXELS); } void rainbowWithGlitter() @@ -1066,14 +1020,14 @@ void rainbowWithGlitter() void rainbowSolid() { - fill_solid(leds, NUM_LEDS, CHSV(gHue, 255, 255)); + fill_solid(leds, NUM_PIXELS, CHSV(gHue, 255, 255)); } void confetti() { // random colored speckles that blink in and fade smoothly - fadeToBlackBy( leds, NUM_LEDS, 10); - int pos = random16(NUM_LEDS); + fadeToBlackBy( leds, NUM_PIXELS, 10); + int pos = random16(NUM_PIXELS); // leds[pos] += CHSV( gHue + random8(64), 200, 255); leds[pos] += ColorFromPalette(palettes[currentPaletteIndex], gHue + random8(64)); } @@ -1081,8 +1035,8 @@ void confetti() void sinelon() { // a colored dot sweeping back and forth, with fading trails - fadeToBlackBy( leds, NUM_LEDS, 20); - int pos = beatsin16(speed, 0, NUM_LEDS); + fadeToBlackBy( leds, NUM_PIXELS, 20); + int pos = beatsin16(speed, 0, NUM_PIXELS); static int prevpos = 0; CRGB color = ColorFromPalette(palettes[currentPaletteIndex], gHue, 255); if ( pos < prevpos ) { @@ -1098,7 +1052,7 @@ void bpm() // colored stripes pulsing at a defined Beats-Per-Minute (BPM) uint8_t beat = beatsin8( speed, 64, 255); CRGBPalette16 palette = palettes[currentPaletteIndex]; - for ( int i = 0; i < NUM_LEDS; i++) { + for ( int i = 0; i < NUM_PIXELS; i++) { leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10)); } } @@ -1129,10 +1083,10 @@ void juggle() // Several colored dots, weaving in and out of sync with each other curhue = thishue; // Reset the hue values. - fadeToBlackBy(leds, NUM_LEDS, faderate); + fadeToBlackBy(leds, NUM_PIXELS, faderate); for ( int i = 0; i < numdots; i++) { //beat16 is a FastLED 3.1 function - leds[beatsin16(basebeat + i + numdots, 0, NUM_LEDS)] += CHSV(gHue + curhue, thissat, thisbright); + leds[beatsin16(basebeat + i + numdots, 0, NUM_PIXELS)] += CHSV(gHue + curhue, thissat, thisbright); curhue += hueinc; } } @@ -1150,7 +1104,7 @@ void water() // Pride2015 by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5 // This function draws rainbows with an ever-changing, // widely-varying set of parameters. -void pride() +void fillWithPride(bool useFibonacciOrder) { static uint16_t sPseudotime = 0; static uint16_t sLastMillis = 0; @@ -1171,7 +1125,7 @@ void pride() sHue16 += deltams * beatsin88( 400, 5, 9); uint16_t brightnesstheta16 = sPseudotime; - for ( uint16_t i = 0 ; i < NUM_LEDS; i++) { + for ( uint16_t i = 0 ; i < NUM_PIXELS; i++) { hue16 += hueinc16; uint8_t hue8 = hue16 / 256; @@ -1185,40 +1139,91 @@ void pride() CRGB newcolor = CHSV( hue8, sat8, bri8); uint16_t pixelnumber = i; - pixelnumber = (NUM_LEDS - 1) - pixelnumber; + +#if IS_FIBONACCI + if (useFibonacciOrder) pixelnumber = fibonacciToPhysical[i]; +#else + (void)useFibonacciOrder; // unused parameter +#endif + + pixelnumber = (NUM_PIXELS - 1) - pixelnumber; nblend( leds[pixelnumber], newcolor, 64); } } +void pride() { + fillWithPride(false); +} +#if IS_FIBONACCI // prideFibonacci() uses fibonacciToPhysical +void prideFibonacci() { + fillWithPride(true); +} +#endif -void radialPaletteShift() +void fillRadialPaletteShift(bool useFibonacciOrder) { - for (uint16_t i = 0; i < NUM_LEDS; i++) { - // leds[i] = ColorFromPalette( gCurrentPalette, gHue + sin8(i*16), brightness); - leds[i] = ColorFromPalette(gCurrentPalette, i + gHue, 255, LINEARBLEND); + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + #if IS_FIBONACCI + uint16_t idx = useFibonacciOrder ? fibonacciToPhysical[i] : i; + #else + (void)useFibonacciOrder; + uint16_t idx = i; + #endif + leds[idx] = ColorFromPalette(gCurrentPalette, i + gHue, 255, LINEARBLEND); } } +void fillRadialPaletteShiftOutward(bool useFibonacciOrder) +{ + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + #if IS_FIBONACCI + uint16_t idx = useFibonacciOrder ? fibonacciToPhysical[i] : i; + #else + (void)useFibonacciOrder; + uint16_t idx = i; + #endif + leds[idx] = ColorFromPalette(gCurrentPalette, i - gHue, 255, LINEARBLEND); + } +} +// TODO: define function radialPaletteShiftFibonacci() +void radialPaletteShift() +{ + #if IS_FIBONACCI + fillRadialPaletteShift(true); + #else + fillRadialPaletteShift(false); + #endif +} +// TODO: define function radialPaletteShiftOutwardFibonacci(), and update to call corresponding function +void radialPaletteShiftOutward() +{ + #if IS_FIBONACCI + fillRadialPaletteShiftOutward(true); + #else + fillRadialPaletteShiftOutward(false); + #endif +} + // based on FastLED example Fire2012WithPalette: https://github.com/FastLED/FastLED/blob/master/examples/Fire2012WithPalette/Fire2012WithPalette.ino -void heatMap(CRGBPalette16 palette, bool up) +void heatMap(const CRGBPalette16& palette, bool up) { - fill_solid(leds, NUM_LEDS, CRGB::Black); + fill_solid(leds, NUM_PIXELS, CRGB::Black); - // Add entropy to random number generator; we use a lot of it. + // Modify random number generator seed; we use a lot of it. (Note: this is still deterministic) random16_add_entropy(random(256)); // Array of temperature readings at each simulation cell - static byte heat[NUM_LEDS]; + static byte heat[NUM_PIXELS]; byte colorindex; // Step 1. Cool down every cell a little - for ( uint16_t i = 0; i < NUM_LEDS; i++) { - heat[i] = qsub8( heat[i], random8(0, ((cooling * 10) / NUM_LEDS) + 2)); + for ( uint16_t i = 0; i < NUM_PIXELS; i++) { + heat[i] = qsub8( heat[i], random8(0, ((cooling * 10) / NUM_PIXELS) + 2)); } // Step 2. Heat from each cell drifts 'up' and diffuses a little - for ( uint16_t k = NUM_LEDS - 1; k >= 2; k--) { + for ( uint16_t k = NUM_PIXELS - 1; k >= 2; k--) { heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3; } @@ -1229,7 +1234,7 @@ void heatMap(CRGBPalette16 palette, bool up) } // Step 4. Map from heat cells to LED colors - for ( uint16_t j = 0; j < NUM_LEDS; j++) { + for ( uint16_t j = 0; j < NUM_PIXELS; j++) { // Scale the heat value from 0-255 down to 0-240 // for best results with color palettes. colorindex = scale8(heat[j], 190); @@ -1240,7 +1245,7 @@ void heatMap(CRGBPalette16 palette, bool up) leds[j] = color; } else { - leds[(NUM_LEDS - 1) - j] = color; + leds[(NUM_PIXELS - 1) - j] = color; } } } @@ -1248,18 +1253,12 @@ void heatMap(CRGBPalette16 palette, bool up) void addGlitter( uint8_t chanceOfGlitter) { if ( random8() < chanceOfGlitter) { - leds[ random16(NUM_LEDS) ] += CRGB::White; + leds[ random16(NUM_PIXELS) ] += CRGB::White; } } /////////////////////////////////////////////////////////////////////// -// Forward declarations of an array of cpt-city gradient palettes, and -// a count of how many there are. The actual color palette definitions -// are at the bottom of this file. -extern const TProgmemRGBGradientPalettePtr gGradientPalettes[]; -extern const uint8_t gGradientPaletteCount; - uint8_t beatsaw8( accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, uint32_t timebase = 0, uint8_t phase_offset = 0) { @@ -1271,15 +1270,11 @@ uint8_t beatsaw8( accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest return result; } -void colorWaves() -{ - colorwaves( leds, NUM_LEDS, gCurrentPalette); -} // ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb // This function draws color waves with an ever-changing, // widely-varying set of parameters, using a color palette. -void colorwaves( CRGB* ledarray, uint16_t numleds, CRGBPalette16& palette) +void fillWithColorwaves( CRGB* ledarray, uint16_t numleds, const CRGBPalette16& palette, bool useFibonacciOrder) { static uint16_t sPseudotime = 0; static uint16_t sLastMillis = 0; @@ -1324,17 +1319,220 @@ void colorwaves( CRGB* ledarray, uint16_t numleds, CRGBPalette16& palette) CRGB newcolor = ColorFromPalette( palette, index, bri8); uint16_t pixelnumber = i; +#if IS_FIBONACCI + if (useFibonacciOrder) pixelnumber = fibonacciToPhysical[i]; +#else + (void)useFibonacciOrder; +#endif pixelnumber = (numleds - 1) - pixelnumber; nblend( ledarray[pixelnumber], newcolor, 128); } } +void colorWaves() +{ + fillWithColorwaves( leds, NUM_PIXELS, gCurrentPalette, false); +} +#if IS_FIBONACCI // colorWavesFibonacci() uses fibonacciToPhysical +void colorWavesFibonacci() +{ + fillWithColorwaves( leds, NUM_PIXELS, gCurrentPalette, true); +} +#endif + // Alternate rendering function just scrolls the current palette // across the defined LED strip. void palettetest( CRGB* ledarray, uint16_t numleds, const CRGBPalette16& gCurrentPalette) { static uint8_t startindex = 0; startindex--; - fill_palette( ledarray, numleds, startindex, (256 / NUM_LEDS) + 1, gCurrentPalette, 255, LINEARBLEND); + fill_palette( ledarray, numleds, startindex, (256 / NUM_PIXELS) + 1, gCurrentPalette, 255, LINEARBLEND); +} + +#if IS_FIBONACCI // swirlFibonacci() uses physicalToFibonacci and angles +void swirlFibonacci() { + + const float z = 2.5; // zoom (2.0) + const float w = 3.0; // number of wings (3) + const float p_min = 0.1; const float p_max = 2.0; // puff up (default: 1.0) + const float d_min = 0.1; const float d_max = 2.0; // dent (default: 0.5) + const float s_min = -3.0; const float s_max = 2.0; // swirl (default: -2.0) + const float g_min = 0.1; const float g_max = 0.5; // glow (default: 0.2) + const float b = 240; // inverse brightness (240) + + const float p = p_min + beatsin88(13*speed) / (float)UINT16_MAX * (p_max - p_min); + const float d = d_min + beatsin88(17*speed) / (float)UINT16_MAX * (d_max - d_min); + const float s = s_min + beatsin88(7*speed) / (float)UINT16_MAX * (s_max - s_min); + const float g = g_min + beatsin88(27*speed) / (float)UINT16_MAX * (g_max - g_min); + + CRGBPalette16 palette( gGradientPalettes[1] ); // es_rivendell_15_gp + + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + float r = physicalToFibonacci[i] / 256.0 * z; + float a = (angles[i] + (beat88(3*speed)>>3)) / 256.0 * TWO_PI; + float v = r - p + d * sin(w * a + s * r * r); + float c = 255 - b * pow(fabs(v), g); + if (c < 0) c = 0; + else if (c > 255) c = 255; + + leds[i] = ColorFromPalette(palette, (uint8_t)c); + } +} +#endif + +#if IS_FIBONACCI // fireFibonacci() uses coordsX/coordsY +// TODO: combine with normal fire effect +void fireFibonacci() { + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t x = coordsX[i]; + uint16_t y = coordsY[i]; + + uint8_t n = qsub8( inoise8((x << 2) - beat88(speed << 2), (y << 2)), x ); + + leds[i] = ColorFromPalette(HeatColors_p, n); + } +} +#endif + +#if IS_FIBONACCI // waterFibonacci() uses coordsX/coordsY +// TODO: combine with normal water effect +void waterFibonacci() { + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint16_t x = coordsX[i]; + uint16_t y = coordsY[i]; + + uint8_t n = inoise8((x << 2) + beat88(speed << 2), (y << 4)); + + leds[i] = ColorFromPalette(IceColors_p, n); + } +} +#endif + +#if IS_FIBONACCI // emitterFibonacci() uses angle, antialiasPixelAR() +/** + * Emits arcs of color spreading out from the center to the edge of the disc. + */ +void emitterFibonacci() { + static CRGB ledBuffer[NUM_PIXELS]; // buffer for better fade behavior + const uint8_t dAngle = 32; // angular span of the traces + const uint8_t dRadius = 12; // radial width of the traces + const uint8_t vSpeed = 16; // max speed variation + + + static const uint8_t eCount = 7; // Number of simultanious traces + static uint8_t angle[eCount]; // individual trace angles + static uint16_t timeOffset[eCount]; // individual offsets from beat8() function + static uint8_t speedOffset[eCount]; // individual speed offsets limited by vSpeed + static uint8_t sparkIdx = 0; // randomizer cycles through traces to spark new ones + + // spark new trace + EVERY_N_MILLIS(20) { + if (random8(17) <= (speed >> 4)) { // increase change rate for higher speeds + angle[sparkIdx] = random8(); + speedOffset[sparkIdx] = random8(vSpeed); // individual speed variation + timeOffset[sparkIdx] = beat8(qadd8(speed,speedOffset[sparkIdx])); + sparkIdx = addmod8(sparkIdx, 1, eCount); // continue randomizer at next spark + } + } + + // fade traces + fadeToBlackBy( ledBuffer, NUM_PIXELS, 6 + (speed >> 3)); + + // draw traces + for (uint8_t e = 0; e < eCount; e++) { + uint8_t startRadius = sub8(beat8(qadd8(speed, speedOffset[e])), timeOffset[e]); + uint8_t endRadius = add8(startRadius, dRadius + (speed>>5)); // increase radial width for higher speeds + antialiasPixelAR(angle[e], dAngle, startRadius, endRadius, ColorFromPalette(gCurrentPalette, startRadius), ledBuffer); + } + + // copy buffer to actual strip + memcpy(leds, ledBuffer, sizeof(ledBuffer[0])*NUM_PIXELS); +} +#endif + +void wheel() { + for (uint16_t i = 0; i < NUM_PIXELS; i++) { + uint8_t j = beat8(speed); + uint8_t hue = i + j; + leds[i] = CHSV(hue, 255, 255); + } } + + +#if (PARALLEL_OUTPUT_CHANNELS > 1) + +void multi_test() { + static bool debug = true; + const uint8_t step = (256 / PARALLEL_OUTPUT_CHANNELS); + + if (debug) { + Serial.print("step: "); + Serial.println(step); + } + + static_assert(PARALLEL_OUTPUT_CHANNELS <= 6, ""); + for (uint8_t strip = 0; strip < PARALLEL_OUTPUT_CHANNELS; strip++) { + uint16_t pixelOffset; + uint16_t pixelCount; + if (strip == 0) { + pixelOffset = LedOffset<1>(); // uses one-based indices... sigh. + pixelCount = LedCount<1>(); // uses one-based indices... sigh. + } +#if (PARALLEL_OUTPUT_CHANNELS >= 2) + else if (strip == 1) { + pixelOffset = LedOffset<2>(); // uses one-based indices... sigh. + pixelCount = LedCount<2>(); // uses one-based indices... sigh. + } +#endif +#if (PARALLEL_OUTPUT_CHANNELS >= 3) + else if (strip == 2) { + pixelOffset = LedOffset<3>(); // uses one-based indices... sigh. + pixelCount = LedCount<3>(); // uses one-based indices... sigh. + } +#endif +#if (PARALLEL_OUTPUT_CHANNELS >= 4) + else if (strip == 3) { + pixelOffset = LedOffset<4>(); // uses one-based indices... sigh. + pixelCount = LedCount<4>(); // uses one-based indices... sigh. + } +#endif +#if (PARALLEL_OUTPUT_CHANNELS > 5) + else if (strip == 4) { + pixelOffset = LedOffset<5>(); // uses one-based indices... sigh. + pixelCount = LedCount<5>(); // uses one-based indices... sigh. + } +#endif +#if (PARALLEL_OUTPUT_CHANNELS > 6) + else if (strip == 5) { + pixelOffset = LedOffset<6>(); // uses one-based indices... sigh. + pixelCount = LedCount<6>(); // uses one-based indices... sigh. + } +#endif + else { + break; + } + + uint8_t hue = gHue + strip * step; + CHSV c = CHSV(hue, 255, 255); + + if (debug) { + Serial.print("hue: "); + Serial.println(hue); + } + + for (uint16_t i = 0; i < pixelCount; i++) { + uint16_t j = i + pixelOffset; + leds[j] = c; + + if (debug) { + Serial.print("j: "); + Serial.println(j); + } + } + } + + debug = false; +} +#endif + diff --git a/esp8266-fastled-webserver/include/FSBrowser.hpp b/esp8266-fastled-webserver/include/FSBrowser.hpp new file mode 100644 index 00000000..7fc021b1 --- /dev/null +++ b/esp8266-fastled-webserver/include/FSBrowser.hpp @@ -0,0 +1,18 @@ +#pragma once +#if !defined(FS_BROWSER_HPP) +#define FS_BROWSER_HPP + + +//holds the current upload +extern File fsUploadFile; + +//format bytes +String formatBytes(size_t bytes); +String getContentType(String filename); +bool handleFileRead(String path); +void handleFileUpload(); +void handleFileDelete(); +void handleFileCreate(); +void handleFileList(); + +#endif \ No newline at end of file diff --git a/esp8266-fastled-webserver/include/Fields.hpp b/esp8266-fastled-webserver/include/Fields.hpp new file mode 100644 index 00000000..e0e2ff8a --- /dev/null +++ b/esp8266-fastled-webserver/include/Fields.hpp @@ -0,0 +1,33 @@ +/* + ESP8266 + FastLED + IR Remote: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) 2016 Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once +#if !defined(FIELDS_HPP) +#define FIELDS_HPP + +extern uint8_t power; +extern uint8_t brightness; + +void setShowClock(uint8_t value); +void setClockBackgroundFade(uint8_t value); + +String getFieldValue(String name); +String setFieldValue(String name, String value); +String getFieldsJson(); + + +#endif diff --git a/esp8266-fastled-webserver/include/GradientPalettes.hpp b/esp8266-fastled-webserver/include/GradientPalettes.hpp new file mode 100644 index 00000000..13afb31a --- /dev/null +++ b/esp8266-fastled-webserver/include/GradientPalettes.hpp @@ -0,0 +1,39 @@ +#pragma once +#if !defined(GRADIENT_PALETTES_HPP) +#define GRADIENT_PALETTES_HPP + +DECLARE_GRADIENT_PALETTE( ib_jul01_gp ); +DECLARE_GRADIENT_PALETTE( es_vintage_57_gp ); +DECLARE_GRADIENT_PALETTE( es_vintage_01_gp ); +DECLARE_GRADIENT_PALETTE( es_rivendell_15_gp ); +DECLARE_GRADIENT_PALETTE( rgi_15_gp ); +DECLARE_GRADIENT_PALETTE( retro2_16_gp ); +DECLARE_GRADIENT_PALETTE( Analogous_1_gp ); +DECLARE_GRADIENT_PALETTE( es_pinksplash_08_gp ); +DECLARE_GRADIENT_PALETTE( es_pinksplash_07_gp ); +DECLARE_GRADIENT_PALETTE( Coral_reef_gp ); +DECLARE_GRADIENT_PALETTE( es_ocean_breeze_068_gp ); +DECLARE_GRADIENT_PALETTE( es_ocean_breeze_036_gp ); +DECLARE_GRADIENT_PALETTE( departure_gp ); +DECLARE_GRADIENT_PALETTE( es_landscape_64_gp ); +DECLARE_GRADIENT_PALETTE( es_landscape_33_gp ); +DECLARE_GRADIENT_PALETTE( rainbowsherbet_gp ); +DECLARE_GRADIENT_PALETTE( gr65_hult_gp ); +DECLARE_GRADIENT_PALETTE( gr64_hult_gp ); +DECLARE_GRADIENT_PALETTE( GMT_drywet_gp ); +DECLARE_GRADIENT_PALETTE( ib15_gp ); +DECLARE_GRADIENT_PALETTE( Fuschia_7_gp ); +DECLARE_GRADIENT_PALETTE( es_emerald_dragon_08_gp ); +DECLARE_GRADIENT_PALETTE( lava_gp ); +DECLARE_GRADIENT_PALETTE( fire_gp ); +DECLARE_GRADIENT_PALETTE( Colorfull_gp ); +DECLARE_GRADIENT_PALETTE( Magenta_Evening_gp ); +DECLARE_GRADIENT_PALETTE( Pink_Purple_gp ); +DECLARE_GRADIENT_PALETTE( Sunset_Real_gp ); +DECLARE_GRADIENT_PALETTE( es_autumn_19_gp ); +DECLARE_GRADIENT_PALETTE( BlacK_Blue_Magenta_White_gp ); +DECLARE_GRADIENT_PALETTE( BlacK_Magenta_Red_gp ); +DECLARE_GRADIENT_PALETTE( BlacK_Red_Magenta_Yellow_gp ); +DECLARE_GRADIENT_PALETTE( Blue_Cyan_Yellow_gp ); + +#endif diff --git a/esp8266-fastled-webserver/include/configs/controller/controller_esp32.h b/esp8266-fastled-webserver/include/configs/controller/controller_esp32.h new file mode 100644 index 00000000..246ee964 --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/controller/controller_esp32.h @@ -0,0 +1,59 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_CONTROLLER_ESP32_H) +#define ESP8266_FASTLED_WEBSERVER_CONTROLLER_ESP32_H + + +static_assert(PARALLEL_OUTPUT_CHANNELS <= 4, "ESP32 only has support for four parallel outputs defined, can be updated to support 16 outputs"); + +// TODO: consider using I2S (instead of RMT) on the ESP32: +// +// #define FASTLED_ESP32_I2S true +// +// See https://github.com/FastLED/FastLED/issues/1220#issuecomment-822677011 + +#define DATA_PIN + +#if !defined(DATA_PIN) + #if PARALLEL_OUTPUT_CHANNELS == 1 + #define DATA_PIN 18 // d1 mini32 (same physical location as D5 on the d1 mini) + #else + #define DATA_PIN 23 // d1 mini32 (same physical location as D7 on the d1 mini) + #endif +#endif + +#if !defined(DATA_PIN_2) && PARALLEL_OUTPUT_CHANNELS >= 2 + #define DATA_PIN_2 19 // d1 mini32 (same physical location as D6 on the d1 mini) +#endif +#if !defined(DATA_PIN_3) && PARALLEL_OUTPUT_CHANNELS >= 3 + #define DATA_PIN_3 5 // d1 mini32 (same physical location as D8 on the d1 mini) +#endif +#if !defined(DATA_PIN_4) && PARALLEL_OUTPUT_CHANNELS >= 4 + #define DATA_PIN_4 18 // d1 mini32 (same physical location as D5 on the d1 mini) +#endif + + + +#if defined(ENABLE_IR) && !defined(IR_RECV_PIN) + // Default pin for ESP32 is 16 (for d1 mini32, this is the same physical location as D4 on the d1 mini) + #define IR_RECV_PIN 16 // TODO: VERIFY THIS IS CORRECT VALUE +#endif + +#endif // ESP8266_FASTLED_WEBSERVER_CONTROLLER_ESP32_H diff --git a/esp8266-fastled-webserver/include/configs/controller/controller_esp8266.h b/esp8266-fastled-webserver/include/configs/controller/controller_esp8266.h new file mode 100644 index 00000000..9ac16079 --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/controller/controller_esp8266.h @@ -0,0 +1,56 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_CONTROLLER_ESP8266_H) +#define ESP8266_FASTLED_WEBSERVER_CONTROLLER_ESP8266_H + +static_assert(PARALLEL_OUTPUT_CHANNELS <= 6, "ESP8266 only supports six parallel outputs"); + +#if !defined(DATA_PIN) + #if PARALLEL_OUTPUT_CHANNELS == 1 + #define DATA_PIN D5 // d1 mini + #else + #define DATA_PIN D7 // Fib512 uses different default for primary output pin + #endif +#endif + +#if !defined(DATA_PIN_2) && PARALLEL_OUTPUT_CHANNELS >= 2 + #define DATA_PIN_2 D6 // d1 mini +#endif +#if !defined(DATA_PIN_3) && PARALLEL_OUTPUT_CHANNELS >= 3 + #define DATA_PIN_3 D8 // d1 mini +#endif +#if !defined(DATA_PIN_4) && PARALLEL_OUTPUT_CHANNELS >= 4 + #define DATA_PIN_4 D5 // d1 mini +#endif +#if !defined(DATA_PIN_5) && PARALLEL_OUTPUT_CHANNELS >= 5 + #define DATA_PIN_5 D1 // d1 mini +#endif +#if !defined(DATA_PIN_6) && PARALLEL_OUTPUT_CHANNELS >= 6 + #define DATA_PIN_6 D2 // d1 mini +#endif + +#if defined(ENABLE_IR) && !defined(IR_RECV_PIN) + #define IR_RECV_PIN D4 +#endif + + +#define FASTLED_INTERRUPT_RETRY_COUNT 0 + +#endif // ESP8266_FASTLED_WEBSERVER_CONTROLLER_ESP8266_H diff --git a/esp8266-fastled-webserver/include/configs/controller/controller_template.h b/esp8266-fastled-webserver/include/configs/controller/controller_template.h new file mode 100644 index 00000000..a658e2db --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/controller/controller_template.h @@ -0,0 +1,45 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_CONTROLLER_TEMPLATE_H) +#define ESP8266_FASTLED_WEBSERVER_CONTROLLER_TEMPLATE_H + +// This header file describes the configuration for specific controllers +// (e.g., ESP8266, ESP32, Adafruit QT Py, etc.) + +// The only MANDATORY setting is DATA_PIN. + + +// The DATA_PIN defines the MCU's pin that is used to control the pixels +#define DATA_PIN D5 // d1 mini +// #define DATA_PIN 18 // d1 mini32 (same physical location as D5 on the d1 mini) + +// TODO: enable SPI-based chipsets based on whether CLOCK_PIN is defined? + +// FastLED configurations that may need to change, depending on the controller in use... +// #define FASTLED_ALLOW_INTERRUPTS 1 +// #define INTERRUPT_THRESHOLD 1 +#define FASTLED_INTERRUPT_RETRY_COUNT 0 + +// ENABLE_IR defines whether to include support for an IR receiver +// #define ENABLE_IR +// #define IR_RECV_PIN D4 // d1 mini +// #define IR_RECV_PIN 16 // d1 mini32 (same physical location as D4 on the d1 mini) + +#endif // ESP8266_FASTLED_WEBSERVER_CONTROLLER_TEMPLATE_H diff --git a/esp8266-fastled-webserver/include/configs/product/1628rings.h b/esp8266-fastled-webserver/include/configs/product/1628rings.h new file mode 100644 index 00000000..af3b02d4 --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/product/1628rings.h @@ -0,0 +1,73 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_PRODUCT_1628RINGS_H) +#define ESP8266_FASTLED_WEBSERVER_PRODUCT_1628RINGS_H + +#if !defined(LED_TYPE) + #define LED_TYPE WS2812B +#endif +#if !defined(COLOR_ORDER) + #define COLOR_ORDER GRB +#endif +#if !defined(NUM_PIXELS) + #define NUM_PIXELS 1628 +#endif +#if !defined(AVAILABLE_MILLI_AMPS) + #define AVAILABLE_MILLI_AMPS 2000 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) +#endif +#if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #define MAX_MILLI_AMPS_PER_PIXEL 60 // IMPORTANT: set to larger value if necessary +#endif +#if !defined(FRAMES_PER_SECOND) + #define FRAMES_PER_SECOND 1000 // No enforced delay? +#endif +#if !defined(DEFAULT_PATTERN_INDEX) + #define DEFAULT_PATTERN_INDEX 0 +#endif +#if !defined(DEFAULT_BRIGHTNESS_INDEX) + #define DEFAULT_BRIGHTNESS_INDEX 0 +#endif +#if !defined(DEFAULT_COLOR_CORRECTION) + #define DEFAULT_COLOR_CORRECTION UncorrectedColor // 1628-Rings did not specify; This is FastLED default +#endif +#if !defined(NAME_PREFIX) + #define NAME_PREFIX "ESP8266-" +#endif +#if !defined(PRODUCT_FRIENDLY_NAME) + #define PRODUCT_FRIENDLY_NAME "ESP8266 FastLED Webserver" +#endif +#if !defined(IS_FIBONACCI) + #define IS_FIBONACCI 0 +#endif +#if !defined(HAS_COORDINATE_MAP) + #define HAS_COORDINATE_MAP 1 +#endif +// TODO: combine HAS_POLAR_COORDS with HAS_COORDINATE_MAP +#if !defined(HAS_POLAR_COORDS) + #define HAS_POLAR_COORDS 1 +#endif +#if !defined(PARALLEL_OUTPUT_CHANNELS) // WARNING: Refresh rate for 1628 pixels over single output is ~15 frames / second MAXIMUM.... + #define PARALLEL_OUTPUT_CHANNELS 1 +#endif + + + + +#endif // ESP8266_FASTLED_WEBSERVER_PRODUCT_1628RINGS_H diff --git a/esp8266-fastled-webserver/include/configs/product/default.h b/esp8266-fastled-webserver/include/configs/product/default.h new file mode 100644 index 00000000..abef6778 --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/product/default.h @@ -0,0 +1,72 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_PRODUCT_DEFAULT_H) +#define ESP8266_FASTLED_WEBSERVER_PRODUCT_DEFAULT_H + +#if !defined(LED_TYPE) + #define LED_TYPE WS2811 +#endif +#if !defined(COLOR_ORDER) + #define COLOR_ORDER RGB +#endif +#if !defined(NUM_PIXELS) + #define NUM_PIXELS 200 +#endif +#if !defined(AVAILABLE_MILLI_AMPS) + #define AVAILABLE_MILLI_AMPS 2000 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) +#endif +#if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #define MAX_MILLI_AMPS_PER_PIXEL 60 // IMPORTANT: set to larger value if necessary +#endif +#if !defined(FRAMES_PER_SECOND) + #define FRAMES_PER_SECOND 120 +#endif +#if !defined(DEFAULT_PATTERN_INDEX) + #define DEFAULT_PATTERN_INDEX 0 +#endif +#if !defined(DEFAULT_BRIGHTNESS_INDEX) + #define DEFAULT_BRIGHTNESS_INDEX 3 +#endif +#if !defined(DEFAULT_COLOR_CORRECTION) + #define DEFAULT_COLOR_CORRECTION TypicalLEDStrip +#endif +#if !defined(NAME_PREFIX) + #define NAME_PREFIX "ESP8266-" +#endif +#if !defined(PRODUCT_FRIENDLY_NAME) + #define PRODUCT_FRIENDLY_NAME "ESP8266 + FastLED" +#endif +#if !defined(IS_FIBONACCI) + #define IS_FIBONACCI 0 +#endif +#if !defined(HAS_COORDINATE_MAP) + #define HAS_COORDINATE_MAP 0 +#endif +#if !defined(HAS_POLAR_COORDS) + #define HAS_POLAR_COORDS 0 +#endif +#if !defined(PARALLEL_OUTPUT_CHANNELS) + #define PARALLEL_OUTPUT_CHANNELS 1 +#endif + + + + +#endif // ESP8266_FASTLED_WEBSERVER_PRODUCT_DEFAULT_H diff --git a/esp8266-fastled-webserver/include/configs/product/esp8266_thing.h b/esp8266-fastled-webserver/include/configs/product/esp8266_thing.h new file mode 100644 index 00000000..4b9399fe --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/product/esp8266_thing.h @@ -0,0 +1,121 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_PRODUCT_ESP8266_THING_H) +#define ESP8266_FASTLED_WEBSERVER_PRODUCT_ESP8266_THING_H + +#if !defined(ARDUINO_ARCH_ESP8266) + #error "ESP8266 Thing currently only supports ESP8266" +#endif + + +#if !defined(LED_TYPE) + #define LED_TYPE WS2811 +#endif +#if !defined(COLOR_ORDER) + #define COLOR_ORDER RGB +#endif +#if !defined(NUM_PIXELS) + #define NUM_PIXELS 300 +#endif +#if !defined(AVAILABLE_MILLI_AMPS) + #define AVAILABLE_MILLI_AMPS 10000 // !!! 10Amps !!! Verify your power supply !!! IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) +#endif +#if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #define MAX_MILLI_AMPS_PER_PIXEL 60 // IMPORTANT: set to larger value if necessary +#endif +#if !defined(FRAMES_PER_SECOND) + #define FRAMES_PER_SECOND 120 +#endif +#if !defined(DEFAULT_PATTERN_INDEX) + #define DEFAULT_PATTERN_INDEX 3 +#endif +#if !defined(DEFAULT_BRIGHTNESS_INDEX) + #define DEFAULT_BRIGHTNESS_INDEX 0 +#endif +#if !defined(DEFAULT_COLOR_CORRECTION) + #define DEFAULT_COLOR_CORRECTION TypicalLEDStrip +#endif +#if !defined(NAME_PREFIX) + #define NAME_PREFIX "ESP8266-" +#endif +#if !defined(PRODUCT_FRIENDLY_NAME) + #define PRODUCT_FRIENDLY_NAME "ESP8266 Thing" +#endif +#if !defined(IS_FIBONACCI) + #define IS_FIBONACCI 0 +#endif +#if !defined(HAS_COORDINATE_MAP) + #define HAS_COORDINATE_MAP 0 +#endif +#if !defined(HAS_POLAR_COORDS) + #define HAS_POLAR_COORDS 0 +#endif +#if !defined(PARALLEL_OUTPUT_CHANNELS) + #define PARALLEL_OUTPUT_CHANNELS 6 +#endif +#if !defined(PIXELS_ON_DATA_PIN_1) + #define PIXELS_ON_DATA_PIN_1 50 +#endif +#if !defined(PIXELS_ON_DATA_PIN_2) + #define PIXELS_ON_DATA_PIN_2 50 +#endif +#if !defined(PIXELS_ON_DATA_PIN_3) + #define PIXELS_ON_DATA_PIN_3 50 +#endif +#if !defined(PIXELS_ON_DATA_PIN_4) + #define PIXELS_ON_DATA_PIN_4 50 +#endif +#if !defined(PIXELS_ON_DATA_PIN_5) + #define PIXELS_ON_DATA_PIN_5 50 +#endif +#if !defined(PIXELS_ON_DATA_PIN_6) + #define PIXELS_ON_DATA_PIN_6 50 +#endif + +#if defined(ARDUINO_ARCH_ESP8266) + // This board uses different data pins.... + #if !defined(DATA_PIN) + #define DATA_PIN D1 // d1 mini + #endif + #if !defined(DATA_PIN_2) && PARALLEL_OUTPUT_CHANNELS >= 2 + #define DATA_PIN_2 D2 // d1 mini + #endif + #if !defined(DATA_PIN_3) && PARALLEL_OUTPUT_CHANNELS >= 3 + #define DATA_PIN_3 D5 // d1 mini + #endif + #if !defined(DATA_PIN_4) && PARALLEL_OUTPUT_CHANNELS >= 4 + #define DATA_PIN_4 D6 // d1 mini + #endif + #if !defined(DATA_PIN_5) && PARALLEL_OUTPUT_CHANNELS >= 5 + #define DATA_PIN_5 D7 // d1 mini + #endif + #if !defined(DATA_PIN_6) && PARALLEL_OUTPUT_CHANNELS >= 6 + #define DATA_PIN_6 D8 // d1 mini + #endif +#elif defined(ARDUINO_ARCH_ESP32) + #error "ESP8266 Thing currently only supports ESP8266" +#else + #error "ESP8266 Thing currently only supports ESP8266" +#endif + + + + +#endif // ESP8266_FASTLED_WEBSERVER_PRODUCT_ESP8266_THING_H diff --git a/esp8266-fastled-webserver/include/configs/product/fibonacci128.h b/esp8266-fastled-webserver/include/configs/product/fibonacci128.h new file mode 100644 index 00000000..923f8c1a --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/product/fibonacci128.h @@ -0,0 +1,70 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB128_H) +#define ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB128_H + +#if !defined(LED_TYPE) + #define LED_TYPE WS2812B +#endif +#if !defined(COLOR_ORDER) + #define COLOR_ORDER GRB +#endif +#if !defined(NUM_PIXELS) + #define NUM_PIXELS 128 +#endif +#if !defined(AVAILABLE_MILLI_AMPS) + #define AVAILABLE_MILLI_AMPS 1400 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) +#endif +#if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #define MAX_MILLI_AMPS_PER_PIXEL 60 // IMPORTANT: set to larger value if necessary +#endif +#if !defined(FRAMES_PER_SECOND) + #define FRAMES_PER_SECOND 120 +#endif +#if !defined(DEFAULT_PATTERN_INDEX) + #define DEFAULT_PATTERN_INDEX 3 +#endif +#if !defined(DEFAULT_BRIGHTNESS_INDEX) + #define DEFAULT_BRIGHTNESS_INDEX 2 +#endif +#if !defined(DEFAULT_COLOR_CORRECTION) + #define DEFAULT_COLOR_CORRECTION TypicalSMD5050 +#endif +#if !defined(NAME_PREFIX) + #define NAME_PREFIX "Fibonacci128-" +#endif +#if !defined(PRODUCT_FRIENDLY_NAME) + #define PRODUCT_FRIENDLY_NAME "Fibonacci128" +#endif +#if !defined(IS_FIBONACCI) + #define IS_FIBONACCI 1 +#endif +#if !defined(HAS_COORDINATE_MAP) + #define HAS_COORDINATE_MAP 1 +#endif +#if !defined(HAS_POLAR_COORDS) + #define HAS_POLAR_COORDS 0 +#endif +#if !defined(PARALLEL_OUTPUT_CHANNELS) + #define PARALLEL_OUTPUT_CHANNELS 1 +#endif + + +#endif // ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB128_H diff --git a/esp8266-fastled-webserver/include/configs/product/fibonacci256.h b/esp8266-fastled-webserver/include/configs/product/fibonacci256.h new file mode 100644 index 00000000..488dc8b2 --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/product/fibonacci256.h @@ -0,0 +1,72 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB256_H) +#define ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB256_H + +#if !defined(LED_TYPE) + #define LED_TYPE WS2812B +#endif +#if !defined(COLOR_ORDER) + #define COLOR_ORDER GRB +#endif +#if !defined(NUM_PIXELS) + #define NUM_PIXELS 256 +#endif +#if !defined(AVAILABLE_MILLI_AMPS) + #define AVAILABLE_MILLI_AMPS 1600 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) +#endif +#if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #define MAX_MILLI_AMPS_PER_PIXEL 12 // IMPORTANT: set to larger value if necessary +#endif +#if !defined(FRAMES_PER_SECOND) + #define FRAMES_PER_SECOND 120 +#endif +#if !defined(DEFAULT_PATTERN_INDEX) + #define DEFAULT_PATTERN_INDEX 3 +#endif +#if !defined(DEFAULT_BRIGHTNESS_INDEX) + #define DEFAULT_BRIGHTNESS_INDEX 3 +#endif +#if !defined(DEFAULT_COLOR_CORRECTION) + #define DEFAULT_COLOR_CORRECTION TypicalSMD5050 +#endif +#if !defined(NAME_PREFIX) + #define NAME_PREFIX "Fibonacci256-" +#endif +#if !defined(PRODUCT_FRIENDLY_NAME) + #define PRODUCT_FRIENDLY_NAME "Fibonacci256" +#endif +#if !defined(IS_FIBONACCI) + #define IS_FIBONACCI 1 +#endif +#if !defined(HAS_COORDINATE_MAP) + #define HAS_COORDINATE_MAP 1 +#endif +#if !defined(HAS_POLAR_COORDS) + #define HAS_POLAR_COORDS 0 +#endif +#if !defined(PARALLEL_OUTPUT_CHANNELS) + #define PARALLEL_OUTPUT_CHANNELS 1 +#endif + + + + +#endif // ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB256_H diff --git a/esp8266-fastled-webserver/include/configs/product/fibonacci32.h b/esp8266-fastled-webserver/include/configs/product/fibonacci32.h new file mode 100644 index 00000000..d3415998 --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/product/fibonacci32.h @@ -0,0 +1,70 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB32_H) +#define ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB32_H + +#if !defined(LED_TYPE) + #define LED_TYPE WS2812B +#endif +#if !defined(COLOR_ORDER) + #define COLOR_ORDER GRB +#endif +#if !defined(NUM_PIXELS) + #define NUM_PIXELS 34 // !!! Two free pixels! :) +#endif +#if !defined(AVAILABLE_MILLI_AMPS) + #define AVAILABLE_MILLI_AMPS 2000 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) +#endif +#if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #define MAX_MILLI_AMPS_PER_PIXEL 60 // IMPORTANT: set to larger value if necessary +#endif +#if !defined(FRAMES_PER_SECOND) + #define FRAMES_PER_SECOND 120 +#endif +#if !defined(DEFAULT_PATTERN_INDEX) + #define DEFAULT_PATTERN_INDEX 0 +#endif +#if !defined(DEFAULT_BRIGHTNESS_INDEX) + #define DEFAULT_BRIGHTNESS_INDEX 0 // very low brightness by default for this board! +#endif +#if !defined(DEFAULT_COLOR_CORRECTION) + #define DEFAULT_COLOR_CORRECTION TypicalSMD5050 +#endif +#if !defined(NAME_PREFIX) + #define NAME_PREFIX "Fibonacci32-" +#endif +#if !defined(PRODUCT_FRIENDLY_NAME) + #define PRODUCT_FRIENDLY_NAME "Fibonacci32" +#endif +#if !defined(IS_FIBONACCI) + #define IS_FIBONACCI 1 +#endif +#if !defined(HAS_COORDINATE_MAP) + #define HAS_COORDINATE_MAP 1 +#endif +#if !defined(HAS_POLAR_COORDS) + #define HAS_POLAR_COORDS 0 +#endif +#if !defined(PARALLEL_OUTPUT_CHANNELS) + #define PARALLEL_OUTPUT_CHANNELS 1 +#endif + + +#endif // ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB32_H diff --git a/esp8266-fastled-webserver/include/configs/product/fibonacci512.h b/esp8266-fastled-webserver/include/configs/product/fibonacci512.h new file mode 100644 index 00000000..e72f204b --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/product/fibonacci512.h @@ -0,0 +1,82 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB512_MINI_H) +#define ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB512_MINI_H + +#if !defined(LED_TYPE) + #define LED_TYPE WS2812B +#endif +#if !defined(COLOR_ORDER) + #define COLOR_ORDER GRB +#endif +#if !defined(NUM_PIXELS) + #define NUM_PIXELS 512 +#endif +#if !defined(AVAILABLE_MILLI_AMPS) + #define AVAILABLE_MILLI_AMPS 2000 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) +#endif +#if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #define MAX_MILLI_AMPS_PER_PIXEL 48 // IMPORTANT: set to larger value if necessary +#endif +#if !defined(FRAMES_PER_SECOND) + #define FRAMES_PER_SECOND 120 +#endif +#if !defined(DEFAULT_PATTERN_INDEX) + #define DEFAULT_PATTERN_INDEX 3 +#endif +#if !defined(DEFAULT_BRIGHTNESS_INDEX) + #define DEFAULT_BRIGHTNESS_INDEX 3 +#endif +#if !defined(DEFAULT_COLOR_CORRECTION) + #define DEFAULT_COLOR_CORRECTION TypicalSMD5050 +#endif +#if !defined(NAME_PREFIX) + #define NAME_PREFIX "Fibonacci512-" +#endif +#if !defined(PRODUCT_FRIENDLY_NAME) + #define PRODUCT_FRIENDLY_NAME "Fibonacci512" +#endif +#if !defined(IS_FIBONACCI) + #define IS_FIBONACCI 1 +#endif +#if !defined(HAS_COORDINATE_MAP) + #define HAS_COORDINATE_MAP 1 +#endif +#if !defined(HAS_POLAR_COORDS) + #define HAS_POLAR_COORDS 0 +#endif +#if !defined(PARALLEL_OUTPUT_CHANNELS) + #define PARALLEL_OUTPUT_CHANNELS 4 +#endif +#if !defined(PIXELS_ON_DATA_PIN_1) + #define PIXELS_ON_DATA_PIN_1 121 +#endif +#if !defined(PIXELS_ON_DATA_PIN_2) + #define PIXELS_ON_DATA_PIN_2 120 +#endif +#if !defined(PIXELS_ON_DATA_PIN_3) + #define PIXELS_ON_DATA_PIN_3 121 +#endif +#if !defined(PIXELS_ON_DATA_PIN_4) + #define PIXELS_ON_DATA_PIN_4 150 +#endif + + +#endif // ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB512_MINI_H diff --git a/esp8266-fastled-webserver/include/configs/product/fibonacci64.h b/esp8266-fastled-webserver/include/configs/product/fibonacci64.h new file mode 100644 index 00000000..89dd1715 --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/product/fibonacci64.h @@ -0,0 +1,117 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB64_H) +#define ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB64_H + +// FIBONACCI64 comes in multiple variants: +// Full (86mm) ==> ESP8266, WS2812B-5050 == ~60mA / pixel, no touch support built-in +// https://www.tindie.com/products/jasoncoon/fibonacci64-86mm-disc-with-64-ws2812b-rgb-leds/ +// +// Mini (64mm) ==> ESP8266, WS2812B-3535 == ~??mA / pixel, no touch support built-in +// https://www.tindie.com/products/jasoncoon/fibonacci64-mini-64mm-disc-with-64-rgb-leds/ +// + +// TODO: Enable Micro and Nano, which have no WiFi and use SAMD21E... +// Micro (40mm) ==> QT Py, WS2812C-2020 == ~5mA / pixel +// Nano (33mm) ==> QT Py, SK6805-EC15 == ~5mA / pixel +// +// https://www.tindie.com/products/jasoncoon/fibonacci64-micro-40mm-disc-with-64-rgb-leds/ +// https://github.com/jasoncoon/fibonacci64-touch-demo +// +// https://www.tindie.com/products/jasoncoon/fibonacci64-nano-33mm-disc-with-64-rgb-leds/ +// https://github.com/jasoncoon/fibonacci64-nano-touch-demo +// +// NOTE: code sets to use WS2812B timings, even on Nano (SK6805 timings differ from WS2812B) +// NOTE: QT Py data pin A10, brightness 32 +// NOTE: QT Py touch pins: +// Micro: A0, A1, A2, A3 +// Nano: A0, A1, A2 +// + +#if defined(PRODUCT_FIBONACCI64_MICRO) || defined(PRODUCT_FIBONACCI64_NANO) + #error "The Fibonacci64 micro and nano are not yet supported." +#endif + +#if !defined(LED_TYPE) + #if defined(PRODUCT_FIBONACCI64_NANO) + #define LED_TYPE SK6812 + #else + #define LED_TYPE WS2812B + #endif +#endif +#if !defined(COLOR_ORDER) + #define COLOR_ORDER GRB +#endif +#if !defined(NUM_PIXELS) + #define NUM_PIXELS 64 +#endif +#if !defined(AVAILABLE_MILLI_AMPS) + #define AVAILABLE_MILLI_AMPS 1400 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) +#endif +#if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #if defined(PRODUCT_FIBONACCI64_MICRO) || defined(PRODUCT_FIBONACCI64_NANO) + #define MAX_MILLI_AMPS_PER_PIXEL 5 // IMPORTANT: set to larger value if necessary + #else + #define MAX_MILLI_AMPS_PER_PIXEL 60 // IMPORTANT: set to larger value if necessary + #endif +#endif +#if !defined(FRAMES_PER_SECOND) + #define FRAMES_PER_SECOND 120 +#endif +#if !defined(DEFAULT_PATTERN_INDEX) + #define DEFAULT_PATTERN_INDEX 3 +#endif +#if !defined(DEFAULT_BRIGHTNESS_INDEX) + #define DEFAULT_BRIGHTNESS_INDEX 3 +#endif +#if !defined(DEFAULT_COLOR_CORRECTION) + #define DEFAULT_COLOR_CORRECTION TypicalSMD5050 +#endif +#if !defined(NAME_PREFIX) + #define NAME_PREFIX "Fibonacci64-" +#endif +#if !defined(PRODUCT_FRIENDLY_NAME) + + #if defined(PRODUCT_FIBONACCI64_FULL) + #define PRODUCT_FRIENDLY_NAME "Fibonacci64" + #elif defined(PRODUCT_FIBONACCI64_MINI) + #define PRODUCT_FRIENDLY_NAME "Fibonacci64 Mini" + #elif defined(PRODUCT_FIBONACCI64_MICRO) + #define PRODUCT_FRIENDLY_NAME "Fibonacci64 Micro" + #elif defined(PRODUCT_FIBONACCI64_NANO) + #define PRODUCT_FRIENDLY_NAME "Fibonacci64 Nano" + #endif + +#endif +#if !defined(IS_FIBONACCI) + #define IS_FIBONACCI 1 +#endif +#if !defined(HAS_COORDINATE_MAP) + #define HAS_COORDINATE_MAP 1 +#endif +#if !defined(HAS_POLAR_COORDS) + #define HAS_POLAR_COORDS 0 +#endif +#if !defined(PARALLEL_OUTPUT_CHANNELS) + #define PARALLEL_OUTPUT_CHANNELS 1 +#endif + + +#endif // ESP8266_FASTLED_WEBSERVER_PRODUCT_FIB64_H diff --git a/esp8266-fastled-webserver/include/configs/product/kraken64.h b/esp8266-fastled-webserver/include/configs/product/kraken64.h new file mode 100644 index 00000000..9a3d9b20 --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/product/kraken64.h @@ -0,0 +1,95 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#if !defined(ESP8266_FASTLED_WEBSERVER_PRODUCT_KRAKEN64_H) +#define ESP8266_FASTLED_WEBSERVER_PRODUCT_KRAKEN64_H + +// FIBONACCI64 comes in multiple variants: +// Full (86mm) ==> ESP8266, WS2812B-5050 == ~60mA / pixel, no touch support built-in +// https://www.tindie.com/products/jasoncoon/fibonacci64-86mm-disc-with-64-ws2812b-rgb-leds/ +// +// Mini (64mm) ==> ESP8266, WS2812B-3535 == ~??mA / pixel, no touch support built-in +// https://www.tindie.com/products/jasoncoon/fibonacci64-mini-64mm-disc-with-64-rgb-leds/ +// + +// TODO: Enable Micro and Nano, which have no WiFi and use SAMD21E... +// Micro (40mm) ==> QT Py, WS2812C-2020 == ~5mA / pixel +// Nano (33mm) ==> QT Py, SK6805-EC15 == ~5mA / pixel +// +// https://www.tindie.com/products/jasoncoon/fibonacci64-micro-40mm-disc-with-64-rgb-leds/ +// https://github.com/jasoncoon/fibonacci64-touch-demo +// +// https://www.tindie.com/products/jasoncoon/fibonacci64-nano-33mm-disc-with-64-rgb-leds/ +// https://github.com/jasoncoon/fibonacci64-nano-touch-demo +// +// NOTE: code sets to use WS2812B timings, even on Nano (SK6805 timings differ from WS2812B) +// NOTE: QT Py data pin A10, brightness 32 +// NOTE: QT Py touch pins: +// Micro: A0, A1, A2, A3 +// Nano: A0, A1, A2 +// + +#if !defined(LED_TYPE) + #define LED_TYPE WS2812B +#endif +#if !defined(COLOR_ORDER) + #define COLOR_ORDER GRB +#endif +#if !defined(NUM_PIXELS) + #define NUM_PIXELS 64 +#endif +#if !defined(AVAILABLE_MILLI_AMPS) + #define AVAILABLE_MILLI_AMPS 1400 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) +#endif +#if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #define MAX_MILLI_AMPS_PER_PIXEL 60 // IMPORTANT: set to larger value if necessary +#endif +#if !defined(FRAMES_PER_SECOND) + #define FRAMES_PER_SECOND 120 +#endif +#if !defined(DEFAULT_PATTERN_INDEX) + #define DEFAULT_PATTERN_INDEX 0 +#endif +#if !defined(DEFAULT_BRIGHTNESS_INDEX) + #define DEFAULT_BRIGHTNESS_INDEX 3 +#endif +#if !defined(DEFAULT_COLOR_CORRECTION) + #define DEFAULT_COLOR_CORRECTION TypicalSMD5050 +#endif +#if !defined(NAME_PREFIX) + #define NAME_PREFIX "Kraken64-" +#endif +#if !defined(PRODUCT_FRIENDLY_NAME) + #define PRODUCT_FRIENDLY_NAME "Kraken64" +#endif +#if !defined(IS_FIBONACCI) + #define IS_FIBONACCI 0 +#endif +#if !defined(HAS_COORDINATE_MAP) + #define HAS_COORDINATE_MAP 1 +#endif +#if !defined(HAS_POLAR_COORDS) + #define HAS_POLAR_COORDS 0 +#endif +#if !defined(PARALLEL_OUTPUT_CHANNELS) + #define PARALLEL_OUTPUT_CHANNELS 1 +#endif + + +#endif // ESP8266_FASTLED_WEBSERVER_PRODUCT_KRAKEN64_H diff --git a/esp8266-fastled-webserver/include/configs/product/product_template.h b/esp8266-fastled-webserver/include/configs/product/product_template.h new file mode 100644 index 00000000..7ea04679 --- /dev/null +++ b/esp8266-fastled-webserver/include/configs/product/product_template.h @@ -0,0 +1,174 @@ +/* + ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver + Copyright (C) Jason Coon + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#pragma once + +#error #if !defined(ESP8266_FASTLED_WEBSERVER_PRODUCT_xyzzy_H) +#error #define ESP8266_FASTLED_WEBSERVER_PRODUCT_xyzzy_H + +// This template documents the settings to configure a specific "product" +// for building from this repository. + +// The following are MANDATORY ... they must be defined to appropriate values +// This template provides the default values as used by the prior main branch + +// LED_TYPE defines the control pattern for the LEDs +// See https://github.com/FastLED/FastLED/blob/b5874b588ade1d2639925e4e9719fa7d3c9d9e94/src/FastLED.h#L92-L119 + +#if !defined(LED_TYPE) + #define LED_TYPE WS2811 +#endif + +// COLOR_ORDER defines the order that each pixel expects the data to arrive in +// See https://github.com/FastLED/FastLED/blob/765d4244889a692bb453cd4087af31e01c937035/src/pixeltypes.h#L852-L859 +#if !defined(COLOR_ORDER) + #define COLOR_ORDER RGB +#endif + +// NUM_PIXELS is the total number of pixels to be generated / output +#if !defined(NUM_PIXELS) + #define NUM_PIXELS 200 +#endif +// AVAILABLE_MILLI_AMPS is based on the power supply. Recommended to use no more than 80% of actual rated maximum. +#if !defined(AVAILABLE_MILLI_AMPS) + #error #define AVAILABLE_MILLI_AMPS x2000x // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA) +#endif + +// MAX_MILLI_AMPS_PER_PIXEL is used by FastLED to reduce change of exceeding total available milliamps. +#if !defined(MAX_MILLI_AMPS_PER_PIXEL) + #define MAX_MILLI_AMPS_PER_PIXEL 60 // IMPORTANT: set to larger value if necessary +#endif + +// FRAMES_PER_SECOND is a frame LIMIT per second. This is approximate. +#if !defined(FRAMES_PER_SECOND) + #define FRAMES_PER_SECOND 120 +#endif + +// DEFAULT_PATTERN_INDEX allows different products to default to different patterns +#if !defined(DEFAULT_PATTERN_INDEX) + #define DEFAULT_PATTERN_INDEX 0 +#endif + +// DEFAULT_BRIGHTNESS_INDEX allows different products to default to different brightness (e.g., from brightness[5] array) +#if !defined(DEFAULT_BRIGHTNESS_INDEX) + #define DEFAULT_BRIGHTNESS_INDEX 3 +#endif + +// DEFAULT_COLOR_CORRECTION defines which FastLED built-in color correction to apply +// Options include: +// TypicalSMD5050 // 0xFFB0F0 == 255, 176, 240 +// TypicalLEDStrip // 0xFFB0F0 == 255, 176, 240 +// Typical8mmPixel // 0xFFE08C == 255, 224, 140 +// TypicalPixelString // 0xFFE08C == 255, 224, 140 +// UncorrectedColor // 0xFFFFFF == 255, 255, 255 +// +// Likely that you can encode any RGB value: +// static_cast(0xRRGGBB) +// +// See https://github.com/FastLED/FastLED/blob/b5874b588ade1d2639925e4e9719fa7d3c9d9e94/src/color.h#L13-L32 +#if !defined(DEFAULT_COLOR_CORRECTION) + #define DEFAULT_COLOR_CORRECTION TypicalLEDStrip +#endif + + +// NAME_PREFIX defines the product-specific prefix for auto-generated hostname +#if !defined(NAME_PREFIX) + #define NAME_PREFIX "ESP8266-" +#endif + +// PRODUCT_FRIENDLY_NAME is used in HTML page's title and navigation bar +// It is modified when js/app.js loads, by parsing json data generated from device +#if !defined(PRODUCT_FRIENDLY_NAME) + #define PRODUCT_FRIENDLY_NAME "ESP8266 + FastLED" +#endif + +// IS_FIBONACCI is true when there are pre-defined mappings from physical pixel +// indices to Vogel order (which is also order of increasing radius), +// and the inverse mapping from Vogel order back to physical pixel index. +// IS_FIBONACCI also implies HAS_COORDINATE_MAP. +// +// When this is true, the following must be defined in map.h: +// +// const uint8_t physicalToFibonacci[NUM_PIXELS]; +// const uint8_t fibonacciToPhysical[NUM_PIXELS]; +// +// NOTE: physicalToFibonacci[] and fibonacciToPhysical[] are uint16_t when +// NUM_PIXELS is greater than 256. +#if !defined(IS_FIBONACCI) + #define IS_FIBONACCI 1 +#endif + +// HAS_COORDINATE_MAP is true when there are mappings to define +// both the X,Y coordinates and the angles for each pixel. +// +// When this is true, the following must be defined in map.h: +// +// const uint8_t coordsX[NUM_PIXELS]; +// const uint8_t coordsY[NUM_PIXELS]; +// const uint8_t angles[NUM_PIXELS]; +#if !defined(HAS_COORDINATE_MAP) + #define HAS_COORDINATE_MAP 1 +#endif + +// HAS_POLAR_COORDS is true when there are mappings to define +// ... TODO: add definition for polar coordinates define ... +#if !defined(HAS_POLAR_COORDS) + #define HAS_POLAR_COORDS 0 +#endif + + +// PARALLEL_OUTPUT_CHANNELS indicates the number of independent channels +// that should be configured. When this value == 1, DATA_PIN is used to +// control all pixels. +// +// When this value >= 2, this file must define: +// +// #define PIXELS_ON_DATA_PIN_1 wc +// #define PIXELS_ON_DATA_PIN_2 xc +// #define PIXELS_ON_DATA_PIN_3 yc +// ... +// #define PIXELS_ON_DATA_PIN_n zc +// +// *AND* the controller must support the required number of channels. +// +// The controller header file will define default values for the data pins, +// by defining the following symbols: +// +// #define DATA_PIN w +// #define DATA_PIN_2 x +// #define DATA_PIN_3 y +// ... +// #define DATA_PIN_n z +// +// These can be overridden from the board-default values by defining these +// values in the product header template. +// +// See Fibonacci512 and ESPTHING as examples of multi-channel outputs. +// +#if !defined(PARALLEL_OUTPUT_CHANNELS) + #define PARALLEL_OUTPUT_CHANNELS 1 +#endif + +// // By default, no IR support is included. Define ENABLE_IR to enable IR support. +// #define ENABLE_IR +// // When ENABLE_IR is defined, can also override controller-specific default: +// // #define IR_RECV_PIN D99 + + + + +#error #endif // ESP8266_FASTLED_WEBSERVER_PRODUCT_xyzz_H diff --git a/esp8266-fastled-webserver/include/simplehacks/array_size2.h b/esp8266-fastled-webserver/include/simplehacks/array_size2.h new file mode 100644 index 00000000..fdf87e11 --- /dev/null +++ b/esp8266-fastled-webserver/include/simplehacks/array_size2.h @@ -0,0 +1,147 @@ +/** + +The MIT License (MIT) + +Copyright (c) SimpleHacks, Henry Gabryjelski +https://github.com/SimpleHacks/UtilHeaders + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef ARRAYSIZE2_H +#define ARRAYSIZE2_H + +/** + The following, if defined prior to inclusion of this header file, + will modify its behavior as noted: + + ARRAYSIZE2_SHOW_VERSION_MESSAGE + -- if defined, will show which version of ARRAY_SIZE2 macro is selected + */ + + +// see example source at: +// [https://godbolt.org/z/FKilKo] +#ifndef __has_feature + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#if __cplusplus >= 201103L || /* any compiler claiming C++11 support */ \ + (_MSC_VER >= 1900 && __cplusplus != 199711L) || /* Visual C++ 2015 or higher */ \ + __has_feature(cxx_constexpr) /* CLang versions supporting constexp */ + + #include // required for size_t + #if defined(ARRAYSIZE2_SHOW_VERSION_MESSAGE) + #pragma message( "ARRAY_SIZE2 -- Using C++11 version" ) + #endif + + namespace detail + { + template + constexpr size_t ARRAY_SIZE2_ARGUMENT_CANNOT_BE_POINTER(T const (&)[N]) noexcept + { + return N; + } + } // namespace detail + #define ARRAY_SIZE2(arr) detail::ARRAY_SIZE2_ARGUMENT_CANNOT_BE_POINTER(arr) + +#elif __cplusplus >= 199711L && ( /* C++ 98 trick */ \ + defined(__INTEL_COMPILER) || \ + defined(__clang__) || \ + (defined(__GNUC__) && ( \ + (__GNUC__ > 4) || \ + (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \ + ))) + + #include // required for size_t + #if defined(ARRAYSIZE2_SHOW_VERSION_MESSAGE) + #pragma message "ARRAY_SIZE2 -- Using C++98 version" + #endif + template + char(&_ArraySizeHelperRequiresArray(T(&)[N]))[N]; + #define ARRAY_SIZE2(x) sizeof(_ArraySizeHelperRequiresArray(x)) + +#elif defined(__cplusplus) // && ((__cplusplus >= 199711L) || defined(__INTEL_COMPILER) || defined(__clang__)) + + #if defined(ARRAYSIZE2_SHOW_VERSION_MESSAGE) + #pragma message( "ARRAY_SIZE2 -- Using Ivan J. Johnson's C++ version" ) + #endif + /* + Works on older compilers, even Visual C++ 6.... + Created by Ivan J. Johnson, March 06, 2007 + See http://drdobbs.com/cpp/197800525?pgno=1 + + Full description is in markdown file array_size2.md + */ + #define ARRAY_SIZE2(arr) ( \ + 0 * sizeof(reinterpret_cast(arr)) + /*check1*/ \ + 0 * sizeof(::Bad_arg_to_ARRAY_SIZE2::check_type((arr), &(arr))) + /*check2*/ \ + sizeof(arr) / sizeof((arr)[0]) /* eval */ \ + ) + + struct Bad_arg_to_ARRAY_SIZE2 { + class Is_pointer; // incomplete + class Is_array {}; + template + static Is_pointer check_type(T const *, T const * const *); + static Is_array check_type(void const *, void const *); + }; + +#elif !defined(__cplusplus) && defined(__GNUC__) + + // Even C can have type-safety for equivalent of ARRAY_SIZE() macro, + // when using the following two GCC extensions: + // typeof() + // __builtin_types_compatible_p() + + #if defined(ARRAYSIZE2_SHOW_VERSION_MESSAGE) + #pragma message( "ARRAY_SIZE2 -- Using GNUC version" ) + #endif + + // validated using: + // MSP430 gcc 4.5.3 + // x86-64 icc 16.0.3 + // x86-64 gcc 4.1.2 + // x86-64 clang 3.0.0 + // AVR gcc 4.5.4 + // ARM gcc 4.5.4 + + #define __SIMPLEHACKS_COMPATIBLE_TYPES__(a,b) __builtin_types_compatible_p(typeof(a), typeof(b)) // GCC extensions + #define __SIMPLEHACKS_BUILD_ERROR_ON_NONZERO__(x) (sizeof(struct { int:-!!(x)*0x1ee7;})) // if x is zero, reports "error: negative width in bit-field ''" + #define __SIMPLEHACKS_MUST_BE_ARRAY__(x) __SIMPLEHACKS_BUILD_ERROR_ON_NONZERO__(__SIMPLEHACKS_COMPATIBLE_TYPES__((x), &(*x))) + #define ARRAY_SIZE2(_arr) ( (sizeof(_arr) / sizeof((_arr)[0])) + __SIMPLEHACKS_MUST_BE_ARRAY__(_arr) ) // compile-time error if not an array + +#else + + // The good news is that all compilers (as of 20202-05-08) + // on godbolt.org are fully supported. Therefore, if some + // other compiler does not support any of the above method, + // it's important to force a compile-time error, to avoid + // any suggestion that this provides a safe macro. + + #error "Unable to provide type-safe ARRAY_SIZE2 macro" + + +#endif + + +#endif // ARRAYSIZE2_H diff --git a/esp8266-fastled-webserver/include/simplehacks/compile_date.h b/esp8266-fastled-webserver/include/simplehacks/compile_date.h new file mode 100644 index 00000000..efac7fd9 --- /dev/null +++ b/esp8266-fastled-webserver/include/simplehacks/compile_date.h @@ -0,0 +1,136 @@ +/** + +The MIT License (MIT) + +Copyright (c) SimpleHacks, Henry Gabryjelski +https://github.com/SimpleHacks/UtilHeaders + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef COMPILE_DATE_H +#define COMPILE_DATE_H + +// see https://godbolt.org/z/3dSuqQ + +#ifndef __has_feature + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +// This allows conditional declaration of the below as `constexpr`, +// unless the compiler has not implemented the relevant feature. +#if __cpp_constexpr >= 200704 || __has_feature(cxx_constexpr) // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf + #define __COMPILE_DATE_H_CONSTEXPR constexpr +#else + #define __COMPILE_DATE_H_CONSTEXPR +#endif + +#define __DATE_YEAR_INT__ ((( \ + (__DATE__ [ 7u] - '0') * 10u + \ + (__DATE__ [ 8u] - '0')) * 10u + \ + (__DATE__ [ 9u] - '0')) * 10u + \ + (__DATE__ [10u] - '0')) + +#define __DATE_MONTH_INT__ ( \ + (__DATE__ [2u] == 'n' && __DATE__ [1u] == 'a') ? 1u /*Jan*/ \ +: (__DATE__ [2u] == 'b' ) ? 2u /*Feb*/ \ +: (__DATE__ [2u] == 'r' && __DATE__ [1u] == 'a') ? 3u /*Mar*/ \ +: (__DATE__ [2u] == 'r' ) ? 4u /*Apr*/ \ +: (__DATE__ [2u] == 'y' ) ? 5u /*May*/ \ +: (__DATE__ [2u] == 'n' ) ? 6u /*Jun*/ \ +: (__DATE__ [2u] == 'l' ) ? 7u /*Jul*/ \ +: (__DATE__ [2u] == 'g' ) ? 8u /*Aug*/ \ +: (__DATE__ [2u] == 'p' ) ? 9u /*Sep*/ \ +: (__DATE__ [2u] == 't' ) ? 10u /*Oct*/ \ +: (__DATE__ [2u] == 'v' ) ? 11u /*Nov*/ \ +: 12u /*Dec*/ ) + +#define __DATE_DAY_INT__ ( \ + (__DATE__ [4u] == ' ' ? 0u : __DATE__ [4u] - '0') * 10u \ + + (__DATE__ [5u] - '0') ) + +// __TIME__ expands to an eight-character string constant +// "23:59:01", or (if cannot determine time) "??:??:??" +#define __TIME_HOUR_INT__ ( \ + (__TIME__ [0u] == '?' ? 0u : __TIME__ [0u] - '0') * 10u \ + + (__TIME__ [1u] == '?' ? 0u : __TIME__ [1u] - '0') ) + +#define __TIME_MINUTE_INT__ ( \ + (__TIME__ [3u] == '?' ? 0u : __TIME__ [3u] - '0') * 10u \ + + (__TIME__ [4u] == '?' ? 0u : __TIME__ [4u] - '0') ) + +#define __TIME_SECONDS_INT__ ( \ + (__TIME__ [6u] == '?' ? 0u : __TIME__ [6u] - '0') * 10u \ + + (__TIME__ [7u] == '?' ? 0u : __TIME__ [7u] - '0') ) + + +#define __DATE_MSDOS_INT__ ( \ + ((__DATE_YEAR_INT__ - 1980u) << 9u) | \ + ( __DATE_MONTH_INT__ << 5u) | \ + ( __DATE_DAY_INT__ << 0u) ) + +#define __TIME_MSDOS_INT__ ( \ + ( __TIME_HOUR_INT__ << 11u) | \ + ( __TIME_MINUTE_INT__ << 5u) | \ + ( __TIME_SECONDS_INT__ << 0u) ) + +__COMPILE_DATE_H_CONSTEXPR +static const char __DATE_ISO8601_DATE__[] = +{ + (char)(( (__DATE_YEAR_INT__ / 1000) % 10 ) + '0'), + (char)(( (__DATE_YEAR_INT__ / 100) % 10 ) + '0'), + (char)(( (__DATE_YEAR_INT__ / 10) % 10 ) + '0'), + (char)(( (__DATE_YEAR_INT__ / 1) % 10 ) + '0'), + '-', + (char)(( (__DATE_MONTH_INT__ / 10) % 10 ) + '0'), + (char)(( (__DATE_MONTH_INT__ / 1) % 10 ) + '0'), + '-', + (char)(( (__DATE_DAY_INT__ / 10) % 10 ) + '0'), + (char)(( (__DATE_DAY_INT__ / 1) % 10 ) + '0'), + '\0' +}; + +__COMPILE_DATE_H_CONSTEXPR +const char __DATE_ISO8601_DATETIME__[] = +{ + (char)(( (__DATE_YEAR_INT__ / 1000) % 10 ) + '0'), + (char)(( (__DATE_YEAR_INT__ / 100) % 10 ) + '0'), + (char)(( (__DATE_YEAR_INT__ / 10) % 10 ) + '0'), + (char)(( (__DATE_YEAR_INT__ / 1) % 10 ) + '0'), + '-', + (char)(( (__DATE_MONTH_INT__ / 10) % 10 ) + '0'), + (char)(( (__DATE_MONTH_INT__ / 1) % 10 ) + '0'), + '-', + (char)(( (__DATE_DAY_INT__ / 10) % 10 ) + '0'), + (char)(( (__DATE_DAY_INT__ / 1) % 10 ) + '0'), + 'T', + (char)(( (__TIME_HOUR_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIME_HOUR_INT__ / 1) % 10 ) + '0'), + ':', + (char)(( (__TIME_MINUTE_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIME_MINUTE_INT__ / 1) % 10 ) + '0'), + ':', + (char)(( (__TIME_SECONDS_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIME_SECONDS_INT__ / 1) % 10 ) + '0'), + '\0' +}; +#endif // COMPILE_DATE_H diff --git a/esp8266-fastled-webserver/include/simplehacks/constexpr_strlen.h b/esp8266-fastled-webserver/include/simplehacks/constexpr_strlen.h new file mode 100644 index 00000000..b0e3703f --- /dev/null +++ b/esp8266-fastled-webserver/include/simplehacks/constexpr_strlen.h @@ -0,0 +1,63 @@ +/** + +The MIT License (MIT) + +Copyright (c) SimpleHacks, Henry Gabryjelski +https://github.com/SimpleHacks/UtilHeaders + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef CONSTEXPR_STRLEN_H +#define CONSTEXPR_STRLEN_H + +// avr gcc 5.4 and higher +// clang 3.3 and higher, using -std=c++11 +// gcc 5.4 and higher, using -std=c++11 +// msvc 19.15 and higher +template< size_t N > +constexpr inline size_t constexpr_strlen( char const (&)[N] ) +{ + return N-1; +} + +#if __cpp_constexpr >= 201603 + // avr gcc -- not supported (as of v 5.4.0) + // msvc -- not supported (as of v 19.22) + // gcc 7.2.1 and higher, using -std=c++17 + // clang 5.0.0 and higher, using -std=c++17 + constexpr inline size_t constexpr_strlen( const char* s ) + { + return ( + (0 == s) ? 0 : + (*s == '\0') ? 0 : + 1 + constexpr_strlen((const char*)(s+1)) + ); + } +#endif + + + + +#endif // #ifndef CONSTEXPR_STRLEN_H + + diff --git a/esp8266-fastled-webserver/include/simplehacks/integer_seq.h b/esp8266-fastled-webserver/include/simplehacks/integer_seq.h new file mode 100644 index 00000000..cba9e81c --- /dev/null +++ b/esp8266-fastled-webserver/include/simplehacks/integer_seq.h @@ -0,0 +1,150 @@ +/** + +The MIT License (MIT) + +Copyright (c) SimpleHacks, Henry Gabryjelski +https://github.com/SimpleHacks/UtilHeaders + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef SIMPLEHACKS_INTEGER_SEQ_H +#define SIMPLEHACKS_INTEGER_SEQ_H + +#include +#include +#include + +// A C++11 implementation of std::integer_sequence from C++14 +// +// Two simpler examples: +// +// // Create sequence of values from 0 ... 255, as type uint8_t: +// auto sequence = SimpleHacks::CompileTime::make_integer_sequence +// +// // Create size_t values from 0 ... 100: +// auto sequence = SimpleHacks::CompileTime::make_index_sequenc( 100 ); +// +namespace SimpleHacks { +namespace CompileTime { + + // Represents a compile-time sequence of integers. + // When used as an argument to a function template, + // the parameter pack Ints can be deduced and used in pack expansion. + template + struct integer_sequence { + static_assert( std::is_integral::value, "Integral type" ); + using type = T; + + static constexpr T size = sizeof...(I); + + /// Generate an integer_sequence with an additional element. + template + using append = integer_sequence; + + using next = append; + }; + // C++11 rules require the static constexpr variable to be instantiated outside the template + template + constexpr T integer_sequence::size; + + // ALIAS: index_sequence ==> integer_sequence + template + using index_sequence = integer_sequence; + + // intended as private namespace to hide details from auto-completion and the like + namespace _Detail + { + // Metafunction that generates an integer_sequence of T containing [0, N) + template + struct iota + { + static_assert( Nt >= 0, "N cannot be negative" ); + using type = typename iota::type::next; + }; + + // Terminal case of the recursive metafunction. + template + struct iota + { + using type = integer_sequence; + }; + } + + // Simplify creation of std::integer_sequence and std::index_sequence types with 0, 1, 2, ..., N-1 as Ints + // ALIAS: make_integer_sequence ==> integer_sequence + template + using make_integer_sequence = typename _Detail::iota::type; + + // Simplify creation for the common case where T is std::size_t + // ALIAS: make_index_sequence ==> make_integer_sequence + // ==> integer_sequence + template + using make_index_sequence = make_integer_sequence; + + // Convert any type parameter pack into an index sequence of the same length + // ALIAS: index_sequence_for<...> ==> make_index_sequence + // ==> make_integer_sequence + // ==> integer_sequence + template + using index_sequence_for = make_index_sequence; + +} // namespace CompileTime +} // namespace SimpleHacks + +#endif // SIMPLEHACKS_INTEGER_SEQ_H + +/* + The concepts are based on a file published by Jonathan Wakely. + Without comment on its necessity, the following text is provided + for your reference. +*/ +/* + Copyright Jonathan Wakely 2012-2013 + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + Boost Software License - Version 1.0 - August 17th, 2003 + + Permission is hereby granted, free of charge, to any person or organization + obtaining a copy of the software and accompanying documentation covered by + this license (the "Software") to use, reproduce, display, distribute, + execute, and transmit the Software, and to prepare derivative works of the + Software, and to permit third-parties to whom the Software is furnished to + do so, all subject to the following: + + The copyright notices in the Software and this entire statement, including + the above license grant, this restriction and the following disclaimer, + must be included in all copies of the Software, in whole or in part, and + all derivative works of the Software, unless such copies or derivative + works are solely in the form of machine-executable object code generated by + a source language processor. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ diff --git a/esp8266-fastled-webserver/include/simplehacks/static_eval.h b/esp8266-fastled-webserver/include/simplehacks/static_eval.h new file mode 100644 index 00000000..c5e9c1aa --- /dev/null +++ b/esp8266-fastled-webserver/include/simplehacks/static_eval.h @@ -0,0 +1,50 @@ +/** + +The MIT License (MIT) + +Copyright (c) SimpleHacks, Henry Gabryjelski +https://github.com/SimpleHacks/UtilHeaders + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef STATIC_EVAL_H +#define STATIC_EVAL_H + +// use to ensure static evaluation occcurs. e.g., +// #include // also in this repository +// if (static_eval::value > 7) { +// .... +// } + +// avr gcc 5.4 and higher +// clang 3.3 and higher, using -std=c++11 +// gcc 5.4 and higher, using -std=c++11 +// msvc 19.15 and higher +template +struct static_eval +{ + static constexpr T value = V; +}; + +#endif // #ifndef STATIC_EVAL_H + diff --git a/esp8266-fastled-webserver/include/simplehacks/timestamp.h b/esp8266-fastled-webserver/include/simplehacks/timestamp.h new file mode 100644 index 00000000..a7f5362b --- /dev/null +++ b/esp8266-fastled-webserver/include/simplehacks/timestamp.h @@ -0,0 +1,126 @@ +/** + +The MIT License (MIT) + +Copyright (c) SimpleHacks, Henry Gabryjelski +https://github.com/SimpleHacks/UtilHeaders + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TIMESTAMP_H +#define TIMESTAMP_H + +// see https://godbolt.org/z/H7WC_4 + + +// presume support for `constexpr` +#define __TIMESTAMP_H_CONSTEXPR constexpr + +#define __TIMESTAMP_YEAR_INT__ ((( \ + (__TIMESTAMP__ [20u] - '0') * 10u + \ + (__TIMESTAMP__ [21u] - '0')) * 10u + \ + (__TIMESTAMP__ [22u] - '0')) * 10u + \ + (__TIMESTAMP__ [23u] - '0')) + +#define __TIMESTAMP_MONTH_INT__ ( \ + (__TIMESTAMP__ [6u] == 'n' && __TIMESTAMP__ [5u] == 'a') ? 1u /*Jan*/ \ +: (__TIMESTAMP__ [6u] == 'b' ) ? 2u /*Feb*/ \ +: (__TIMESTAMP__ [6u] == 'r' && __TIMESTAMP__ [5u] == 'a') ? 3u /*Mar*/ \ +: (__TIMESTAMP__ [6u] == 'r' ) ? 4u /*Apr*/ \ +: (__TIMESTAMP__ [6u] == 'y' ) ? 5u /*May*/ \ +: (__TIMESTAMP__ [6u] == 'n' ) ? 6u /*Jun*/ \ +: (__TIMESTAMP__ [6u] == 'l' ) ? 7u /*Jul*/ \ +: (__TIMESTAMP__ [6u] == 'g' ) ? 8u /*Aug*/ \ +: (__TIMESTAMP__ [6u] == 'p' ) ? 9u /*Sep*/ \ +: (__TIMESTAMP__ [6u] == 't' ) ? 10u /*Oct*/ \ +: (__TIMESTAMP__ [6u] == 'v' ) ? 11u /*Nov*/ \ +: 12u /*Dec*/ ) + +#define __TIMESTAMP_DAY_INT__ ( \ + (__TIMESTAMP__ [4u] == ' ' ? 0u : __TIMESTAMP__ [4u] - '0') * 10u \ + + (__TIMESTAMP__ [5u] - '0') ) + + +#define __TIMESTAMP_HOUR_INT__ ( \ + (__TIMESTAMP__ [11u] == '?' ? 0u : __TIMESTAMP__ [11u] - '0') * 10u \ + + (__TIMESTAMP__ [12u] == '?' ? 0u : __TIMESTAMP__ [12u] - '0') ) + +#define __TIMESTAMP_MINUTE_INT__ ( \ + (__TIMESTAMP__ [14u] == '?' ? 0u : __TIMESTAMP__ [14u] - '0') * 10u \ + + (__TIMESTAMP__ [15u] == '?' ? 0u : __TIMESTAMP__ [15u] - '0') ) + +#define __TIMESTAMP_SECONDS_INT__ ( \ + (__TIMESTAMP__ [17u] == '?' ? 0u : __TIMESTAMP__ [17u] - '0') * 10u \ + + (__TIMESTAMP__ [18u] == '?' ? 0u : __TIMESTAMP__ [18u] - '0') ) + + +#define __TIMESTAMP_MSDOS_DATE_INT__ ( \ + ((__TIMESTAMP_YEAR_INT__ - 1980u) << 9u) | \ + ( __TIMESTAMP_MONTH_INT__ << 5u) | \ + ( __TIMESTAMP_DAY_INT__ << 0u) ) + +#define __TIMESTAMP_MSDOS_TIME_INT__ ( \ + ( __TIMESTAMP_HOUR_INT__ << 11u) | \ + ( __TIMESTAMP_MINUTE_INT__ << 5u) | \ + ( __TIMESTAMP_SECONDS_INT__ << 0u) ) + +__TIMESTAMP_H_CONSTEXPR +static const char __TIMESTAMP_ISO8601_DATE__[] = +{ + (char)(( (__TIMESTAMP_YEAR_INT__ / 1000) % 10 ) + '0'), + (char)(( (__TIMESTAMP_YEAR_INT__ / 100) % 10 ) + '0'), + (char)(( (__TIMESTAMP_YEAR_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIMESTAMP_YEAR_INT__ / 1) % 10 ) + '0'), + '-', + (char)(( (__TIMESTAMP_MONTH_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIMESTAMP_MONTH_INT__ / 1) % 10 ) + '0'), + '-', + (char)(( (__TIMESTAMP_DAY_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIMESTAMP_DAY_INT__ / 1) % 10 ) + '0'), + '\0' +}; +__TIMESTAMP_H_CONSTEXPR +const char __TIMESTAMP_ISO8601_DATETIME__[] = +{ + (char)(( (__TIMESTAMP_YEAR_INT__ / 1000) % 10 ) + '0'), + (char)(( (__TIMESTAMP_YEAR_INT__ / 100) % 10 ) + '0'), + (char)(( (__TIMESTAMP_YEAR_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIMESTAMP_YEAR_INT__ / 1) % 10 ) + '0'), + '-', + (char)(( (__TIMESTAMP_MONTH_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIMESTAMP_MONTH_INT__ / 1) % 10 ) + '0'), + '-', + (char)(( (__TIMESTAMP_DAY_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIMESTAMP_DAY_INT__ / 1) % 10 ) + '0'), + 'T', + (char)(( (__TIMESTAMP_HOUR_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIMESTAMP_HOUR_INT__ / 1) % 10 ) + '0'), + ':', + (char)(( (__TIMESTAMP_MINUTE_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIMESTAMP_MINUTE_INT__ / 1) % 10 ) + '0'), + ':', + (char)(( (__TIMESTAMP_SECONDS_INT__ / 10) % 10 ) + '0'), + (char)(( (__TIMESTAMP_SECONDS_INT__ / 1) % 10 ) + '0'), + '\0' +}; +#endif // TIMESTAMP_H