diff --git a/ESPixelStick/src/FileMgr.cpp b/ESPixelStick/src/FileMgr.cpp index 5f2a5bb08..f7755dbc4 100644 --- a/ESPixelStick/src/FileMgr.cpp +++ b/ESPixelStick/src/FileMgr.cpp @@ -793,15 +793,19 @@ void c_FileMgr::DescribeSdCardToUser () } // DescribeSdCardToUser //----------------------------------------------------------------------------- -void c_FileMgr::GetListOfSdFiles (String & Response) +void c_FileMgr::GetListOfSdFiles (String & Response, uint32_t FirstFileToSend) { // DEBUG_START; + #define EntryReservedSpace 75 + #define EntryUsageFactor 3 - DynamicJsonDocument ResponseJsonDoc (3 * 1024); + DynamicJsonDocument ResponseJsonDoc (1 * 1024); do // once { - if (0 == ResponseJsonDoc.capacity ()) + uint32_t capacity = ResponseJsonDoc.capacity (); + + if (0 == capacity) { logcon (String(CN_stars) + F ("ERROR: Failed to allocate memory for the GetListOfSdFiles web request response.") + CN_stars); break; @@ -820,6 +824,12 @@ void c_FileMgr::GetListOfSdFiles (String & Response) ResponseJsonDoc[F ("totalBytes")] = ESP_SD.size64 (); #endif uint64_t usedBytes = 0; + uint32_t last = 0; + + ResponseJsonDoc[F("usedBytes")] = uint32_t(-1); + ResponseJsonDoc[F("first")] = FirstFileToSend; + ResponseJsonDoc[F("last")] = uint32_t(-1); + ResponseJsonDoc[F("final")] = false; File dir = ESP_SDFS.open ("/", CN_r); @@ -829,24 +839,42 @@ void c_FileMgr::GetListOfSdFiles (String & Response) if (!entry) { - // no more files + // DEBUG_V("no more files to add to list"); + ResponseJsonDoc[F("final")] = true; break; } usedBytes += entry.size (); + ++last; + + // have we gotten to a file we have not sent yet? + if(FirstFileToSend) + { + --FirstFileToSend; + continue; + } String EntryName = String (entry.name ()); EntryName = EntryName.substring ((('/' == EntryName[0]) ? 1 : 0)); // DEBUG_V ("EntryName: " + EntryName); // DEBUG_V ("EntryName.length(): " + String(EntryName.length ())); - if ((0 != EntryName.length ()) && - (EntryName != String (F ("System Volume Information"))) && + if ((!EntryName.isEmpty ()) && + (!EntryName.equals(String (F ("System Volume Information")))) && (0 != entry.size ()) ) { - // DEBUG_V ("Adding File: '" + EntryName + "'"); + uint32_t neededMemory = EntryReservedSpace + (EntryName.length() * EntryUsageFactor); + uint32_t usedSpace = ResponseJsonDoc.memoryUsage(); + uint32_t availableSpace = capacity - usedSpace; + if(neededMemory >= availableSpace) + { + // DEBUG_V("No more file names will fit in the list"); + entry.close (); + break; + } + // DEBUG_V ("Adding File: '" + EntryName + "'"); JsonObject CurrentFile = FileArray.createNestedObject (); CurrentFile[CN_name] = EntryName; CurrentFile[F ("date")] = entry.getLastWrite (); @@ -854,11 +882,12 @@ void c_FileMgr::GetListOfSdFiles (String & Response) } entry.close (); - } + } // end while true dir.close(); ResponseJsonDoc[F("usedBytes")] = usedBytes; + ResponseJsonDoc[F("last")] = last; if(ResponseJsonDoc.overflowed()) { @@ -866,7 +895,7 @@ void c_FileMgr::GetListOfSdFiles (String & Response) break; } - } while (false); + } while (false); // once // DEBUG_V(String("ResponseJsonDoc.size(): ") + String(ResponseJsonDoc.size())); Response.reserve(1024); @@ -909,8 +938,8 @@ void c_FileMgr::GetListOfSdFiles (std::vector & Response) // DEBUG_V ("EntryName: '" + EntryName + "'"); // DEBUG_V ("EntryName.length(): " + String(EntryName.length ())); - if ((0 != EntryName.length ()) && - (EntryName != String (F ("System Volume Information"))) && + if ((!EntryName.isEmpty ()) && + (!EntryName.equals(String (F ("System Volume Information")))) && (0 != entry.size ()) ) { diff --git a/ESPixelStick/src/FileMgr.hpp b/ESPixelStick/src/FileMgr.hpp index 941c7c7e7..eef291d4a 100644 --- a/ESPixelStick/src/FileMgr.hpp +++ b/ESPixelStick/src/FileMgr.hpp @@ -92,7 +92,7 @@ class c_FileMgr size_t WriteSdFile (const FileId & FileHandle, byte * FileData, size_t NumBytesToWrite); size_t WriteSdFile (const FileId & FileHandle, byte * FileData, size_t NumBytesToWrite, size_t StartingPosition); void CloseSdFile (const FileId & FileHandle); - void GetListOfSdFiles (String & Response); + void GetListOfSdFiles (String & Response, uint32_t FirstFileToSend); void GetListOfSdFiles (std::vector & Response); size_t GetSdFileSize (const String & FileName); size_t GetSdFileSize (const FileId & FileHandle); diff --git a/ESPixelStick/src/WebMgr.cpp b/ESPixelStick/src/WebMgr.cpp index 8615ea462..2af2435d2 100644 --- a/ESPixelStick/src/WebMgr.cpp +++ b/ESPixelStick/src/WebMgr.cpp @@ -250,8 +250,12 @@ void c_WebMgr::init () } else { + // DEBUG_V(String("URL: ") + request->url ()); + uint32_t StartingFileIndex = request->url ().substring(String(F("/files/")).length()).toInt(); + // DEBUG_V(String("StartingFileIndex: ") + StartingFileIndex); + String Response; - FileMgr.GetListOfSdFiles(Response); + FileMgr.GetListOfSdFiles(Response, StartingFileIndex); request->send (200, CN_applicationSLASHjson, Response); // DEBUG_V(String("Files: ") + Response); } diff --git a/ESPixelStick/src/input/InputFPPRemote.cpp b/ESPixelStick/src/input/InputFPPRemote.cpp index de2ed3a68..2afa49217 100644 --- a/ESPixelStick/src/input/InputFPPRemote.cpp +++ b/ESPixelStick/src/input/InputFPPRemote.cpp @@ -332,7 +332,7 @@ void c_InputFPPRemote::StartPlaying (String& FileName) do // once { // DEBUG_V (String ("FileName: '") + FileName + "'"); - if ((0 == FileName.length ()) || + if ((FileName.isEmpty ()) || (FileName.equals("null"))) { // DEBUG_V ("No file to play"); diff --git a/ESPixelStick/src/input/InputFPPRemotePlayFileFsm.cpp b/ESPixelStick/src/input/InputFPPRemotePlayFileFsm.cpp index 284963f14..1c37db008 100644 --- a/ESPixelStick/src/input/InputFPPRemotePlayFileFsm.cpp +++ b/ESPixelStick/src/input/InputFPPRemotePlayFileFsm.cpp @@ -423,7 +423,7 @@ bool fsm_PlayFile_state_PlayingFile::Sync (String& FileName, float ElapsedSecond do // once { // are we on the correct file? - if (FileName != p_Parent->GetFileName ()) + if (!FileName.equals(p_Parent->GetFileName ())) { // DEBUG_V ("Sync: Filename change"); p_Parent->Stop (); @@ -620,7 +620,7 @@ void fsm_PlayFile_state_Error::Start (String& FileName, float ElapsedSeconds, ui // DEBUG_START; // DEBUG_V("fsm_PlayFile_state_Error::Start"); - if (FileName != p_Parent->GetFileName ()) + if (!FileName.equals(p_Parent->GetFileName ())) { p_Parent->fsm_PlayFile_state_Idle_imp.Start (FileName, ElapsedSeconds, PlayCount); } @@ -647,7 +647,7 @@ bool fsm_PlayFile_state_Error::Sync (String& FileName, float ElapsedSeconds) // DEBUG_START; // DEBUG_V("State:Error"); - if (FileName != p_Parent->GetFileName ()) + if (!FileName.equals(p_Parent->GetFileName ())) { p_Parent->fsm_PlayFile_state_Idle_imp.Start (FileName, ElapsedSeconds, 1); } diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_QUINLED_Dig-Octa.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_QUINLED_Dig-Octa.hpp index e7cf03d70..ec1327bc4 100644 --- a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_QUINLED_Dig-Octa.hpp +++ b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_QUINLED_Dig-Octa.hpp @@ -79,7 +79,7 @@ // Not Finished - #define SUPPORT_OutputType_TLS3001 // #define SUPPORT_OutputType_APA102 // SPI // #define SUPPORT_OutputType_DMX // UART / RMT -// #define SUPPORT_OutputType_GECE // UART / RMT +#define SUPPORT_OutputType_GECE // UART / RMT #define SUPPORT_OutputType_GS8208 // UART / RMT // #define SUPPORT_OutputType_Renard // UART / RMT // #define SUPPORT_OutputType_Serial // UART / RMT diff --git a/ESPixelStick/src/service/FPPDiscovery.cpp b/ESPixelStick/src/service/FPPDiscovery.cpp index 20a79f3dc..6eab93395 100644 --- a/ESPixelStick/src/service/FPPDiscovery.cpp +++ b/ESPixelStick/src/service/FPPDiscovery.cpp @@ -1112,7 +1112,7 @@ void c_FPPDiscovery::StartPlaying (String & FileName, float SecondsElapsed) } // DEBUG_V (""); - if (0 == FileName.length()) + if (FileName.isEmpty()) { // DEBUG_V("Do not have a file to start"); break; diff --git a/html/script.js b/html/script.js index 99a1b8045..3c4a4249a 100644 --- a/html/script.js +++ b/html/script.js @@ -1,5 +1,6 @@ var StatusRequestTimer = null; var FseqFileListRequestTimer = null; +let ExpectedStartingFileIndex = 0; var DiagTimer = null; // global data @@ -243,7 +244,7 @@ $(function () { // console.log(file); // console.log(resp); Dropzone.forElement('#filemanagementupload').removeAllFiles(true) - RequestListOfFiles(); + RequestListOfFiles(0); }); this.on('complete', function (file, resp) { @@ -387,14 +388,14 @@ function ProcessWindowChange(NextWindow) { } else if (NextWindow === "#config") { - RequestListOfFiles(); + RequestListOfFiles(0); RcfResponse = RequestConfigFile("config.json"); RcfResponse = RequestConfigFile("output_config.json"); RcfResponse = RequestConfigFile("input_config.json"); } else if (NextWindow === "#filemanagement") { - RequestListOfFiles(); + RequestListOfFiles(0); } UpdateAdvancedOptionsMode(); @@ -507,7 +508,9 @@ function RequestStatusUpdate() } // RequestStatusUpdate -function RequestListOfFiles() { +function RequestListOfFiles(StartingFileIndex) { + ExpectedStartingFileIndex = StartingFileIndex; + // is the timer running? if (null === FseqFileListRequestTimer) { // timer runs until we get a response @@ -515,14 +518,14 @@ function RequestListOfFiles() { clearTimeout(FseqFileListRequestTimer); FseqFileListRequestTimer = null; - RequestListOfFiles(); + RequestListOfFiles(StartingFileIndex); }, 1000); } // end timer was not running // ask for a file list from the server - return fetch("HTTP://" + target + "/files", { + return fetch("HTTP://" + target + "/files/" + StartingFileIndex, { method: 'GET', mode: "cors", // no-cors, *cors, same-origin headers: { 'Content-Type': 'application/json' }, @@ -586,20 +589,27 @@ function ProcessGetFileListResponse(JsonConfigData) { clearTimeout(FseqFileListRequestTimer); FseqFileListRequestTimer = null; - // console.info("$('#FileManagementTable > tr').length " + $('#FileManagementTable > tr').length); + // are we starting a fresh list (first chunk) + if(JsonConfigData.first === 0) + { + // console.info("$('#FileManagementTable > tr').length " + $('#FileManagementTable > tr').length); - while (1 < $('#FileManagementTable > tr').length) { - // console.info("Deleting $('#FileManagementTable tr').length " + $('#FileManagementTable tr').length); - $('#FileManagementTable tr').last().remove(); - // console.log("After Delete: $('#FileManagementTable tr').length " + $('#FileManagementTable tr').length); + while (1 < $('#FileManagementTable > tr').length) { + // console.info("Deleting $('#FileManagementTable tr').length " + $('#FileManagementTable tr').length); + $('#FileManagementTable tr').last().remove(); + // console.log("After Delete: $('#FileManagementTable tr').length " + $('#FileManagementTable tr').length); + } } - let CurrentRowId = 0; + console.info("Expected File Index: " + ExpectedStartingFileIndex); + console.info("Received File index: " + JsonConfigData.first); + JsonConfigData.files.forEach(function (file) { + let CurrentRowId = $('#FileManagementTable > tr').length; let SelectedPattern = ''; - let NamePattern = ''; - let DatePattern = ''; - let SizePattern = ''; + let NamePattern = ''; + let DatePattern = ''; + let SizePattern = ''; let rowPattern = '' + SelectedPattern + NamePattern + DatePattern + SizePattern + ''; $('#FileManagementTable tr:last').after(rowPattern); @@ -615,9 +625,14 @@ function ProcessGetFileListResponse(JsonConfigData) { $('#FileDate_' + (CurrentRowId)).val(new Date(0).toISOString()); $('#FileSize_' + (CurrentRowId)).val(0); } + }); // end foreach - CurrentRowId++; - }); + // was this the last chunk? + if(false === JsonConfigData.final) + { + // not last. Ask for the next chunk + RequestListOfFiles(JsonConfigData.last); + } } // ProcessGetFileListResponse function RequestFileDeletion() { @@ -631,7 +646,7 @@ function RequestFileDeletion() { } }); - RequestListOfFiles(); + RequestListOfFiles(0); } // RequestFileDeletion