Meinst du ein Ordner hochladen? Ja, das funktioniert, weil bei einem Form Upload nur nachdem der gesamte Upload fertig ist 1x der Handler für das AsyncWebServerRequest ausgelöst wird. Das sieht man auch sehr schon in dem Debugger von Firefox/Chrome bei dem Network Pfad, da kann man beobachten, wann dass HTTP-200 von dem ESP zurück kommt.
Was noch nicht ganz sauber funktioniert ist, wenn man schnell hintereinander einzelne Dateien hochladet, dann wird der Buffer jedes einzelne mal allokiert und wieder zerstört. Hier überlege ich noch, wie das gut zu lösen wäre. Ein Timestamp und eine fest kodierte Zeit (zb bis 15s nach dem letzten Upload), wird der Buffer gehalten und danach wieder freigegeben.
Stimmt! Guter Punkt, ich habe auch kein Abfangmechanismus dagegen. Ich schau, wie ich die reduktion einbauen kann (wahscheinlich recht einfach mit dividion durch 2). Werde auch schauen, dass ich statt 1 zusammen hängenden Block zu allokieren auch 2 (bzw nr_of_buffers) Blöcke machen.
Was mir bei der Lösung (und auch bei dem aktuellen Code) einen kalten Schauer über den Rücken jagt ist der Umstand, dass wir direkt auf die rohe NVS Datenstruktur zugreifen. Wenn espressif das Layout auch nur im Ansatz ändert (und in den NVS Treiber ein Kompabilitäts-Layer einzieht), explodiert uns der Code potenziell ins Gesicht.
Wenn wir schon eine Unterstützung für einen Iterator im NVS von esp-idf haben, sollten wir den verwenden, statt so low-level auf die NVS-Partition zuzugreifen. Machen wir ja bei der FAT32 Partition der SD-Karte ja auch nicht 
Zu Nr 3 habe ich zwei Lösungen: Commits · laszloh/ESPuino · GitHub
a) std::vector verwenden
Damit verbrauchen wir noch immer Speicher (im schlimmsten Fall weiterhin die 10 * sizeof(WiFiSettings
). Im Schnitt sollte das aber schon eine Einsparung bringen, zB ich habe bis heute max 3 WiFi Netzwerke in meinem ESPuino gehabt → 70% Einsparung (okay, weniger, weil std::vector auch ein Overhead hat).
Hier ändere ich an der Struktur im NVS nichts, damit sind die Änderungen einfach und überschaubar. Aber die Einstellungen sind noch immer im RAM, auch wenn wir sie nicht mehr benötigen… (siehe Punkt b
)
Commit: Change knownNetworks to std::vector
b) Die WiFi Einstellungen nicht in den RAM laden
Hier gehe ich ein Schritt weiter. Mit der Annahme, dass wir 99% der Zeit die WiFi Einstellungen nicht brauchen, sollten sie auch nciht im RAM liegen. Stattdessen sollten wir sie direkt aus dem NVS laden, wenn sie gebraucht werden. Am Besten ohne viel Speicher allokieren zu müssen, am Besten: nur auf dem Stack → keine dynamische Speicherallokierung.
Aktuell wir das Array mit den aktiven Einstellungen 1:1 in einen einzelnen NVS Eintrag geschrieben. Dadurch dass die Einstellungen auch im RAM sind, macht das die Änderung einfach:
- Änderung im RAM ausführen
- RAM Bereich 1:1 in den NVS schreiben
- Profit
Wenn wir aber nun den RAM Block weg lassen haben wir das Problem, dass wir den NVS Eintrag laden müssen → bis zu 1,2kB an Speicher wird benötigt → malloc zwingend notwendig. Die Schritte schauen so aus:
- malloc von max 1200 Bytes
- NVS in den RAM laden
- Änderung durchführen / Eintrag auslesen
- RAM Bereich zurückschreiben
- RAM freigeben
Um hier kein malloc zu machen, habe ich mir überlegt, die Struktur der WiFi Einstellungen in NVS zu ändern. Statt 1 Eintrag für alle Netzwerkeinstellungen zu haben, mache ich 1 Eintrag / Netzwerkeinstellung. Es wäre super, wenn man die SSID als key nehmen könnte, geht aber nicht, da keys nur 15 Charekter lang sein können, SSIDs das Doppelte (wäre ja zu einfach gewesen). Somit gleibt mir nichts anderes übrig als die Keys durchzunummerieren (ein Vorteil, damit kann ich schön auf „eh nicht mehr als 10 Einträge, gelle“ prüfen). Ich packe alle in ein eigenes NVS namespace, womit ich schnell über alle Einträge mit den NVS Iterator drüber gehen kann um den Richtigen zu finden.
Danach muss nur noch der gefundene Eintrag geladen/geändert/gelöscht werden. Wir ersparen uns den dynamischen Speicher, da ein WiFiSettings 120 Byte ist was noch recht angenehm auf den Stack passt. Ein Nachteil ist das leicht höhere NVS Speicherverbrauch (rechnerisch sollten es 5 Entries / Eintrag sein, statt 5 - 40 für einen gesamten Eintrag). Meiner Meinung nach ist das zu verkraften:
alt:
leer (0 WiFi Einträge):
used: 819, total: 8064 (precent: 10.15)
voll (10 WiFi Einträge):
used: 859, total: 8064 (precent: 10.65)
neu:
leer (0 WiFi Einträge):
used: 819, total: 8064 (precent: 10.15)
voll (10 WiFi Einträge):
used: 878, total: 8064 (precent: 10.88)
Commit: Remove all wifi settings from RAM