diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp
index 3197375f13..59467590c4 100644
--- a/wled00/dmx_input.cpp
+++ b/wled00/dmx_input.cpp
@@ -22,7 +22,7 @@ void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) {
const uint8_t personality = dmx_get_current_personality(dmx->inputPortNum);
DMXMode = std::min(DMX_MODE_PRESET, std::max(DMX_MODE_SINGLE_RGB, int(personality)));
- doSerializeConfig = true;
+ configNeedsWrite = true;
DEBUG_PRINTF("DMX personality changed to to: %d\n", DMXMode);
}
}
@@ -40,7 +40,7 @@ void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) {
const uint16_t addr = dmx_get_start_address(dmx->inputPortNum);
DMXAddress = std::min(512, int(addr));
- doSerializeConfig = true;
+ configNeedsWrite = true;
DEBUG_PRINTF("DMX start addr changed to: %d\n", DMXAddress);
}
}
diff --git a/wled00/e131.cpp b/wled00/e131.cpp
index c16ed9332e..98cfe28fb0 100644
--- a/wled00/e131.cpp
+++ b/wled00/e131.cpp
@@ -38,8 +38,7 @@ void handleDDPPacket(e131_packet_t* p) {
if (realtimeMode != REALTIME_MODE_DDP) ddpSeenPush = false; // just starting, no push yet
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
- if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) {
- if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
+ if (!realtimeOverride) {
for (unsigned i = start; i < stop; i++, c += ddpChannelsPerLed) {
setRealtimePixel(i, data[c], data[c+1], data[c+2], ddpChannelsPerLed >3 ? data[c+3] : 0);
}
@@ -150,10 +149,9 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8
realtimeLock(realtimeTimeoutMs, mde);
- if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
+ if (realtimeOverride) return;
wChannel = (availDMXLen > 3) ? e131_data[dataOffset+3] : 0;
- if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
for (unsigned i = 0; i < totalLen; i++)
setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel);
break;
@@ -163,7 +161,7 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8
if (availDMXLen < 4) return;
realtimeLock(realtimeTimeoutMs, mde);
- if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
+ if (realtimeOverride) return;
wChannel = (availDMXLen > 4) ? e131_data[dataOffset+4] : 0;
if (bri != e131_data[dataOffset+0]) {
@@ -171,7 +169,6 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8
strip.setBrightness(bri, true);
}
- if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
for (unsigned i = 0; i < totalLen; i++)
setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel);
break;
@@ -228,16 +225,16 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8
if (e131_data[dataOffset+3] != seg.intensity) seg.intensity = e131_data[dataOffset+3];
if (e131_data[dataOffset+4] != seg.palette) seg.setPalette(e131_data[dataOffset+4]);
- if ((e131_data[dataOffset+5] & 0b00000010) != seg.reverse_y) { seg.setOption(SEG_OPTION_REVERSED_Y, e131_data[dataOffset+5] & 0b00000010); }
- if ((e131_data[dataOffset+5] & 0b00000100) != seg.mirror_y) { seg.setOption(SEG_OPTION_MIRROR_Y, e131_data[dataOffset+5] & 0b00000100); }
- if ((e131_data[dataOffset+5] & 0b00001000) != seg.transpose) { seg.setOption(SEG_OPTION_TRANSPOSED, e131_data[dataOffset+5] & 0b00001000); }
- if ((e131_data[dataOffset+5] & 0b00110000) / 8 != seg.map1D2D) {
- seg.map1D2D = (e131_data[dataOffset+5] & 0b00110000) / 8;
+ if (bool(e131_data[dataOffset+5] & 0b00000010) != seg.reverse_y) { seg.reverse_y = bool(e131_data[dataOffset+5] & 0b00000010); }
+ if (bool(e131_data[dataOffset+5] & 0b00000100) != seg.mirror_y) { seg.mirror_y = bool(e131_data[dataOffset+5] & 0b00000100); }
+ if (bool(e131_data[dataOffset+5] & 0b00001000) != seg.transpose) { seg.transpose = bool(e131_data[dataOffset+5] & 0b00001000); }
+ if ((e131_data[dataOffset+5] & 0b00110000) >> 4 != seg.map1D2D) {
+ seg.map1D2D = (e131_data[dataOffset+5] & 0b00110000) >> 4;
}
// To maintain backwards compatibility with prior e1.31 values, reverse is fixed to mask 0x01000000
- if ((e131_data[dataOffset+5] & 0b01000000) != seg.reverse) { seg.setOption(SEG_OPTION_REVERSED, e131_data[dataOffset+5] & 0b01000000); }
+ if ((e131_data[dataOffset+5] & 0b01000000) != seg.reverse) { seg.reverse = bool(e131_data[dataOffset+5] & 0b01000000); }
// To maintain backwards compatibility with prior e1.31 values, mirror is fixed to mask 0x10000000
- if ((e131_data[dataOffset+5] & 0b10000000) != seg.mirror) { seg.setOption(SEG_OPTION_MIRROR, e131_data[dataOffset+5] & 0b10000000); }
+ if ((e131_data[dataOffset+5] & 0b10000000) != seg.mirror) { seg.mirror = bool(e131_data[dataOffset+5] & 0b10000000); }
uint32_t colors[3];
byte whites[3] = {0,0,0};
@@ -271,7 +268,7 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8
case DMX_MODE_MULTIPLE_RGB:
case DMX_MODE_MULTIPLE_RGBW:
{
- bool is4Chan = (DMXMode == DMX_MODE_MULTIPLE_RGBW);
+ const bool is4Chan = (DMXMode == DMX_MODE_MULTIPLE_RGBW);
const unsigned dmxChannelsPerLed = is4Chan ? 4 : 3;
const unsigned ledsPerUniverse = is4Chan ? MAX_4_CH_LEDS_PER_UNIVERSE : MAX_3_CH_LEDS_PER_UNIVERSE;
uint8_t stripBrightness = bri;
@@ -303,7 +300,7 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8
}
realtimeLock(realtimeTimeoutMs, mde);
- if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
+ if (realtimeOverride) return;
if (ledsTotal > totalLen) {
ledsTotal = totalLen;
@@ -316,17 +313,9 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8
}
}
- if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
- if (!is4Chan) {
- for (unsigned i = previousLeds; i < ledsTotal; i++) {
- setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], 0);
- dmxOffset+=3;
- }
- } else {
- for (unsigned i = previousLeds; i < ledsTotal; i++) {
- setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], e131_data[dmxOffset+3]);
- dmxOffset+=4;
- }
+ for (unsigned i = previousLeds; i < ledsTotal; i++) {
+ setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], is4Chan ? e131_data[dmxOffset+3] : 0);
+ dmxOffset += dmxChannelsPerLed;
}
break;
}
@@ -529,7 +518,7 @@ void sendArtnetPollReply(ArtPollReply *reply, IPAddress ipAddress, uint16_t port
reply->reply_sub_sw = (uint8_t)((portAddress >> 4) & 0x000F);
reply->reply_sw_out[0] = (uint8_t)(portAddress & 0x000F);
- snprintf_P((char *)reply->reply_node_report, sizeof(reply->reply_node_report)-1, PSTR("#0001 [%04u] OK - WLED v" TOSTRING(WLED_VERSION)), pollReplyCount);
+ snprintf_P((char *)reply->reply_node_report, sizeof(reply->reply_node_report)-1, PSTR("#0001 [%04u] OK - WLED v%s"), pollReplyCount, versionString);
if (pollReplyCount < 9999) {
pollReplyCount++;
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h
index 497a775ee0..d2f62870d5 100644
--- a/wled00/fcn_declare.h
+++ b/wled00/fcn_declare.h
@@ -27,7 +27,8 @@ void IRAM_ATTR touchButtonISR();
bool deserializeConfig(JsonObject doc, bool fromFS = false);
void deserializeConfigFromFS();
bool deserializeConfigSec();
-void serializeConfig();
+void serializeConfig(JsonObject doc);
+void serializeConfigToFS();
void serializeConfigSec();
template
@@ -157,13 +158,18 @@ class NeoGammaWLEDMethod {
public:
[[gnu::hot]] static uint8_t Correct(uint8_t value); // apply Gamma to single channel
[[gnu::hot]] static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB)
- static void calcGammaTable(float gamma); // re-calculates & fills gamma table
+ [[gnu::hot]] static uint32_t inverseGamma32(uint32_t color); // apply inverse Gamma to RGBW32 color
+ static void calcGammaTable(float gamma); // re-calculates & fills gamma tables
static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB)
+ static inline uint8_t rawInverseGamma8(uint8_t val) { return gammaT_inv[val]; } // get value from inverse Gamma table (WLED specific, not used by NPB)
private:
static uint8_t gammaT[];
+ static uint8_t gammaT_inv[];
};
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
+#define gamma32inv(c) NeoGammaWLEDMethod::inverseGamma32(c)
+#define gamma8inv(c) NeoGammaWLEDMethod::rawInverseGamma8(c)
[[gnu::hot, gnu::pure]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend);
inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); };
[[gnu::hot, gnu::pure]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false);
@@ -171,6 +177,9 @@ inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return col
[[gnu::hot, gnu::pure]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND);
CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette);
CRGBPalette16 generateRandomPalette();
+void loadCustomPalettes();
+extern std::vector customPalettes;
+inline size_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); }
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
void hsv2rgb(const CHSV32& hsv, uint32_t& rgb);
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb);
@@ -222,9 +231,8 @@ void onHueConnect(void* arg, AsyncClient* client);
void sendHuePoll();
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
-#include "FX.h" // must be below colors.cpp declarations (potentially due to duplicate declarations of e.g. color_blend)
-
//image_loader.cpp
+class Segment;
#ifdef WLED_ENABLE_GIF
bool fileSeekCallback(unsigned long position);
unsigned long filePositionCallback(void);
@@ -260,9 +268,7 @@ void handleIR();
#include "ESPAsyncWebServer.h"
#include "src/dependencies/json/ArduinoJson-v6.h"
#include "src/dependencies/json/AsyncJson-v6.h"
-#include "FX.h"
-bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0);
bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0);
void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false);
@@ -276,8 +282,8 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
//led.cpp
void setValuesFromSegment(uint8_t s);
-void setValuesFromMainSeg();
-void setValuesFromFirstSelectedSeg();
+#define setValuesFromMainSeg() setValuesFromSegment(strip.getMainSegmentId())
+#define setValuesFromFirstSelectedSeg() setValuesFromSegment(strip.getFirstSelectedSegId())
void toggleOnOff();
void applyBri();
void applyFinalBri();
@@ -486,12 +492,14 @@ void userLoop();
#include "soc/wdev_reg.h"
#define HW_RND_REGISTER REG_READ(WDEV_RND_REG)
#endif
+#define inoise8 perlin8 // fastled legacy alias
+#define inoise16 perlin16 // fastled legacy alias
#define hex2int(a) (((a)>='0' && (a)<='9') ? (a)-'0' : ((a)>='A' && (a)<='F') ? (a)-'A'+10 : ((a)>='a' && (a)<='f') ? (a)-'a'+10 : 0)
-[[gnu::pure]] int getNumVal(const String* req, uint16_t pos);
-void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255);
-bool getVal(JsonVariant elem, byte* val, byte vmin=0, byte vmax=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form)
+[[gnu::pure]] int getNumVal(const String &req, uint16_t pos);
+void parseNumber(const char* str, byte &val, byte minv=0, byte maxv=255);
+bool getVal(JsonVariant elem, byte &val, byte vmin=0, byte vmax=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form)
[[gnu::pure]] bool getBoolVal(const JsonVariant &elem, bool dflt);
-bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255);
+bool updateVal(const char* req, const char* key, byte &val, byte minv=0, byte maxv=255);
size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val);
size_t printSetFormValue(Print& settingsScript, const char* key, int val);
size_t printSetFormValue(Print& settingsScript, const char* key, const char* val);
@@ -514,6 +522,15 @@ void enumerateLedmaps();
[[gnu::hot]] uint8_t get_random_wheel_index(uint8_t pos);
[[gnu::hot, gnu::pure]] float mapf(float x, float in_min, float in_max, float out_min, float out_max);
uint32_t hashInt(uint32_t s);
+int32_t perlin1D_raw(uint32_t x, bool is16bit = false);
+int32_t perlin2D_raw(uint32_t x, uint32_t y, bool is16bit = false);
+int32_t perlin3D_raw(uint32_t x, uint32_t y, uint32_t z, bool is16bit = false);
+uint16_t perlin16(uint32_t x);
+uint16_t perlin16(uint32_t x, uint32_t y);
+uint16_t perlin16(uint32_t x, uint32_t y, uint32_t z);
+uint8_t perlin8(uint16_t x);
+uint8_t perlin8(uint16_t x, uint16_t y);
+uint8_t perlin8(uint16_t x, uint16_t y, uint16_t z);
// fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1
// note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz)
@@ -532,6 +549,29 @@ inline uint8_t hw_random8() { return HW_RND_REGISTER; };
inline uint8_t hw_random8(uint32_t upperlimit) { return (hw_random8() * upperlimit) >> 8; }; // input range 0-255
inline uint8_t hw_random8(uint32_t lowerlimit, uint32_t upperlimit) { uint32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random8(range); }; // input range 0-255
+// PSRAM allocation wrappers
+#ifndef ESP8266
+extern "C" {
+ void *p_malloc(size_t); // prefer PSRAM over DRAM
+ void *p_calloc(size_t, size_t); // prefer PSRAM over DRAM
+ void *p_realloc(void *, size_t); // prefer PSRAM over DRAM
+ inline void p_free(void *ptr) { heap_caps_free(ptr); }
+ void *d_malloc(size_t); // prefer DRAM over PSRAM
+ void *d_calloc(size_t, size_t); // prefer DRAM over PSRAM
+ void *d_realloc(void *, size_t); // prefer DRAM over PSRAM
+ inline void d_free(void *ptr) { heap_caps_free(ptr); }
+}
+#else
+#define p_malloc malloc
+#define p_calloc calloc
+#define p_realloc realloc
+#define p_free free
+#define d_malloc malloc
+#define d_calloc calloc
+#define d_realloc realloc
+#define d_free free
+#endif
+
// RAII guard class for the JSON Buffer lock
// Modeled after std::lock_guard
class JSONBufferGuard {
diff --git a/wled00/file.cpp b/wled00/file.cpp
index d390207d45..c1960e616c 100644
--- a/wled00/file.cpp
+++ b/wled00/file.cpp
@@ -39,7 +39,7 @@ void closeFile() {
uint32_t s = millis();
#endif
f.close();
- DEBUGFS_PRINTF("took %d ms\n", millis() - s);
+ DEBUGFS_PRINTF("took %lu ms\n", millis() - s);
doCloseFile = false;
}
@@ -69,14 +69,14 @@ static bool bufferedFind(const char *target, bool fromStart = true) {
if(buf[count] == target[index]) {
if(++index >= targetLen) { // return true if all chars in the target match
f.seek((f.position() - bufsize) + count +1);
- DEBUGFS_PRINTF("Found at pos %d, took %d ms", f.position(), millis() - s);
+ DEBUGFS_PRINTF("Found at pos %d, took %lu ms", f.position(), millis() - s);
return true;
}
}
count++;
}
}
- DEBUGFS_PRINTF("No match, took %d ms\n", millis() - s);
+ DEBUGFS_PRINTF("No match, took %lu ms\n", millis() - s);
return false;
}
@@ -111,7 +111,7 @@ static bool bufferedFindSpace(size_t targetLen, bool fromStart = true) {
f.seek((f.position() - bufsize) + count +1 - targetLen);
knownLargestSpace = MAX_SPACE; //there may be larger spaces after, so we don't know
}
- DEBUGFS_PRINTF("Found at pos %d, took %d ms", f.position(), millis() - s);
+ DEBUGFS_PRINTF("Found at pos %d, took %lu ms", f.position(), millis() - s);
return true;
}
} else {
@@ -125,7 +125,7 @@ static bool bufferedFindSpace(size_t targetLen, bool fromStart = true) {
count++;
}
}
- DEBUGFS_PRINTF("No match, took %d ms\n", millis() - s);
+ DEBUGFS_PRINTF("No match, took %lu ms\n", millis() - s);
return false;
}
@@ -151,13 +151,13 @@ static bool bufferedFindObjectEnd() {
if (buf[count] == '}') objDepth--;
if (objDepth == 0) {
f.seek((f.position() - bufsize) + count +1);
- DEBUGFS_PRINTF("} at pos %d, took %d ms", f.position(), millis() - s);
+ DEBUGFS_PRINTF("} at pos %d, took %lu ms", f.position(), millis() - s);
return true;
}
count++;
}
}
- DEBUGFS_PRINTF("No match, took %d ms\n", millis() - s);
+ DEBUGFS_PRINTF("No match, took %lu ms\n", millis() - s);
return false;
}
@@ -203,7 +203,7 @@ static bool appendObjectToFile(const char* key, const JsonDocument* content, uin
if (f.position() > 2) f.write(','); //add comma if not first object
f.print(key);
serializeJson(*content, f);
- DEBUGFS_PRINTF("Inserted, took %d ms (total %d)", millis() - s1, millis() - s);
+ DEBUGFS_PRINTF("Inserted, took %lu ms (total %lu)", millis() - s1, millis() - s);
doCloseFile = true;
return true;
}
@@ -251,7 +251,7 @@ static bool appendObjectToFile(const char* key, const JsonDocument* content, uin
f.write('}');
doCloseFile = true;
- DEBUGFS_PRINTF("Appended, took %d ms (total %d)", millis() - s1, millis() - s);
+ DEBUGFS_PRINTF("Appended, took %lu ms (total %lu)", millis() - s1, millis() - s);
return true;
}
@@ -321,7 +321,7 @@ bool writeObjectToFile(const char* file, const char* key, const JsonDocument* co
}
doCloseFile = true;
- DEBUGFS_PRINTF("Replaced/deleted, took %d ms\n", millis() - s);
+ DEBUGFS_PRINTF("Replaced/deleted, took %lu ms\n", millis() - s);
return true;
}
@@ -356,7 +356,7 @@ bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest, c
else deserializeJson(*dest, f);
f.close();
- DEBUGFS_PRINTF("Read, took %d ms\n", millis() - s);
+ DEBUGFS_PRINTF("Read, took %lu ms\n", millis() - s);
return true;
}
@@ -392,7 +392,7 @@ static const uint8_t *getPresetCache(size_t &size) {
if ((presetsModifiedTime != presetsCachedTime) || (presetsCachedValidate != cacheInvalidate)) {
if (presetsCached) {
- free(presetsCached);
+ p_free(presetsCached);
presetsCached = nullptr;
}
}
@@ -403,7 +403,7 @@ static const uint8_t *getPresetCache(size_t &size) {
presetsCachedTime = presetsModifiedTime;
presetsCachedValidate = cacheInvalidate;
presetsCachedSize = 0;
- presetsCached = (uint8_t*)ps_malloc(file.size() + 1);
+ presetsCached = (uint8_t*)p_malloc(file.size() + 1);
if (presetsCached) {
presetsCachedSize = file.size();
file.read(presetsCached, presetsCachedSize);
@@ -419,7 +419,7 @@ static const uint8_t *getPresetCache(size_t &size) {
#endif
bool handleFileRead(AsyncWebServerRequest* request, String path){
- DEBUG_PRINT(F("WS FileRead: ")); DEBUG_PRINTLN(path);
+ DEBUGFS_PRINT(F("WS FileRead: ")); DEBUGFS_PRINTLN(path);
if(path.endsWith("/")) path += "index.htm";
if(path.indexOf(F("sec")) > -1) return false;
#ifdef ARDUINO_ARCH_ESP32
diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp
index 9665057942..aa4ae2e161 100644
--- a/wled00/image_loader.cpp
+++ b/wled00/image_loader.cpp
@@ -78,7 +78,7 @@ void drawPixelCallback(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t
byte renderImageToSegment(Segment &seg) {
if (!seg.name) return IMAGE_ERROR_NO_NAME;
// disable during effect transition, causes flickering, multiple allocations and depending on image, part of old FX remaining
- if (seg.mode != seg.currentMode()) return IMAGE_ERROR_WAITING;
+ //if (seg.mode != seg.currentMode()) return IMAGE_ERROR_WAITING;
if (activeSeg && activeSeg != &seg) return IMAGE_ERROR_SEG_LIMIT; // only one segment at a time
activeSeg = &seg;
diff --git a/wled00/improv.cpp b/wled00/improv.cpp
index 197148b2bf..0bc7a6698f 100644
--- a/wled00/improv.cpp
+++ b/wled00/improv.cpp
@@ -272,5 +272,5 @@ void parseWiFiCommand(char* rpcData) {
improvActive = 2;
forceReconnect = true;
- serializeConfig();
+ serializeConfigToFS();
}
\ No newline at end of file
diff --git a/wled00/ir.cpp b/wled00/ir.cpp
index 9f7950a2fb..b2fec76f1f 100644
--- a/wled00/ir.cpp
+++ b/wled00/ir.cpp
@@ -425,8 +425,8 @@ static void decodeIR44(uint32_t code)
case IR44_COLDWHITE2 : changeColor(COLOR_COLDWHITE2, 255); changeEffect(FX_MODE_STATIC); break;
case IR44_REDPLUS : changeEffect(relativeChange(effectCurrent, 1, 0, strip.getModeCount() -1)); break;
case IR44_REDMINUS : changeEffect(relativeChange(effectCurrent, -1, 0, strip.getModeCount() -1)); break;
- case IR44_GREENPLUS : changePalette(relativeChange(effectPalette, 1, 0, strip.getPaletteCount() -1)); break;
- case IR44_GREENMINUS : changePalette(relativeChange(effectPalette, -1, 0, strip.getPaletteCount() -1)); break;
+ case IR44_GREENPLUS : changePalette(relativeChange(effectPalette, 1, 0, getPaletteCount() -1)); break;
+ case IR44_GREENMINUS : changePalette(relativeChange(effectPalette, -1, 0, getPaletteCount() -1)); break;
case IR44_BLUEPLUS : changeEffectIntensity( 16); break;
case IR44_BLUEMINUS : changeEffectIntensity(-16); break;
case IR44_QUICK : changeEffectSpeed( 16); break;
@@ -435,7 +435,7 @@ static void decodeIR44(uint32_t code)
case IR44_DIY2 : presetFallback(2, FX_MODE_BREATH, 0); break;
case IR44_DIY3 : presetFallback(3, FX_MODE_FIRE_FLICKER, 0); break;
case IR44_DIY4 : presetFallback(4, FX_MODE_RAINBOW, 0); break;
- case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR, 0); break;
+ case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR, 0); break;
case IR44_DIY6 : presetFallback(6, FX_MODE_RAIN, 0); break;
case IR44_AUTO : changeEffect(FX_MODE_STATIC); break;
case IR44_FLASH : changeEffect(FX_MODE_PALETTE); break;
@@ -484,7 +484,7 @@ static void decodeIR6(uint32_t code)
case IR6_CHANNEL_UP: incBrightness(); break;
case IR6_CHANNEL_DOWN: decBrightness(); break;
case IR6_VOLUME_UP: changeEffect(relativeChange(effectCurrent, 1, 0, strip.getModeCount() -1)); break;
- case IR6_VOLUME_DOWN: changePalette(relativeChange(effectPalette, 1, 0, strip.getPaletteCount() -1));
+ case IR6_VOLUME_DOWN: changePalette(relativeChange(effectPalette, 1, 0, getPaletteCount() -1));
switch(lastIR6ColourIdx) {
case 0: changeColor(COLOR_RED); break;
case 1: changeColor(COLOR_REDDISH); break;
@@ -530,7 +530,7 @@ static void decodeIR9(uint32_t code)
/*
This allows users to customize IR actions without the need to edit C code and compile.
-From the https://github.com/wled-dev/WLED/wiki/Infrared-Control page, download the starter
+From the https://github.com/wled/WLED/wiki/Infrared-Control page, download the starter
ir.json file that corresponds to the number of buttons on your remote.
Many of the remotes with the same number of buttons emit the same codes, but will have
different labels or colors. Once you edit the ir.json file, upload it to your controller
diff --git a/wled00/json.cpp b/wled00/json.cpp
index 24988be153..4414681023 100644
--- a/wled00/json.cpp
+++ b/wled00/json.cpp
@@ -14,11 +14,62 @@
/*
* JSON API (De)serialization
*/
+namespace {
+ typedef struct {
+ uint32_t colors[NUM_COLORS];
+ uint16_t start;
+ uint16_t stop;
+ uint16_t offset;
+ uint16_t grouping;
+ uint16_t spacing;
+ uint16_t startY;
+ uint16_t stopY;
+ uint16_t options;
+ uint8_t mode;
+ uint8_t palette;
+ uint8_t opacity;
+ uint8_t speed;
+ uint8_t intensity;
+ uint8_t custom1;
+ uint8_t custom2;
+ uint8_t custom3;
+ bool check1;
+ bool check2;
+ bool check3;
+ } SegmentCopy;
+
+ uint8_t differs(const Segment& b, const SegmentCopy& a) {
+ uint8_t d = 0;
+ if (a.start != b.start) d |= SEG_DIFFERS_BOUNDS;
+ if (a.stop != b.stop) d |= SEG_DIFFERS_BOUNDS;
+ if (a.offset != b.offset) d |= SEG_DIFFERS_GSO;
+ if (a.grouping != b.grouping) d |= SEG_DIFFERS_GSO;
+ if (a.spacing != b.spacing) d |= SEG_DIFFERS_GSO;
+ if (a.opacity != b.opacity) d |= SEG_DIFFERS_BRI;
+ if (a.mode != b.mode) d |= SEG_DIFFERS_FX;
+ if (a.speed != b.speed) d |= SEG_DIFFERS_FX;
+ if (a.intensity != b.intensity) d |= SEG_DIFFERS_FX;
+ if (a.palette != b.palette) d |= SEG_DIFFERS_FX;
+ if (a.custom1 != b.custom1) d |= SEG_DIFFERS_FX;
+ if (a.custom2 != b.custom2) d |= SEG_DIFFERS_FX;
+ if (a.custom3 != b.custom3) d |= SEG_DIFFERS_FX;
+ if (a.startY != b.startY) d |= SEG_DIFFERS_BOUNDS;
+ if (a.stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS;
+
+ //bit pattern: (msb first)
+ // set:2, sound:2, mapping:3, transposed, mirrorY, reverseY, [reset,] paused, mirrored, on, reverse, [selected]
+ if ((a.options & 0b1111111111011110U) != (b.options & 0b1111111111011110U)) d |= SEG_DIFFERS_OPT;
+ if ((a.options & 0x0001U) != (b.options & 0x0001U)) d |= SEG_DIFFERS_SEL;
+ for (unsigned i = 0; i < NUM_COLORS; i++) if (a.colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
+
+ return d;
+ }
+}
-bool deserializeSegment(JsonObject elem, byte it, byte presetId)
+static bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0)
{
byte id = elem["id"] | it;
- if (id >= strip.getMaxSegments()) return false;
+ if (id >= WS2812FX::getMaxSegments()) return false;
bool newSeg = false;
int stop = elem["stop"] | -1;
@@ -26,16 +77,37 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
// append segment
if (id >= strip.getSegmentsNum()) {
if (stop <= 0) return false; // ignore empty/inactive segments
- strip.appendSegment(Segment(0, strip.getLengthTotal()));
+ strip.appendSegment(0, strip.getLengthTotal());
id = strip.getSegmentsNum()-1; // segments are added at the end of list
newSeg = true;
}
//DEBUG_PRINTLN(F("-- JSON deserialize segment."));
Segment& seg = strip.getSegment(id);
- //DEBUG_PRINTF_P(PSTR("-- Original segment: %p (%p)\n"), &seg, seg.data);
- const Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor)
- //DEBUG_PRINTF_P(PSTR("-- Duplicate segment: %p (%p)\n"), &prev, prev.data);
+ // we do not want to make segment copy as it may use a lot of RAM (effect data and pixel buffer)
+ // so we will create a copy of segment options and compare it with original segment when done processing
+ SegmentCopy prev = {
+ {seg.colors[0], seg.colors[1], seg.colors[2]},
+ seg.start,
+ seg.stop,
+ seg.offset,
+ seg.grouping,
+ seg.spacing,
+ seg.startY,
+ seg.stopY,
+ seg.options,
+ seg.mode,
+ seg.palette,
+ seg.opacity,
+ seg.speed,
+ seg.intensity,
+ seg.custom1,
+ seg.custom2,
+ seg.custom3,
+ seg.check1,
+ seg.check2,
+ seg.check3
+ };
int start = elem["start"] | seg.start;
if (stop < 0) {
@@ -53,7 +125,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
elem.remove("rpt"); // remove for recursive call
elem.remove("n"); // remove for recursive call
unsigned len = stop - start;
- for (size_t i=id+1; i= strip.getLengthTotal()) break;
//TODO: add support for 2D
@@ -67,28 +139,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
if (elem["n"]) {
// name field exists
- if (seg.name) { //clear old name
- free(seg.name);
- seg.name = nullptr;
- }
-
const char * name = elem["n"].as();
- size_t len = 0;
- if (name != nullptr) len = strlen(name);
- if (len > 0) {
- if (len > WLED_MAX_SEGNAME_LEN) len = WLED_MAX_SEGNAME_LEN;
- seg.name = static_cast(malloc(len+1));
- if (seg.name) strlcpy(seg.name, name, WLED_MAX_SEGNAME_LEN+1);
- } else {
- // but is empty (already deleted above)
- elem.remove("n");
- }
+ seg.setName(name); // will resolve empty and null correctly
} else if (start != seg.start || stop != seg.stop) {
// clearing or setting segment without name field
- if (seg.name) {
- free(seg.name);
- seg.name = nullptr;
- }
+ seg.clearName();
}
uint16_t grp = elem["grp"] | seg.grouping;
@@ -106,6 +161,12 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
bool transpose = getBoolVal(elem[F("tp")], seg.transpose);
#endif
+ // if segment's virtual dimensions change we need to restart effect (segment blending and PS rely on dimensions)
+ if (seg.mirror != mirror) seg.markForReset();
+ #ifndef WLED_DISABLE_2D
+ if (seg.mirror_y != mirror_y || seg.transpose != transpose) seg.markForReset();
+ #endif
+
int len = (stop > start) ? stop - start : 1;
int offset = elem[F("of")] | INT32_MAX;
if (offset != INT32_MAX) {
@@ -127,8 +188,8 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
}
byte segbri = seg.opacity;
- if (getVal(elem["bri"], &segbri)) {
- if (segbri > 0) seg.setOpacity(segbri);
+ if (getVal(elem["bri"], segbri)) {
+ if (segbri > 0) seg.setOpacity(segbri); // use transition
seg.setOption(SEG_OPTION_ON, segbri); // use transition
}
@@ -184,13 +245,13 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
if (!colValid) continue;
- seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]));
+ seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3])); // use transition
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
}
} else {
// non RGB & non White segment (usually On/Off bus)
- seg.setColor(0, ULTRAWHITE);
- seg.setColor(1, BLACK);
+ seg.setColor(0, ULTRAWHITE); // use transition
+ seg.setColor(1, BLACK); // use transition
}
}
@@ -206,7 +267,6 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
}
#endif
- //seg.map1D2D = constrain(map1D2D, 0, 7); // done in setGeometry()
seg.set = constrain(set, 0, 3);
seg.soundSim = constrain(soundSim, 0, 3);
seg.selected = selected;
@@ -219,57 +279,58 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
#endif
byte fx = seg.mode;
- if (getVal(elem["fx"], &fx, 0, strip.getModeCount())) {
+ if (getVal(elem["fx"], fx, 0, strip.getModeCount())) {
if (!presetId && currentPlaylist>=0) unloadPlaylist();
- if (fx != seg.mode) seg.setMode(fx, elem[F("fxdef")]);
+ if (fx != seg.mode) seg.setMode(fx, elem[F("fxdef")]); // use transition (WARNING: may change map1D2D causing geometry change)
}
- getVal(elem["sx"], &seg.speed);
- getVal(elem["ix"], &seg.intensity);
+ getVal(elem["sx"], seg.speed);
+ getVal(elem["ix"], seg.intensity);
uint8_t pal = seg.palette;
if (seg.getLightCapabilities() & 1) { // ignore palette for White and On/Off segments
- if (getVal(elem["pal"], &pal, 0, strip.getPaletteCount())) seg.setPalette(pal);
+ if (getVal(elem["pal"], pal, 0, getPaletteCount())) seg.setPalette(pal);
}
- getVal(elem["c1"], &seg.custom1);
- getVal(elem["c2"], &seg.custom2);
+ getVal(elem["c1"], seg.custom1);
+ getVal(elem["c2"], seg.custom2);
uint8_t cust3 = seg.custom3;
- getVal(elem["c3"], &cust3, 0, 31); // we can't pass reference to bitfield
+ getVal(elem["c3"], cust3, 0, 31); // we can't pass reference to bitfield
seg.custom3 = constrain(cust3, 0, 31);
seg.check1 = getBoolVal(elem["o1"], seg.check1);
seg.check2 = getBoolVal(elem["o2"], seg.check2);
seg.check3 = getBoolVal(elem["o3"], seg.check3);
+ uint8_t blend = seg.blendMode;
+ getVal(elem["bm"], blend, 0, 15); // we can't pass reference to bitfield
+ seg.blendMode = constrain(blend, 0, 15);
+
JsonArray iarr = elem[F("i")]; //set individual LEDs
if (!iarr.isNull()) {
- uint8_t oldMap1D2D = seg.map1D2D;
- seg.map1D2D = M12_Pixels; // no mapping
-
// set brightness immediately and disable transition
jsonTransitionOnce = true;
- seg.stopTransition();
+ if (seg.isInTransition()) seg.startTransition(0); // setting transition time to 0 will stop transition in next frame
strip.setTransition(0);
strip.setBrightness(scaledBri(bri), true);
// freeze and init to black
if (!seg.freeze) {
seg.freeze = true;
- seg.fill(BLACK);
+ seg.clear();
}
- start = 0, stop = 0;
- set = 0; //0 nothing set, 1 start set, 2 range set
+ unsigned iStart = 0, iStop = 0;
+ unsigned iSet = 0; //0 nothing set, 1 start set, 2 range set
for (size_t i = 0; i < iarr.size(); i++) {
- if(iarr[i].is()) {
- if (!set) {
- start = abs(iarr[i].as());
- set++;
+ if (iarr[i].is()) {
+ if (!iSet) {
+ iStart = abs(iarr[i].as());
+ iSet++;
} else {
- stop = abs(iarr[i].as());
- set++;
+ iStop = abs(iarr[i].as());
+ iSet++;
}
} else { //color
uint8_t rgbw[] = {0,0,0,0};
@@ -285,17 +346,16 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
}
}
- if (set < 2 || stop <= start) stop = start + 1;
- uint32_t c = gamma32(RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
- while (start < stop) seg.setPixelColor(start++, c);
- set = 0;
+ if (iSet < 2 || iStop <= iStart) iStop = iStart + 1;
+ uint32_t c = RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
+ while (iStart < iStop) seg.setRawPixelColor(iStart++, c); // sets pixel color without 1D->2D expansion, grouping or spacing
+ iSet = 0;
}
}
- seg.map1D2D = oldMap1D2D; // restore mapping
strip.trigger(); // force segment update
}
// send UDP/WS if segment options changed (except selection; will also deselect current preset)
- if (seg.differs(prev) & 0x7F) stateChanged = true;
+ if (differs(seg, prev) & ~SEG_DIFFERS_SEL) stateChanged = true;
return true;
}
@@ -311,7 +371,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
#endif
bool onBefore = bri;
- getVal(root["bri"], &bri);
+ getVal(root["bri"], bri);
+ if (bri != briOld) stateChanged = true;
bool on = root["on"] | (bri > 0);
if (!on != !bri) toggleOnOff();
@@ -338,10 +399,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
}
}
-#ifndef WLED_DISABLE_MODE_BLEND
blendingStyle = root[F("bs")] | blendingStyle;
blendingStyle &= 0x1F;
-#endif
// temporary transition (applies only once)
tr = root[F("tt")] | -1;
@@ -354,6 +413,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (tr >= 0) strip.timebase = (unsigned long)tr - millis();
JsonObject nl = root["nl"];
+ if (!nl.isNull()) stateChanged = true;
nightlightActive = getBoolVal(nl["on"], nightlightActive);
nightlightDelayMins = nl["dur"] | nightlightDelayMins;
nightlightMode = nl["mode"] | nightlightMode;
@@ -380,6 +440,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
if (realtimeMode && useMainSegmentOnly) {
strip.getMainSegment().freeze = !realtimeOverride;
+ realtimeOverride = REALTIME_OVERRIDE_NONE; // ignore request for override if using main segment only
}
if (root.containsKey("live")) {
@@ -397,18 +458,14 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (!segVar.isNull()) {
// we may be called during strip.service() so we must not modify segments while effects are executing
strip.suspend();
- const unsigned long start = millis();
- while (strip.isServicing() && millis() - start < strip.getFrameTime()) yield(); // wait until frame is over
- #ifdef WLED_DEBUG
- if (millis() - start > 0) DEBUG_PRINTLN(F("JSON: Waited for strip to finish servicing."));
- #endif
+ strip.waitForIt();
if (segVar.is()) {
int id = segVar["id"] | -1;
//if "seg" is not an array and ID not specified, apply to all selected/checked segments
if (id < 0) {
//apply all selected segments
for (size_t s = 0; s < strip.getSegmentsNum(); s++) {
- Segment &sg = strip.getSegment(s);
+ const Segment &sg = strip.getSegment(s);
if (sg.isActive() && sg.isSelected()) {
deserializeSegment(segVar, s, presetId);
}
@@ -458,7 +515,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
DEBUG_PRINTF_P(PSTR("Preset direct: %d\n"), currentPreset);
} else if (!root["ps"].isNull()) {
// we have "ps" call (i.e. from button or external API call) or "pd" that includes "ps" (i.e. from UI call)
- if (root["win"].isNull() && getVal(root["ps"], &presetCycCurr, 1, 250) && presetCycCurr > 0 && presetCycCurr < 251 && presetCycCurr != currentPreset) {
+ if (root["win"].isNull() && getVal(root["ps"], presetCycCurr, 1, 250) && presetCycCurr > 0 && presetCycCurr < 251 && presetCycCurr != currentPreset) {
DEBUG_PRINTF_P(PSTR("Preset select: %d\n"), presetCycCurr);
// b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal())
applyPreset(presetCycCurr, callMode); // async load from file system (only preset ID was specified)
@@ -474,11 +531,11 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
}
if (root.containsKey(F("rmcpal")) && root[F("rmcpal")].as()) {
- if (strip.customPalettes.size()) {
+ if (customPalettes.size()) {
char fileName[32];
- sprintf_P(fileName, PSTR("/palette%d.json"), strip.customPalettes.size()-1);
+ sprintf_P(fileName, PSTR("/palette%d.json"), customPalettes.size()-1);
if (WLED_FS.exists(fileName)) WLED_FS.remove(fileName);
- strip.loadCustomPalettes();
+ loadCustomPalettes();
}
}
@@ -497,13 +554,13 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
//if (restart) forceReconnect = true;
}
- stateUpdated(callMode);
+ if (stateChanged) stateUpdated(callMode);
if (presetToRestore) currentPreset = presetToRestore;
return stateResponse;
}
-void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool forPreset, bool segmentBounds)
+static void serializeSegment(JsonObject& root, const Segment& seg, byte id, bool forPreset, bool segmentBounds)
{
root["id"] = id;
if (segmentBounds) {
@@ -526,6 +583,7 @@ void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool
root["bri"] = (segbri) ? segbri : 255;
root["cct"] = seg.cct;
root[F("set")] = seg.set;
+ root["lc"] = seg.getLightCapabilities();
if (seg.name != nullptr) root["n"] = reinterpret_cast(seg.name); //not good practice, but decreases required JSON buffer
else if (forPreset) root["n"] = "";
@@ -570,6 +628,7 @@ void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool
root["o3"] = seg.check3;
root["si"] = seg.soundSim;
root["m12"] = seg.map1D2D;
+ root["bm"] = seg.blendMode;
}
void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segmentBounds, bool selectedSegmentsOnly)
@@ -578,9 +637,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
root["on"] = (bri > 0);
root["bri"] = briLast;
root[F("transition")] = transitionDelay/100; //in 100ms
-#ifndef WLED_DISABLE_MODE_BLEND
root[F("bs")] = blendingStyle;
-#endif
}
if (!forPreset) {
@@ -611,7 +668,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
root[F("mainseg")] = strip.getMainSegmentId();
JsonArray seg = root.createNestedArray("seg");
- for (size_t s = 0; s < strip.getMaxSegments(); s++) {
+ for (size_t s = 0; s < WS2812FX::getMaxSegments(); s++) {
if (s >= strip.getSegmentsNum()) {
if (forPreset && segmentBounds && !selectedSegmentsOnly) { //disable segments not part of preset
JsonObject seg0 = seg.createNestedObject();
@@ -620,7 +677,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
} else
break;
}
- Segment &sg = strip.getSegment(s);
+ const Segment &sg = strip.getSegment(s);
if (forPreset && selectedSegmentsOnly && !sg.isSelected()) continue;
if (sg.isActive()) {
JsonObject seg0 = seg.createNestedObject();
@@ -644,7 +701,7 @@ void serializeInfo(JsonObject root)
leds[F("pwr")] = BusManager::currentMilliamps();
leds["fps"] = strip.getFps();
leds[F("maxpwr")] = BusManager::currentMilliamps()>0 ? BusManager::ablMilliampsMax() : 0;
- leds[F("maxseg")] = strip.getMaxSegments();
+ leds[F("maxseg")] = WS2812FX::getMaxSegments();
//leds[F("actseg")] = strip.getActiveSegmentsNum();
//leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config
leds[F("bootps")] = bootPreset;
@@ -658,13 +715,13 @@ void serializeInfo(JsonObject root)
#endif
unsigned totalLC = 0;
- JsonArray lcarr = leds.createNestedArray(F("seglc"));
+ JsonArray lcarr = leds.createNestedArray(F("seglc")); // deprecated, use state.seg[].lc
size_t nSegs = strip.getSegmentsNum();
for (size_t s = 0; s < nSegs; s++) {
if (!strip.getSegment(s).isActive()) continue;
unsigned lc = strip.getSegment(s).getLightCapabilities();
totalLC |= lc;
- lcarr.add(lc);
+ lcarr.add(lc); // deprecated, use state.seg[].lc
}
leds["lc"] = totalLC;
@@ -712,8 +769,8 @@ void serializeInfo(JsonObject root)
#endif
root[F("fxcount")] = strip.getModeCount();
- root[F("palcount")] = strip.getPaletteCount();
- root[F("cpalcount")] = strip.customPalettes.size(); //number of custom palettes
+ root[F("palcount")] = getPaletteCount();
+ root[F("cpalcount")] = customPalettes.size(); //number of custom palettes
JsonArray ledmaps = root.createNestedArray(F("maps"));
for (size_t i=0; i maxPage) page = maxPage;
int start = itemPerPage * page;
int end = start + itemPerPage;
- if (end > palettesCount + customPalettes) end = palettesCount + customPalettes;
+ if (end > palettesCount + customPalettesCount) end = palettesCount + customPalettesCount;
root[F("m")] = maxPage; // inform caller how many pages there are
JsonObject palettes = root.createNestedObject("p");
@@ -920,7 +977,7 @@ void serializePalettes(JsonObject root, int page)
break;
default:
if (i >= palettesCount)
- setPaletteColors(curPalette, strip.customPalettes[i - palettesCount]);
+ setPaletteColors(curPalette, customPalettes[i - palettesCount]);
else if (i < 13) // palette 6 - 12, fastled palettes
setPaletteColors(curPalette, *fastledPalettes[i-6]);
else {
@@ -1036,16 +1093,21 @@ class LockedJsonResponse: public AsyncJsonResponse {
void serveJson(AsyncWebServerRequest* request)
{
- byte subJson = 0;
+ enum class json_target {
+ all, state, info, state_info, nodes, effects, palettes, fxdata, networks, config
+ };
+ json_target subJson = json_target::all;
+
const String& url = request->url();
- if (url.indexOf("state") > 0) subJson = JSON_PATH_STATE;
- else if (url.indexOf("info") > 0) subJson = JSON_PATH_INFO;
- else if (url.indexOf("si") > 0) subJson = JSON_PATH_STATE_INFO;
- else if (url.indexOf(F("nodes")) > 0) subJson = JSON_PATH_NODES;
- else if (url.indexOf(F("eff")) > 0) subJson = JSON_PATH_EFFECTS;
- else if (url.indexOf(F("palx")) > 0) subJson = JSON_PATH_PALETTES;
- else if (url.indexOf(F("fxda")) > 0) subJson = JSON_PATH_FXDATA;
- else if (url.indexOf(F("net")) > 0) subJson = JSON_PATH_NETWORKS;
+ if (url.indexOf("state") > 0) subJson = json_target::state;
+ else if (url.indexOf("info") > 0) subJson = json_target::info;
+ else if (url.indexOf("si") > 0) subJson = json_target::state_info;
+ else if (url.indexOf(F("nodes")) > 0) subJson = json_target::nodes;
+ else if (url.indexOf(F("eff")) > 0) subJson = json_target::effects;
+ else if (url.indexOf(F("palx")) > 0) subJson = json_target::palettes;
+ else if (url.indexOf(F("fxda")) > 0) subJson = json_target::fxdata;
+ else if (url.indexOf(F("net")) > 0) subJson = json_target::networks;
+ else if (url.indexOf(F("cfg")) > 0) subJson = json_target::config;
#ifdef WLED_ENABLE_JSONLIVE
else if (url.indexOf("live") > 0) {
serveLiveLeds(request);
@@ -1056,9 +1118,6 @@ void serveJson(AsyncWebServerRequest* request)
request->send_P(200, FPSTR(CONTENT_TYPE_JSON), JSON_palette_names);
return;
}
- else if (url.indexOf(F("cfg")) > 0 && handleFileRead(request, F("/cfg.json"))) {
- return;
- }
else if (url.length() > 6) { //not just /json
serveJsonError(request, 501, ERR_NOT_IMPL);
return;
@@ -1070,32 +1129,35 @@ void serveJson(AsyncWebServerRequest* request)
}
// releaseJSONBufferLock() will be called when "response" is destroyed (from AsyncWebServer)
// make sure you delete "response" if no "request->send(response);" is made
- LockedJsonResponse *response = new LockedJsonResponse(pDoc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary
+ LockedJsonResponse *response = new LockedJsonResponse(pDoc, subJson==json_target::fxdata || subJson==json_target::effects); // will clear and convert JsonDocument into JsonArray if necessary
JsonVariant lDoc = response->getRoot();
switch (subJson)
{
- case JSON_PATH_STATE:
+ case json_target::state:
serializeState(lDoc); break;
- case JSON_PATH_INFO:
+ case json_target::info:
serializeInfo(lDoc); break;
- case JSON_PATH_NODES:
+ case json_target::nodes:
serializeNodes(lDoc); break;
- case JSON_PATH_PALETTES:
+ case json_target::palettes:
serializePalettes(lDoc, request->hasParam(F("page")) ? request->getParam(F("page"))->value().toInt() : 0); break;
- case JSON_PATH_EFFECTS:
+ case json_target::effects:
serializeModeNames(lDoc); break;
- case JSON_PATH_FXDATA:
+ case json_target::fxdata:
serializeModeData(lDoc); break;
- case JSON_PATH_NETWORKS:
+ case json_target::networks:
serializeNetworks(lDoc); break;
- default: //all
+ case json_target::config:
+ serializeConfig(lDoc); break;
+ case json_target::state_info:
+ case json_target::all:
JsonObject state = lDoc.createNestedObject("state");
serializeState(state);
JsonObject info = lDoc.createNestedObject("info");
serializeInfo(info);
- if (subJson != JSON_PATH_STATE_INFO)
+ if (subJson == json_target::all)
{
JsonArray effects = lDoc.createNestedArray(F("effects"));
serializeModeNames(effects); // remove WLED-SR extensions from effect names
diff --git a/wled00/led.cpp b/wled00/led.cpp
index 2d2f5b6f21..43771f9d53 100644
--- a/wled00/led.cpp
+++ b/wled00/led.cpp
@@ -4,11 +4,9 @@
* LED methods
*/
-void setValuesFromMainSeg() { setValuesFromSegment(strip.getMainSegmentId()); }
-void setValuesFromFirstSelectedSeg() { setValuesFromSegment(strip.getFirstSelectedSegId()); }
-void setValuesFromSegment(uint8_t s)
-{
- Segment& seg = strip.getSegment(s);
+ // applies chosen setment properties to legacy values
+void setValuesFromSegment(uint8_t s) {
+ const Segment& seg = strip.getSegment(s);
colPri[0] = R(seg.colors[0]);
colPri[1] = G(seg.colors[0]);
colPri[2] = B(seg.colors[0]);
@@ -24,25 +22,19 @@ void setValuesFromSegment(uint8_t s)
}
-// applies global legacy values (col, colSec, effectCurrent...)
-// problem: if the first selected segment already has the value to be set, other selected segments are not updated
-void applyValuesToSelectedSegs()
-{
- // copy of first selected segment to tell if value was updated
- unsigned firstSel = strip.getFirstSelectedSegId();
- Segment selsegPrev = strip.getSegment(firstSel);
+// applies global legacy values (colPri, colSec, effectCurrent...) to each selected segment
+void applyValuesToSelectedSegs() {
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i);
- if (i != firstSel && (!seg.isActive() || !seg.isSelected())) continue;
-
- if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
- if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
- if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette);}
- if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent);}
+ if (!(seg.isActive() && seg.isSelected())) continue;
+ if (effectSpeed != seg.speed) {seg.speed = effectSpeed; stateChanged = true;}
+ if (effectIntensity != seg.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
+ if (effectPalette != seg.palette) {seg.setPalette(effectPalette);}
+ if (effectCurrent != seg.mode) {seg.setMode(effectCurrent);}
uint32_t col0 = RGBW32(colPri[0], colPri[1], colPri[2], colPri[3]);
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
- if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0);}
- if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1);}
+ if (col0 != seg.colors[0]) {seg.setColor(0, col0);}
+ if (col1 != seg.colors[1]) {seg.setColor(1, col1);}
}
}
@@ -73,7 +65,8 @@ byte scaledBri(byte in)
//applies global temporary brightness (briT) to strip
void applyBri() {
- if (!(realtimeMode && arlsForceMaxBri)) {
+ if (realtimeOverride || !(realtimeMode && arlsForceMaxBri))
+ {
//DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld);
strip.setBrightness(scaledBri(briT));
}
@@ -94,7 +87,7 @@ void applyFinalBri() {
void stateUpdated(byte callMode) {
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa 11: ws send only 12: button preset
- setValuesFromFirstSelectedSeg();
+ setValuesFromFirstSelectedSeg(); // a much better approach would be to use main segment: setValuesFromMainSeg()
if (bri != briOld || stateChanged) {
if (stateChanged) currentPreset = 0; //something changed, so we are no longer in the preset
@@ -104,7 +97,6 @@ void stateUpdated(byte callMode) {
//set flag to update ws and mqtt
interfaceUpdateCallMode = callMode;
- stateChanged = false;
} else {
if (nightlightActive && !nightlightActiveOld && callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) {
notify(CALL_MODE_NIGHTLIGHT);
@@ -134,15 +126,16 @@ void stateUpdated(byte callMode) {
jsonTransitionOnce = false;
transitionActive = false;
applyFinalBri();
- return;
+ strip.trigger();
+ } else {
+ if (transitionActive) {
+ briOld = briT;
+ } else if (bri != briOld || stateChanged)
+ strip.setTransitionMode(true); // force all segments to transition mode
+ transitionActive = true;
+ transitionStartTime = now;
}
-
- if (transitionActive) {
- briOld = briT;
- } else
- strip.setTransitionMode(true); // force all segments to transition mode
- transitionActive = true;
- transitionStartTime = now;
+ stateChanged = false;
}
diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp
index a462881ec7..62f2961047 100644
--- a/wled00/mqtt.cpp
+++ b/wled00/mqtt.cpp
@@ -27,7 +27,7 @@ static void parseMQTTBriPayload(char* payload)
static void onMqttConnect(bool sessionPresent)
{
//(re)subscribe to required topics
- char subuf[MQTT_MAX_TOPIC_LEN + 6];
+ char subuf[MQTT_MAX_TOPIC_LEN + 9];
if (mqttDeviceTopic[0] != 0) {
strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1);
@@ -52,6 +52,13 @@ static void onMqttConnect(bool sessionPresent)
UsermodManager::onMqttConnect(sessionPresent);
DEBUG_PRINTLN(F("MQTT ready"));
+
+#ifndef USERMOD_SMARTNEST
+ strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1);
+ strcat_P(subuf, PSTR("/status"));
+ mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
+#endif
+
publishMqtt();
}
@@ -68,8 +75,8 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
}
if (index == 0) { // start (1st partial packet or the only packet)
- if (payloadStr) free(payloadStr); // fail-safe: release buffer
- payloadStr = static_cast(malloc(total+1)); // allocate new buffer
+ p_free(payloadStr); // release buffer if it exists
+ payloadStr = static_cast(p_malloc(total+1)); // allocate new buffer
}
if (payloadStr == nullptr) return; // buffer not allocated
@@ -94,7 +101,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
} else {
// Non-Wled Topic used here. Probably a usermod subscribed to this topic.
UsermodManager::onMqttMessage(topic, payloadStr);
- free(payloadStr);
+ p_free(payloadStr);
payloadStr = nullptr;
return;
}
@@ -124,7 +131,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp
// topmost topic (just wled/MAC)
parseMQTTBriPayload(payloadStr);
}
- free(payloadStr);
+ p_free(payloadStr);
payloadStr = nullptr;
}
@@ -174,10 +181,6 @@ void publishMqtt()
strcat_P(subuf, PSTR("/c"));
mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263)
- strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1);
- strcat_P(subuf, PSTR("/status"));
- mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT
-
// TODO: use a DynamicBufferList. Requires a list-read-capable MQTT client API.
DynamicBuffer buf(1024);
bufferPrint pbuf(buf.data(), buf.size());
@@ -196,7 +199,8 @@ bool initMqtt()
if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false;
if (mqtt == nullptr) {
- mqtt = new AsyncMqttClient();
+ void *ptr = p_malloc(sizeof(AsyncMqttClient));
+ mqtt = new (ptr) AsyncMqttClient(); // use placement new (into PSRAM), client will never be deleted
if (!mqtt) return false;
mqtt->onMessage(onMqttMessage);
mqtt->onConnect(onMqttConnect);
diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp
index fcd0a40c2c..3f6e631214 100644
--- a/wled00/overlay.cpp
+++ b/wled00/overlay.cpp
@@ -90,9 +90,8 @@ void _overlayAnalogCountdown()
void handleOverlayDraw() {
UsermodManager::handleOverlayDraw();
if (analogClockSolidBlack) {
- const Segment* segments = strip.getSegments();
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
- const Segment& segment = segments[i];
+ const Segment& segment = strip.getSegment(i);
if (!segment.isActive()) continue;
if (segment.mode > 0 || segment.colors[0] > 0) {
return;
diff --git a/wled00/palettes.h b/wled00/palettes.h
old mode 100644
new mode 100755
index c84c1fb97a..a77540fd1f
--- a/wled00/palettes.h
+++ b/wled00/palettes.h
@@ -1,500 +1,374 @@
+#ifndef PalettesWLED_h
+#define PalettesWLED_h
+
/*
- * Color palettes for FastLED effects (65-73).
- * 4 bytes per color: index, red, green, blue
+ * WLED Color palettes
+ *
+ * Note: palettes imported from http://seaviewsensing.com/pub/cpt-city are gamma corrected using gammas (1.182, 1.0, 1.136)
+ * this is done to match colors of the palettes after applying the (default) global gamma of 2.2 to versions
+ * prior to WLED 0.16 which used pre-applied gammas of (2.6,2.2,2.5) for these palettes.
+ * Palettes from FastLED are intended to be used without gamma correction, an inverse gamma of 2.2 is applied to original colors
*/
-// From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
-// Unfortunately, these are stored in RAM!
-
// Gradient palette "ib_jul01_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/xmas/tn/ib_jul01.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 16 bytes of program space.
-
-#ifndef PalettesWLED_h
-#define PalettesWLED_h
-
-const byte ib_jul01_gp[] PROGMEM = {
- 0, 194, 1, 1,
- 94, 1, 29, 18,
- 132, 57,131, 28,
- 255, 113, 1, 1};
+// http://seaviewsensing.com/pub/cpt-city/ing/xmas/ib_jul01.c3g
+const uint8_t ib_jul01_gp[] PROGMEM = {
+ 0, 226, 6, 12,
+ 94, 26, 96, 78,
+ 132, 130, 189, 94,
+ 255, 177, 3, 9};
// Gradient palette "es_vintage_57_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/vintage/tn/es_vintage_57.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 20 bytes of program space.
-
-const byte es_vintage_57_gp[] PROGMEM = {
- 0, 2, 1, 1,
- 53, 18, 1, 0,
- 104, 69, 29, 1,
- 153, 167,135, 10,
- 255, 46, 56, 4};
-
+// http://seaviewsensing.com/pub/cpt-city/es/vintage/es_vintage_57.c3g
+const uint8_t es_vintage_57_gp[] PROGMEM = {
+ 0, 29, 8, 3,
+ 53, 76, 1, 0,
+ 104, 142, 96, 28,
+ 153, 211, 191, 61,
+ 255, 117, 129, 42};
// Gradient palette "es_vintage_01_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/vintage/tn/es_vintage_01.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 32 bytes of program space.
-
-const byte es_vintage_01_gp[] PROGMEM = {
- 0, 4, 1, 1,
- 51, 16, 0, 1,
- 76, 97,104, 3,
- 101, 255,131, 19,
- 127, 67, 9, 4,
- 153, 16, 0, 1,
- 229, 4, 1, 1,
- 255, 4, 1, 1};
-
+// http://seaviewsensing.com/pub/cpt-city/es/vintage/es_vintage_01.c3g
+const uint8_t es_vintage_01_gp[] PROGMEM = {
+ 0, 41, 18, 24,
+ 51, 73, 0, 22,
+ 76, 165, 170, 38,
+ 101, 255, 189, 80,
+ 127, 139, 56, 40,
+ 153, 73, 0, 22,
+ 229, 41, 18, 24,
+ 255, 41, 18, 24};
// Gradient palette "es_rivendell_15_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/rivendell/tn/es_rivendell_15.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 20 bytes of program space.
-
-const byte es_rivendell_15_gp[] PROGMEM = {
- 0, 1, 14, 5,
- 101, 16, 36, 14,
- 165, 56, 68, 30,
- 242, 150,156, 99,
- 255, 150,156, 99};
-
+// http://seaviewsensing.com/pub/cpt-city/es/rivendell/es_rivendell_15.c3g
+const uint8_t es_rivendell_15_gp[] PROGMEM = {
+ 0, 24, 69, 44,
+ 101, 73, 105, 70,
+ 165, 129, 140, 97,
+ 242, 200, 204, 166,
+ 255, 200, 204, 166};
// Gradient palette "rgi_15_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ds/rgi/tn/rgi_15.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 36 bytes of program space.
-// Edited to be brighter
-
-const byte rgi_15_gp[] PROGMEM = {
- 0, 4, 1, 70,
- 31, 55, 1, 30,
- 63, 255, 4, 7,
- 95, 59, 2, 29,
- 127, 11, 3, 50,
- 159, 39, 8, 60,
- 191, 112, 19, 40,
- 223, 78, 11, 39,
- 255, 29, 8, 59};
-
+// http://seaviewsensing.com/pub/cpt-city/ds/rgi/rgi_15.c3g
+const uint8_t rgi_15_gp[] PROGMEM = {
+ 0, 41, 14, 99,
+ 31, 128, 24, 74,
+ 63, 227, 34, 50,
+ 95, 132, 31, 76,
+ 127, 47, 29, 102,
+ 159, 109, 47, 101,
+ 191, 176, 66, 100,
+ 223, 129, 57, 104,
+ 255, 84, 48, 108};
// Gradient palette "retro2_16_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ma/retro2/tn/retro2_16.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 8 bytes of program space.
-
-const byte retro2_16_gp[] PROGMEM = {
- 0, 188,135, 1,
- 255, 46, 7, 1};
-
+// http://seaviewsensing.com/pub/cpt-city/ma/retro2/retro2_16.c3g
+const uint8_t retro2_16_gp[] PROGMEM = {
+ 0, 222, 191, 8,
+ 255, 117, 52, 1};
// Gradient palette "Analogous_1_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/red/tn/Analogous_1.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 20 bytes of program space.
-
-const byte Analogous_1_gp[] PROGMEM = {
- 0, 3, 0,255,
- 63, 23, 0,255,
- 127, 67, 0,255,
- 191, 142, 0, 45,
- 255, 255, 0, 0};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/red/Analogous_1.c3g
+const uint8_t Analogous_1_gp[] PROGMEM = {
+ 0, 38, 0, 255,
+ 63, 86, 0, 255,
+ 127, 139, 0, 255,
+ 191, 196, 0, 117,
+ 255, 255, 0, 0};
// Gradient palette "es_pinksplash_08_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/pink_splash/tn/es_pinksplash_08.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 20 bytes of program space.
-
-const byte es_pinksplash_08_gp[] PROGMEM = {
- 0, 126, 11,255,
- 127, 197, 1, 22,
- 175, 210,157,172,
- 221, 157, 3,112,
- 255, 157, 3,112};
-
+// http://seaviewsensing.com/pub/cpt-city/es/pink_splash/es_pinksplash_08.c3g
+const uint8_t es_pinksplash_08_gp[] PROGMEM = {
+ 0, 186, 63, 255,
+ 127, 227, 9, 85,
+ 175, 234, 205, 213,
+ 221, 205, 38, 176,
+ 255, 205, 38, 176,
+};
// Gradient palette "es_ocean_breeze_036_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/ocean_breeze/tn/es_ocean_breeze_036.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 16 bytes of program space.
-
-const byte es_ocean_breeze_036_gp[] PROGMEM = {
- 0, 1, 6, 7,
- 89, 1, 99,111,
- 153, 144,209,255,
- 255, 0, 73, 82};
-
+// http://seaviewsensing.com/pub/cpt-city/es/ocean_breeze/es_ocean_breeze_036.c3g
+const uint8_t es_ocean_breeze_036_gp[] PROGMEM = {
+ 0, 16, 48, 51,
+ 89, 27, 166, 175,
+ 153, 197, 233, 255,
+ 255, 0, 145, 152};
// Gradient palette "departure_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/mjf/tn/departure.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 88 bytes of program space.
-
-const byte departure_gp[] PROGMEM = {
- 0, 8, 3, 0,
- 42, 23, 7, 0,
- 63, 75, 38, 6,
- 84, 169, 99, 38,
- 106, 213,169,119,
- 116, 255,255,255,
- 138, 135,255,138,
- 148, 22,255, 24,
- 170, 0,255, 0,
- 191, 0,136, 0,
- 212, 0, 55, 0,
- 255, 0, 55, 0};
-
+// http://seaviewsensing.com/pub/cpt-city/mjf/departure.c3g
+const uint8_t departure_gp[] PROGMEM = {
+ 0, 53, 34, 0,
+ 42, 86, 51, 0,
+ 63, 147, 108, 49,
+ 84, 212, 166, 108,
+ 106, 235, 212, 180,
+ 116, 255, 255, 255,
+ 138, 191, 255, 193,
+ 148, 84, 255, 88,
+ 170, 0, 255, 0,
+ 191, 0, 192, 0,
+ 212, 0, 128, 0,
+ 255, 0, 128, 0};
// Gradient palette "es_landscape_64_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/landscape/tn/es_landscape_64.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 36 bytes of program space.
-
-const byte es_landscape_64_gp[] PROGMEM = {
- 0, 0, 0, 0,
- 37, 2, 25, 1,
- 76, 15,115, 5,
- 127, 79,213, 1,
- 128, 126,211, 47,
- 130, 188,209,247,
- 153, 144,182,205,
- 204, 59,117,250,
- 255, 1, 37,192};
-
+// http://seaviewsensing.com/pub/cpt-city/es/landscape/es_landscape_64.c3g
+const uint8_t es_landscape_64_gp[] PROGMEM = {
+ 0, 0, 0, 0,
+ 37, 31, 89, 19,
+ 76, 72, 178, 43,
+ 127, 150, 235, 5,
+ 128, 186, 234, 119,
+ 130, 222, 233, 252,
+ 153, 197, 219, 231,
+ 204, 132, 179, 253,
+ 255, 28, 107, 225};
// Gradient palette "es_landscape_33_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/landscape/tn/es_landscape_33.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 24 bytes of program space.
-
-const byte es_landscape_33_gp[] PROGMEM = {
- 0, 1, 5, 0,
- 19, 32, 23, 1,
- 38, 161, 55, 1,
- 63, 229,144, 1,
- 66, 39,142, 74,
- 255, 1, 4, 1};
-
+// http://seaviewsensing.com/pub/cpt-city/es/landscape/es_landscape_33.c3g
+const uint8_t es_landscape_33_gp[] PROGMEM = {
+ 0, 12, 45, 0,
+ 19, 101, 86, 2,
+ 38, 207, 128, 4,
+ 63, 243, 197, 18,
+ 66, 109, 196, 146,
+ 255, 5, 39, 7};
// Gradient palette "rainbowsherbet_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ma/icecream/tn/rainbowsherbet.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 28 bytes of program space.
-
-const byte rainbowsherbet_gp[] PROGMEM = {
- 0, 255, 33, 4,
- 43, 255, 68, 25,
- 86, 255, 7, 25,
- 127, 255, 82,103,
- 170, 255,255,242,
- 209, 42,255, 22,
- 255, 87,255, 65};
-
+// http://seaviewsensing.com/pub/cpt-city/ma/icecream/rainbowsherbet.c3g
+const uint8_t rainbowsherbet_gp[] PROGMEM = {
+ 0, 255, 102, 41,
+ 43, 255, 140, 90,
+ 86, 255, 51, 90,
+ 127, 255, 153, 169,
+ 170, 255, 255, 249,
+ 209, 113, 255, 85,
+ 255, 157, 255, 137};
// Gradient palette "gr65_hult_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/hult/tn/gr65_hult.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 24 bytes of program space.
-
-const byte gr65_hult_gp[] PROGMEM = {
- 0, 247,176,247,
- 48, 255,136,255,
- 89, 220, 29,226,
- 160, 7, 82,178,
- 216, 1,124,109,
- 255, 1,124,109};
-
+// http://seaviewsensing.com/pub/cpt-city/hult/gr65_hult.c3g
+const uint8_t gr65_hult_gp[] PROGMEM = {
+ 0, 251, 216, 252,
+ 48, 255, 192, 255,
+ 89, 239, 95, 241,
+ 160, 51, 153, 217,
+ 216, 24, 184, 174,
+ 255, 24, 184, 174};
// Gradient palette "gr64_hult_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/hult/tn/gr64_hult.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 32 bytes of program space.
-
-const byte gr64_hult_gp[] PROGMEM = {
- 0, 1,124,109,
- 66, 1, 93, 79,
- 104, 52, 65, 1,
- 130, 115,127, 1,
- 150, 52, 65, 1,
- 201, 1, 86, 72,
- 239, 0, 55, 45,
- 255, 0, 55, 45};
-
+// http://seaviewsensing.com/pub/cpt-city/hult/gr64_hult.c3g
+const uint8_t gr64_hult_gp[] PROGMEM = {
+ 0, 24, 184, 174,
+ 66, 8, 162, 150,
+ 104, 124, 137, 7,
+ 130, 178, 186, 22,
+ 150, 124, 137, 7,
+ 201, 6, 156, 144,
+ 239, 0, 128, 117,
+ 255, 0, 128, 117};
// Gradient palette "GMT_drywet_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/gmt/tn/GMT_drywet.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 28 bytes of program space.
-
-const byte GMT_drywet_gp[] PROGMEM = {
- 0, 47, 30, 2,
- 42, 213,147, 24,
- 84, 103,219, 52,
- 127, 3,219,207,
- 170, 1, 48,214,
- 212, 1, 1,111,
- 255, 1, 7, 33};
-
+// http://seaviewsensing.com/pub/cpt-city/gmt/GMT_drywet.c3g
+const uint8_t GMT_drywet_gp[] PROGMEM = {
+ 0, 119, 97, 33,
+ 42, 235, 199, 88,
+ 84, 169, 238, 124,
+ 127, 37, 238, 232,
+ 170, 7, 120, 236,
+ 212, 27, 1, 175,
+ 255, 4, 51, 101};
// Gradient palette "ib15_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/general/tn/ib15.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 24 bytes of program space.
-
-const byte ib15_gp[] PROGMEM = {
- 0, 113, 91,147,
- 72, 157, 88, 78,
- 89, 208, 85, 33,
- 107, 255, 29, 11,
- 141, 137, 31, 39,
- 255, 59, 33, 89};
-
+// http://seaviewsensing.com/pub/cpt-city/ing/general/ib15.c3g
+const uint8_t ib15_gp[] PROGMEM = {
+ 0, 177, 160, 199,
+ 72, 205, 158, 149,
+ 89, 233, 155, 101,
+ 107, 255, 95, 63,
+ 141, 192, 98, 109,
+ 255, 132, 101, 159};
// Gradient palette "Tertiary_01_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/vermillion/tn/Tertiary_01.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 20 bytes of program space.
-
-const byte Tertiary_01_gp[] PROGMEM = {
- 0, 0, 1,255,
- 63, 3, 68, 45,
- 127, 23,255, 0,
- 191, 100, 68, 1,
- 255, 255, 1, 4};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/vermillion/Tertiary_01.c3g
+const uint8_t Tertiary_01_gp[] PROGMEM = {
+ 0, 0, 25, 255,
+ 63, 38, 140, 117,
+ 127, 86, 255, 0,
+ 191, 167, 140, 19,
+ 255, 255, 25, 41};
// Gradient palette "lava_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/neota/elem/tn/lava.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 52 bytes of program space.
-
-const byte lava_gp[] PROGMEM = {
- 0, 0, 0, 0,
- 46, 18, 0, 0,
- 96, 113, 0, 0,
- 108, 142, 3, 1,
- 119, 175, 17, 1,
- 146, 213, 44, 2,
- 174, 255, 82, 4,
- 188, 255,115, 4,
- 202, 255,156, 4,
- 218, 255,203, 4,
- 234, 255,255, 4,
- 244, 255,255, 71,
- 255, 255,255,255};
-
-
-// Gradient palette "fierce_ice_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/neota/elem/tn/fierce-ice.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 28 bytes of program space.
-
-const byte fierce_ice_gp[] PROGMEM = {
- 0, 0, 0, 0,
- 59, 0, 9, 45,
- 119, 0, 38,255,
- 149, 3,100,255,
- 180, 23,199,255,
- 217, 100,235,255,
- 255, 255,255,255};
-
+// http://seaviewsensing.com/pub/cpt-city/neota/elem/lava.c3g
+const uint8_t lava_gp[] PROGMEM = {
+ 0, 0, 0, 0,
+ 46, 77, 0, 0,
+ 96, 177, 0, 0,
+ 108, 196, 38, 9,
+ 119, 215, 76, 19,
+ 146, 235, 115, 29,
+ 174, 255, 153, 41,
+ 188, 255, 178, 41,
+ 202, 255, 204, 41,
+ 218, 255, 230, 41,
+ 234, 255, 255, 41,
+ 244, 255, 255, 143,
+ 255, 255, 255, 255};
+
+// Gradient palette "fierce-ice_gp", originally from
+// http://seaviewsensing.com/pub/cpt-city/neota/elem/fierce-ice.c3g
+const uint8_t fierce_ice_gp[] PROGMEM = {
+ 0, 0, 0, 0,
+ 59, 0, 51, 117,
+ 119, 0, 102, 255,
+ 149, 38, 153, 255,
+ 180, 86, 204, 255,
+ 217, 167, 230, 255,
+ 255, 255, 255, 255};
// Gradient palette "Colorfull_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Colorfull.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 44 bytes of program space.
-
-const byte Colorfull_gp[] PROGMEM = {
- 0, 10, 85, 5,
- 25, 29,109, 18,
- 60, 59,138, 42,
- 93, 83, 99, 52,
- 106, 110, 66, 64,
- 109, 123, 49, 65,
- 113, 139, 35, 66,
- 116, 192,117, 98,
- 124, 255,255,137,
- 168, 100,180,155,
- 255, 22,121,174};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Colorfull.c3g
+const uint8_t Colorfull_gp[] PROGMEM = {
+ 0, 61, 155, 44,
+ 25, 95, 174, 77,
+ 60, 132, 193, 113,
+ 93, 154, 166, 125,
+ 106, 175, 138, 136,
+ 109, 183, 121, 137,
+ 113, 194, 104, 138,
+ 116, 225, 179, 165,
+ 124, 255, 255, 192,
+ 168, 167, 218, 203,
+ 255, 84, 182, 215};
// Gradient palette "Pink_Purple_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Pink_Purple.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 44 bytes of program space.
-
-const byte Pink_Purple_gp[] PROGMEM = {
- 0, 19, 2, 39,
- 25, 26, 4, 45,
- 51, 33, 6, 52,
- 76, 68, 62,125,
- 102, 118,187,240,
- 109, 163,215,247,
- 114, 217,244,255,
- 122, 159,149,221,
- 149, 113, 78,188,
- 183, 128, 57,155,
- 255, 146, 40,123};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Pink_Purple.c3g
+const uint8_t Pink_Purple_gp[] PROGMEM = {
+ 0, 79, 32, 109,
+ 25, 90, 40, 117,
+ 51, 102, 48, 124,
+ 76, 141, 135, 185,
+ 102, 180, 222, 248,
+ 109, 208, 236, 252,
+ 114, 237, 250, 255,
+ 122, 206, 200, 239,
+ 149, 177, 149, 222,
+ 183, 187, 130, 203,
+ 255, 198, 111, 184};
// Gradient palette "Sunset_Real_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Real.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 28 bytes of program space.
-
-const byte Sunset_Real_gp[] PROGMEM = {
- 0, 120, 0, 0,
- 22, 179, 22, 0,
- 51, 255,104, 0,
- 85, 167, 22, 18,
- 135, 100, 0,103,
- 198, 16, 0,130,
- 255, 0, 0,160};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Sunset_Real.c3g
+const uint8_t Sunset_Real_gp[] PROGMEM = {
+ 0, 181, 0, 0,
+ 22, 218, 85, 0,
+ 51, 255, 170, 0,
+ 85, 211, 85, 77,
+ 135, 167, 0, 169,
+ 198, 73, 0, 188,
+ 255, 0, 0, 207};
// Gradient palette "Sunset_Yellow_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Yellow.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 44 bytes of program space.
-
-const byte Sunset_Yellow_gp[] PROGMEM = {
- 0, 10, 62,123,
- 36, 56,130,103,
- 87, 153,225, 85,
- 100, 199,217, 68,
- 107, 255,207, 54,
- 115, 247,152, 57,
- 120, 239,107, 61,
- 128, 247,152, 57,
- 180, 255,207, 54,
- 223, 255,227, 48,
- 255, 255,248, 42};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Sunset_Yellow.c3g
+const uint8_t Sunset_Yellow_gp[] PROGMEM = {
+ 0, 61, 135, 184,
+ 36, 129, 188, 169,
+ 87, 203, 241, 155,
+ 100, 228, 237, 141,
+ 107, 255, 232, 127,
+ 115, 251, 202, 130,
+ 120, 248, 172, 133,
+ 128, 251, 202, 130,
+ 180, 255, 232, 127,
+ 223, 255, 242, 120,
+ 255, 255, 252, 113};
// Gradient palette "Beech_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Beech.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 60 bytes of program space.
-
-const byte Beech_gp[] PROGMEM = {
- 0, 255,252,214,
- 12, 255,252,214,
- 22, 255,252,214,
- 26, 190,191,115,
- 28, 137,141, 52,
- 28, 112,255,205,
- 50, 51,246,214,
- 71, 17,235,226,
- 93, 2,193,199,
- 120, 0,156,174,
- 133, 1,101,115,
- 136, 1, 59, 71,
- 136, 7,131,170,
- 208, 1, 90,151,
- 255, 0, 56,133};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Beech.c3g
+const uint8_t Beech_gp[] PROGMEM = {
+ 0, 255, 254, 236,
+ 12, 255, 254, 236,
+ 22, 255, 254, 236,
+ 26, 223, 224, 178,
+ 28, 192, 195, 124,
+ 28, 176, 255, 231,
+ 50, 123, 251, 236,
+ 71, 74, 246, 241,
+ 93, 33, 225, 228,
+ 120, 0, 204, 215,
+ 133, 4, 168, 178,
+ 136, 10, 132, 143,
+ 136, 51, 189, 212,
+ 208, 23, 159, 201,
+ 255, 0, 129, 190};
// Gradient palette "Another_Sunset_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Another_Sunset.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 32 bytes of program space.
-
-const byte Another_Sunset_gp[] PROGMEM = {
- 0, 110, 49, 11,
- 29, 55, 34, 10,
- 68, 22, 22, 9,
- 68, 239,124, 8,
- 97, 220,156, 27,
- 124, 203,193, 61,
- 178, 33, 53, 56,
- 255, 0, 1, 52};
-
-
-
-
+// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Another_Sunset.c3g
+const uint8_t Another_Sunset_gp[] PROGMEM = {
+ 0, 175, 121, 62,
+ 29, 128, 103, 60,
+ 68, 84, 84, 58,
+ 68, 248, 184, 55,
+ 97, 239, 204, 93,
+ 124, 230, 225, 133,
+ 178, 102, 125, 129,
+ 255, 0, 26, 125};
// Gradient palette "es_autumn_19_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/autumn/tn/es_autumn_19.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 52 bytes of program space.
-
-const byte es_autumn_19_gp[] PROGMEM = {
- 0, 26, 1, 1,
- 51, 67, 4, 1,
- 84, 118, 14, 1,
- 104, 137,152, 52,
- 112, 113, 65, 1,
- 122, 133,149, 59,
- 124, 137,152, 52,
- 135, 113, 65, 1,
- 142, 139,154, 46,
- 163, 113, 13, 1,
- 204, 55, 3, 1,
- 249, 17, 1, 1,
- 255, 17, 1, 1};
-
+// http://seaviewsensing.com/pub/cpt-city/es/autumn/es_autumn_19.c3g
+const uint8_t es_autumn_19_gp[] PROGMEM = {
+ 0, 90, 14, 5,
+ 51, 139, 41, 13,
+ 84, 180, 70, 17,
+ 104, 192, 202, 125,
+ 112, 177, 137, 3,
+ 122, 190, 200, 131,
+ 124, 192, 202, 124,
+ 135, 177, 137, 3,
+ 142, 194, 203, 118,
+ 163, 177, 68, 17,
+ 204, 128, 35, 12,
+ 249, 74, 5, 2,
+ 255, 74, 5, 2};
// Gradient palette "BlacK_Blue_Magenta_White_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Blue_Magenta_White.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 28 bytes of program space.
-
-const byte BlacK_Blue_Magenta_White_gp[] PROGMEM = {
- 0, 0, 0, 0,
- 42, 0, 0, 45,
- 84, 0, 0,255,
- 127, 42, 0,255,
- 170, 255, 0,255,
- 212, 255, 55,255,
- 255, 255,255,255};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/basic/BlacK_Blue_Magenta_White.c3g
+const uint8_t BlacK_Blue_Magenta_White_gp[] PROGMEM = {
+ 0, 0, 0, 0,
+ 42, 0, 0, 117,
+ 84, 0, 0, 255,
+ 127, 113, 0, 255,
+ 170, 255, 0, 255,
+ 212, 255, 128, 255,
+ 255, 255, 255, 255};
// Gradient palette "BlacK_Magenta_Red_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Magenta_Red.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 20 bytes of program space.
-
-const byte BlacK_Magenta_Red_gp[] PROGMEM = {
- 0, 0, 0, 0,
- 63, 42, 0, 45,
- 127, 255, 0,255,
- 191, 255, 0, 45,
- 255, 255, 0, 0};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/basic/BlacK_Magenta_Red.c3g
+const uint8_t BlacK_Magenta_Red_gp[] PROGMEM = {
+ 0, 0, 0, 0,
+ 63, 113, 0, 117,
+ 127, 255, 0, 255,
+ 191, 255, 0, 117,
+ 255, 255, 0, 0};
// Gradient palette "BlacK_Red_Magenta_Yellow_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Red_Magenta_Yellow.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 28 bytes of program space.
-
-const byte BlacK_Red_Magenta_Yellow_gp[] PROGMEM = {
- 0, 0, 0, 0,
- 42, 42, 0, 0,
- 84, 255, 0, 0,
- 127, 255, 0, 45,
- 170, 255, 0,255,
- 212, 255, 55, 45,
- 255, 255,255, 0};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/basic/BlacK_Red_Magenta_Yellow.c3g
+const uint8_t BlacK_Red_Magenta_Yellow_gp[] PROGMEM = {
+ 0, 0, 0, 0,
+ 42, 113, 0, 0,
+ 84, 255, 0, 0,
+ 127, 255, 0, 117,
+ 170, 255, 0, 255,
+ 212, 255, 128, 117,
+ 255, 255, 255, 0};
// Gradient palette "Blue_Cyan_Yellow_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/Blue_Cyan_Yellow.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 20 bytes of program space.
-
-const byte Blue_Cyan_Yellow_gp[] PROGMEM = {
- 0, 0, 0,255,
- 63, 0, 55,255,
- 127, 0,255,255,
- 191, 42,255, 45,
- 255, 255,255, 0};
-
+// http://seaviewsensing.com/pub/cpt-city/nd/basic/Blue_Cyan_Yellow.c3g
+const uint8_t Blue_Cyan_Yellow_gp[] PROGMEM = {
+ 0, 0, 0, 255,
+ 63, 0, 128, 255,
+ 127, 0, 255, 255,
+ 191, 113, 255, 117,
+ 255, 255, 255, 0};
//Custom palette by Aircoookie
-
const byte Orange_Teal_gp[] PROGMEM = {
0, 0,150, 92,
55, 0,150, 92,
@@ -502,7 +376,6 @@ const byte Orange_Teal_gp[] PROGMEM = {
255, 255, 72, 0};
//Custom palette by Aircoookie
-
const byte Tiamat_gp[] PROGMEM = {
0, 1, 2, 14, //gc
33, 2, 5, 35, //gc from 47, 61,126
@@ -517,7 +390,6 @@ const byte Tiamat_gp[] PROGMEM = {
255, 255,249,255};
//Custom palette by Aircoookie
-
const byte April_Night_gp[] PROGMEM = {
0, 1, 5, 45, //deep blue
10, 1, 5, 45,
@@ -585,288 +457,257 @@ const byte Atlantica_gp[] PROGMEM = {
const byte C9_2_gp[] PROGMEM = {
0, 6, 126, 2, //green
45, 6, 126, 2,
- 45, 4, 30, 114, //blue
+ 46, 4, 30, 114, //blue
90, 4, 30, 114,
- 90, 255, 5, 0, //red
+ 91, 255, 5, 0, //red
135, 255, 5, 0,
- 135, 196, 57, 2, //amber
+ 136, 196, 57, 2, //amber
180, 196, 57, 2,
- 180, 137, 85, 2, //yellow
+ 181, 137, 85, 2, //yellow
255, 137, 85, 2};
//C9, but brighter and with a less purple blue
const byte C9_new_gp[] PROGMEM = {
0, 255, 5, 0, //red
60, 255, 5, 0,
- 60, 196, 57, 2, //amber (start 61?)
+ 61, 196, 57, 2, //amber (start 61?)
120, 196, 57, 2,
- 120, 6, 126, 2, //green (start 126?)
+ 121, 6, 126, 2, //green (start 126?)
180, 6, 126, 2,
- 180, 4, 30, 114, //blue (start 191?)
+ 181, 4, 30, 114, //blue (start 191?)
255, 4, 30, 114};
// Gradient palette "temperature_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/arendal/tn/temperature.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 144 bytes of program space.
-
-const byte temperature_gp[] PROGMEM = {
- 0, 1, 27,105,
- 14, 1, 40,127,
- 28, 1, 70,168,
- 42, 1, 92,197,
- 56, 1,119,221,
- 70, 3,130,151,
- 84, 23,156,149,
- 99, 67,182,112,
- 113, 121,201, 52,
- 127, 142,203, 11,
- 141, 224,223, 1,
- 155, 252,187, 2,
- 170, 247,147, 1,
- 184, 237, 87, 1,
- 198, 229, 43, 1,
- 226, 171, 2, 2,
- 240, 80, 3, 3,
- 255, 80, 3, 3};
-
- const byte Aurora2_gp[] PROGMEM = {
- 0, 17, 177, 13, //Greenish
- 64, 121, 242, 5, //Greenish
- 128, 25, 173, 121, //Turquoise
- 192, 250, 77, 127, //Pink
- 255, 171, 101, 221 //Purple
- };
-
- // Gradient palette "bhw1_01_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_01.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 12 bytes of program space.
-
-const byte retro_clown_gp[] PROGMEM = {
- 0, 227,101, 3,
- 117, 194, 18, 19,
- 255, 92, 8,192};
+// http://seaviewsensing.com/pub/cpt-city/arendal/temperature.c3g
+const uint8_t temperature_gp[] PROGMEM = {
+ 0, 20, 92, 171,
+ 14, 15, 111, 186,
+ 28, 6, 142, 211,
+ 42, 2, 161, 227,
+ 56, 16, 181, 239,
+ 70, 38, 188, 201,
+ 84, 86, 204, 200,
+ 99, 139, 219, 176,
+ 113, 182, 229, 125,
+ 127, 196, 230, 63,
+ 141, 241, 240, 22,
+ 155, 254, 222, 30,
+ 170, 251, 199, 4,
+ 184, 247, 157, 9,
+ 198, 243, 114, 15,
+ 226, 213, 30, 29,
+ 240, 151, 38, 35,
+ 255, 151, 38, 35};
+
+// Gradient palette "bhw1_01_gp", originally from
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_01.c3g
+const uint8_t retro_clown_gp[] PROGMEM = {
+ 0, 242, 168, 38,
+ 117, 226, 78, 80,
+ 255, 161, 54, 225,
+};
// Gradient palette "bhw1_04_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_04.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 20 bytes of program space.
-
-const byte candy_gp[] PROGMEM = {
- 0, 229,227, 1,
- 15, 227,101, 3,
- 142, 40, 1, 80,
- 198, 17, 1, 79,
- 255, 0, 0, 45};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_04.c3g
+const uint8_t candy_gp[] PROGMEM = {
+ 0, 243, 242, 23,
+ 15, 242, 168, 38,
+ 142, 111, 21, 151,
+ 198, 74, 22, 150,
+ 255, 0, 0, 117};
// Gradient palette "bhw1_05_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_05.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 8 bytes of program space.
-
-const byte toxy_reaf_gp[] PROGMEM = {
- 0, 1,221, 53,
- 255, 73, 3,178};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_05.c3g
+const uint8_t toxy_reaf_gp[] PROGMEM = {
+ 0, 2, 239, 126,
+ 255, 145, 35, 217};
// Gradient palette "bhw1_06_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_06.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 16 bytes of program space.
-
-const byte fairy_reaf_gp[] PROGMEM = {
- 0, 184, 1,128,
- 160, 1,193,182,
- 219, 153,227,190,
- 255, 255,255,255};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_06.c3g
+const uint8_t fairy_reaf_gp[] PROGMEM = {
+ 0, 220, 19, 187,
+ 160, 12, 225, 219,
+ 219, 203, 242, 223,
+ 255, 255, 255, 255};
// Gradient palette "bhw1_14_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_14.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 36 bytes of program space.
-
-const byte semi_blue_gp[] PROGMEM = {
- 0, 0, 0, 0,
- 12, 1, 1, 3,
- 53, 8, 1, 22,
- 80, 4, 6, 89,
- 119, 2, 25,216,
- 145, 7, 10, 99,
- 186, 15, 2, 31,
- 233, 2, 1, 5,
- 255, 0, 0, 0};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_14.c3g
+const uint8_t semi_blue_gp[] PROGMEM = {
+ 0, 0, 0, 0,
+ 12, 24, 4, 38,
+ 53, 55, 8, 84,
+ 80, 43, 48, 159,
+ 119, 31, 89, 237,
+ 145, 50, 59, 166,
+ 186, 71, 30, 98,
+ 233, 31, 15, 45,
+ 255, 0, 0, 0};
// Gradient palette "bhw1_three_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_three.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 32 bytes of program space.
-
-const byte pink_candy_gp[] PROGMEM = {
- 0, 255,255,255,
- 45, 7, 12,255,
- 112, 227, 1,127,
- 112, 227, 1,127,
- 140, 255,255,255,
- 155, 227, 1,127,
- 196, 45, 1, 99,
- 255, 255,255,255};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_three.c3g
+const uint8_t pink_candy_gp[] PROGMEM = {
+ 0, 255, 255, 255,
+ 45, 50, 64, 255,
+ 112, 242, 16, 186,
+ 140, 255, 255, 255,
+ 155, 242, 16, 186,
+ 196, 116, 13, 166,
+ 255, 255, 255, 255};
// Gradient palette "bhw1_w00t_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_w00t.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 16 bytes of program space.
-
-const byte red_reaf_gp[] PROGMEM = {
- 0, 3, 13, 43,
- 104, 78,141,240,
- 188, 255, 0, 0,
- 255, 28, 1, 1};
-
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_w00t.c3g
+const uint8_t red_reaf_gp[] PROGMEM = {
+ 0, 36, 68, 114,
+ 104, 149, 195, 248,
+ 188, 255, 0, 0,
+ 255, 94, 14, 9};
// Gradient palette "bhw2_23_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_23.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Red & Flash in SR
-// Size: 28 bytes of program space.
-
-const byte aqua_flash_gp[] PROGMEM = {
- 0, 0, 0, 0,
- 66, 57,227,233,
- 96, 255,255, 8,
- 124, 255,255,255,
- 153, 255,255, 8,
- 188, 57,227,233,
- 255, 0, 0, 0};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_23.c3g
+const uint8_t aqua_flash_gp[] PROGMEM = {
+ 0, 0, 0, 0,
+ 66, 130, 242, 245,
+ 96, 255, 255, 53,
+ 124, 255, 255, 255,
+ 153, 255, 255, 53,
+ 188, 130, 242, 245,
+ 255, 0, 0, 0};
// Gradient palette "bhw2_xc_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_xc.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// YBlue in SR
-// Size: 28 bytes of program space.
-
-const byte yelblu_hot_gp[] PROGMEM = {
- 0, 4, 2, 9,
- 58, 16, 0, 47,
- 122, 24, 0, 16,
- 158, 144, 9, 1,
- 183, 179, 45, 1,
- 219, 220,114, 2,
- 255, 234,237, 1};
-
- // Gradient palette "bhw2_45_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_45.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 24 bytes of program space.
-
-const byte lite_light_gp[] PROGMEM = {
- 0, 0, 0, 0,
- 9, 1, 1, 1,
- 40, 5, 5, 6,
- 66, 5, 5, 6,
- 101, 10, 1, 12,
- 255, 0, 0, 0};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_xc.c3g
+const uint8_t yelblu_hot_gp[] PROGMEM = {
+ 0, 43, 30, 57,
+ 58, 73, 0, 119,
+ 122, 87, 0, 74,
+ 158, 197, 57, 22,
+ 183, 218, 117, 27,
+ 219, 239, 177, 32,
+ 255, 246, 247, 27,
+};
+
+// Gradient palette "bhw2_45_gp", originally from
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_45.c3g
+const uint8_t lite_light_gp[] PROGMEM = {
+ 0, 0, 0, 0,
+ 9, 20, 21, 22,
+ 40, 46, 43, 49,
+ 66, 46, 43, 49,
+ 101, 61, 16, 65,
+ 255, 0, 0, 0};
// Gradient palette "bhw2_22_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_22.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Pink Plasma in SR
-// Size: 20 bytes of program space.
-
-const byte red_flash_gp[] PROGMEM = {
- 0, 0, 0, 0,
- 99, 227, 1, 1,
- 130, 249,199, 95,
- 155, 227, 1, 1,
- 255, 0, 0, 0};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_22.c3g
+const uint8_t red_flash_gp[] PROGMEM = {
+ 0, 0, 0, 0,
+ 99, 242, 12, 8,
+ 130, 253, 228, 163,
+ 155, 242, 12, 8,
+ 255, 0, 0, 0};
// Gradient palette "bhw3_40_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw3/tn/bhw3_40.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 32 bytes of program space.
-
-const byte blink_red_gp[] PROGMEM = {
- 0, 1, 1, 1,
- 43, 4, 1, 11,
- 76, 10, 1, 3,
- 109, 161, 4, 29,
- 127, 255, 86,123,
- 165, 125, 16,160,
- 204, 35, 13,223,
- 255, 18, 2, 18};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw3/bhw3_40.c3g
+const uint8_t blink_red_gp[] PROGMEM = {
+ 0, 4, 7, 4,
+ 43, 40, 25, 62,
+ 76, 61, 15, 36,
+ 109, 207, 39, 96,
+ 127, 255, 156, 184,
+ 165, 185, 73, 207,
+ 204, 105, 66, 240,
+ 255, 77, 29, 78};
// Gradient palette "bhw3_52_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw3/tn/bhw3_52.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Yellow2Blue in SR
-// Size: 28 bytes of program space.
-
-const byte red_shift_gp[] PROGMEM = {
- 0, 31, 1, 27,
- 45, 34, 1, 16,
- 99, 137, 5, 9,
- 132, 213,128, 10,
- 175, 199, 22, 1,
- 201, 199, 9, 6,
- 255, 1, 0, 1};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw3/bhw3_52.c3g
+const uint8_t red_shift_gp[] PROGMEM = {
+ 0, 98, 22, 93,
+ 45, 103, 22, 73,
+ 99, 192, 45, 56,
+ 132, 235, 187, 59,
+ 175, 228, 85, 26,
+ 201, 228, 56, 48,
+ 255, 2, 0, 2};
// Gradient palette "bhw4_097_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw4/tn/bhw4_097.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Yellow2Red in SR
-// Size: 44 bytes of program space.
-
-const byte red_tide_gp[] PROGMEM = {
- 0, 247, 5, 0,
- 28, 255, 67, 1,
- 43, 234, 88, 11,
- 58, 234,176, 51,
- 84, 229, 28, 1,
- 114, 113, 12, 1,
- 140, 255,225, 44,
- 168, 113, 12, 1,
- 196, 244,209, 88,
- 216, 255, 28, 1,
- 255, 53, 1, 1};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw4/bhw4_097.c3g
+const uint8_t red_tide_gp[] PROGMEM = {
+ 0, 251, 46, 0,
+ 28, 255, 139, 25,
+ 43, 246, 158, 63,
+ 58, 246, 216, 123,
+ 84, 243, 94, 10,
+ 114, 177, 65, 11,
+ 140, 255, 241, 115,
+ 168, 177, 65, 11,
+ 196, 250, 233, 158,
+ 216, 255, 94, 6,
+ 255, 126, 8, 4};
// Gradient palette "bhw4_017_gp", originally from
-// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw4/tn/bhw4_017.png.index.html
-// converted for FastLED with gammas (2.6, 2.2, 2.5)
-// Size: 40 bytes of program space.
-
-const byte candy2_gp[] PROGMEM = {
- 0, 39, 33, 34,
- 25, 4, 6, 15,
- 48, 49, 29, 22,
- 73, 224,173, 1,
- 89, 177, 35, 5,
- 130, 4, 6, 15,
- 163, 255,114, 6,
- 186, 224,173, 1,
- 211, 39, 33, 34,
- 255, 1, 1, 1};
+// http://seaviewsensing.com/pub/cpt-city/bhw/bhw4/bhw4_017.c3g
+const uint8_t candy2_gp[] PROGMEM = {
+ 0, 109, 102, 102,
+ 25, 42, 49, 71,
+ 48, 121, 96, 84,
+ 73, 241, 214, 26,
+ 89, 216, 104, 44,
+ 130, 42, 49, 71,
+ 163, 255, 177, 47,
+ 186, 241, 214, 26,
+ 211, 109, 102, 102,
+ 255, 20, 19, 13};
const byte trafficlight_gp[] PROGMEM = {
- 0, 0, 0, 0, //black
- 85, 0, 255, 0, //green
- 170, 255, 255, 0, //yellow
- 255, 255, 0, 0}; //red
+ 0, 0, 0, 0, //black
+ 85, 0, 255, 0, //green
+ 170, 255, 255, 0, //yellow
+ 255, 255, 0, 0}; //red
+
+const byte Aurora2_gp[] PROGMEM = {
+ 0, 17, 177, 13, //Greenish
+ 64, 121, 242, 5, //Greenish
+ 128, 25, 173, 121, //Turquoise
+ 192, 250, 77, 127, //Pink
+ 255, 171, 101, 221}; //Purple
+
+// FastLed palettes, corrected with inverse gamma of 2.2 to match original looks
+
+// Party colors
+const TProgmemRGBPalette16 PartyColors_gc22 FL_PROGMEM = {
+ 0x9B00D5, 0xBD00B8, 0xDA0092, 0xF3005C,
+ 0xF45500, 0xDC8F00, 0xD5B400, 0xD5D500,
+ 0xD59B00, 0xEF6600, 0xF90044, 0xE10086,
+ 0xC400B0, 0xA300CF, 0x7600E8, 0x0032FC};
+
+// Rainbow colors
+const TProgmemRGBPalette16 RainbowColors_gc22 FL_PROGMEM = {
+ 0xFF0000, 0xEB7000, 0xD59B00, 0xD5BA00,
+ 0xD5D500, 0x9CEB00, 0x00FF00, 0x00EB70,
+ 0x00D59B, 0x009CD4, 0x0000FF, 0x7000EB,
+ 0x9B00D5, 0xBA00BB, 0xD5009B, 0xEB0072};
+
+// Rainbow colors with alternatating stripes of black
+const TProgmemRGBPalette16 RainbowStripeColors_gc22 FL_PROGMEM = {
+ 0xFF0000, 0x000000, 0xD59B00, 0x000000,
+ 0xD5D500, 0x000000, 0x00FF00, 0x000000,
+ 0x00D59B, 0x000000, 0x0000FF, 0x000000,
+ 0x9B00D5, 0x000000, 0xD5009B, 0x000000};
// array of fastled palettes (palette 6 - 12)
const TProgmemRGBPalette16 *const fastledPalettes[] PROGMEM = {
- &PartyColors_p, //06-00 Party
+ &PartyColors_gc22, //06-00 Party
&CloudColors_p, //07-01 Cloud
&LavaColors_p, //08-02 Lava
&OceanColors_p, //09-03 Ocean
&ForestColors_p, //10-04 Forest
- &RainbowColors_p, //11-05 Rainbow
- &RainbowStripeColors_p //12-06 Rainbow Bands
+ &RainbowColors_gc22, //11-05 Rainbow
+ &RainbowStripeColors_gc22 //12-06 Rainbow Bands
};
// Single array of defined cpt-city color palettes.
// This will let us programmatically choose one based on
// a number, rather than having to activate each explicitly
// by name every time.
-const byte* const gGradientPalettes[] PROGMEM = {
+const uint8_t* const gGradientPalettes[] PROGMEM = {
Sunset_Real_gp, //13-00 Sunset
es_rivendell_15_gp, //14-01 Rivendell
es_ocean_breeze_036_gp, //15-02 Breeze
diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp
index 6f16523010..cdbb852670 100644
--- a/wled00/pin_manager.cpp
+++ b/wled00/pin_manager.cpp
@@ -1,5 +1,5 @@
-#include "pin_manager.h"
#include "wled.h"
+#include "pin_manager.h"
#ifdef ARDUINO_ARCH_ESP32
#ifdef bitRead
diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h
index b285b6ee5d..662e499b2a 100644
--- a/wled00/pin_manager.h
+++ b/wled00/pin_manager.h
@@ -3,11 +3,6 @@
/*
* Registers pins so there is no attempt for two interfaces to use the same pin
*/
-#include
-#ifdef ARDUINO_ARCH_ESP32
-#include "driver/ledc.h" // needed for analog/LEDC channel counts
-#endif
-#include "const.h" // for USERMOD_* values
#ifdef ESP8266
#define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17)
diff --git a/wled00/presets.cpp b/wled00/presets.cpp
index 54f052637b..fed2c1ed92 100644
--- a/wled00/presets.cpp
+++ b/wled00/presets.cpp
@@ -29,8 +29,9 @@ bool presetNeedsSaving() {
static void doSaveState() {
bool persist = (presetToSave < 251);
- unsigned long start = millis();
- while (strip.isUpdating() && millis()-start < (2*FRAMETIME_FIXED)+1) yield(); // wait 2 frames
+ unsigned long maxWait = millis() + strip.getFrameTime();
+ while (strip.isUpdating() && millis() < maxWait) delay(1); // wait for strip to finish updating, accessing FS during sendout causes glitches
+
if (!requestJSONBufferLock(10)) return;
initPresetsFile(); // just in case if someone deleted presets.json using /edit
@@ -56,14 +57,10 @@ static void doSaveState() {
*/
#if defined(ARDUINO_ARCH_ESP32)
if (!persist) {
- if (tmpRAMbuffer!=nullptr) free(tmpRAMbuffer);
+ p_free(tmpRAMbuffer);
size_t len = measureJson(*pDoc) + 1;
- DEBUG_PRINTLN(len);
// if possible use SPI RAM on ESP32
- if (psramSafe && psramFound())
- tmpRAMbuffer = (char*) ps_malloc(len);
- else
- tmpRAMbuffer = (char*) malloc(len);
+ tmpRAMbuffer = (char*)p_malloc(len);
if (tmpRAMbuffer!=nullptr) {
serializeJson(*pDoc, tmpRAMbuffer, len);
} else {
@@ -80,8 +77,8 @@ static void doSaveState() {
// clean up
saveLedmap = -1;
presetToSave = 0;
- free(saveName);
- free(quickLoad);
+ p_free(saveName);
+ p_free(quickLoad);
saveName = nullptr;
quickLoad = nullptr;
playlistSave = false;
@@ -168,9 +165,9 @@ void handlePresets()
DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset);
- #if defined(ARDUINO_ARCH_ESP32S3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3)
- unsigned long start = millis();
- while (strip.isUpdating() && millis() - start < FRAMETIME_FIXED) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches
+ #if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3)
+ unsigned long maxWait = millis() + strip.getFrameTime();
+ while (strip.isUpdating() && millis() < maxWait) delay(1); // wait for strip to finish updating, accessing FS during sendout causes glitches
#endif
#ifdef ARDUINO_ARCH_ESP32
@@ -206,7 +203,7 @@ void handlePresets()
#if defined(ARDUINO_ARCH_ESP32)
//Aircoookie recommended not to delete buffer
if (tmpPreset==255 && tmpRAMbuffer!=nullptr) {
- free(tmpRAMbuffer);
+ p_free(tmpRAMbuffer);
tmpRAMbuffer = nullptr;
}
#endif
@@ -220,8 +217,8 @@ void handlePresets()
//called from handleSet(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)]
void savePreset(byte index, const char* pname, JsonObject sObj)
{
- if (!saveName) saveName = static_cast(malloc(33));
- if (!quickLoad) quickLoad = static_cast(malloc(9));
+ if (!saveName) saveName = static_cast(p_malloc(33));
+ if (!quickLoad) quickLoad = static_cast(p_malloc(9));
if (!saveName || !quickLoad) return;
if (index == 0 || (index > 250 && index < 255)) return;
@@ -242,7 +239,7 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
if (!sObj[FPSTR(bootPS)].isNull()) {
bootPreset = sObj[FPSTR(bootPS)] | bootPreset;
sObj.remove(FPSTR(bootPS));
- doSerializeConfig = true;
+ configNeedsWrite = true;
}
if (sObj.size()==0 || sObj["o"].isNull()) { // no "o" means not a playlist or custom API call, saving of state is async (not immediately)
@@ -267,8 +264,8 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
presetsModifiedTime = toki.second(); //unix time
updateFSInfo();
}
- free(saveName);
- free(quickLoad);
+ p_free(saveName);
+ p_free(quickLoad);
saveName = nullptr;
quickLoad = nullptr;
} else {
diff --git a/wled00/remote.cpp b/wled00/remote.cpp
index 8c060a70ca..14c3c0d01d 100644
--- a/wled00/remote.cpp
+++ b/wled00/remote.cpp
@@ -181,16 +181,10 @@ static bool remoteJson(int button)
return parsed;
}
-// Callback function that will be executed when data is received
+// Callback function that will be executed when data is received from a linked remote
void handleWiZdata(uint8_t *incomingData, size_t len) {
message_structure_t *incoming = reinterpret_cast(incomingData);
- if (strcmp(last_signal_src, linked_remote) != 0) {
- DEBUG_PRINT(F("ESP Now Message Received from Unlinked Sender: "));
- DEBUG_PRINTLN(last_signal_src);
- return;
- }
-
if (len != sizeof(message_structure_t)) {
DEBUG_PRINTF_P(PSTR("Unknown incoming ESP Now message received of length %u\n"), len);
return;
diff --git a/wled00/set.cpp b/wled00/set.cpp
index 00333788d4..6229ba28ef 100644
--- a/wled00/set.cpp
+++ b/wled00/set.cpp
@@ -28,7 +28,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
char gw[5] = "GW"; gw[2] = 48+n; gw[4] = 0; //GW address
char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask
if (request->hasArg(cs)) {
- if (n >= multiWiFi.size()) multiWiFi.push_back(WiFiConfig()); // expand vector by one
+ if (n >= multiWiFi.size()) multiWiFi.emplace_back(); // expand vector by one
char oldSSID[33]; strcpy(oldSSID, multiWiFi[n].clientSSID);
char oldPass[65]; strcpy(oldPass, multiWiFi[n].clientPass);
@@ -91,8 +91,21 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
bool oldESPNow = enableESPNow;
enableESPNow = request->hasArg(F("RE"));
if (oldESPNow != enableESPNow) forceReconnect = true;
- strlcpy(linked_remote, request->arg(F("RMAC")).c_str(), 13);
- strlwr(linked_remote); //Normalize MAC format to lowercase
+ linked_remotes.clear(); // clear old remotes
+ for (size_t n = 0; n < 10; n++) {
+ char rm[4];
+ snprintf(rm, sizeof(rm), "RM%d", n); // "RM0" to "RM9"
+ if (request->hasArg(rm)) {
+ const String& arg = request->arg(rm);
+ if (arg.isEmpty()) continue;
+ std::array mac{};
+ strlcpy(mac.data(), request->arg(rm).c_str(), 13);
+ strlwr(mac.data());
+ if (mac[0] != '\0') {
+ linked_remotes.emplace_back(mac);
+ }
+ }
+ }
#endif
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
@@ -129,6 +142,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
unsigned length, start, maMax;
uint8_t pins[5] = {255, 255, 255, 255, 255};
+ // this will set global ABL max current used when per-port ABL is not used
unsigned ablMilliampsMax = request->arg(F("MA")).toInt();
BusManager::setMilliampsMax(ablMilliampsMax);
@@ -136,17 +150,17 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
strip.correctWB = request->hasArg(F("CCT"));
strip.cctFromRgb = request->hasArg(F("CR"));
cctICused = request->hasArg(F("IC"));
- Bus::setCCTBlend(request->arg(F("CB")).toInt());
+ uint8_t cctBlending = request->arg(F("CB")).toInt();
+ Bus::setCCTBlend(cctBlending);
Bus::setGlobalAWMode(request->arg(F("AW")).toInt());
strip.setTargetFps(request->arg(F("FR")).toInt());
- useGlobalLedBuffer = request->hasArg(F("LD"));
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
useParallelI2S = request->hasArg(F("PR"));
#endif
bool busesChanged = false;
for (int s = 0; s < 36; s++) { // theoretical limit is 36 : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- int offset = s < 10 ? '0' : 'A';
+ int offset = s < 10 ? '0' : 'A' - 10;
char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin
char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length
char co[4] = "CO"; co[2] = offset+s; co[3] = 0; //strip color order
@@ -207,12 +221,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
maMax = 0;
} else {
maPerLed = request->arg(la).toInt();
- maMax = request->arg(ma).toInt(); // if ABL is disabled this will be 0
+ maMax = request->arg(ma).toInt() * request->hasArg(F("PPL")); // if PP-ABL is disabled maMax (per bus) must be 0
}
type |= request->hasArg(rf) << 7; // off refresh override
// actual finalization is done in WLED::loop() (removing old busses and adding new)
// this may happen even before this loop is finished so we do "doInitBusses" after the loop
- busConfigs.emplace_back(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax);
+ busConfigs.emplace_back(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, maPerLed, maMax);
busesChanged = true;
}
//doInitBusses = busesChanged; // we will do that below to ensure all input data is processed
@@ -220,7 +234,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
// we will not bother with pre-allocating ColorOrderMappings vector
BusManager::getColorOrderMap().reset();
for (int s = 0; s < WLED_MAX_COLOR_ORDER_MAPPINGS; s++) {
- int offset = s < 10 ? '0' : 'A';
+ int offset = s < 10 ? '0' : 'A' - 10;
char xs[4] = "XS"; xs[2] = offset+s; xs[3] = 0; //start LED
char xc[4] = "XC"; xc[2] = offset+s; xc[3] = 0; //strip length
char xo[4] = "XO"; xo[2] = offset+s; xo[3] = 0; //color order
@@ -259,7 +273,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
disablePullUp = (bool)request->hasArg(F("IP"));
touchThreshold = request->arg(F("TT")).toInt();
for (int i = 0; i < WLED_MAX_BUTTONS; i++) {
- int offset = i < 10 ? '0' : 'A';
+ int offset = i < 10 ? '0' : 'A' - 10;
char bt[4] = "BT"; bt[2] = offset+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10)
char be[4] = "BE"; be[2] = offset+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10)
int hw_btn_pin = request->arg(bt).toInt();
@@ -327,13 +341,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
gammaCorrectBri = false;
gammaCorrectCol = false;
}
- NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
+ NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables
t = request->arg(F("TD")).toInt();
if (t >= 0) transitionDelayDefault = t;
t = request->arg(F("TP")).toInt();
randomPaletteChangeTime = MIN(255,MAX(1,t));
useHarmonicRandomPalette = request->hasArg(F("TH"));
+ useRainbowWheel = request->hasArg(F("RW"));
nightlightTargetBri = request->arg(F("TB")).toInt();
t = request->arg(F("TL")).toInt();
@@ -342,7 +357,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
nightlightMode = request->arg(F("TW")).toInt();
t = request->arg(F("PB")).toInt();
- if (t >= 0 && t < 4) strip.paletteBlend = t;
+ if (t >= 0 && t < 4) paletteBlend = t;
t = request->arg(F("BF")).toInt();
if (t > 0) briMultiplier = t;
@@ -358,7 +373,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
DEBUG_PRINTLN(F("Enumerating ledmaps"));
enumerateLedmaps();
DEBUG_PRINTLN(F("Loading custom palettes"));
- strip.loadCustomPalettes(); // (re)load all custom palettes
+ loadCustomPalettes(); // (re)load all custom palettes
}
//SYNC
@@ -593,7 +608,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
{
otaLock = request->hasArg(F("NO"));
wifiLock = request->hasArg(F("OW"));
+ #ifndef WLED_DISABLE_OTA
aOtaEnabled = request->hasArg(F("AO"));
+ #endif
//createEditHandler(correctPIN && !otaLock);
}
}
@@ -771,14 +788,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (subPage == SUBPAGE_2D)
{
strip.isMatrix = request->arg(F("SOMP")).toInt();
- strip.panel.clear(); // release memory if allocated
+ strip.panel.clear();
if (strip.isMatrix) {
- strip.panels = MAX(1,MIN(WLED_MAX_PANELS,request->arg(F("MPC")).toInt()));
- strip.panel.reserve(strip.panels); // pre-allocate memory
- for (unsigned i=0; iarg(F("MPC")).toInt(), 1, WLED_MAX_PANELS);
+ strip.panel.reserve(panels); // pre-allocate memory
+ for (unsigned i=0; iarg(pO).toInt();
strip.panel.push_back(p);
}
- strip.setUpMatrix(); // will check limits
- strip.makeAutoSegments(true);
- strip.deserializeMap();
- } else {
- Segment::maxWidth = strip.getLengthTotal();
- Segment::maxHeight = 1;
}
+ strip.panel.shrink_to_fit(); // release unused memory
+ strip.deserializeMap(); // (re)load default ledmap (will also setUpMatrix() if ledmap does not exist)
+ strip.makeAutoSegments(true); // force re-creation of segments
}
#endif
lastEditTime = millis();
// do not save if factory reset or LED settings (which are saved after LED re-init)
- doSerializeConfig = subPage != SUBPAGE_LEDS && !(subPage == SUBPAGE_SEC && doReboot);
- if (subPage == SUBPAGE_UM) doReboot = request->hasArg(F("RBT")); // prevent race condition on dual core system (set reboot here, after doSerializeConfig has been set)
+ configNeedsWrite = subPage != SUBPAGE_LEDS && !(subPage == SUBPAGE_SEC && doReboot);
+ if (subPage == SUBPAGE_UM) doReboot = request->hasArg(F("RBT")); // prevent race condition on dual core system (set reboot here, after configNeedsWrite has been set)
#ifndef WLED_DISABLE_ALEXA
if (subPage == SUBPAGE_SYNC) alexaInit();
#endif
@@ -824,7 +838,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//segment select (sets main segment)
pos = req.indexOf(F("SM="));
if (pos > 0 && !realtimeMode) {
- strip.setMainSegmentId(getNumVal(&req, pos));
+ strip.setMainSegmentId(getNumVal(req, pos));
}
byte selectedSeg = strip.getFirstSelectedSegId();
@@ -833,7 +847,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("SS="));
if (pos > 0) {
- unsigned t = getNumVal(&req, pos);
+ unsigned t = getNumVal(req, pos);
if (t < strip.getSegmentsNum()) {
selectedSeg = t;
singleSegment = true;
@@ -843,7 +857,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
Segment& selseg = strip.getSegment(selectedSeg);
pos = req.indexOf(F("SV=")); //segment selected
if (pos > 0) {
- unsigned t = getNumVal(&req, pos);
+ unsigned t = getNumVal(req, pos);
if (t == 2) for (unsigned i = 0; i < strip.getSegmentsNum(); i++) strip.getSegment(i).selected = false; // unselect other segments
selseg.selected = t;
}
@@ -872,19 +886,19 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
uint16_t spcI = selseg.spacing;
pos = req.indexOf(F("&S=")); //segment start
if (pos > 0) {
- startI = std::abs(getNumVal(&req, pos));
+ startI = std::abs(getNumVal(req, pos));
}
pos = req.indexOf(F("S2=")); //segment stop
if (pos > 0) {
- stopI = std::abs(getNumVal(&req, pos));
+ stopI = std::abs(getNumVal(req, pos));
}
pos = req.indexOf(F("GP=")); //segment grouping
if (pos > 0) {
- grpI = std::max(1,getNumVal(&req, pos));
+ grpI = std::max(1,getNumVal(req, pos));
}
pos = req.indexOf(F("SP=")); //segment spacing
if (pos > 0) {
- spcI = std::max(0,getNumVal(&req, pos));
+ spcI = std::max(0,getNumVal(req, pos));
}
strip.suspend(); // must suspend strip operations before changing geometry
selseg.setGeometry(startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY, selseg.map1D2D);
@@ -898,7 +912,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("SB=")); //Segment brightness/opacity
if (pos > 0) {
- byte segbri = getNumVal(&req, pos);
+ byte segbri = getNumVal(req, pos);
selseg.setOption(SEG_OPTION_ON, segbri); // use transition
if (segbri) {
selseg.setOpacity(segbri);
@@ -907,7 +921,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("SW=")); //segment power
if (pos > 0) {
- switch (getNumVal(&req, pos)) {
+ switch (getNumVal(req, pos)) {
case 0: selseg.setOption(SEG_OPTION_ON, false); break; // use transition
case 1: selseg.setOption(SEG_OPTION_ON, true); break; // use transition
default: selseg.setOption(SEG_OPTION_ON, !selseg.on); break; // use transition
@@ -915,16 +929,16 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
}
pos = req.indexOf(F("PS=")); //saves current in preset
- if (pos > 0) savePreset(getNumVal(&req, pos));
+ if (pos > 0) savePreset(getNumVal(req, pos));
pos = req.indexOf(F("P1=")); //sets first preset for cycle
- if (pos > 0) presetCycMin = getNumVal(&req, pos);
+ if (pos > 0) presetCycMin = getNumVal(req, pos);
pos = req.indexOf(F("P2=")); //sets last preset for cycle
- if (pos > 0) presetCycMax = getNumVal(&req, pos);
+ if (pos > 0) presetCycMax = getNumVal(req, pos);
//apply preset
- if (updateVal(req.c_str(), "PL=", &presetCycCurr, presetCycMin, presetCycMax)) {
+ if (updateVal(req.c_str(), "PL=", presetCycCurr, presetCycMin, presetCycMax)) {
applyPreset(presetCycCurr);
}
@@ -932,25 +946,25 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (pos > 0) doAdvancePlaylist = true;
//set brightness
- updateVal(req.c_str(), "&A=", &bri);
+ updateVal(req.c_str(), "&A=", bri);
bool col0Changed = false, col1Changed = false, col2Changed = false;
//set colors
- col0Changed |= updateVal(req.c_str(), "&R=", &colIn[0]);
- col0Changed |= updateVal(req.c_str(), "&G=", &colIn[1]);
- col0Changed |= updateVal(req.c_str(), "&B=", &colIn[2]);
- col0Changed |= updateVal(req.c_str(), "&W=", &colIn[3]);
+ col0Changed |= updateVal(req.c_str(), "&R=", colIn[0]);
+ col0Changed |= updateVal(req.c_str(), "&G=", colIn[1]);
+ col0Changed |= updateVal(req.c_str(), "&B=", colIn[2]);
+ col0Changed |= updateVal(req.c_str(), "&W=", colIn[3]);
- col1Changed |= updateVal(req.c_str(), "R2=", &colInSec[0]);
- col1Changed |= updateVal(req.c_str(), "G2=", &colInSec[1]);
- col1Changed |= updateVal(req.c_str(), "B2=", &colInSec[2]);
- col1Changed |= updateVal(req.c_str(), "W2=", &colInSec[3]);
+ col1Changed |= updateVal(req.c_str(), "R2=", colInSec[0]);
+ col1Changed |= updateVal(req.c_str(), "G2=", colInSec[1]);
+ col1Changed |= updateVal(req.c_str(), "B2=", colInSec[2]);
+ col1Changed |= updateVal(req.c_str(), "W2=", colInSec[3]);
#ifdef WLED_ENABLE_LOXONE
//lox parser
pos = req.indexOf(F("LX=")); // Lox primary color
if (pos > 0) {
- int lxValue = getNumVal(&req, pos);
+ int lxValue = getNumVal(req, pos);
if (parseLx(lxValue, colIn)) {
bri = 255;
nightlightActive = false; //always disable nightlight when toggling
@@ -959,7 +973,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
}
pos = req.indexOf(F("LY=")); // Lox secondary color
if (pos > 0) {
- int lxValue = getNumVal(&req, pos);
+ int lxValue = getNumVal(req, pos);
if(parseLx(lxValue, colInSec)) {
bri = 255;
nightlightActive = false; //always disable nightlight when toggling
@@ -971,11 +985,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set hue
pos = req.indexOf(F("HU="));
if (pos > 0) {
- uint16_t temphue = getNumVal(&req, pos);
+ uint16_t temphue = getNumVal(req, pos);
byte tempsat = 255;
pos = req.indexOf(F("SA="));
if (pos > 0) {
- tempsat = getNumVal(&req, pos);
+ tempsat = getNumVal(req, pos);
}
byte sec = req.indexOf(F("H2"));
colorHStoRGB(temphue, tempsat, (sec>0) ? colInSec : colIn);
@@ -986,25 +1000,25 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("&K="));
if (pos > 0) {
byte sec = req.indexOf(F("K2"));
- colorKtoRGB(getNumVal(&req, pos), (sec>0) ? colInSec : colIn);
+ colorKtoRGB(getNumVal(req, pos), (sec>0) ? colInSec : colIn);
col0Changed |= (!sec); col1Changed |= sec;
}
//set color from HEX or 32bit DEC
pos = req.indexOf(F("CL="));
if (pos > 0) {
- colorFromDecOrHexString(colIn, req.substring(pos + 3).c_str());
+ colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str());
col0Changed = true;
}
pos = req.indexOf(F("C2="));
if (pos > 0) {
- colorFromDecOrHexString(colInSec, req.substring(pos + 3).c_str());
+ colorFromDecOrHexString(colInSec, (char*)req.substring(pos + 3).c_str());
col1Changed = true;
}
pos = req.indexOf(F("C3="));
if (pos > 0) {
byte tmpCol[4];
- colorFromDecOrHexString(tmpCol, req.substring(pos + 3).c_str());
+ colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
selseg.setColor(2, col2); // defined above (SS= or main)
col2Changed = true;
@@ -1013,7 +1027,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set to random hue SR=0->1st SR=1->2nd
pos = req.indexOf(F("SR"));
if (pos > 0) {
- byte sec = getNumVal(&req, pos);
+ byte sec = getNumVal(req, pos);
setRandomColor(sec? colInSec : colIn);
col0Changed |= (!sec); col1Changed |= sec;
}
@@ -1039,19 +1053,19 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
bool fxModeChanged = false, speedChanged = false, intensityChanged = false, paletteChanged = false;
bool custom1Changed = false, custom2Changed = false, custom3Changed = false, check1Changed = false, check2Changed = false, check3Changed = false;
// set effect parameters
- if (updateVal(req.c_str(), "FX=", &effectIn, 0, strip.getModeCount()-1)) {
+ if (updateVal(req.c_str(), "FX=", effectIn, 0, strip.getModeCount()-1)) {
if (request != nullptr) unloadPlaylist(); // unload playlist if changing FX using web request
fxModeChanged = true;
}
- speedChanged = updateVal(req.c_str(), "SX=", &speedIn);
- intensityChanged = updateVal(req.c_str(), "IX=", &intensityIn);
- paletteChanged = updateVal(req.c_str(), "FP=", &paletteIn, 0, strip.getPaletteCount()-1);
- custom1Changed = updateVal(req.c_str(), "X1=", &custom1In);
- custom2Changed = updateVal(req.c_str(), "X2=", &custom2In);
- custom3Changed = updateVal(req.c_str(), "X3=", &custom3In);
- check1Changed = updateVal(req.c_str(), "M1=", &check1In);
- check2Changed = updateVal(req.c_str(), "M2=", &check2In);
- check3Changed = updateVal(req.c_str(), "M3=", &check3In);
+ speedChanged = updateVal(req.c_str(), "SX=", speedIn);
+ intensityChanged = updateVal(req.c_str(), "IX=", intensityIn);
+ paletteChanged = updateVal(req.c_str(), "FP=", paletteIn, 0, getPaletteCount()-1);
+ custom1Changed = updateVal(req.c_str(), "X1=", custom1In);
+ custom2Changed = updateVal(req.c_str(), "X2=", custom2In);
+ custom3Changed = updateVal(req.c_str(), "X3=", custom3In);
+ check1Changed = updateVal(req.c_str(), "M1=", check1In);
+ check2Changed = updateVal(req.c_str(), "M2=", check2In);
+ check3Changed = updateVal(req.c_str(), "M3=", check3In);
stateChanged |= (fxModeChanged || speedChanged || intensityChanged || paletteChanged || custom1Changed || custom2Changed || custom3Changed || check1Changed || check2Changed || check3Changed);
@@ -1077,13 +1091,13 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set advanced overlay
pos = req.indexOf(F("OL="));
if (pos > 0) {
- overlayCurrent = getNumVal(&req, pos);
+ overlayCurrent = getNumVal(req, pos);
}
//apply macro (deprecated, added for compatibility with pre-0.11 automations)
pos = req.indexOf(F("&M="));
if (pos > 0) {
- applyPreset(getNumVal(&req, pos) + 16);
+ applyPreset(getNumVal(req, pos) + 16);
}
//toggle send UDP direct notifications
@@ -1102,7 +1116,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("&T="));
if (pos > 0) {
nightlightActive = false; //always disable nightlight when toggling
- switch (getNumVal(&req, pos))
+ switch (getNumVal(req, pos))
{
case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off, only if it was previously on
case 1: if (bri == 0) bri = briLast; break; //on, only if it was previously off
@@ -1121,7 +1135,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
nightlightActive = false;
} else {
nightlightActive = true;
- if (!aNlDef) nightlightDelayMins = getNumVal(&req, pos);
+ if (!aNlDef) nightlightDelayMins = getNumVal(req, pos);
else nightlightDelayMins = nightlightDelayMinsDefault;
nightlightStartTime = millis();
}
@@ -1135,7 +1149,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set nightlight target brightness
pos = req.indexOf(F("NT="));
if (pos > 0) {
- nightlightTargetBri = getNumVal(&req, pos);
+ nightlightTargetBri = getNumVal(req, pos);
nightlightActiveOld = false; //re-init
}
@@ -1143,35 +1157,36 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("NF="));
if (pos > 0)
{
- nightlightMode = getNumVal(&req, pos);
+ nightlightMode = getNumVal(req, pos);
nightlightActiveOld = false; //re-init
}
if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN;
pos = req.indexOf(F("TT="));
- if (pos > 0) transitionDelay = getNumVal(&req, pos);
+ if (pos > 0) transitionDelay = getNumVal(req, pos);
strip.setTransition(transitionDelay);
//set time (unix timestamp)
pos = req.indexOf(F("ST="));
if (pos > 0) {
- setTimeFromAPI(getNumVal(&req, pos));
+ setTimeFromAPI(getNumVal(req, pos));
}
//set countdown goal (unix timestamp)
pos = req.indexOf(F("CT="));
if (pos > 0) {
- countdownTime = getNumVal(&req, pos);
+ countdownTime = getNumVal(req, pos);
if (countdownTime - toki.second() > 0) countdownOverTriggered = false;
}
pos = req.indexOf(F("LO="));
if (pos > 0) {
- realtimeOverride = getNumVal(&req, pos);
+ realtimeOverride = getNumVal(req, pos);
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
if (realtimeMode && useMainSegmentOnly) {
strip.getMainSegment().freeze = !realtimeOverride;
+ realtimeOverride = REALTIME_OVERRIDE_NONE; // ignore request for override if using main segment only
}
}
@@ -1184,12 +1199,12 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("U0=")); //user var 0
if (pos > 0) {
- userVar0 = getNumVal(&req, pos);
+ userVar0 = getNumVal(req, pos);
}
pos = req.indexOf(F("U1=")); //user var 1
if (pos > 0) {
- userVar1 = getNumVal(&req, pos);
+ userVar1 = getNumVal(req, pos);
}
// you can add more if you need
diff --git a/wled00/udp.cpp b/wled00/udp.cpp
index 4395b285d0..f2fee53540 100644
--- a/wled00/udp.cpp
+++ b/wled00/udp.cpp
@@ -6,7 +6,7 @@
#define UDP_SEG_SIZE 36
#define SEG_OFFSET (41)
-#define WLEDPACKETSIZE (41+(MAX_NUM_SEGMENTS*UDP_SEG_SIZE)+0)
+#define WLEDPACKETSIZE (41+(WS2812FX::getMaxSegments()*UDP_SEG_SIZE)+0)
#define UDP_IN_MAXSIZE 1472
#define PRESUMED_NETWORK_DELAY 3 //how many ms could it take on avg to reach the receiver? This will be added to transmitted times
@@ -55,7 +55,7 @@ void notify(byte callMode, bool followUp)
//0: old 1: supports white 2: supports secondary color
//3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette
//6: supports timebase syncing, 29 byte packet 7: supports tertiary color 8: supports sys time sync, 36 byte packet
- //9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet 11: per segment options, variable packet length (40+MAX_NUM_SEGMENTS*3)
+ //9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet 11: per segment options, variable packet length (40+WS2812FX::getMaxSegments()*3)
//12: enhanced effect sliders, 2D & mapping options
udpOut[11] = 12;
col = mainseg.colors[1];
@@ -104,7 +104,7 @@ void notify(byte callMode, bool followUp)
udpOut[40] = UDP_SEG_SIZE; //size of each loop iteration (one segment)
size_t s = 0, nsegs = strip.getSegmentsNum();
for (size_t i = 0; i < nsegs; i++) {
- Segment &selseg = strip.getSegment(i);
+ const Segment &selseg = strip.getSegment(i);
if (!selseg.isActive()) continue;
unsigned ofs = 41 + s*UDP_SEG_SIZE; //start of segment offset byte
udpOut[0 +ofs] = s;
@@ -177,7 +177,7 @@ void notify(byte callMode, bool followUp)
memcpy(buffer.data + packetSize, &udpOut[41+i*UDP_SEG_SIZE], UDP_SEG_SIZE);
packetSize += UDP_SEG_SIZE;
if (packetSize + UDP_SEG_SIZE < bufferSize) continue;
- DEBUG_PRINTF_P(PSTR("ESP-NOW sending packet: %d (%d)\n"), (int)buffer.packet, packetSize+3);
+ DEBUG_PRINTF_P(PSTR("ESP-NOW sending packet: %d (%u)\n"), (int)buffer.packet, packetSize+3);
err = quickEspNow.send(ESPNOW_BROADCAST_ADDRESS, reinterpret_cast(&buffer), packetSize+3);
buffer.packet++;
packetSize = 0;
@@ -266,13 +266,13 @@ static void parseNotifyPacket(const uint8_t *udpIn) {
strip.resume();
}
size_t inactiveSegs = 0;
- for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) {
+ for (size_t i = 0; i < numSrcSegs && i < WS2812FX::getMaxSegments(); i++) {
unsigned ofs = 41 + i*udpIn[40]; //start of segment offset byte
unsigned id = udpIn[0 +ofs];
DEBUG_PRINTF_P(PSTR("UDP segment received: %u\n"), id);
if (id > strip.getSegmentsNum()) break;
else if (id == strip.getSegmentsNum()) {
- if (receiveSegmentBounds && id < strip.getMaxSegments()) strip.appendSegment();
+ if (receiveSegmentBounds && id < WS2812FX::getMaxSegments()) strip.appendSegment();
else break;
}
DEBUG_PRINTF_P(PSTR("UDP segment check: %u\n"), id);
@@ -327,7 +327,7 @@ static void parseNotifyPacket(const uint8_t *udpIn) {
// freeze, reset should never be synced
// LSB to MSB: select, reverse, on, mirror, freeze, reset, reverse_y, mirror_y, transpose, map1d2d (3), ssim (2), set (2)
DEBUG_PRINTF_P(PSTR("Apply options: %u\n"), id);
- selseg.options = (selseg.options & 0b0000000000110001U) | (udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0b11001110U); // ignore selected, freeze, reset
+ selseg.options = (selseg.options & 0b0000000000110001U) | ((uint16_t)udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0b11001110U); // ignore selected, freeze, reset
if (applyEffects) {
DEBUG_PRINTF_P(PSTR("Apply sliders: %u\n"), id);
selseg.custom1 = udpIn[29+ofs];
@@ -406,31 +406,26 @@ static void parseNotifyPacket(const uint8_t *udpIn) {
stateUpdated(CALL_MODE_NOTIFICATION);
}
+// realtimeLock() is called from UDP notifications, JSON API or serial Ada
void realtimeLock(uint32_t timeoutMs, byte md)
{
if (!realtimeMode && !realtimeOverride) {
- unsigned stop, start;
if (useMainSegmentOnly) {
Segment& mainseg = strip.getMainSegment();
- start = mainseg.start;
- stop = mainseg.stop;
+ mainseg.clear(); // clear entire segment (in case sender transmits less pixels)
mainseg.freeze = true;
// if WLED was off and using main segment only, freeze non-main segments so they stay off
if (bri == 0) {
- for (size_t s = 0; s < strip.getSegmentsNum(); s++) {
- strip.getSegment(s).freeze = true;
- }
+ for (size_t s = 0; s < strip.getSegmentsNum(); s++) strip.getSegment(s).freeze = true;
}
} else {
- start = 0;
- stop = strip.getLengthTotal();
+ // clear entire strip
+ strip.fill(BLACK);
+ }
+ // if strip is off (bri==0) and not already in RTM
+ if (briT == 0) {
+ strip.setBrightness(scaledBri(briLast), true);
}
- // clear strip/segment
- for (size_t i = start; i < stop; i++) strip.setPixelColor(i,BLACK);
- }
- // if strip is off (bri==0) and not already in RTM
- if (briT == 0 && !realtimeMode && !realtimeOverride) {
- strip.setBrightness(scaledBri(briLast), true);
}
if (realtimeTimeout != UINT32_MAX) {
@@ -452,6 +447,7 @@ void exitRealtime() {
realtimeIP[0] = 0;
if (useMainSegmentOnly) { // unfreeze live segment again
strip.getMainSegment().freeze = false;
+ strip.trigger();
} else {
strip.show(); // possible fix for #3589
}
@@ -481,7 +477,8 @@ void handleNotifications()
if (e131NewData && millis() - strip.getLastShow() > 15)
{
e131NewData = false;
- strip.show();
+ if (useMainSegmentOnly) strip.trigger();
+ else strip.show();
}
//unlock strip when realtime UDP times out
@@ -508,13 +505,13 @@ void handleNotifications()
uint8_t lbuf[packetSize];
rgbUdp.read(lbuf, packetSize);
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
- if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
+ if (realtimeOverride) return;
unsigned totalLen = strip.getLengthTotal();
- if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
for (size_t i = 0, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++) {
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
}
- if (!(realtimeMode && useMainSegmentOnly)) strip.show();
+ if (useMainSegmentOnly) strip.trigger();
+ else strip.show();
return;
}
}
@@ -583,7 +580,7 @@ void handleNotifications()
realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP();
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
- if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
+ if (realtimeOverride) return;
tpmPacketCount++; //increment the packet count
if (tpmPacketCount == 1) tpmPayloadFrameSize = (udpIn[2] << 8) + udpIn[3]; //save frame size for the whole payload if this is the first packet
@@ -592,13 +589,13 @@ void handleNotifications()
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
unsigned totalLen = strip.getLengthTotal();
- if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
}
if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received
tpmPacketCount = 0;
- strip.show();
+ if (useMainSegmentOnly) strip.trigger();
+ else strip.show();
}
return;
}
@@ -610,17 +607,15 @@ void handleNotifications()
DEBUG_PRINTLN(realtimeIP);
if (packetSize < 2) return;
- if (udpIn[1] == 0)
- {
- realtimeTimeout = 0;
+ if (udpIn[1] == 0) {
+ realtimeTimeout = 0; // cancel realtime mode immediately
return;
} else {
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
}
- if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
+ if (realtimeOverride) return;
unsigned totalLen = strip.getLengthTotal();
- if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
if (udpIn[0] == 1 && packetSize > 5) //warls
{
for (size_t i = 2; i < packetSize -3; i += 4)
@@ -654,7 +649,8 @@ void handleNotifications()
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
}
}
- strip.show();
+ if (useMainSegmentOnly) strip.trigger();
+ else strip.show();
return;
}
@@ -679,20 +675,7 @@ void handleNotifications()
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
{
unsigned pix = i + arlsOffset;
- if (pix < strip.getLengthTotal()) {
- if (!arlsDisableGammaCorrection && gammaCorrectCol) {
- r = gamma8(r);
- g = gamma8(g);
- b = gamma8(b);
- w = gamma8(w);
- }
- uint32_t col = RGBW32(r,g,b,w);
- if (useMainSegmentOnly) {
- strip.getMainSegment().setPixelColor(pix, col); // this expects that strip.getMainSegment().beginDraw() has been called in handleNotification()
- } else {
- strip.setPixelColor(pix, col);
- }
- }
+ strip.setRealtimePixelColor(pix, RGBW32(r,g,b,w));
}
/*********************************************************************************************\
@@ -808,7 +791,7 @@ static size_t sequenceNumber = 0; // this needs to be shared across all ou
static const size_t ART_NET_HEADER_SIZE = 12;
static const byte ART_NET_HEADER[] PROGMEM = {0x41,0x72,0x74,0x2d,0x4e,0x65,0x74,0x00,0x00,0x50,0x00,0x0e};
-uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri, bool isRGBW) {
+uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t *buffer, uint8_t bri, bool isRGBW) {
if (!(apActive || interfacesInited) || !client[0] || !length) return 1; // network not initialised or dummy/unset IP address 031522 ajn added check for ap
WiFiUDP ddpUdp;
@@ -959,14 +942,22 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs
// usermods hook can override processing
if (UsermodManager::onEspNowMessage(address, data, len)) return;
- // handle WiZ Mote data
- if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) {
- handleWiZdata(data, len);
+ bool knownRemote = false;
+ for (const auto& mac : linked_remotes) {
+ if (strlen(mac.data()) == 12 && strcmp(last_signal_src, mac.data()) == 0) {
+ knownRemote = true;
+ break;
+ }
+ }
+ if (!knownRemote) {
+ DEBUG_PRINT(F("ESP Now Message Received from Unlinked Sender: "));
+ DEBUG_PRINTLN(last_signal_src);
return;
}
- if (strlen(linked_remote) == 12 && strcmp(last_signal_src, linked_remote) != 0) {
- DEBUG_PRINTLN(F("ESP-NOW unpaired remote sender."));
+ // handle WiZ Mote data
+ if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) {
+ handleWiZdata(data, len);
return;
}
diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp
index 9bfb7e7372..1a7cc22694 100644
--- a/wled00/um_manager.cpp
+++ b/wled00/um_manager.cpp
@@ -39,7 +39,13 @@ bool UsermodManager::getUMData(um_data_t **data, uint8_t mod_id) {
return false;
}
void UsermodManager::addToJsonState(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->addToJsonState(obj); }
-void UsermodManager::addToJsonInfo(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->addToJsonInfo(obj); }
+void UsermodManager::addToJsonInfo(JsonObject& obj) {
+ auto um_id_list = obj.createNestedArray("um");
+ for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) {
+ um_id_list.add((*mod)->getId());
+ (*mod)->addToJsonInfo(obj);
+ }
+}
void UsermodManager::readFromJsonState(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->readFromJsonState(obj); }
void UsermodManager::addToConfig(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->addToConfig(obj); }
bool UsermodManager::readFromConfig(JsonObject& obj) {
diff --git a/wled00/util.cpp b/wled00/util.cpp
index 16af85e712..97e1e3b035 100644
--- a/wled00/util.cpp
+++ b/wled00/util.cpp
@@ -4,17 +4,17 @@
//helper to get int value at a position in string
-int getNumVal(const String* req, uint16_t pos)
+int getNumVal(const String &req, uint16_t pos)
{
- return req->substring(pos+3).toInt();
+ return req.substring(pos+3).toInt();
}
//helper to get int value with in/decrementing support via ~ syntax
-void parseNumber(const char* str, byte* val, byte minv, byte maxv)
+void parseNumber(const char* str, byte &val, byte minv, byte maxv)
{
if (str == nullptr || str[0] == '\0') return;
- if (str[0] == 'r') {*val = hw_random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0
+ if (str[0] == 'r') {val = hw_random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0
bool wrap = false;
if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;}
if (str[0] == '~') {
@@ -22,19 +22,19 @@ void parseNumber(const char* str, byte* val, byte minv, byte maxv)
if (out == 0) {
if (str[1] == '0') return;
if (str[1] == '-') {
- *val = (int)(*val -1) < (int)minv ? maxv : min((int)maxv,(*val -1)); //-1, wrap around
+ val = (int)(val -1) < (int)minv ? maxv : min((int)maxv,(val -1)); //-1, wrap around
} else {
- *val = (int)(*val +1) > (int)maxv ? minv : max((int)minv,(*val +1)); //+1, wrap around
+ val = (int)(val +1) > (int)maxv ? minv : max((int)minv,(val +1)); //+1, wrap around
}
} else {
- if (wrap && *val == maxv && out > 0) out = minv;
- else if (wrap && *val == minv && out < 0) out = maxv;
+ if (wrap && val == maxv && out > 0) out = minv;
+ else if (wrap && val == minv && out < 0) out = maxv;
else {
- out += *val;
+ out += val;
if (out > maxv) out = maxv;
if (out < minv) out = minv;
}
- *val = out;
+ val = out;
}
return;
} else if (minv == maxv && minv == 0) { // limits "unset" i.e. both 0
@@ -49,14 +49,14 @@ void parseNumber(const char* str, byte* val, byte minv, byte maxv)
}
}
}
- *val = atoi(str);
+ val = atoi(str);
}
//getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form)
-bool getVal(JsonVariant elem, byte* val, byte vmin, byte vmax) {
+bool getVal(JsonVariant elem, byte &val, byte vmin, byte vmax) {
if (elem.is()) {
if (elem < 0) return false; //ignore e.g. {"ps":-1}
- *val = elem;
+ val = elem;
return true;
} else if (elem.is()) {
const char* str = elem;
@@ -82,7 +82,7 @@ bool getBoolVal(const JsonVariant &elem, bool dflt) {
}
-bool updateVal(const char* req, const char* key, byte* val, byte minv, byte maxv)
+bool updateVal(const char* req, const char* key, byte &val, byte minv, byte maxv)
{
const char *v = strstr(req, key);
if (v) v += strlen(key);
@@ -506,12 +506,12 @@ um_data_t* simulateSound(uint8_t simulationId)
break;
case UMS_10_13:
for (int i = 0; i<16; i++)
- fftResult[i] = inoise8(beatsin8_t(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
+ fftResult[i] = perlin8(beatsin8_t(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3);
volumeSmth = fftResult[8];
break;
case UMS_14_3:
for (int i = 0; i<16; i++)
- fftResult[i] = inoise8(beatsin8_t(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3);
+ fftResult[i] = perlin8(beatsin8_t(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3);
volumeSmth = fftResult[8];
break;
}
@@ -618,3 +618,240 @@ int32_t hw_random(int32_t lowerlimit, int32_t upperlimit) {
uint32_t diff = upperlimit - lowerlimit;
return hw_random(diff) + lowerlimit;
}
+
+#ifndef ESP8266
+void *p_malloc(size_t size) {
+ int caps1 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
+ int caps2 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT;
+ if (psramSafe) {
+ if (heap_caps_get_free_size(caps2) > 3*MIN_HEAP_SIZE && size < 512) std::swap(caps1, caps2); // use DRAM for small alloactions & when heap is plenty
+ return heap_caps_malloc_prefer(size, 2, caps1, caps2); // otherwise prefer PSRAM if it exists
+ }
+ return heap_caps_malloc(size, caps2);
+}
+
+void *p_realloc(void *ptr, size_t size) {
+ int caps1 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
+ int caps2 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT;
+ if (psramSafe) {
+ if (heap_caps_get_free_size(caps2) > 3*MIN_HEAP_SIZE && size < 512) std::swap(caps1, caps2); // use DRAM for small alloactions & when heap is plenty
+ return heap_caps_realloc_prefer(ptr, size, 2, caps1, caps2); // otherwise prefer PSRAM if it exists
+ }
+ return heap_caps_realloc(ptr, size, caps2);
+}
+
+void *p_calloc(size_t count, size_t size) {
+ int caps1 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
+ int caps2 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT;
+ if (psramSafe) {
+ if (heap_caps_get_free_size(caps2) > 3*MIN_HEAP_SIZE && size < 512) std::swap(caps1, caps2); // use DRAM for small alloactions & when heap is plenty
+ return heap_caps_calloc_prefer(count, size, 2, caps1, caps2); // otherwise prefer PSRAM if it exists
+ }
+ return heap_caps_calloc(count, size, caps2);
+}
+
+void *d_malloc(size_t size) {
+ int caps1 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT;
+ int caps2 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
+ if (psramSafe) {
+ if (size > MIN_HEAP_SIZE) std::swap(caps1, caps2); // prefer PSRAM for large alloactions
+ return heap_caps_malloc_prefer(size, 2, caps1, caps2); // otherwise prefer DRAM
+ }
+ return heap_caps_malloc(size, caps1);
+}
+
+void *d_realloc(void *ptr, size_t size) {
+ int caps1 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT;
+ int caps2 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
+ if (psramSafe) {
+ if (size > MIN_HEAP_SIZE) std::swap(caps1, caps2); // prefer PSRAM for large alloactions
+ return heap_caps_realloc_prefer(ptr, size, 2, caps1, caps2); // otherwise prefer DRAM
+ }
+ return heap_caps_realloc(ptr, size, caps1);
+}
+
+void *d_calloc(size_t count, size_t size) {
+ int caps1 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT;
+ int caps2 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
+ if (psramSafe) {
+ if (size > MIN_HEAP_SIZE) std::swap(caps1, caps2); // prefer PSRAM for large alloactions
+ return heap_caps_calloc_prefer(count, size, 2, caps1, caps2); // otherwise prefer DRAM
+ }
+ return heap_caps_calloc(count, size, caps1);
+}
+#endif
+
+/*
+ * Fixed point integer based Perlin noise functions by @dedehai
+ * Note: optimized for speed and to mimic fastled inoise functions, not for accuracy or best randomness
+ */
+#define PERLIN_SHIFT 1
+
+// calculate gradient for corner from hash value
+static inline __attribute__((always_inline)) int32_t hashToGradient(uint32_t h) {
+ // using more steps yields more "detailed" perlin noise but looks less like the original fastled version (adjust PERLIN_SHIFT to compensate, also changes range and needs proper adustment)
+ // return (h & 0xFF) - 128; // use PERLIN_SHIFT 7
+ // return (h & 0x0F) - 8; // use PERLIN_SHIFT 3
+ // return (h & 0x07) - 4; // use PERLIN_SHIFT 2
+ return (h & 0x03) - 2; // use PERLIN_SHIFT 1 -> closest to original fastled version
+}
+
+// Gradient functions for 1D, 2D and 3D Perlin noise note: forcing inline produces smaller code and makes it 3x faster!
+static inline __attribute__((always_inline)) int32_t gradient1D(uint32_t x0, int32_t dx) {
+ uint32_t h = x0 * 0x27D4EB2D;
+ h ^= h >> 15;
+ h *= 0x92C3412B;
+ h ^= h >> 13;
+ h ^= h >> 7;
+ return (hashToGradient(h) * dx) >> PERLIN_SHIFT;
+}
+
+static inline __attribute__((always_inline)) int32_t gradient2D(uint32_t x0, int32_t dx, uint32_t y0, int32_t dy) {
+ uint32_t h = (x0 * 0x27D4EB2D) ^ (y0 * 0xB5297A4D);
+ h ^= h >> 15;
+ h *= 0x92C3412B;
+ h ^= h >> 13;
+ return (hashToGradient(h) * dx + hashToGradient(h>>PERLIN_SHIFT) * dy) >> (1 + PERLIN_SHIFT);
+}
+
+static inline __attribute__((always_inline)) int32_t gradient3D(uint32_t x0, int32_t dx, uint32_t y0, int32_t dy, uint32_t z0, int32_t dz) {
+ // fast and good entropy hash from corner coordinates
+ uint32_t h = (x0 * 0x27D4EB2D) ^ (y0 * 0xB5297A4D) ^ (z0 * 0x1B56C4E9);
+ h ^= h >> 15;
+ h *= 0x92C3412B;
+ h ^= h >> 13;
+ return ((hashToGradient(h) * dx + hashToGradient(h>>(1+PERLIN_SHIFT)) * dy + hashToGradient(h>>(1 + 2*PERLIN_SHIFT)) * dz) * 85) >> (8 + PERLIN_SHIFT); // scale to 16bit, x*85 >> 8 = x/3
+}
+
+// fast cubic smoothstep: t*(3 - 2t²), optimized for fixed point, scaled to avoid overflows
+static uint32_t smoothstep(const uint32_t t) {
+ uint32_t t_squared = (t * t) >> 16;
+ uint32_t factor = (3 << 16) - ((t << 1));
+ return (t_squared * factor) >> 18; // scale to avoid overflows and give best resolution
+}
+
+// simple linear interpolation for fixed-point values, scaled for perlin noise use
+static inline int32_t lerpPerlin(int32_t a, int32_t b, int32_t t) {
+ return a + (((b - a) * t) >> 14); // match scaling with smoothstep to yield 16.16bit values
+}
+
+// 1D Perlin noise function that returns a value in range of -24691 to 24689
+int32_t perlin1D_raw(uint32_t x, bool is16bit) {
+ // integer and fractional part coordinates
+ int32_t x0 = x >> 16;
+ int32_t x1 = x0 + 1;
+ if(is16bit) x1 = x1 & 0xFF; // wrap back to zero at 0xFF instead of 0xFFFF
+
+ int32_t dx0 = x & 0xFFFF;
+ int32_t dx1 = dx0 - 0x10000;
+ // gradient values for the two corners
+ int32_t g0 = gradient1D(x0, dx0);
+ int32_t g1 = gradient1D(x1, dx1);
+ // interpolate and smooth function
+ int32_t tx = smoothstep(dx0);
+ int32_t noise = lerpPerlin(g0, g1, tx);
+ return noise;
+}
+
+// 2D Perlin noise function that returns a value in range of -20633 to 20629
+int32_t perlin2D_raw(uint32_t x, uint32_t y, bool is16bit) {
+ int32_t x0 = x >> 16;
+ int32_t y0 = y >> 16;
+ int32_t x1 = x0 + 1;
+ int32_t y1 = y0 + 1;
+
+ if(is16bit) {
+ x1 = x1 & 0xFF; // wrap back to zero at 0xFF instead of 0xFFFF
+ y1 = y1 & 0xFF;
+ }
+
+ int32_t dx0 = x & 0xFFFF;
+ int32_t dy0 = y & 0xFFFF;
+ int32_t dx1 = dx0 - 0x10000;
+ int32_t dy1 = dy0 - 0x10000;
+
+ int32_t g00 = gradient2D(x0, dx0, y0, dy0);
+ int32_t g10 = gradient2D(x1, dx1, y0, dy0);
+ int32_t g01 = gradient2D(x0, dx0, y1, dy1);
+ int32_t g11 = gradient2D(x1, dx1, y1, dy1);
+
+ uint32_t tx = smoothstep(dx0);
+ uint32_t ty = smoothstep(dy0);
+
+ int32_t nx0 = lerpPerlin(g00, g10, tx);
+ int32_t nx1 = lerpPerlin(g01, g11, tx);
+
+ int32_t noise = lerpPerlin(nx0, nx1, ty);
+ return noise;
+}
+
+// 3D Perlin noise function that returns a value in range of -16788 to 16381
+int32_t perlin3D_raw(uint32_t x, uint32_t y, uint32_t z, bool is16bit) {
+ int32_t x0 = x >> 16;
+ int32_t y0 = y >> 16;
+ int32_t z0 = z >> 16;
+ int32_t x1 = x0 + 1;
+ int32_t y1 = y0 + 1;
+ int32_t z1 = z0 + 1;
+
+ if(is16bit) {
+ x1 = x1 & 0xFF; // wrap back to zero at 0xFF instead of 0xFFFF
+ y1 = y1 & 0xFF;
+ z1 = z1 & 0xFF;
+ }
+
+ int32_t dx0 = x & 0xFFFF;
+ int32_t dy0 = y & 0xFFFF;
+ int32_t dz0 = z & 0xFFFF;
+ int32_t dx1 = dx0 - 0x10000;
+ int32_t dy1 = dy0 - 0x10000;
+ int32_t dz1 = dz0 - 0x10000;
+
+ int32_t g000 = gradient3D(x0, dx0, y0, dy0, z0, dz0);
+ int32_t g001 = gradient3D(x0, dx0, y0, dy0, z1, dz1);
+ int32_t g010 = gradient3D(x0, dx0, y1, dy1, z0, dz0);
+ int32_t g011 = gradient3D(x0, dx0, y1, dy1, z1, dz1);
+ int32_t g100 = gradient3D(x1, dx1, y0, dy0, z0, dz0);
+ int32_t g101 = gradient3D(x1, dx1, y0, dy0, z1, dz1);
+ int32_t g110 = gradient3D(x1, dx1, y1, dy1, z0, dz0);
+ int32_t g111 = gradient3D(x1, dx1, y1, dy1, z1, dz1);
+
+ uint32_t tx = smoothstep(dx0);
+ uint32_t ty = smoothstep(dy0);
+ uint32_t tz = smoothstep(dz0);
+
+ int32_t nx0 = lerpPerlin(g000, g100, tx);
+ int32_t nx1 = lerpPerlin(g010, g110, tx);
+ int32_t nx2 = lerpPerlin(g001, g101, tx);
+ int32_t nx3 = lerpPerlin(g011, g111, tx);
+ int32_t ny0 = lerpPerlin(nx0, nx1, ty);
+ int32_t ny1 = lerpPerlin(nx2, nx3, ty);
+
+ int32_t noise = lerpPerlin(ny0, ny1, tz);
+ return noise;
+}
+
+// scaling functions for fastled replacement
+uint16_t perlin16(uint32_t x) {
+ return ((perlin1D_raw(x) * 1159) >> 10) + 32803; //scale to 16bit and offset (fastled range: about 4838 to 60766)
+}
+
+uint16_t perlin16(uint32_t x, uint32_t y) {
+ return ((perlin2D_raw(x, y) * 1537) >> 10) + 32725; //scale to 16bit and offset (fastled range: about 1748 to 63697)
+}
+
+uint16_t perlin16(uint32_t x, uint32_t y, uint32_t z) {
+ return ((perlin3D_raw(x, y, z) * 1731) >> 10) + 33147; //scale to 16bit and offset (fastled range: about 4766 to 60840)
+}
+
+uint8_t perlin8(uint16_t x) {
+ return (((perlin1D_raw((uint32_t)x << 8, true) * 1353) >> 10) + 32769) >> 8; //scale to 16 bit, offset, then scale to 8bit
+}
+
+uint8_t perlin8(uint16_t x, uint16_t y) {
+ return (((perlin2D_raw((uint32_t)x << 8, (uint32_t)y << 8, true) * 1620) >> 10) + 32771) >> 8; //scale to 16 bit, offset, then scale to 8bit
+}
+
+uint8_t perlin8(uint16_t x, uint16_t y, uint16_t z) {
+ return (((perlin3D_raw((uint32_t)x << 8, (uint32_t)y << 8, (uint32_t)z << 8, true) * 2015) >> 10) + 33168) >> 8; //scale to 16 bit, offset, then scale to 8bit
+}
\ No newline at end of file
diff --git a/wled00/wled.cpp b/wled00/wled.cpp
index 34caeefa3f..63af7c2b89 100644
--- a/wled00/wled.cpp
+++ b/wled00/wled.cpp
@@ -193,14 +193,14 @@ void WLED::loop()
if (aligned) strip.makeAutoSegments();
else strip.fixInvalidSegments();
BusManager::setBrightness(bri); // fix re-initialised bus' brightness
- doSerializeConfig = true;
+ configNeedsWrite = true;
}
if (loadLedmap >= 0) {
strip.deserializeMap(loadLedmap);
loadLedmap = -1;
}
yield();
- if (doSerializeConfig) serializeConfig();
+ if (configNeedsWrite) serializeConfigToFS();
yield();
handleWs();
@@ -223,7 +223,7 @@ void WLED::loop()
}
#endif
- if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration
+ if (doReboot && (!doInitBusses || !configNeedsWrite)) // if busses have to be inited & saved, wait until next iteration
reset();
// DEBUG serial logging (every 30s)
@@ -342,7 +342,6 @@ void WLED::setup()
#else
DEBUG_PRINTLN(F("arduino-esp32 v1.0.x\n")); // we can't say in more detail.
#endif
-
DEBUG_PRINTF_P(PSTR("CPU: %s rev.%d, %d core(s), %d MHz.\n"), ESP.getChipModel(), (int)ESP.getChipRevision(), ESP.getChipCores(), ESP.getCpuFreqMHz());
DEBUG_PRINTF_P(PSTR("FLASH: %d MB, Mode %d "), (ESP.getFlashChipSize()/1024)/1024, (int)ESP.getFlashChipMode());
#ifdef WLED_DEBUG
@@ -530,6 +529,7 @@ void WLED::setup()
void WLED::beginStrip()
{
// Initialize NeoPixel Strip and button
+ strip.setTransition(0); // temporarily prevent transitions to reduce segment copies
strip.finalizeInit(); // busses created during deserializeConfig() if config existed
strip.makeAutoSegments();
strip.setBrightness(0);
@@ -558,6 +558,8 @@ void WLED::beginStrip()
applyPreset(bootPreset, CALL_MODE_INIT);
}
+ strip.setTransition(transitionDelayDefault); // restore transitions
+
// init relay pin
if (rlyPin >= 0) {
pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT);
@@ -739,9 +741,6 @@ void WLED::initInterfaces()
e131.begin(e131Multicast, e131Port, e131Universe, E131_MAX_UNIVERSE_COUNT);
ddp.begin(false, DDP_DEFAULT_PORT);
reconnectHue();
-#ifndef WLED_DISABLE_MQTT
- initMqtt();
-#endif
interfacesInited = true;
wasConnected = true;
}
@@ -751,7 +750,9 @@ void WLED::handleConnection()
static bool scanDone = true;
static byte stacO = 0;
const unsigned long now = millis();
+ #ifdef WLED_DEBUG
const unsigned long nowS = now/1000;
+ #endif
const bool wifiConfigured = WLED_WIFI_CONFIGURED;
// ignore connection handling if WiFi is configured and scan still running
diff --git a/wled00/wled.h b/wled00/wled.h
index ea40c5dfe2..e4cab539a0 100644
--- a/wled00/wled.h
+++ b/wled00/wled.h
@@ -64,6 +64,9 @@
//This is generally a terrible idea, but improves boot success on boards with a 3.3v regulator + cap setup that can't provide 400mA peaks
//#define WLED_DISABLE_BROWNOUT_DET
+#include
+#include
+
// Library inclusions.
#include
#ifdef ESP8266
@@ -417,7 +420,7 @@ WLED_GLOBAL bool cctICused _INIT(false); // CCT IC used (Athom 15W bulb
#endif
WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors
WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness
-WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value
+WLED_GLOBAL float gammaCorrectVal _INIT(2.2f); // gamma correction value
WLED_GLOBAL byte colPri[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. colPri[] should be updated if you want to change the color.
WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) secondary color
@@ -538,7 +541,8 @@ WLED_GLOBAL bool serialCanTX _INIT(false);
WLED_GLOBAL bool enableESPNow _INIT(false); // global on/off for ESP-NOW
WLED_GLOBAL byte statusESPNow _INIT(ESP_NOW_STATE_UNINIT); // state of ESP-NOW stack (0 uninitialised, 1 initialised, 2 error)
WLED_GLOBAL bool useESPNowSync _INIT(false); // use ESP-NOW wireless technology for sync
-WLED_GLOBAL char linked_remote[13] _INIT(""); // MAC of ESP-NOW remote (Wiz Mote)
+//WLED_GLOBAL char linked_remote[13] _INIT(""); // MAC of ESP-NOW remote (Wiz Mote)
+WLED_GLOBAL std::vector> linked_remotes; // MAC of ESP-NOW remotes (Wiz Mote)
WLED_GLOBAL char last_signal_src[13] _INIT(""); // last seen ESP-NOW sender
#endif
@@ -558,7 +562,7 @@ WLED_GLOBAL byte currentTimezone _INIT(WLED_TIMEZONE); // Timezone ID. Refer
WLED_GLOBAL int utcOffsetSecs _INIT(WLED_UTC_OFFSET); // Seconds to offset from UTC before timzone calculation
WLED_GLOBAL byte overlayCurrent _INIT(0); // 0: no overlay 1: analog clock 2: was single-digit clock 3: was cronixie
-WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(DEFAULT_LED_COUNT - 1); // boundaries of overlay mode
+WLED_GLOBAL uint16_t overlayMin _INIT(0), overlayMax _INIT(DEFAULT_LED_COUNT - 1); // boundaries of overlay mode
WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be
WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel
@@ -584,7 +588,11 @@ WLED_GLOBAL bool otaLock _INIT(true); // prevents OTA firmware update
WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks
#endif
WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled
+#ifndef WLED_DISABLE_OTA
WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on
+#else
+WLED_GLOBAL bool aOtaEnabled _INIT(false); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on
+#endif
WLED_GLOBAL char settingsPIN[5] _INIT(WLED_PIN); // PIN for settings pages
WLED_GLOBAL bool correctPIN _INIT(!strlen(settingsPIN));
WLED_GLOBAL unsigned long lastEditTime _INIT(0);
@@ -602,6 +610,8 @@ WLED_GLOBAL bool wasConnected _INIT(false);
// color
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
+WLED_GLOBAL std::vector customPalettes; // custom palettes
+WLED_GLOBAL uint8_t paletteBlend _INIT(0); // determines blending and wrapping of palette: 0: blend, wrap if moving (SEGMENT.speed>0); 1: blend, always wrap; 2: blend, never wrap; 3: don't blend or wrap
// transitions
WLED_GLOBAL uint8_t blendingStyle _INIT(0); // effect blending/transitionig style
@@ -612,6 +622,7 @@ WLED_GLOBAL unsigned long transitionStartTime;
WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt")
WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s)
WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmonic* random palette generation (nicer looking) or truly random
+WLED_GLOBAL bool useRainbowWheel _INIT(false); // use "rainbow" color wheel instead of "spectrum" color wheel
// nightlight
WLED_GLOBAL bool nightlightActive _INIT(false);
@@ -877,7 +888,7 @@ WLED_GLOBAL byte errorFlag _INIT(0);
WLED_GLOBAL String messageHead, messageSub;
WLED_GLOBAL byte optionType;
-WLED_GLOBAL bool doSerializeConfig _INIT(false); // flag to initiate saving of config
+WLED_GLOBAL bool configNeedsWrite _INIT(false); // flag to initiate saving of config
WLED_GLOBAL bool doReboot _INIT(false); // flag to initiate reboot from async handlers
WLED_GLOBAL bool psramSafe _INIT(true); // is it safe to use PSRAM (on ESP32 rev.1; compiler fix used "-mfix-esp32-psram-cache-issue")
diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp
index d0451d9a93..fb63bc6460 100644
--- a/wled00/wled_eeprom.cpp
+++ b/wled00/wled_eeprom.cpp
@@ -225,7 +225,7 @@ void loadSettingsFromEEPROM()
if (lastEEPROMversion > 7)
{
//strip.paletteFade = EEPROM.read(374);
- strip.paletteBlend = EEPROM.read(382);
+ paletteBlend = EEPROM.read(382);
for (int i = 0; i < 8; ++i)
{
diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp
index 77f4133c0e..c7a4cc0030 100644
--- a/wled00/wled_server.cpp
+++ b/wled00/wled_server.cpp
@@ -176,7 +176,7 @@ static void handleUpload(AsyncWebServerRequest *request, const String& filename,
doReboot = true;
request->send(200, FPSTR(CONTENT_TYPE_PLAIN), F("Configuration restore successful.\nRebooting..."));
} else {
- if (filename.indexOf(F("palette")) >= 0 && filename.indexOf(F(".json")) >= 0) strip.loadCustomPalettes();
+ if (filename.indexOf(F("palette")) >= 0 && filename.indexOf(F(".json")) >= 0) loadCustomPalettes();
request->send(200, FPSTR(CONTENT_TYPE_PLAIN), F("File Uploaded!"));
}
cacheInvalidate++;
@@ -328,7 +328,7 @@ void initServer()
interfaceUpdateCallMode = CALL_MODE_WS_SEND; // schedule WS update
serveJson(request); return; //if JSON contains "v"
} else {
- doSerializeConfig = true; //serializeConfig(); //Save new settings to FS
+ configNeedsWrite = true; //Save new settings to FS
}
}
request->send(200, CONTENT_TYPE_JSON, F("{\"success\":true}"));
@@ -365,7 +365,6 @@ void initServer()
createEditHandler(correctPIN);
static const char _update[] PROGMEM = "/update";
-#ifndef WLED_DISABLE_OTA
//init ota page
server.on(_update, HTTP_GET, [](AsyncWebServerRequest *request){
if (otaLock) {
@@ -419,12 +418,6 @@ void initServer()
}
}
});
-#else
- server.on(_update, HTTP_GET, [](AsyncWebServerRequest *request){
- serveMessage(request, 501, FPSTR(s_notimplemented), F("OTA updating is disabled in this build."), 254);
- });
-#endif
-
#ifdef WLED_ENABLE_DMX
server.on(F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){
diff --git a/wled00/xml.cpp b/wled00/xml.cpp
index 19868d01d9..a3cf6fe428 100644
--- a/wled00/xml.cpp
+++ b/wled00/xml.cpp
@@ -216,7 +216,11 @@ void getSettingsJS(byte subPage, Print& settingsScript)
#ifndef WLED_DISABLE_ESPNOW
printSetFormCheckbox(settingsScript,PSTR("RE"),enableESPNow);
- printSetFormValue(settingsScript,PSTR("RMAC"),linked_remote);
+ settingsScript.printf_P(PSTR("rstR();")); // reset remote list
+ for (size_t i = 0; i < linked_remotes.size(); i++) {
+ settingsScript.printf_P(PSTR("aR(\"RM%u\",\"%s\");"), i, linked_remotes[i].data()); // add remote to list
+ }
+ settingsScript.print(F("tE();")); // fill fields
#else
//hide remote settings if not compiled
settingsScript.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting
@@ -258,10 +262,6 @@ void getSettingsJS(byte subPage, Print& settingsScript)
#ifndef WLED_DISABLE_ESPNOW
if (strlen(last_signal_src) > 0) { //Have seen an ESP-NOW Remote
printSetClassElementHTML(settingsScript,PSTR("rlid"),0,last_signal_src);
- } else if (!enableESPNow) {
- printSetClassElementHTML(settingsScript,PSTR("rlid"),0,(char*)F("(Enable ESP-NOW to listen)"));
- } else {
- printSetClassElementHTML(settingsScript,PSTR("rlid"),0,(char*)F("None"));
}
#endif
}
@@ -291,14 +291,13 @@ void getSettingsJS(byte subPage, Print& settingsScript)
printSetFormValue(settingsScript,PSTR("CB"),Bus::getCCTBlend());
printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps());
printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode());
- printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer);
printSetFormCheckbox(settingsScript,PSTR("PR"),BusManager::hasParallelOutput()); // get it from bus manager not global variable
unsigned sumMa = 0;
- for (int s = 0; s < BusManager::getNumBusses(); s++) {
- const Bus* bus = BusManager::getBus(s);
+ for (size_t s = 0; s < BusManager::getNumBusses(); s++) {
+ const Bus *bus = BusManager::getBus(s);
if (!bus || !bus->isOk()) break; // should not happen but for safety
- int offset = s < 10 ? '0' : 'A';
+ int offset = s < 10 ? '0' : 'A' - 10;
char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin
char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length
char co[4] = "CO"; co[2] = offset+s; co[3] = 0; //strip color order
@@ -380,7 +379,8 @@ void getSettingsJS(byte subPage, Print& settingsScript)
printSetFormValue(settingsScript,PSTR("TB"),nightlightTargetBri);
printSetFormValue(settingsScript,PSTR("TL"),nightlightDelayMinsDefault);
printSetFormValue(settingsScript,PSTR("TW"),nightlightMode);
- printSetFormIndex(settingsScript,PSTR("PB"),strip.paletteBlend);
+ printSetFormIndex(settingsScript,PSTR("PB"),paletteBlend);
+ printSetFormCheckbox(settingsScript,PSTR("RW"),useRainbowWheel);
printSetFormValue(settingsScript,PSTR("RL"),rlyPin);
printSetFormCheckbox(settingsScript,PSTR("RM"),rlyMde);
printSetFormCheckbox(settingsScript,PSTR("RO"),rlyOpenDrain);
@@ -595,6 +595,10 @@ void getSettingsJS(byte subPage, Print& settingsScript)
snprintf_P(tmp_buf,sizeof(tmp_buf),PSTR("WLED %s (build %d)"),versionString,VERSION);
printSetClassElementHTML(settingsScript,PSTR("sip"),0,tmp_buf);
settingsScript.printf_P(PSTR("sd=\"%s\";"), serverDescription);
+ #ifdef WLED_DISABLE_OTA
+ //hide settings if not compiled
+ settingsScript.print(F("toggle('aOTA');")); // hide ArduinoOTA checkbox
+ #endif
}
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
@@ -666,16 +670,14 @@ void getSettingsJS(byte subPage, Print& settingsScript)
#ifndef WLED_DISABLE_2D
settingsScript.printf_P(PSTR("maxPanels=%d;resetPanels();"),WLED_MAX_PANELS);
if (strip.isMatrix) {
- if(strip.panels>0){
- printSetFormValue(settingsScript,PSTR("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience
- printSetFormValue(settingsScript,PSTR("PH"),strip.panel[0].height);
- }
- printSetFormValue(settingsScript,PSTR("MPC"),strip.panels);
+ printSetFormValue(settingsScript,PSTR("PW"),strip.panel.size()>0?strip.panel[0].width:8); //Set generator Width and Height to first panel size for convenience
+ printSetFormValue(settingsScript,PSTR("PH"),strip.panel.size()>0?strip.panel[0].height:8);
+ printSetFormValue(settingsScript,PSTR("MPC"),strip.panel.size());
// panels
- for (unsigned i=0; i