From dfc99faea893733879c288bfbda55e8b2711cc0d Mon Sep 17 00:00:00 2001 From: cschwinne Date: Tue, 5 May 2020 09:01:09 +0200 Subject: [PATCH 1/2] First preset progress --- platformio.ini | 8 +- wled00/NpbWrapper.h | 4 +- wled00/fcn_declare.h | 6 ++ wled00/file.cpp | 161 ++++++++++++++++++++++++++++++++++++++++- wled00/wled.cpp | 8 ++ wled00/wled.h | 8 +- wled00/wled_eeprom.cpp | 8 +- 7 files changed, 192 insertions(+), 11 deletions(-) diff --git a/platformio.ini b/platformio.ini index 492799df2..fbb630b8b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,7 +16,7 @@ extra_configs = # ------------------------------------------------------------------------------ # Travis CI binaries (comment this out when building for single board) -default_envs = d1_mini, esp01, esp01_1m_ota, esp32dev +;default_envs = d1_mini, esp01, esp01_1m_ota, esp32dev # Release binaries ; default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom32_LEDPIN_16 @@ -27,11 +27,11 @@ default_envs = d1_mini, esp01, esp01_1m_ota, esp32dev ; default_envs = esp01_1m_ota ; default_envs = esp01_1m_full ; default_envs = esp07 -; default_envs = d1_mini +default_envs = d1_mini ; default_envs = heltec_wifi_kit_8 ; default_envs = h803wf ; default_envs = d1_mini_debug -; default_envs = d1_mini_ota +;default_envs = d1_mini_ota ; default_envs = esp32dev ; default_envs = esp8285_4CH_MagicHome ; default_envs = esp8285_4CH_H801 @@ -245,7 +245,7 @@ build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ board = d1_mini platform = ${common.platform_latest} board_build.ldscript = ${common.ldscript_4m1m} -build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D SHOJO_PCB -D WLED_ENABLE_5CH_LEDS +build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_SHOJO_PCB -D WLED_ENABLE_5CH_LEDS # ------------------------------------------------------------------------------ # DEVELOPMENT BOARDS diff --git a/wled00/NpbWrapper.h b/wled00/NpbWrapper.h index faee293a3..8a3f95448 100644 --- a/wled00/NpbWrapper.h +++ b/wled00/NpbWrapper.h @@ -14,6 +14,8 @@ //#define WLED_USE_ANALOG_LEDS //Uncomment for using "dumb" PWM controlled LEDs (see pins below, default R: gpio5, G: 12, B: 15, W: 13) //#define WLED_USE_H801 //H801 controller. Please uncomment #define WLED_USE_ANALOG_LEDS as well //#define WLED_USE_5CH_LEDS //5 Channel H801 for cold and warm white +//#define WLED_USE_BWLT11 +//#define WLED_USE_SHOJO_PCB #ifndef BTNPIN #define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended) @@ -62,7 +64,7 @@ #define GPIN 4 //G pin for analog LED strip #define BPIN 14 //B pin for analog LED strip #define WPIN 5 //W pin for analog LED strip - #elif defined(SHOJO_PCB) + #elif defined(WLED_USE_SHOJO_PCB) //PWM pins - to use with Shojo PCB (https://www.bastelbunker.de/esp-rgbww-wifi-led-controller-vbs-edition/) #define RPIN 14 //R pin for analog LED strip #define GPIN 4 //G pin for analog LED strip diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 2d8401bc8..78a74b031 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -45,7 +45,13 @@ void handleDMX(); void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet); //file.cpp +bool find(const char* target, File f); bool handleFileRead(AsyncWebServerRequest*, String path); +bool writeObjectToFileUsing(const char* file, const char* key, JsonObject content, File input, bool doClose); +bool writeObjectToFile(const char* file, const char* key, JsonObject content, File input, bool doClose); +bool appendObjectToFile(const char* file, const char* key, JsonObject& content, File input, bool doClose); +bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest); +bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest); //hue.cpp void handleHue(); diff --git a/wled00/file.cpp b/wled00/file.cpp index eb0dcb931..4a2cf278e 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -13,6 +13,163 @@ #include "SPIFFSEditor.h" #endif +#ifndef WLED_DISABLE_FILESYSTEM + +bool find(const char *target, File f) { + size_t targetLen = strlen(target); + size_t index = 0; + int c; + + while(f.position() < f.size() -1) { + c = f.read(); + if(c != target[index]) + index = 0; // reset index if any char does not match + + if(c == target[index]) { + if(++index >= targetLen) { // return true if all chars in the target match + return true; + } + } + } + return false; +} + +bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonObject content, File input, bool doClose = true) +{ + char objKey[10]; + sprintf(objKey, "\"%ld\":", id); + writeObjectToFile(file, objKey, content, input, doClose); +} + +bool writeObjectToFile(const char* file, const char* key, JsonObject content, File input, bool doClose = true) +{ + uint32_t pos = 0; + File f = (input) ? input : SPIFFS.open(file, "r+"); + if (!f) f = SPIFFS.open(file,"w"); + if (!f) return false; + //f.setTimeout(1); + f.seek(0, SeekSet); + + if (!find(key, f)) //key does not exist in file + { + return appendObjectToFile(file, key, content, f, true); + } + + //exists + pos = f.position(); + //measure out end of old object + StaticJsonDocument<512> doc; + deserializeJson(doc, f); + uint32_t pos2 = f.position(); + uint32_t oldLen = pos2 - pos; + + if (!content.isNull() && measureJson(content) <= oldLen) //replace + { + serializeJson(content, f); + //pad rest + for (uint32_t i = f.position(); i < pos2; i++) { + f.write(' '); + } + } else { //delete + pos -+ strlen(key); + oldLen = pos2 - pos; + f.seek(pos, SeekSet); + for (uint32_t i = pos; i < pos2; i++) { + f.write(' '); + } + if (!content.isNull()) return appendObjectToFile(file, key, content, f, true); + } + f.close(); +} + +bool appendObjectToFile(const char* file, const char* key, JsonObject& content, File input, bool doClose = true) +{ + uint32_t pos = 0; + File f = (input) ? input : SPIFFS.open(file, "r+"); + if (!f) f = SPIFFS.open(file,"w"); + if (!f) return false; + f.setTimeout(1); + if (f.size() < 3) f.print("{}"); + + //if there is enough empty space in file, insert there instead of appending + uint32_t contentLen = measureJson(content); + uint32_t spaces = 0, spaceI = 0, spacesMax = 0, spaceMaxI = 0; + f.seek(1, SeekSet); + for (uint32_t i = 1; i < f.size(); i++) + { + if (f.read() == ' ') { + if (!spaces) spaceI = i; spaces++; + } else { + if (spaces > spacesMax) { spacesMax = spaces; spaceMaxI = spaceI;} + spaces = 0; + if (spacesMax >= contentLen) { + f.seek(spaceMaxI, SeekSet); + serializeJson(content, f); + return true; + } + } + } + + //check if last character in file is '}' (typical) + uint32_t lastByte = f.size() -1; + f.seek(1, SeekEnd); + if (f.read() == '}') pos = lastByte; + + if (pos == 0) //not found + { + while (find("}",f)) //find last closing bracket in JSON if not last char + { + pos = f.position(); + } + } + + if (pos) + { + f.seek(pos -1, SeekSet); + f.write(','); + } else { //file content is not valid JSON object + f.seek(0, SeekSet); + f.write('{'); //start JSON + } + + f.print("\""); + f.print(key); + f.print("\":"); + //Append object + serializeJson(content, f); + + f.write('}'); + if (doClose) f.close(); +} + +bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest) +{ + char objKey[10]; + sprintf(objKey, "\"%ld\":", id); + readObjectFromFile(file, objKey, dest); +} + +bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest) +{ + //if (id == playlistId) return true; + //playlist is already loaded, but we can't be sure that file hasn't changed since loading + + File f = SPIFFS.open(file, "r"); + if (!f) return false; + f.setTimeout(0); + Serial.println(key); + if (f.find(key)) //key does not exist in file + { + f.close(); + return false; + } + + deserializeJson(*dest, f); + + f.close(); + return true; +} +#endif #if !defined WLED_DISABLE_FILESYSTEM && defined WLED_ENABLE_FS_SERVING //Un-comment any file types you need @@ -38,11 +195,11 @@ bool handleFileRead(AsyncWebServerRequest* request, String path){ DEBUG_PRINTLN("FileRead: " + path); if(path.endsWith("/")) path += "index.htm"; String contentType = getContentType(request, path); - String pathWithGz = path + ".gz"; + /*String pathWithGz = path + ".gz"; if(SPIFFS.exists(pathWithGz)){ request->send(SPIFFS, pathWithGz, contentType); return true; - } + }*/ if(SPIFFS.exists(path)) { request->send(SPIFFS, path, contentType); return true; diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 40ce6f604..5421d79c7 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -81,6 +81,14 @@ void WLED::loop() handleHue(); handleBlynk(); + if (presetToApply) { + StaticJsonDocument<1024> temp; + errorFlag = !readObjectFromFileUsingId("/presets.json", presetToApply, &temp); + serializeJson(temp, Serial); + deserializeState(temp.as()); + presetToApply = 0; + } + yield(); if (!offMode) strip.service(); diff --git a/wled00/wled.h b/wled00/wled.h index c791f4ee2..4aa8da783 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -29,9 +29,9 @@ #define WLED_ENABLE_ADALIGHT // saves 500b only //#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2) -#define WLED_DISABLE_FILESYSTEM // SPIFFS is not used by any WLED feature yet -//#define WLED_ENABLE_FS_SERVING // Enable sending html file from SPIFFS before serving progmem version -//#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing SPIFFS content. Will also be disabled with OTA lock +//#define WLED_DISABLE_FILESYSTEM // SPIFFS is not used by any WLED feature yet +#define WLED_ENABLE_FS_SERVING // Enable sending html file from SPIFFS before serving progmem version +#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing SPIFFS content. Will also be disabled with OTA lock // to toggle usb serial debug (un)comment the following line //#define WLED_DEBUG @@ -158,6 +158,8 @@ WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS); // Hardware CONFIG (only changeble HERE, not at runtime) // LED strip pin, button pin and IR pin changeable in NpbWrapper.h! +WLED_GLOBAL byte presetToApply _INIT(0); + WLED_GLOBAL byte auxDefaultState _INIT(0); // 0: input 1: high 2: low WLED_GLOBAL byte auxTriggeredState _INIT(0); // 0: input 1: high 2: low WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index 807d3a447..fc00c2c94 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -594,7 +594,7 @@ void savedToPresets() savedPresets &= ~(0x01 << (index-1)); } } - if (EEPROM.read(700) == 2) { + if (EEPROM.read(700) == 2 || EEPROM.read(700) == 3) { savedPresets |= 0x01 << 15; } else { @@ -604,6 +604,12 @@ void savedToPresets() bool applyPreset(byte index, bool loadBri) { + StaticJsonDocument<1024> temp; + errorFlag = !readObjectFromFileUsingId("/presets.json", index, &temp); + serializeJson(temp, Serial); + deserializeState(temp.as()); + //presetToApply = index; + return true; if (index == 255 || index == 0) { loadSettingsFromEEPROM(false);//load boot defaults From 8bb70fb1b01c5bad0b754fc8f0a496ec4a54e7d7 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Fri, 8 May 2020 22:53:59 +0200 Subject: [PATCH 2/2] Filesystem Tests --- platformio.ini | 4 +- wled00/FX.cpp | 2 +- wled00/data/index.htm | 2 +- wled00/fcn_declare.h | 7 +-- wled00/file.cpp | 123 +++++++++++++++++++++++++---------------- wled00/wled_eeprom.cpp | 6 ++ 6 files changed, 90 insertions(+), 54 deletions(-) diff --git a/platformio.ini b/platformio.ini index fbb630b8b..f37f16158 100644 --- a/platformio.ini +++ b/platformio.ini @@ -54,6 +54,7 @@ default_envs = d1_mini # arduino core 2.6.1 = platformIO 2.3.0 # arduino core 2.6.2 = platformIO 2.3.1 # arduino core 2.6.3 = platformIO 2.3.2 +# arduino core 2.7.0 = platformIO 2.5.0 # ------------------------------------------------------------------------------ arduino_core_2_3_0 = espressif8266@1.5.0 arduino_core_2_4_0 = espressif8266@1.6.0 @@ -65,12 +66,13 @@ arduino_core_2_5_2 = espressif8266@2.2.3 arduino_core_2_6_1 = espressif8266@2.3.0 arduino_core_2_6_2 = espressif8266@2.3.1 arduino_core_2_6_3 = espressif8266@2.3.3 +arduino_core_2_7_0 = espressif8266@2.5.0 # Development platforms arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage -platform = ${common.arduino_core_2_4_2} +# Platform to use for ESP8266 platform_latest = ${common.arduino_core_2_6_3} # ------------------------------------------------------------------------------ diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 14fee5cb8..1b8624844 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1598,7 +1598,7 @@ uint16_t WS2812FX::mode_oscillate(void) uint16_t WS2812FX::mode_lightning(void) { uint16_t ledstart = random16(SEGLEN); // Determine starting location of flash - uint16_t ledlen = random16(SEGLEN -1 -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) + uint16_t ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) uint8_t bri = 255/random8(1, 3); if (SEGENV.step == 0) diff --git a/wled00/data/index.htm b/wled00/data/index.htm index 9bf3de6b3..7248c076d 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -274,7 +274,7 @@ button { background: var(--c-bg); top: 0px; z-index: 1; - margin-top: 1px; + margin-top: 2px; } #staytop1 { diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 78a74b031..5d5ab2b5c 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -45,11 +45,10 @@ void handleDMX(); void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet); //file.cpp -bool find(const char* target, File f); bool handleFileRead(AsyncWebServerRequest*, String path); -bool writeObjectToFileUsing(const char* file, const char* key, JsonObject content, File input, bool doClose); -bool writeObjectToFile(const char* file, const char* key, JsonObject content, File input, bool doClose); -bool appendObjectToFile(const char* file, const char* key, JsonObject& content, File input, bool doClose); +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); diff --git a/wled00/file.cpp b/wled00/file.cpp index 4a2cf278e..7fcbc43cd 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -15,44 +15,83 @@ #ifndef WLED_DISABLE_FILESYSTEM -bool find(const char *target, File f) { +//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) { size_t targetLen = strlen(target); + Serial.println(target); + //Serial.println(f.position()); size_t index = 0; - int c; + byte c; + uint16_t bufsize = 0, count = 0; + byte buf[256]; - while(f.position() < f.size() -1) { - c = f.read(); - if(c != target[index]) + while (f.position() < f.size() -1) { + //c = f.read(); + //Serial.println(f.position()); + bufsize = f.read(buf, 256); + count = 0; + while (count < bufsize) { + if(buf[count] != target[index]) index = 0; // reset index if any char does not match - if(c == target[index]) { - if(++index >= targetLen) { // return true if all chars in the target match - return 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); + return true; + } } + count++; } } return false; } -bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonObject content, File input, bool doClose = true) +//find empty spots in file stream in 256-byte blocks. +bool bufferedFindSpace(uint16_t targetLen, File f) { + size_t index = 0; + byte c; + uint16_t bufsize = 0, count = 0; + byte buf[256]; + + while (f.position() < f.size() -1) { + bufsize = f.read(buf, 256); + count = 0; + while (count < bufsize) { + 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() - targetLen); + return true; + } + } + count++; + } + } + return false; +} + +bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content) { char objKey[10]; sprintf(objKey, "\"%ld\":", id); - writeObjectToFile(file, objKey, content, input, doClose); + writeObjectToFile(file, objKey, content); } -bool writeObjectToFile(const char* file, const char* key, JsonObject content, File input, bool doClose = true) +bool writeObjectToFile(const char* file, const char* key, JsonDocument* content) { uint32_t pos = 0; - File f = (input) ? input : SPIFFS.open(file, "r+"); + File f = SPIFFS.open(file, "r+"); if (!f) f = SPIFFS.open(file,"w"); if (!f) return false; //f.setTimeout(1); f.seek(0, SeekSet); - if (!find(key, f)) //key does not exist in file + if (!bufferedFind(key, f)) //key does not exist in file { - return appendObjectToFile(file, key, content, f, true); + return appendObjectToFile(file, key, content, f); } //exists @@ -63,9 +102,9 @@ bool writeObjectToFile(const char* file, const char* key, JsonObject content, Fi uint32_t pos2 = f.position(); uint32_t oldLen = pos2 - pos; - if (!content.isNull() && measureJson(content) <= oldLen) //replace + if (!content->isNull() && measureJson(*content) <= oldLen) //replace { - serializeJson(content, f); + serializeJson(*content, f); //pad rest for (uint32_t i = f.position(); i < pos2; i++) { f.write(' '); @@ -77,53 +116,43 @@ bool writeObjectToFile(const char* file, const char* key, JsonObject content, Fi for (uint32_t i = pos; i < pos2; i++) { f.write(' '); } - if (!content.isNull()) return appendObjectToFile(file, key, content, f, true); + if (!content->isNull()) return appendObjectToFile(file, key, content, f); } f.close(); } -bool appendObjectToFile(const char* file, const char* key, JsonObject& content, File input, bool doClose = true) +bool appendObjectToFile(const char* file, const char* key, JsonDocument* content, File input) { + Serial.println("Append"); uint32_t pos = 0; File f = (input) ? input : SPIFFS.open(file, "r+"); if (!f) f = SPIFFS.open(file,"w"); if (!f) return false; - f.setTimeout(1); if (f.size() < 3) f.print("{}"); //if there is enough empty space in file, insert there instead of appending - uint32_t contentLen = measureJson(content); - uint32_t spaces = 0, spaceI = 0, spacesMax = 0, spaceMaxI = 0; - f.seek(1, SeekSet); - for (uint32_t i = 1; i < f.size(); i++) - { - if (f.read() == ' ') { - if (!spaces) spaceI = i; spaces++; - } else { - if (spaces > spacesMax) { spacesMax = spaces; spaceMaxI = spaceI;} - spaces = 0; - if (spacesMax >= contentLen) { - f.seek(spaceMaxI, SeekSet); - serializeJson(content, f); - return true; - } - } + uint32_t contentLen = measureJson(*content); + Serial.print("clen"); Serial.println(contentLen); + if (bufferedFindSpace(contentLen, f)) { + Serial.println("space"); + serializeJson(*content, f); + return true; } //check if last character in file is '}' (typical) - uint32_t lastByte = f.size() -1; f.seek(1, SeekEnd); - if (f.read() == '}') pos = lastByte; + if (f.read() == '}') pos = f.size() -1; if (pos == 0) //not found { - while (find("}",f)) //find last closing bracket in JSON if not last char + Serial.println("not}"); + while (bufferedFind("}",f)) //find last closing bracket in JSON if not last char { pos = f.position(); } } - - if (pos) + Serial.print("pos"); Serial.println(pos); + if (pos < 3) { f.seek(pos -1, SeekSet); f.write(','); @@ -132,14 +161,14 @@ bool appendObjectToFile(const char* file, const char* key, JsonObject& content, f.write('{'); //start JSON } - f.print("\""); + //f.print("\""); f.print(key); - f.print("\":"); + //f.print("\":"); //Append object - serializeJson(content, f); + serializeJson(*content, f); f.write('}'); - if (doClose) f.close(); + f.close(); } bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest) @@ -156,9 +185,9 @@ bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest) File f = SPIFFS.open(file, "r"); if (!f) return false; - f.setTimeout(0); - Serial.println(key); - if (f.find(key)) //key does not exist in file + //f.setTimeout(0); + //Serial.println(key); + if (!bufferedFind(key, f)) //key does not exist in file { f.close(); return false; diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index fc00c2c94..f980afee7 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -657,6 +657,12 @@ bool applyPreset(byte index, bool loadBri) void savePreset(byte index, bool persist) { + StaticJsonDocument<1024> doc; + serializeState(doc.to()); + doc["p"]=50; + serializeJson(doc, Serial); + writeObjectToFileUsingId("/presets.json", index, &doc); + return; if (index > 16) return; if (index < 1) {saveSettingsToEEPROM();return;} uint16_t i = 380 + index*20;//min400