diff --git a/platformio.ini b/platformio.ini index b96a5fec6..63ebc68f5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -226,6 +226,7 @@ platform = ${common.platform_wled_default} upload_speed = 921600 board_build.ldscript = ${common.ldscript_4m1m} build_flags = ${common.build_flags_esp8266} +monitor_filters = esp8266_exception_decoder [env:heltec_wifi_kit_8] board = d1_mini diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index bc5926fc2..bdfc6ef0c 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -48,7 +48,6 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet); bool handleFileRead(AsyncWebServerRequest*, String path); bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content); bool writeObjectToFile(const char* file, const char* key, JsonDocument* content); -bool appendObjectToFile(const char* file, const char* key, JsonDocument* content, File input); bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest); bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest); @@ -195,7 +194,7 @@ void saveSettingsToEEPROM(); void loadSettingsFromEEPROM(bool first); void savedToPresets(); bool applyPreset(byte index, bool loadBri = true); -void savePreset(byte index, bool persist = true, const char* pname = nullptr, byte prio = 50); +void savePreset(byte index, bool persist = true, const char* pname = nullptr, byte prio = 50, JsonObject saveobj = JsonObject()); void loadMacro(byte index, char* m); void applyMacro(byte index); void saveMacro(byte index, String mc, bool persist = true); //only commit on single save, not in settings diff --git a/wled00/file.cpp b/wled00/file.cpp index 879ed39ba..f96bf8f97 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -18,11 +18,15 @@ //find() that reads and buffers data from file stream in 256-byte blocks. //Significantly faster, f.find(key) can take SECONDS for multi-kB files bool bufferedFind(const char *target, File f) { + #ifdef WLED_DEBUG_FS + DEBUGFS_PRINT("Find "); + DEBUGFS_PRINTLN(target); + uint32_t s = millis(); + #endif + if (!f || !f.size()) return false; size_t targetLen = strlen(target); - Serial.print("bfind "); - Serial.println(target); - //Serial.println(f.position()); + size_t index = 0; byte c; uint16_t bufsize = 0, count = 0; @@ -30,8 +34,6 @@ bool bufferedFind(const char *target, File f) { f.seek(0); while (f.position() < f.size() -1) { - //c = f.read(); - Serial.println(f.position()); bufsize = f.read(buf, 256); count = 0; while (count < bufsize) { @@ -41,21 +43,27 @@ bool bufferedFind(const char *target, File f) { 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); return true; } } count++; } } - Serial.println("No match"); + DEBUGFS_PRINTF("No match, took %d ms\n", millis() - s); return false; } //find empty spots in file stream in 256-byte blocks. bool bufferedFindSpace(uint16_t targetLen, File f) { - Serial.print("bfs "); + #ifdef WLED_DEBUG_FS + DEBUGFS_PRINTF("Find %d spaces\n", targetLen); + uint32_t s = millis(); + #endif + if (!f || !f.size()) return false; - Serial.print(targetLen); + DEBUGFS_PRINTF("Filesize %d\n", f.size()); + uint16_t index = 0; uint16_t bufsize = 0, count = 0; byte buf[256]; @@ -64,108 +72,39 @@ bool bufferedFindSpace(uint16_t targetLen, File f) { while (f.position() < f.size() -1) { bufsize = f.read(buf, 256); count = 0; + while (count < bufsize) { - Serial.print(count); - Serial.write(' '); - Serial.println(index); if(buf[count] != ' ') index = 0; // reset index if not space if(buf[count] == ' ') { if(++index >= targetLen) { // return true if space long enough f.seek((f.position() - bufsize) + count +1 - targetLen); - Serial.print("SPAAAACE!"); + DEBUGFS_PRINTF("Found at pos %d, took %d ms", f.position(), millis() - s); return true; } } count++; } } + DEBUGFS_PRINTF("No match, took %d ms\n", millis() - s); return false; } -bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content) -{ - char objKey[10]; - sprintf(objKey, "\"%ld\":", id); - writeObjectToFile(file, objKey, content); -} - -bool writeObjectToFile(const char* file, const char* key, JsonDocument* content) +bool appendObjectToFile(File f, const char* key, JsonDocument* content, uint32_t s) { + #ifdef WLED_DEBUG_FS + DEBUG_PRINTLN("Append"); + uint32_t s1 = millis(); + #endif uint32_t pos = 0; - File f = WLED_FS.open(file, "r+"); - if (!f) f = WLED_FS.open(file, "w"); - if (!f) return false; - - f.seek(0, SeekSet); - - Serial.print("Writing to "); - Serial.print(file); - Serial.print(" with key "); - Serial.print(key); - Serial.print(" > "); - serializeJson(*content, Serial); - Serial.println(); - - if (!bufferedFind(key, f)) //key does not exist in file - { - Serial.println("Key not found"); - return appendObjectToFile(file, key, content, f); - } - - Serial.println("Key found!"); - //exists - pos = f.position(); - Serial.println(pos); - //measure out end of old object - StaticJsonDocument<1024> doc; - deserializeJson(doc, f); - uint32_t pos2 = f.position(); - - uint32_t oldLen = pos2 - pos; - Serial.print("Old obj len: "); - Serial.print(oldLen); - Serial.print(" > "); - serializeJson(doc, Serial); - Serial.println(); - - if (!content->isNull() && measureJson(*content) <= oldLen) //replace - { - Serial.println("replace"); - f.seek(pos); - serializeJson(*content, f); - //pad rest - for (uint32_t i = f.position(); i < pos2; i++) { - f.write(' '); - } - } else { //delete - Serial.println("delete"); - pos -= strlen(key); - if (pos > 3) pos--; //also delete leading comma if not first object - f.seek(pos); - for (uint32_t i = pos; i < pos2; i++) { - f.write(' '); - } - if (!content->isNull()) return appendObjectToFile(file, key, content, f); - } - f.close(); -} - -bool appendObjectToFile(const char* file, const char* key, JsonDocument* content, File input) -{ - Serial.println("Append"); - uint32_t pos = 0; - File f = (input) ? input : WLED_FS.open(file, "r+"); - if (!f) f = WLED_FS.open(file,"w"); if (!f) return false; if (f.size() < 3) f.print("{}"); //if there is enough empty space in file, insert there instead of appending uint32_t contentLen = measureJson(*content); - Serial.print("clen"); Serial.println(contentLen); + DEBUGFS_PRINTF("CLen %d\n", contentLen); if (bufferedFindSpace(contentLen + strlen(key) + 1, f)) { - Serial.println("space"); if (f.position() > 2) f.write(','); //add comma if not first object f.print(key); serializeJson(*content, f); @@ -178,13 +117,13 @@ bool appendObjectToFile(const char* file, const char* key, JsonDocument* content if (pos == 0) //not found { - Serial.println("not}"); + DEBUGFS_PRINTLN("not }"); while (bufferedFind("}",f)) //find last closing bracket in JSON if not last char { pos = f.position(); } } - Serial.print("pos"); Serial.println(pos); + DEBUGFS_PRINT("pos "); DEBUGFS_PRINTLN(pos); if (pos > 2) { f.seek(pos, SeekSet); @@ -201,6 +140,74 @@ bool appendObjectToFile(const char* file, const char* key, JsonDocument* content f.write('}'); f.close(); + DEBUGFS_PRINTF("Appended, took %d ms (total %d)", millis() - s1, millis() - s); +} + +bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content) +{ + char objKey[10]; + sprintf(objKey, "\"%ld\":", id); + writeObjectToFile(file, objKey, content); +} + +bool writeObjectToFile(const char* file, const char* key, JsonDocument* content) +{ + uint32_t s = 0; //timing + #ifdef WLED_DEBUG_FS + DEBUGFS_PRINTF("Write to %s with key %s >>>\n", file, key); + serializeJson(*content, Serial); DEBUGFS_PRINTLN(); + s = millis(); + #endif + + uint32_t pos = 0; + File f = WLED_FS.open(file, "r+"); + if (!f && !WLED_FS.exists(file)) f = WLED_FS.open(file, "w+"); + if (!f) { + DEBUGFS_PRINTLN("Failed to open!"); + return false; + } + + if (!bufferedFind(key, f)) //key does not exist in file + { + return appendObjectToFile(f, key, content, s); + } + + //exists + pos = f.position(); + //measure out end of old object + StaticJsonDocument<1024> doc; + deserializeJson(doc, f); + uint32_t pos2 = f.position(); + + uint32_t oldLen = pos2 - pos; + #ifdef WLED_DEBUG_FS + DEBUGFS_PRINTF("Old obj len %d >>> ", oldLen); + serializeJson(doc, Serial); + DEBUGFS_PRINTLN(); + #endif + + if (!content->isNull() && measureJson(*content) <= oldLen) //replace + { + DEBUG_PRINTLN("replace"); + f.seek(pos); + serializeJson(*content, f); + //pad rest + for (uint32_t i = f.position(); i < pos2; i++) { + f.write(' '); + } + } else { //delete + DEBUG_PRINTLN("delete"); + pos -= strlen(key); + if (pos > 3) pos--; //also delete leading comma if not first object + f.seek(pos); + for (uint32_t i = pos; i < pos2; i++) { + f.write(' '); + } + if (!content->isNull()) return appendObjectToFile(f, key, content, s); + } + f.close(); + DEBUGFS_PRINTF("Deleted, took %d ms\n", millis() - s); + return true; } bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest) @@ -212,19 +219,24 @@ bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest) { + #ifdef WLED_DEBUG_FS + DEBUGFS_PRINTF("Read from %s with key %s >>>\n", file, key); + uint32_t s = millis(); + #endif File f = WLED_FS.open(file, "r"); if (!f) return false; - //f.setTimeout(0); if (!bufferedFind(key, f)) //key does not exist in file { f.close(); + DEBUGFS_PRINTLN("Obj not found."); return false; } deserializeJson(*dest, f); f.close(); + DEBUGFS_PRINTF("Read, took %d ms\n", millis() - s); return true; } #endif diff --git a/wled00/json.cpp b/wled00/json.cpp index 5bfbb4b03..f002a2f2c 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -225,7 +225,7 @@ bool deserializeState(JsonObject root) bool persistSaves = !(root["np"] | false); ps = root["psave"] | -1; - if (ps >= 0) savePreset(ps, persistSaves, root["n"], root["p"]); + if (ps >= 0) savePreset(ps, persistSaves, root["n"], root["p"] | 50, root["o"].as()); return stateResponse; } diff --git a/wled00/wled.h b/wled00/wled.h index ec5bb4e0a..db0b91d2a 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -41,12 +41,16 @@ // to toggle usb serial debug (un)comment the following line //#define WLED_DEBUG +// filesystem specific debugging +#define WLED_DEBUG_FS + // Library inclusions. #include #ifdef ESP8266 #include #include #include + #include extern "C" { #include @@ -119,7 +123,7 @@ #endif //Filesystem to use for preset and config files. SPIFFS or LittleFS on ESP8266, SPIFFS only on ESP32 -#define WLED_FS SPIFFS +#define WLED_FS LittleFS // remove flicker because PWM signal of RGB channels can become out of phase (part of core as of Arduino core v2.7.0) //#if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266) @@ -500,7 +504,7 @@ WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); #endif #define DEBUG_PRINT(x) Serial.print(x) #define DEBUG_PRINTLN(x) Serial.println(x) - #define DEBUG_PRINTF(x) Serial.printf(x) + #define DEBUG_PRINTF(x...) Serial.printf(x) #else #define DEBUG_PRINT(x) #define DEBUG_PRINTLN(x) @@ -510,7 +514,7 @@ WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); #ifdef WLED_DEBUG_FS #define DEBUGFS_PRINT(x) Serial.print(x) #define DEBUGFS_PRINTLN(x) Serial.println(x) - #define DEBUGFS_PRINTF(x) Serial.printf(x) + #define DEBUGFS_PRINTF(x...) Serial.printf(x) #else #define DEBUGFS_PRINT(x) #define DEBUGFS_PRINTLN(x) diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index f23fdb170..12836f16c 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -622,7 +622,7 @@ void savedToPresets() bool applyPreset(byte index, bool loadBri) { StaticJsonDocument<1024> temp; - if (!readObjectFromFileUsingId("/presets.json", index, &temp)) errorFlag = ERR_FS_PLOAD; + errorFlag = readObjectFromFileUsingId("/presets.json", index, &temp) ? ERR_NONE : ERR_FS_PLOAD; serializeJson(temp, Serial); deserializeState(temp.as()); //presetToApply = index; @@ -672,16 +672,24 @@ bool applyPreset(byte index, bool loadBri) return true; } -void savePreset(byte index, bool persist, const char* pname, byte priority) +void savePreset(byte index, bool persist, const char* pname, byte priority, JsonObject saveobj) { StaticJsonDocument<1024> doc; - serializeState(doc.to(), true); + if (saveobj.isNull()) { + Serial.println("Save current state"); + serializeState(doc.to(), true); + } else { + Serial.println("Save custom"); + doc = saveobj; + } doc["p"] = priority; if (pname) doc["n"] = pname; //serializeJson(doc, Serial); writeObjectToFileUsingId("/presets.json", index, &doc); + //Serial.println("Done!"); return; + if (index > 16) return; if (index < 1) {saveSettingsToEEPROM();return;} uint16_t i = 380 + index*20;//min400 diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index d3f20bfe5..8a2094dc9 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -159,7 +159,7 @@ void initServer() #ifdef ARDUINO_ARCH_ESP32 server.addHandler(new SPIFFSEditor(WLED_FS));//http_username,http_password)); #else - server.addHandler(new SPIFFSEditor());//http_username,http_password)); + server.addHandler(new SPIFFSEditor("","",WLED_FS));//http_username,http_password)); #endif #else server.on("/edit", HTTP_GET, [](AsyncWebServerRequest *request){