diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ef90cbfb0..dfb2b46e5 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -98,12 +98,18 @@ jobs: chip: "esp32" - target: "esp32_quinled_uno_espsv3" chip: "esp32" - # + # - target: "esp32_tetra2go" chip: "esp32" # KR Lights - target: "esp32_kr_lights_msm" chip: "esp32" + # + - target: "esp32_ka" + chip: "esp32" + # + - target: "esp32_breakdancev2" + chip: "esp32" runs-on: ubuntu-latest steps: diff --git a/.scripts/deleteSD.py b/.scripts/deleteSD.py new file mode 100644 index 000000000..eb42e0a02 --- /dev/null +++ b/.scripts/deleteSD.py @@ -0,0 +1,27 @@ +import platform +import shutil +import os +Import("env") + +f = open("./MyEnv.txt", "a") +f.write(env.Dump()) +f.close() + +PACKAGES_DIR = env['PROJECT_PACKAGES_DIR'] +FRAMEWORK_DIR = os.path.join(PACKAGES_DIR, "framework-arduinoespressif8266/libraries") +SD_DIR = os.path.join(FRAMEWORK_DIR, "SD") +SDFAT_DIR = os.path.join(FRAMEWORK_DIR, "ESP8266SdFat") +# print("PACKAGES_DIR " + PACKAGES_DIR) +# print("FRAMEWORK_DIR " + FRAMEWORK_DIR) +# print("SD_DIR " + SD_DIR) + +if os.path.exists(SD_DIR): + shutil.rmtree(SD_DIR) + +if os.path.exists(SDFAT_DIR): + shutil.rmtree(SDFAT_DIR) + +def before_build(target, source, env): + print("BeforeBuild") + +env.AddPreAction("buildprog", before_build) diff --git a/ESPixelStick/ESPixelStick.ino b/ESPixelStick/ESPixelStick.ino index 47c50e966..281c15f3f 100644 --- a/ESPixelStick/ESPixelStick.ino +++ b/ESPixelStick/ESPixelStick.ino @@ -513,6 +513,8 @@ void loop() WebMgr.Process (); + FileMgr.Poll(); + #ifdef SUPPORT_SENSOR_DS18B20 SensorDS18B20.Poll(); #endif // def SUPPORT_SENSOR_DS18B20 diff --git a/ESPixelStick/src/FileMgr.cpp b/ESPixelStick/src/FileMgr.cpp index 4ba58c072..983101cda 100644 --- a/ESPixelStick/src/FileMgr.cpp +++ b/ESPixelStick/src/FileMgr.cpp @@ -2,7 +2,7 @@ * FileMgr.cpp - Output Management class * * Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver -* Copyright (c) 2021, 2022 Shelby Merrick +* Copyright (c) 2021, 2024 Shelby Merrick * http://www.forkineye.com * * This program is provided free for you to use in any way that you wish, @@ -19,15 +19,113 @@ #include "ESPixelStick.h" #include +#include #include "FileMgr.hpp" +#include "network/NetworkMgr.hpp" + +SdFat sd; + +oflag_t XlateFileMode[3] = { O_READ , O_WRITE | O_CREAT, O_WRITE | O_APPEND }; +#ifdef SUPPORT_FTP +#include +FtpServer ftpSrv; + +//----------------------------------------------------------------------------- +void ftp_callback(FtpOperation ftpOperation, unsigned int freeSpace, unsigned int totalSpace) +{ + FeedWDT(); + switch (ftpOperation) + { + case FTP_CONNECT: + { + LOG_PORT.println(F("FTP: Connected!")); + break; + } + + case FTP_DISCONNECT: + { + LOG_PORT.println(F("FTP: Disconnected!")); + break; + } + + case FTP_FREE_SPACE_CHANGE: + { + FileMgr.BuildFseqList(); + LOG_PORT.printf("FTP: Free space change, free %u of %u! Rebuilding FSEQ file list\n", freeSpace, totalSpace); + break; + } + + default: + { + LOG_PORT.println(F("FTP: unknown callback!")); + break; + } + } +}; + +//----------------------------------------------------------------------------- +void ftp_transferCallback(FtpTransferOperation ftpOperation, const char* name, unsigned int transferredSize) +{ + FeedWDT(); + switch (ftpOperation) + { + case FTP_UPLOAD_START: + { + LOG_PORT.println(String(F("FTP: Start Uploading '")) + name + "'"); + break; + } + + case FTP_UPLOAD: + { + // LOG_PORT.printf("FTP: Upload of file %s byte %u\n", name, transferredSize); + break; + } + + case FTP_TRANSFER_STOP: + { + LOG_PORT.println(String(F("FTP: Done Uploading '")) + name + "'"); + break; + } + + case FTP_TRANSFER_ERROR: + { + LOG_PORT.println(String(F("FTP: Error Uploading '")) + name + "'"); + break; + } + + default: + { + LOG_PORT.println(F("FTP: Unknown Transfer Callback!")); + break; + } + } + + /* FTP_UPLOAD_START = 0, + * FTP_UPLOAD = 1, + * + * FTP_DOWNLOAD_START = 2, + * FTP_DOWNLOAD = 3, + * + * FTP_TRANSFER_STOP = 4, + * FTP_DOWNLOAD_STOP = 4, + * FTP_UPLOAD_STOP = 4, + * + * FTP_TRANSFER_ERROR = 5, + * FTP_DOWNLOAD_ERROR = 5, + * FTP_UPLOAD_ERROR = 5 + */ +}; +#endif // def SUPPORT_FTP + +//----------------------------------------------------------------------------- +static PROGMEM const char DefaultFseqResponse[] = + "{\"totalBytes\" : 0," \ + "\"files\" : []," \ + "\"usedBytes\" : 0," \ + "\"numFiles\" : 0" \ + "}"; -#define HTML_TRANSFER_BLOCK_SIZE 563 -#ifdef ARDUINO_ARCH_ESP32 -# define NumBlocksToBuffer 7 -#else -# define NumBlocksToBuffer 9 -#endif //----------------------------------------------------------------------------- ///< Start up the driver and put it into a safe mode c_FileMgr::c_FileMgr () @@ -76,6 +174,42 @@ void c_FileMgr::Begin () // DEBUG_END; } // begin +//----------------------------------------------------------------------------- +void c_FileMgr::NetworkStateChanged (bool NewState) +{ + // DEBUG_START; +#ifdef SUPPORT_FTP + ftpSrv.end(); + + // DEBUG_V(String(" NewState: ") + String(NewState)); + // DEBUG_V(String("SdCardInstalled: ") + String(SdCardInstalled)); + // DEBUG_V(String(" FtpEnabled: ") + String(FtpEnabled)); + if(NewState && SdCardInstalled && FtpEnabled) + { + ftpSrv.end(); + logcon("Starting FTP server."); + ftpSrv.begin(FtpUserName.c_str(), FtpPassword.c_str(), WelcomeString.c_str()); + ftpSrv.setCallback(ftp_callback); + ftpSrv.setTransferCallback(ftp_transferCallback); + } +#endif // def SUPPORT_FTP + + // DEBUG_END; +} // NetworkStateChanged + +//----------------------------------------------------------------------------- + void c_FileMgr::Poll() + { + // DEBUG_START; +#ifdef SUPPORT_FTP + if(FtpEnabled) + { + FeedWDT(); + ftpSrv.handleFTP(); + } +#endif // def SUPPORT_FTP + } // Poll + //----------------------------------------------------------------------------- bool c_FileMgr::SetConfig (JsonObject & json) { @@ -89,22 +223,26 @@ bool c_FileMgr::SetConfig (JsonObject & json) extern void PrettyPrint (JsonObject& jsonStuff, String Name); PrettyPrint (JsonDeviceConfig, "c_FileMgr"); - DEBUG_V("miso_pin: " + String(miso_pin)); - DEBUG_V("mosi_pin: " + String(mosi_pin)); - DEBUG_V(" clk_pin: " + String(clk_pin)); - DEBUG_V(" cs_pin: " + String(cs_pin)); + // DEBUG_V("miso_pin: " + String(miso_pin)); + // DEBUG_V("mosi_pin: " + String(mosi_pin)); + // DEBUG_V(" clk_pin: " + String(clk_pin)); + // DEBUG_V(" cs_pin: " + String(cs_pin)); */ ConfigChanged |= setFromJSON (miso_pin, JsonDeviceConfig, CN_miso_pin); ConfigChanged |= setFromJSON (mosi_pin, JsonDeviceConfig, CN_mosi_pin); ConfigChanged |= setFromJSON (clk_pin, JsonDeviceConfig, CN_clock_pin); ConfigChanged |= setFromJSON (cs_pin, JsonDeviceConfig, CN_cs_pin); + + ConfigChanged |= setFromJSON (FtpUserName, JsonDeviceConfig, CN_user); + ConfigChanged |= setFromJSON (FtpPassword, JsonDeviceConfig, CN_password); + ConfigChanged |= setFromJSON (FtpEnabled, JsonDeviceConfig, CN_enabled); /* - DEBUG_V("miso_pin: " + String(miso_pin)); - DEBUG_V("mosi_pin: " + String(mosi_pin)); - DEBUG_V(" clk_pin: " + String(clk_pin)); - DEBUG_V(" cs_pin: " + String(cs_pin)); + // DEBUG_V("miso_pin: " + String(miso_pin)); + // DEBUG_V("mosi_pin: " + String(mosi_pin)); + // DEBUG_V(" clk_pin: " + String(clk_pin)); + // DEBUG_V(" cs_pin: " + String(cs_pin)); - DEBUG_V("ConfigChanged: " + String(ConfigChanged)); + // DEBUG_V("ConfigChanged: " + String(ConfigChanged)); */ } else @@ -117,6 +255,7 @@ bool c_FileMgr::SetConfig (JsonObject & json) if (ConfigChanged) { SetSpiIoPins (); + NetworkStateChanged(NetworkMgr.IsConnected()); } // DEBUG_END; @@ -135,6 +274,10 @@ void c_FileMgr::GetConfig (JsonObject& json) json[CN_clock_pin] = clk_pin; json[CN_cs_pin] = cs_pin; + json[CN_user] = FtpUserName; + json[CN_password] = FtpPassword; + json[CN_enabled] = FtpEnabled; + // DEBUG_END; } // GetConfig @@ -153,6 +296,34 @@ void c_FileMgr::GetStatus (JsonObject& json) } // GetConfig +//------------------------------------------------------------------------------ +// Call back for file timestamps. Only called for file create and sync(). +void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) +{ + // LOG_PORT.println("DateTime Start"); + + tmElements_t tm; + breakTime(now(), tm); + + // LOG_PORT.println(String("time_t:") + String(now())); + // LOG_PORT.println(String("Year Raw:") + String(tm.Year)); + // LOG_PORT.println(String("Year Adj:") + String(tm.Year + 1970)); + // LOG_PORT.println(String("Month:") + String(tm.Month)); + // LOG_PORT.println(String("Day:") + String(tm.Day)); + + // Return date using FS_DATE macro to format fields. + *date = FS_DATE(tm.Year+1970, tm.Month, tm.Day); + // LOG_PORT.println(String("date:") + String(*date)); + + // Return time using FS_TIME macro to format fields. + *time = FS_TIME(tm.Hour, tm.Minute, tm.Second); + // LOG_PORT.println(String("time:") + String(*time)); + + // Return low time bits in units of 10 ms, 0 <= ms10 <= 199. + *ms10 = 0; + // LOG_PORT.println("DateTime End"); +} + //----------------------------------------------------------------------------- void c_FileMgr::SetSpiIoPins () { @@ -163,6 +334,8 @@ void c_FileMgr::SetSpiIoPins () // DEBUG_V("Terminate current SD session"); ESP_SD.end (); } + + FsDateTime::setCallback(dateTime); #ifdef ARDUINO_ARCH_ESP32 // DEBUG_V(); try @@ -199,29 +372,96 @@ void c_FileMgr::SetSpiIoPins () // DEBUG_V(); pinMode(miso_pin, INPUT); # endif // def USE_MISO_PULLUP - - // DEBUG_V(); SPI.begin (clk_pin, miso_pin, mosi_pin, cs_pin); +# else // ESP8266 + SPI.end (); + SPI.begin (); +# endif // ! ARDUINO_ARCH_ESP32 // DEBUG_V(); ResetSdCard(); // DEBUG_V(); - if (!ESP_SD.begin (cs_pin)) -# else // ! ARDUINO_ARCH_ESP32 - if (!ESP_SD.begin (SD_CARD_CS_PIN, SD_CARD_CLK_MHZ)) -# endif // ! ARDUINO_ARCH_ESP32 + if (!ESP_SD.begin (SdSpiConfig(cs_pin, SHARED_SPI, SD_CARD_CLK_MHZ, &SPI))) #endif // !def SUPPORT_SD_MMC { // DEBUG_V(); logcon(String(F("No SD card installed"))); SdCardInstalled = false; + // DEBUG_V(); + if(nullptr == ESP_SD.card()) + { + logcon(F("SD 'Card' setup failed.")); + } + else if (ESP_SD.card()->errorCode()) + { + logcon(String(F("SD initialization failed - code: ")) + String(ESP_SD.card()->errorCode())); + // DEBUG_V(String(F("SD initialization failed - data: ")) + String(ESP_SD.card()->errorData())); + printSdErrorText(&Serial, ESP_SD.card()->errorCode()); LOG_PORT.println(""); + } + else if (ESP_SD.vol()->fatType() == 0) + { + logcon(F("SD Can't find a valid FAT16/FAT32 partition.")); + } + else + { + logcon(F("SD Can't determine error type")); + } } else { // DEBUG_V(); SdCardInstalled = true; + // DEBUG_V(); + csd_t csd; + uint8_t tran_speed = 0; + + CSD MyCsd; + // DEBUG_V(); + ESP_SD.card()->readCSD(&csd); + memcpy (&MyCsd, &csd.csd[0], sizeof(csd.csd)); + // DEBUG_V(String("TRAN Speed: 0x") + String(MyCsd.Decode_0.tran_speed,HEX)); + tran_speed = MyCsd.Decode_0.tran_speed; + + switch(tran_speed) + { + case 0x32: + { + SPI.setFrequency(25 * 1024 * 1024); + logcon("Set SD speed to 25Mhz"); + break; + } + case 0x5A: + { + SPI.setFrequency(50 * 1024 * 1024); + logcon("Set SD speed to 50Mhz"); + break; + } + case 0x0B: + { + SPI.setFrequency(100 * 1024 * 1024); + logcon("Set SD speed to 100Mhz"); + break; + } + case 0x2B: + { + SPI.setFrequency(200 * 1024 * 1024); + logcon("Set SD speed to 200Mhz"); + break; + } + default: + { + SPI.setFrequency(25 * 1024 * 1024); + logcon("Set Default SD speed to 25Mhz"); + } + } + // DEBUG_V(); + SdCardSizeMB = 0.000512 * csd.capacity(); + // DEBUG_V(String("SdCardSizeMB: ") + String(SdCardSizeMB)); + DescribeSdCardToUser (); + // DEBUG_V(); BuildFseqList(); + // DEBUG_V(); } } #ifdef ARDUINO_ARCH_ESP32 @@ -232,6 +472,8 @@ void c_FileMgr::SetSpiIoPins () } #endif // def ARDUINO_ARCH_ESP32 + // SdFile::dateTimeCallback(dateTime); + #else // no sd defined SdCardInstalled = false; #endif // defined (SUPPORT_SD) || defined(SUPPORT_SD_MMC) @@ -510,9 +752,9 @@ bool c_FileMgr::SaveFlashFile(const String FileName, uint32_t index, uint8_t *da // DEBUG_V(String(" final: ") + String(final)); fs::File file; - - if(0 == index) - { + + if(0 == index) + { file = LittleFS.open(FileName.c_str(), "w"); } else @@ -745,6 +987,7 @@ c_FileMgr::FileId c_FileMgr::CreateSdFileHandle () { currentFileListEntry.handle = FileHandle; response = FileHandle; + // DEBUG_V(String("handle: ") + currentFileListEntry.handle); break; } } @@ -764,17 +1007,11 @@ c_FileMgr::FileId c_FileMgr::CreateSdFileHandle () void c_FileMgr::DeleteSdFile (const String & FileName) { // DEBUG_START; - String FileNamePrefix; - if (!FileName.startsWith ("/")) - { - FileNamePrefix = "/"; - } - // DEBUG_V (); - if (ESP_SD.exists (FileNamePrefix+FileName)) + if (ESP_SD.exists (FileName)) { // DEBUG_V (String ("Deleting '") + FileName + "'"); - ESP_SD.remove (FileNamePrefix+FileName); + ESP_SD.remove (FileName); BuildFseqList(); } @@ -787,16 +1024,12 @@ void c_FileMgr::DescribeSdCardToUser () { // DEBUG_START; -#ifdef ARDUINO_ARCH_ESP32 - uint64_t cardSize = ESP_SD.cardSize () / (1024 * 1024); -#else - uint64_t cardSize = ESP_SD.size64 () / (1024 * 1024); -#endif // def ARDUINO_ARCH_ESP32 - - logcon (String (F ("SD Card Size: ")) + int64String (cardSize) + "MB"); + logcon (String (F ("SD Card Size: ")) + int64String (SdCardSizeMB) + "MB"); /* // DEBUG_V("Open Root"); - File root = ESP_SD.open("/"); + FsFile root; + ESP_SD.chdir(); + root.open("/", O_READ); printDirectory (root, 0); root.close(); // DEBUG_V("Close Root"); @@ -810,6 +1043,9 @@ void c_FileMgr::GetListOfSdFiles (std::vector & Response) { // DEBUG_START; + char entryName[256]; + FsFile Entry; + Response.clear(); do // once { @@ -819,33 +1055,39 @@ void c_FileMgr::GetListOfSdFiles (std::vector & Response) break; } - File dir = ESP_SDFS.open ("/", CN_r); - - while (true) + FsFile dir; + ESP_SD.chdir(); // Set to sd root + if(!dir.open ("/", O_READ)) { - File entry = dir.openNextFile (); + logcon("ERROR:GetListOfSdFiles: Could not open root dir"); + break; + } - if (!entry) + while (Entry.openNext (&dir, O_READ)) + { + if(!Entry.isFile() || Entry.isHidden()) { - // DEBUG_V("no more files"); - break; + // not a file we are looking for + continue; } - String EntryName = String (entry.name ()); + memset(entryName, 0x0, sizeof(entryName)); + Entry.getName(entryName, sizeof(entryName)-1); + String EntryName = String (entryName); EntryName = EntryName.substring ((('/' == EntryName[0]) ? 1 : 0)); // DEBUG_V ("EntryName: '" + EntryName + "'"); // DEBUG_V ("EntryName.length(): " + String(EntryName.length ())); if ((!EntryName.isEmpty ()) && (!EntryName.equals(String (F ("System Volume Information")))) && - (0 != entry.size ()) + (0 != Entry.size ()) ) { // DEBUG_V ("Adding File: '" + EntryName + "'"); Response.push_back(EntryName); } - entry.close (); + Entry.close (); } dir.close(); @@ -855,37 +1097,41 @@ void c_FileMgr::GetListOfSdFiles (std::vector & Response) } // GetListOfSdFiles //----------------------------------------------------------------------------- -void c_FileMgr::printDirectory (File dir, int numTabs) +void c_FileMgr::printDirectory (FsFile & dir, int numTabs) { // DEBUG_START; - while (true) + + char entryName[256]; + FsFile Entry; + String tabs = emptyString; + tabs.reserve(2 * (numTabs + 1)); + for (uint8_t i = 0; i < numTabs; i++) + { + tabs = tabs + " "; + } + + while (Entry.openNext(&dir, O_READ)) { FeedWDT(); - File entry = dir.openNextFile(); - String tabs = ""; - if (!entry) - { - // no more files - break; - } + memset(entryName, 0x0, sizeof(entryName)); + Entry.getName(entryName, sizeof(entryName)-1); + // DEBUG_V(String("entryName: '") + String(entryName) + "'"); - for (uint8_t i = 0; i < numTabs; i++) + if (Entry.isDirectory ()) { - tabs = tabs + " "; + logcon (tabs + F ("> ") + entryName); + printDirectory (dir, numTabs + 1); + Entry.close(); + continue; } - if (entry.isDirectory ()) - { - logcon (tabs + F ("> ") + entry.name()); - printDirectory (entry, numTabs + 1); - } - else + if(!Entry.isHidden()) { // files have sizes, directories do not - logcon (tabs + entry.name() + F (" - ") + String(entry.size ())); + logcon (tabs + entryName + F (" - ") + int64String(Entry.size ())); } - entry.close (); + Entry.close(); } // DEBUG_END; @@ -926,37 +1172,31 @@ void c_FileMgr::SaveSdFile (const String & FileName, JsonVariant & FileData) } // SaveSdFile //----------------------------------------------------------------------------- -bool c_FileMgr::OpenSdFile (const String & FileName, FileMode Mode, FileId & FileHandle) +bool c_FileMgr::OpenSdFile (const String & FileName, FileMode Mode, FileId & FileHandle, int FileListIndex) { // DEBUG_START; + // DEBUG_V(String("Mode: ") + String(Mode)); + bool FileIsOpen = false; - FileHandle = 0; - char ReadWrite[2] = { XlateFileMode[Mode], 0 }; - FileHandle = INVALID_FILE_HANDLE; do // once { if (!SdCardInstalled) { // no SD card is installed + FileHandle = INVALID_FILE_HANDLE; break; } // DEBUG_V (); - String FileNamePrefix; - if (!FileName.startsWith ("/")) - { - FileNamePrefix = "/"; - } - // DEBUG_V (String("FileName: '") + FileNamePrefix + FileName + "'"); if (FileMode::FileRead == Mode) { // DEBUG_V (String("Read FIle")); - if (false == ESP_SDFS.exists (FileNamePrefix + FileName)) + if (false == ESP_SD.exists (FileName)) { logcon (String (F ("ERROR: Cannot find '")) + FileName + F ("' for reading. File does not exist.")); break; @@ -964,37 +1204,57 @@ bool c_FileMgr::OpenSdFile (const String & FileName, FileMode Mode, FileId & Fil } // DEBUG_V ("File Exists"); - FileHandle = CreateSdFileHandle (); - // DEBUG_V (String("FileHandle: ") + String(FileHandle)); + // do we have a pre defined index? + if(-1 == FileListIndex) + { + // DEBUG_V("No predefined File Handle"); + FileHandle = CreateSdFileHandle (); + // DEBUG_V (String("FileHandle: ") + String(FileHandle)); - int FileListIndex; - if (-1 != (FileListIndex = FileListFindSdFileHandle (FileHandle))) + FileListIndex = FileListFindSdFileHandle (FileHandle); + // DEBUG_V(String("Using lookup File Index: ") + String(FileListIndex)); + } + else + { + // DEBUG_V(String("Using predefined File Index: ") + String(FileListIndex)); + FileHandle = FileList[FileListIndex].handle; + } + + // did we get an index + if (-1 != FileListIndex) { - FileList[FileListIndex].Filename = FileNamePrefix + FileName; + // DEBUG_V(String("Valid FileListIndex: ") + String(FileListIndex)); + FileList[FileListIndex].Filename = FileName; // DEBUG_V(String("Got file handle: ") + String(FileHandle)); - FileList[FileListIndex].info = ESP_SDFS.open(FileList[FileListIndex].Filename, ReadWrite); + FileList[FileListIndex].IsOpen = FileList[FileListIndex].fsFile.open(FileList[FileListIndex].Filename.c_str(), XlateFileMode[Mode]); + + // DEBUG_V(String("ReadWrite: ") + String(XlateFileMode[Mode])); + // DEBUG_V(String("File Size: ") + String64(FileList[FileListIndex].fsFile.size())); + FileList[FileListIndex].mode = Mode; + FileList[FileListIndex].Paused = false; + // DEBUG_V("Open return"); - if (!FileList[FileListIndex].info) + if (!FileList[FileListIndex].IsOpen) { logcon(String(F("ERROR: Cannot open '")) + FileName + F("'.")); // release the file list entry - FileList[FileListIndex].handle = INVALID_FILE_HANDLE; CloseSdFile(FileHandle); break; } // DEBUG_V(""); - FileList[FileListIndex].size = FileList[FileListIndex].info.size(); + FileList[FileListIndex].size = FileList[FileListIndex].fsFile.size(); // DEBUG_V(String(FileList[FileListIndex].info.name()) + " - " + String(FileList[FileListIndex].size)); if (FileMode::FileWrite == Mode) { // DEBUG_V ("Write Mode"); - FileList[FileListIndex].info.seek (0, SeekSet); + FileList[FileListIndex].fsFile.seek (0); } // DEBUG_V (); FileIsOpen = true; + // DEBUG_V (String ("File.Handle: ") + String (FileList[FileListIndex].handle)); } } while (false); @@ -1019,8 +1279,8 @@ bool c_FileMgr::ReadSdFile (const String & FileName, String & FileData) int FileListIndex; if (-1 != (FileListIndex = FileListFindSdFileHandle (FileHandle))) { - FileList[FileListIndex].info.seek (0, SeekSet); - FileData = FileList[FileListIndex].info.readString (); + FileList[FileListIndex].fsFile.seek (0); + FileData = FileList[FileListIndex].fsFile.readString (); } CloseSdFile (FileHandle); @@ -1055,8 +1315,8 @@ bool c_FileMgr::ReadSdFile (const String & FileName, JsonDocument & FileData) if (-1 != (FileListIndex = FileListFindSdFileHandle (FileHandle))) { - FileList[FileListIndex].info.seek (0, SeekSet); - String RawFileData = FileList[FileListIndex].info.readString (); + FileList[FileListIndex].fsFile.seek (0); + String RawFileData = FileList[FileListIndex].fsFile.readString (); // DEBUG_V ("Convert File to JSON document"); DeserializationError error = deserializeJson (FileData, RawFileData); @@ -1104,7 +1364,7 @@ size_t c_FileMgr::ReadSdFile (const FileId& FileHandle, byte* FileData, size_t N size_t ActualBytesToRead = min(NumBytesToRead, BytesRemaining); // DEBUG_V(String(" BytesRemaining: ") + String(BytesRemaining)); // DEBUG_V(String("ActualBytesToRead: ") + String(ActualBytesToRead)); - if(!FileList[FileListIndex].info.seek(StartingPosition, SeekSet)) + if(!FileList[FileListIndex].fsFile.seek(StartingPosition)) { logcon(F("ERROR: SD Card: Could not set file read start position")); } @@ -1136,7 +1396,7 @@ size_t c_FileMgr::ReadSdFile (const FileId& FileHandle, byte* FileData, size_t N int FileListIndex; if (-1 != (FileListIndex = FileListFindSdFileHandle (FileHandle))) { - response = FileList[FileListIndex].info.readBytes(((char *)FileData), NumBytesToRead); + response = FileList[FileListIndex].fsFile.readBytes(((char *)FileData), NumBytesToRead); // DEBUG_V(String(" response: ") + String(response)); } else @@ -1158,14 +1418,27 @@ void c_FileMgr::CloseSdFile (FileId& FileHandle) int FileListIndex; if (-1 != (FileListIndex = FileListFindSdFileHandle (FileHandle))) { - FileList[FileListIndex].info.close (); + if(!FileList[FileListIndex].Paused) + { + FileList[FileListIndex].fsFile.close (); + } + FileList[FileListIndex].IsOpen = false; FileList[FileListIndex].handle = INVALID_FILE_HANDLE; + FileList[FileListIndex].Paused = false; + + if (nullptr != FileList[FileListIndex].buffer.DataBuffer) + { + free(FileList[FileListIndex].buffer.DataBuffer); + } + FileList[FileListIndex].buffer.DataBuffer = nullptr; + FileList[FileListIndex].buffer.size = 0; + FileList[FileListIndex].buffer.offset = 0; } else { logcon (String (F ("CloseSdFile::ERROR::Invalid File Handle: ")) + String (FileHandle)); } - + FileHandle = INVALID_FILE_HANDLE; // DEBUG_END; @@ -1173,116 +1446,120 @@ void c_FileMgr::CloseSdFile (FileId& FileHandle) } // CloseSdFile //----------------------------------------------------------------------------- -bool c_FileMgr::ReopenSdFile(FileId& FileHandle) -{ - // DEBUG_START; - bool response = false; - int FileListIndex; - if (-1 != (FileListIndex = FileListFindSdFileHandle (FileHandle))) - { - response = ReopenSdFile(FileListIndex); - } - // DEBUG_END; - return response; -} // ReopenSdFile - -//----------------------------------------------------------------------------- -bool c_FileMgr::ReopenSdFile(int FileListIndex) +size_t c_FileMgr::WriteSdFile (const FileId& FileHandle, byte* FileData, size_t NumBytesToWrite) { // DEBUG_START; - bool response = false; - // DEBUG_V ("Trying to reopen SD file"); + size_t NumBytesWritten = 0; do // once { - yield(); - // close the file - FileList[FileListIndex].info.close(); - FileList[FileListIndex].writeCount = 0; - // open the file in append mode - FileList[FileListIndex].info = ESP_SDFS.open(FileList[FileListIndex].Filename, "a"); - // DEBUG_V(String("FileSize: ") + String(FileList[FileListIndex].info.size())); - // DEBUG_V(String("RcvCount: ") + String(FileList[FileListIndex].rcvCount)); - - if(!FileList[FileListIndex].info) + int FileListIndex; + // DEBUG_V (String("Bytes to write: ") + String(NumBytesToWrite)); + if (-1 == (FileListIndex = FileListFindSdFileHandle (FileHandle))) { - logcon("ERROR: Failed to reopen the SD file."); + logcon (String (F ("WriteSdFile::ERROR::Invalid File Handle: ")) + String (FileHandle)); break; } - response = true; + + NumBytesWritten = FileList[FileListIndex].fsFile.write(FileData, NumBytesToWrite); + FileList[FileListIndex].fsFile.flush(); + // DEBUG_V (String (" FileHandle: ") + String (FileHandle)); + // DEBUG_V (String ("File.Handle: ") + String (FileList[FileListIndex].handle)); + + if(NumBytesWritten != NumBytesToWrite) + { + logcon(String(F("ERROR: SD Write failed. Tried writting ")) + String(NumBytesToWrite) + F(" bytes. Actually wrote ") + String(NumBytesWritten) + F(" bytes.")); + NumBytesWritten = 0; + break; + } } while(false); // DEBUG_END; - return response; -} // ReopenSdFile + return NumBytesWritten; + +} // WriteSdFile //----------------------------------------------------------------------------- -size_t c_FileMgr::RecoverSdWrite(int FileListIndex, byte* FileData, size_t TotalNumBytesToWrite, size_t NumBytesAlreadyWritten) +/* + Specialized function that buffers data until the buffer is + full and then writes out the buffer as a single operation. +*/ +size_t c_FileMgr::WriteSdFileBuf (const FileId& FileHandle, byte* FileData, size_t NumBytesToWrite) { // DEBUG_START; - size_t response = NumBytesAlreadyWritten; - size_t NumBytesToWrite = TotalNumBytesToWrite - NumBytesAlreadyWritten; - logcon ("Trying to recover SD write operation after write failure"); + size_t NumBytesWritten = 0; do // once { - // DEBUG_V (String ("rcvCount: ") + String(FileList[FileListIndex].rcvCount)); - - ReopenSdFile(FileListIndex); - - if(!FileList[FileListIndex].info) + int FileListIndex; + // DEBUG_V (String("NumBytesToWrite: ") + String(NumBytesToWrite)); + if (-1 == (FileListIndex = FileListFindSdFileHandle (FileHandle))) { - // DEBUG_V("ERROR: Failed to reopen the SD file."); + logcon (String (F ("WriteSdFileBuf::ERROR::Invalid File Handle: ")) + String (FileHandle)); break; } - - // write the remainder of the data to the file - response += FileList[FileListIndex].info.write(&FileData[NumBytesAlreadyWritten], NumBytesToWrite); - // DEBUG_V(" FileListIndex: " + String(FileListIndex)); - // DEBUG_V(" TotalNumBytesToWrite: " + String(TotalNumBytesToWrite)); - // DEBUG_V("NumBytesAlreadyWritten: " + String(NumBytesAlreadyWritten)); - // DEBUG_V(" NumBytesToWrite: " + String(NumBytesToWrite)); - // DEBUG_V(" response: " + String(response)); - - if(response != TotalNumBytesToWrite) +#ifdef ARDUINO_ARCH_ESP32x + if (nullptr == FileList[FileListIndex].buffer.DataBuffer) { - logcon("ERROR: 2nd write failed"); - break; + FileList[FileListIndex].buffer.DataBuffer = (byte *)malloc(DATABUFFERSIZE); + FileList[FileListIndex].buffer.size = DATABUFFERSIZE; + FileList[FileListIndex].buffer.offset = 0; } - } while(false); +#endif // defined (ARDUINO_ARCH_ESP32) - DEBUG_END; - return response; -} // RecoverSdWrite - -//----------------------------------------------------------------------------- -size_t c_FileMgr::WriteSdFile (const FileId& FileHandle, byte* FileData, size_t NumBytesToWrite) -{ - size_t NumBytesWritten = 0; - int FileListIndex; - // DEBUG_V (String("Bytes to write: ") + String(NumBytesToWrite)); - if (-1 != (FileListIndex = FileListFindSdFileHandle (FileHandle))) - { - if(1*1024*1024 < FileList[FileListIndex].writeCount) + // are we using a buffer in front of the SD card? + if(nullptr == FileList[FileListIndex].buffer.DataBuffer) { - ReopenSdFile(FileListIndex); + // DEBUG_V("Not using buffers"); + NumBytesWritten = FileList[FileListIndex].fsFile.write(FileData, NumBytesToWrite); + FileList[FileListIndex].fsFile.flush(); } - FileList[FileListIndex].rcvCount += NumBytesToWrite; - FileList[FileListIndex].writeCount += NumBytesToWrite; - NumBytesWritten = FileList[FileListIndex].info.write(FileData, NumBytesToWrite); - // FileList[FileListIndex].info.flush(); + else // buffered mode + { + // DEBUG_V("Using buffers"); + // does the buffer have room for this data? + bool WontFit = (FileList[FileListIndex].buffer.offset + NumBytesToWrite) > FileList[FileListIndex].buffer.size; + bool WriteRemainder = (0 == NumBytesToWrite) && (0 != FileList[FileListIndex].buffer.offset); + // DEBUG_V(String(" WontFit: ") + String(WontFit)); + // DEBUG_V(String("WriteRemainder: ") + String(WriteRemainder)); + // DEBUG_V(String(" Offset: ") + String(FileList[FileListIndex].buffer.offset)); + if(WontFit || WriteRemainder) + { + // DEBUG_V("Buffer cant hold this data. Write out the buffer"); + ResumeSdFile(FileHandle); + size_t bufferWriteSize = FileList[FileListIndex].fsFile.write(FileData, FileList[FileListIndex].buffer.offset); + FileList[FileListIndex].fsFile.flush(); + PauseSdFile(FileHandle); + if(FileList[FileListIndex].buffer.offset != bufferWriteSize) + { + logcon (String("WriteSdFileBuf:ERROR:SD Write Failed. Tried to write: ") + + String(FileList[FileListIndex].buffer.offset) + + " bytes. Actually wrote: " + String(bufferWriteSize)) + NumBytesWritten = 0; + break; + } // end write failed + + FileList[FileListIndex].buffer.offset = 0; + } // End buffer cant take the new data + + // DEBUG_V(String("Writing ") + String(NumBytesToWrite) + " bytes to the buffer"); + memcpy(&FileList[FileListIndex].buffer.DataBuffer[FileList[FileListIndex].buffer.offset], + FileData, NumBytesToWrite); + FileList[FileListIndex].buffer.offset += NumBytesToWrite; + NumBytesWritten = NumBytesToWrite; + } + // DEBUG_V (String (" FileHandle: ") + String (FileHandle)); + // DEBUG_V (String ("File.Handle: ") + String (FileList[FileListIndex].handle)); if(NumBytesWritten != NumBytesToWrite) { - logcon (String (F ("WriteSdFile::ERROR:: Could not write data. Tried to write: ")) + String (NumBytesToWrite) + " Wrote: " + String(NumBytesWritten)); - NumBytesWritten = RecoverSdWrite(FileListIndex, FileData, NumBytesToWrite, NumBytesWritten); + logcon(String(F("ERROR: SD Write failed. Tried writting ")) + String(NumBytesToWrite) + F(" bytes. Actually wrote ") + String(NumBytesWritten) + F(" bytes.")); + NumBytesWritten = 0; + break; } - } - else - { - logcon (String (F ("WriteSdFile::ERROR::Invalid File Handle: ")) + String (FileHandle)); - } + } while(false); + // DEBUG_END; return NumBytesWritten; } // WriteSdFile @@ -1294,7 +1571,9 @@ size_t c_FileMgr::WriteSdFile (const FileId& FileHandle, byte* FileData, size_t int FileListIndex; if (-1 != (FileListIndex = FileListFindSdFileHandle (FileHandle))) { - FileList[FileListIndex].info.seek (StartingPosition, SeekSet); + // DEBUG_V (String (" FileHandle: ") + String (FileHandle)); + // DEBUG_V (String ("File.Handle: ") + String (FileList[FileListIndex].handle)); + FileList[FileListIndex].fsFile.seek (StartingPosition); response = WriteSdFile (FileHandle, FileData, NumBytesToWrite); } else @@ -1307,9 +1586,9 @@ size_t c_FileMgr::WriteSdFile (const FileId& FileHandle, byte* FileData, size_t } // WriteSdFile //----------------------------------------------------------------------------- -size_t c_FileMgr::GetSdFileSize (const String& FileName) +uint64_t c_FileMgr::GetSdFileSize (const String& FileName) { - size_t response = 0; + uint64_t response = 0; FileId Handle = INVALID_FILE_HANDLE; if(OpenSdFile (FileName, FileMode::FileRead, Handle)) { @@ -1318,7 +1597,7 @@ size_t c_FileMgr::GetSdFileSize (const String& FileName) } else { - logcon(String("Could not open '") + FileName + "' to check size."); + logcon(String(F("Could not open '")) + FileName + F("' to check size.")); } return response; @@ -1326,13 +1605,13 @@ size_t c_FileMgr::GetSdFileSize (const String& FileName) } // GetSdFileSize //----------------------------------------------------------------------------- -size_t c_FileMgr::GetSdFileSize (const FileId& FileHandle) +uint64_t c_FileMgr::GetSdFileSize (const FileId& FileHandle) { - size_t response = 0; + uint64_t response = 0; int FileListIndex; if (-1 != (FileListIndex = FileListFindSdFileHandle (FileHandle))) { - response = FileList[FileListIndex].info.size (); + response = FileList[FileListIndex].fsFile.size (); } else { @@ -1344,113 +1623,214 @@ size_t c_FileMgr::GetSdFileSize (const FileId& FileHandle) } // GetSdFileSize //----------------------------------------------------------------------------- -void c_FileMgr::BuildFseqList() +void c_FileMgr::ResumeSdFile (const FileId & FileHandle) +{ + // DEBUG_START; + + do // once + { + int FileListIndex; + if (-1 == (FileListIndex = FileListFindSdFileHandle (FileHandle))) + { + logcon (String (F ("ResumeSdFile::ERROR::Invalid File Handle: ")) + String (FileHandle)); + break; + } + // DEBUG_V (String (" FileHandle: ") + String (FileHandle)); + // DEBUG_V (String ("File.Handle: ") + String (FileList[FileListIndex].handle)); + + if(!FileList[FileListIndex].Paused) + { + // DEBUG_V("File is not paused. Ignore Resume request"); + break; + } + + FileList[FileListIndex].mode = FileMode::FileAppend; + OpenSdFile(FileList[FileListIndex].Filename, + FileMode::FileAppend, + FileList[FileListIndex].handle, + FileListIndex); + // DEBUG_V (String (" FileHandle: ") + String (FileHandle)); + // DEBUG_V (String ("File.Handle: ") + String (FileList[FileListIndex].handle)); + + } while(false); + + // DEBUG_END; +} // ResumeSdFile + +//----------------------------------------------------------------------------- +void c_FileMgr::PauseSdFile (const FileId & FileHandle) { // DEBUG_START; - // cant perform operation - FeedWDT (); + do // once + { + int FileListIndex; + if (-1 == (FileListIndex = FileListFindSdFileHandle (FileHandle))) + { + logcon (String (F ("PauseSdFile::ERROR::Invalid File Handle: ")) + String (FileHandle)); + break; + } + + // DEBUG_V (String (" FileHandle: ") + String (FileHandle)); + // DEBUG_V (String ("File.Handle: ") + String (FileList[FileListIndex].handle)); + + if(FileList[FileListIndex].Paused) + { + // DEBUG_V("File is paused. Ignore Pause request"); + break; + } + + FileList[FileListIndex].fsFile.close (); + FileList[FileListIndex].Paused = true; + + } while(false); + + // DEBUG_END; +} // PauseSdFile + +//----------------------------------------------------------------------------- +void c_FileMgr::BuildFseqList() +{ + // DEBUG_START; + char entryName [256]; do // once { if(!SdCardIsInstalled()) { - DEBUG_V("No SD card installed."); + // DEBUG_V("No SD card installed."); break; } - fs::File InputFile = ESP_SDFS.open ("/", "r"); - if(!InputFile) + FsFile InputFile; + ESP_SD.chdir(); // Set to sd root + if(!InputFile.open ("/", O_READ)) { - logcon("ERROR: Could not open SD card."); + logcon(F("ERROR: Could not open SD card.")); break; } // open output file, erase old data - fs::File OutputFile = ESP_SDFS.open ("/fseqfilelist.json", "w"); - if(!OutputFile) + ESP_SD.chdir(); // Set to sd root + FileMgr.DeleteSdFile(String(FSEQFILELIST)); + + FsFile OutputFile; + if(!OutputFile.open (String(F(FSEQFILELIST)).c_str(), O_WRITE | O_CREAT)) { - logcon("ERROR: Could not save SD file list."); + InputFile.close(); + logcon(F("ERROR: Could not Open SD file list.")); break; } OutputFile.print("{"); + // LOG_PORT.print("{"); + // DEBUG_V(); - uint64_t totalBytes = 0; - -#ifdef ARDUINO_ARCH_ESP32 - totalBytes = ESP_SD.cardSize (); -#else - totalBytes = ESP_SD.size64 (); -#endif - String Entry = String("\"totalBytes\" : ") + int64String(totalBytes) + ","; + String Entry = String(F("\"totalBytes\" : ")) + int64String(SdCardSizeMB * 1024 * 1024) + ","; OutputFile.print(Entry); + // LOG_PORT.print(Entry); uint64_t usedBytes = 0; uint32_t numFiles = 0; OutputFile.print("\"files\" : ["); - while (true) + // LOG_PORT.print("\"files\" : ["); + FsFile CurrentEntry; + while (CurrentEntry.openNext (&InputFile, O_READ)) { + // DEBUG_V("Process a file entry"); FeedWDT(); - File entry = InputFile.openNextFile (); - - if (!entry) - { - // DEBUG_V("no more files to add to list"); - break; - } - - if(entry.isDirectory()) + if(CurrentEntry.isDirectory() || CurrentEntry.isHidden()) { - // DEBUG_V("Skip embedded directory"); + // DEBUG_V("Skip embedded directory and hidden files"); + CurrentEntry.close(); continue; } - String EntryName = String (entry.name ()); + memset(entryName, 0x0, sizeof(entryName)); + CurrentEntry.getName (entryName, sizeof(entryName)-1); + String EntryName = String (entryName); // DEBUG_V ( "EntryName: " + EntryName); - EntryName = EntryName.substring ((('/' == EntryName[0]) ? 1 : 0)); // DEBUG_V ("EntryName.length(): " + String(EntryName.length ())); - // DEBUG_V (" entry.size(): " + String(entry.size ())); + // DEBUG_V (" entry.size(): " + int64String(CurrentEntry.size ())); if ((!EntryName.isEmpty ()) && - (!EntryName.equals(String (F ("System Volume Information")))) && - (0 != entry.size () && - !EntryName.equals("fseqfilelist.json")) +// (!EntryName.equals(String (F ("System Volume Information")))) && + (0 != CurrentEntry.size () && + !EntryName.equals(FSEQFILELIST)) ) { - // do we need to add a seperator? + // do we need to add a separator? if(numFiles) { // DEBUG_V("Adding trailing comma"); OutputFile.print(","); + // LOG_PORT.print(","); } - usedBytes += entry.size (); + usedBytes += CurrentEntry.size (); ++numFiles; if(IsBooting) { - logcon ("SD File: '" + EntryName + "'"); + logcon (String(F("SD File: '")) + EntryName + "'"); } + uint16_t Date; + uint16_t Time; + CurrentEntry.getCreateDateTime (&Date, &Time); + // DEBUG_V(String("Date: ") + String(Date)); + // DEBUG_V(String("Year: ") + String(FS_YEAR(Date))); + // DEBUG_V(String("Day: ") + String(FS_DAY(Date))); + // DEBUG_V(String("Month: ") + String(FS_MONTH(Date))); + + // DEBUG_V(String("Time: ") + String(Time)); + // DEBUG_V(String("Hours: ") + String(FS_HOUR(Time))); + // DEBUG_V(String("Minutes: ") + String(FS_MINUTE(Time))); + // DEBUG_V(String("Seconds: ") + String(FS_SECOND(Time))); + + tmElements_t tm; + tm.Year = FS_YEAR(Date) - 1970; + tm.Month = FS_MONTH(Date); + tm.Day = FS_DAY(Date); + tm.Hour = FS_HOUR(Time); + tm.Minute = FS_MINUTE(Time); + tm.Second = FS_SECOND(Time); + + // DEBUG_V(String("tm: ") + String(time_t(makeTime(tm)))); + OutputFile.print(String("{\"name\" : \"") + EntryName + - "\",\"date\" : " + entry.getLastWrite () + - ",\"length\" : " + entry.size () + "}"); + "\",\"date\" : " + String(makeTime(tm)) + + ",\"length\" : " + int64String(CurrentEntry.size ()) + "}"); + /*LOG_PORT.print(String("{\"name\" : \"") + EntryName + + "\",\"date\" : " + String(Date) + + ",\"length\" : " + int64String(CurrentEntry.size ()) + "}"); + */ } - - entry.close (); + else + { + // DEBUG_V("Skipping File"); + } + CurrentEntry.close(); } // end while true // close the array and add the descriptive data - OutputFile.print(String("], \"usedBytes\" : ") + int64String(usedBytes) + ","); - OutputFile.print(String("\"numFiles\" : ") + String(numFiles)); + OutputFile.print(String("], \"usedBytes\" : ") + int64String(usedBytes)); + // LOG_PORT.print(String("], \"usedBytes\" : ") + int64String(usedBytes)); + OutputFile.print(String(", \"numFiles\" : ") + String(numFiles)); + // LOG_PORT.print(String(", \"numFiles\" : ") + String(numFiles)); // close the data section OutputFile.print("}"); + // LOG_PORT.println("}"); OutputFile.close(); + InputFile.close(); } while(false); + // String Temp; + // ReadSdFile(FSEQFILELIST, Temp); + // DEBUG_V(Temp); + // DEBUG_END; } // BuildFseqList @@ -1473,39 +1853,76 @@ bool c_FileMgr::handleFileUpload ( // DEBUG_V (String (" final: ") + String (final)); // DEBUG_V (String (" total: ") + String (totalLen)); - if (0 == index) - { - handleFileUploadNewFile (filename); - expectedIndex = 0; - } - else if (index != expectedIndex) + do // once { - logcon(String("ERROR: Expected index: ") + String(expectedIndex) + " does not match actual index: " + String(index)); - } + if ((0 == index)) + { + // DEBUG_V("New File"); + handleFileUploadNewFile (filename); + expectedIndex = 0; + } - // update the next expected chunk id - expectedIndex = index + len; + if (index != expectedIndex) + { + if(fsUploadFileHandle != INVALID_FILE_HANDLE) + { + logcon (String(F("ERROR: Expected index: ")) + String(expectedIndex) + F(" does not match actual index: ") + String(index)); + + CloseSdFile(fsUploadFileHandle); + DeleteSdFile (fsUploadFileName); + fsUploadFileHandle = INVALID_FILE_HANDLE; + BuildFseqList(); + expectedIndex = 0; + fsUploadFileName = emptyString; + } + break; + } - if (len) - { - // Write data - // DEBUG_V ("UploadWrite: " + String (len) + String (" bytes")); - response = (len == WriteSdFile (fsUploadFile, data, len)); - // DEBUG_V (String ("Writing bytes: ") + String (index)); - // LOG_PORT.print ("."); - } + // DEBUG_V (String ("fsUploadFile: ") + String (fsUploadFile)); + + // update the next expected chunk id + expectedIndex = index + len; + size_t bytesWritten = 0; - if (((true == final) || (false == response)) && (0 != fsUploadFileName.length ())) + if (len) + { + // Write data + // DEBUG_V ("UploadWrite: " + String (len) + String (" bytes")); + bytesWritten = WriteSdFileBuf (fsUploadFileHandle, data, len); + // DEBUG_V (String ("Writing bytes: ") + String (index)); + // LOG_PORT.print ("."); + } + // PauseSdFile(fsUploadFile); + + if(len != bytesWritten) + { + // DEBUG_V("Write failed. Stop transfer"); + CloseSdFile(fsUploadFileHandle); + DeleteSdFile (fsUploadFileName); + fsUploadFileHandle = INVALID_FILE_HANDLE; + BuildFseqList(); + expectedIndex = 0; + fsUploadFileName = emptyString; + break; + } + response = true; + } while(false); + + if ((true == final) && (fsUploadFileHandle != INVALID_FILE_HANDLE)) { + // cause the remainder in the buffer to be written. + WriteSdFileBuf (fsUploadFileHandle, data, 0); uint32_t uploadTime = (uint32_t)(millis() - fsUploadStartTime) / 1000; - CloseSdFile (fsUploadFile); + CloseSdFile (fsUploadFileHandle); + fsUploadFileHandle = INVALID_FILE_HANDLE; logcon (String (F ("Upload File: '")) + fsUploadFileName + - F ("' Done (") + String (uploadTime) + - F ("s). Received: ") + String(expectedIndex) + - F(" Bytes out of ") + String(totalLen) + + F ("' Done (") + String (uploadTime) + + F ("s). Received: ") + String(expectedIndex) + + F(" Bytes out of ") + String(totalLen) + F(" bytes. FileLen: ") + GetSdFileSize(filename)); + expectedIndex = 0; BuildFseqList(); // DEBUG_V(String("Expected: ") + String(totalLen)); @@ -1532,7 +1949,7 @@ void c_FileMgr::handleFileUploadNewFile (const String & filename) if (0 != fsUploadFileName.length ()) { logcon (String (F ("Aborting Previous File Upload For: '")) + fsUploadFileName + String (F ("'"))); - FileMgr.CloseSdFile (fsUploadFile); + CloseSdFile (fsUploadFileHandle); fsUploadFileName = ""; } @@ -1541,14 +1958,28 @@ void c_FileMgr::handleFileUploadNewFile (const String & filename) logcon (String (F ("Upload File: '")) + fsUploadFileName + String (F ("' Started"))); - FileMgr.DeleteSdFile (fsUploadFileName); + DeleteSdFile (fsUploadFileName); // Open the file for writing - FileMgr.OpenSdFile (fsUploadFileName, FileMode::FileWrite, fsUploadFile); + OpenSdFile (fsUploadFileName, FileMode::FileWrite, fsUploadFileHandle, -1 /*first access*/); // DEBUG_END; } // handleFileUploadNewFile +//----------------------------------------------------------------------------- +size_t c_FileMgr::GetDefaultFseqFileList(uint8_t * buffer, size_t maxlen) +{ + // DEBUG_START; + + memset(buffer, 0x0, maxlen); + strcpy_P((char*)&buffer[0], DefaultFseqResponse); + + // DEBUG_V(String("buffer: ") + String((char*)buffer)); + // DEBUG_END; + + return strlen((char*)&buffer[0]); +} // GetDefaultFseqFileList + // create a global instance of the File Manager c_FileMgr FileMgr; diff --git a/ESPixelStick/src/FileMgr.hpp b/ESPixelStick/src/FileMgr.hpp index 90ff5f7c3..6d6e22e46 100644 --- a/ESPixelStick/src/FileMgr.hpp +++ b/ESPixelStick/src/FileMgr.hpp @@ -3,7 +3,7 @@ * FileMgr.hpp - Output Management class * * Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver -* Copyright (c) 2021, 2022 Shelby Merrick +* Copyright (c) 2021, 2024 Shelby Merrick * http://www.forkineye.com * * This program is provided free for you to use in any way that you wish, @@ -22,10 +22,8 @@ #include #ifdef SUPPORT_SD_MMC # include -#else -# include -# include #endif // def SUPPORT_SD_MMC +#include "SdFat.h" #include #include @@ -34,12 +32,13 @@ # define ESP_SD SD_MMC # define ESP_SDFS SD_MMC # else // !def SUPPORT_SD_MMC -# define ESP_SD SD -# define ESP_SDFS SD +extern SdFat sd; +# define ESP_SD sd +# define ESP_SDFS SdFile # endif // !def SUPPORT_SD_MMC #else // !ARDUINO_ARCH_ESP32 -# define ESP_SD SD -# define ESP_SDFS SDFS +# define ESP_SD sd +# define ESP_SDFS SdFile #endif // !ARDUINO_ARCH_ESP32 class c_FileMgr @@ -52,7 +51,7 @@ class c_FileMgr const static FileId INVALID_FILE_HANDLE = 0; void Begin (); - void Poll () {} + void Poll (); void GetConfig (JsonObject& json); bool SetConfig (JsonObject& json); void GetStatus (JsonObject& json); @@ -85,21 +84,27 @@ class c_FileMgr void DeleteSdFile (const String & FileName); void SaveSdFile (const String & FileName, String & FileData); void SaveSdFile (const String & FileName, JsonVariant & FileData); - bool OpenSdFile (const String & FileName, FileMode Mode, FileId & FileHandle); + bool OpenSdFile (const String & FileName, FileMode Mode, FileId & FileHandle, int FileListIndex = -1); size_t ReadSdFile (const FileId & FileHandle, byte * FileData, size_t NumBytesToRead); size_t ReadSdFile (const FileId & FileHandle, byte * FileData, size_t NumBytesToRead, size_t StartingPosition); bool ReadSdFile (const String & FileName, String & FileData); bool ReadSdFile (const String & FileName, JsonDocument & FileData); + size_t WriteSdFileBuf (const FileId & FileHandle, byte * FileData, size_t NumBytesToWrite); 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 (FileId & FileHandle); void GetListOfSdFiles (std::vector & Response); - size_t GetSdFileSize (const String & FileName); - size_t GetSdFileSize (const FileId & FileHandle); + uint64_t GetSdFileSize (const String & FileName); + uint64_t GetSdFileSize (const FileId & FileHandle); void BuildFseqList (); - + void ResumeSdFile (const FileId & FileHandle); + void PauseSdFile (const FileId & FileHandle); + void GetDriverName (String& Name) { Name = "FileMgr"; } + void NetworkStateChanged (bool NewState); + size_t GetDefaultFseqFileList(uint8_t * buffer, size_t maxlen); +#define FSEQFILELIST "fseqfilelist.json" // Configuration file params #if defined ARDUINO_ARCH_ESP8266 # // define CONFIG_MAX_SIZE (3*1024) ///< Sanity limit for config file @@ -110,38 +115,118 @@ class c_FileMgr void SetSpiIoPins (); void ResetSdCard (); -# define SD_CARD_CLK_MHZ SD_SCK_MHZ(50) // 50 MHz SPI clock +# define SD_CARD_CLK_MHZ SD_SCK_MHZ(37) // 50 MHz SPI clock void listDir (fs::FS& fs, String dirname, uint8_t levels); void DescribeSdCardToUser (); void handleFileUploadNewFile (const String & filename); - void printDirectory (File dir, int numTabs); - size_t RecoverSdWrite(int FileListIndex, byte* FileData, size_t NumBytesToWrite, size_t NumBytesWritten); - bool ReopenSdFile(int FileListIndex); - bool ReopenSdFile(FileId& FileHandle); + void printDirectory (FsFile & dir, int numTabs); bool SdCardInstalled = false; uint8_t miso_pin = SD_CARD_MISO_PIN; uint8_t mosi_pin = SD_CARD_MOSI_PIN; uint8_t clk_pin = SD_CARD_CLK_PIN; uint8_t cs_pin = SD_CARD_CS_PIN; - FileId fsUploadFile; + FileId fsUploadFileHandle; String fsUploadFileName; bool fsUploadFileSavedIsEnabled = false; uint32_t fsUploadStartTime; - char XlateFileMode[3] = { 'r', 'w', 'w' }; - + String FtpUserName = "esps"; + String FtpPassword = "esps"; + String WelcomeString = "ESPS V4 FTP"; + bool FtpEnabled = true; + uint64_t SdCardSizeMB = 0; + +public: struct __attribute__((__packed__, aligned(4))) CSD { + public: union { + public: struct __attribute__((__packed__, aligned(1))) { + public: enum { + CSD_VERSION_1 = 0, // enum CSD version 1.0 - 1.1, Version 2.00/Standard Capacity + CSD_VERSION_2 = 1, // enum CSD cersion 2.0, Version 2.00/High Capacity and Extended Capacity + } csd_structure : 2; // @127-126 CSD Structure Version as on SD CSD bits + unsigned spec_vers : 6; // @125-120 CSD version as on SD CSD bits + uint8_t taac; // @119-112 taac as on SD CSD bits + uint8_t nsac; // @111-104 nsac as on SD CSD bits + uint8_t tran_speed; // @103-96 trans_speed as on SD CSD bits + }Decode_0; + public: uint32_t Raw32_0; // @127-96 Union to access 32 bits as a uint32_t + }; + public: union { + public: struct __attribute__((__packed__, aligned(1))) { + unsigned ccc : 12; // @95-84 ccc as on SD CSD bits + unsigned read_bl_len : 4; // @83-80 read_bl_len on SD CSD bits + unsigned read_bl_partial : 1; // @79 read_bl_partial as on SD CSD bits + unsigned write_blk_misalign : 1; // @78 write_blk_misalign as on SD CSD bits + unsigned read_blk_misalign : 1; // @77 read_blk_misalign as on SD CSD bits + unsigned dsr_imp : 1; // @76 dsr_imp as on SD CSD bits + unsigned c_size : 12; // @75-64 Version 1 C_Size as on SD CSD bits + }; + public: uint32_t Raw32_1; // @0-31 Union to access 32 bits as a uint32_t + }; + public: union { + public: struct __attribute__((__packed__, aligned(1))) { + public: union { + public: struct __attribute__((__packed__, aligned(1))) { + unsigned vdd_r_curr_min : 3; // @61-59 vdd_r_curr_min as on SD CSD bits + unsigned vdd_r_curr_max : 3; // @58-56 vdd_r_curr_max as on SD CSD bits + unsigned vdd_w_curr_min : 3; // @55-53 vdd_w_curr_min as on SD CSD bits + unsigned vdd_w_curr_max : 3; // @52-50 vdd_w_curr_max as on SD CSD bits + unsigned c_size_mult : 3; // @49-47 c_size_mult as on SD CSD bits + unsigned reserved0 : 7; // reserved for CSD ver 2.0 size match + }; + unsigned ver2_c_size : 22; // Version 2 C_Size + }; + unsigned erase_blk_en : 1; // @46 erase_blk_en as on SD CSD bits + unsigned sector_size : 7; // @45-39 sector_size as on SD CSD bits + unsigned reserved1 : 2; // 2 Spares bit unused + }; + public: uint32_t Raw32_2; // @0-31 Union to access 32 bits as a uint32_t + }; + public: union { + public: struct __attribute__((__packed__, aligned(1))) { + unsigned wp_grp_size : 7; // @38-32 wp_grp_size as on SD CSD bits + unsigned wp_grp_enable : 1; // @31 wp_grp_enable as on SD CSD bits + unsigned reserved2 : 2; // @30-29 Write as zero read as don't care + unsigned r2w_factor : 3; // @28-26 r2w_factor as on SD CSD bits + unsigned write_bl_len : 4; // @25-22 write_bl_len as on SD CSD bits + unsigned write_bl_partial : 1; // @21 write_bl_partial as on SD CSD bits + unsigned default_ecc : 5; // @20-16 default_ecc as on SD CSD bits + unsigned file_format_grp : 1; // @15 file_format_grp as on SD CSD bits + unsigned copy : 1; // @14 copy as on SD CSD bits + unsigned perm_write_protect : 1; // @13 perm_write_protect as on SD CSD bits + unsigned tmp_write_protect : 1; // @12 tmp_write_protect as on SD CSD bits + public: enum { + // FAT_PARTITION_TABLE = 0, // enum SD card is FAT with partition table + // FAT_NO_PARTITION_TABLE = 1, // enum SD card is FAT with no partition table + // FS_UNIVERSAL = 2, // enum SD card file system is universal + // FS_OTHER = 3, // enum SD card file system is other + } file_format : 2; // @11-10 File format as on SD CSD bits + unsigned ecc : 2; // @9-8 ecc as on SD CSD bits + unsigned reserved3 : 1; // 1 spare bit unused + }; + public: uint32_t Raw32_3; // @0-31 Union to access 32 bits as a uint32_t + }; +}; #define MaxOpenFiles 5 struct FileListEntry_t { - FileId handle; - File info; - size_t size = 0; - size_t writeCount = 0; - size_t rcvCount = 0; - int entryId; - String Filename; + FileId handle = INVALID_FILE_HANDLE; + FsFile fsFile; + uint64_t size = 0; + int entryId = -1; + String Filename = emptyString; + bool Paused = false; + FileMode mode = FileMode::FileRead; + bool IsOpen = false; + struct + { + byte *DataBuffer = nullptr; + size_t size = 0; + size_t offset = 0; + } buffer; }; +#define DATABUFFERSIZE (5 * 1024) + FileListEntry_t FileList[MaxOpenFiles]; int FileListFindSdFileHandle (FileId HandleToFind); void InitSdFileList (); diff --git a/ESPixelStick/src/GPIO_Defs.hpp b/ESPixelStick/src/GPIO_Defs.hpp index 0659324fb..ddd3a6df6 100644 --- a/ESPixelStick/src/GPIO_Defs.hpp +++ b/ESPixelStick/src/GPIO_Defs.hpp @@ -80,6 +80,8 @@ typedef enum # include "platformDefinitions/GPIO_Defs_ESP32_D1_MINI_ETH.hpp" #elif defined (BOARD_ESP32_D1_MINI) # include "platformDefinitions/GPIO_Defs_ESP32_D1_MINI.hpp" +#elif defined (BOARD_ESP32_KA) +# include "platformDefinitions/GPIO_Defs_ESP32_KA.hpp" #elif defined (BOARD_ESP32_LOLIN_D32_PRO_ETH) # include "platformDefinitions/GPIO_Defs_ESP32_LoLin_D32_PRO_ETH.hpp" #elif defined (BOARD_ESP32_LOLIN_D32_PRO) @@ -134,6 +136,8 @@ typedef enum # include "platformDefinitions/GPIO_Defs_ESP32_Tetra2go.hpp" #elif defined (BOARD_ESP32_KR_LIGHTS_MSM) # include "platformDefinitions/GPIO_Defs_ESP32_kr_lights_msm.hpp" +#elif defined (BOARD_ESP32_BREAKDANCEV2) +# include "platformDefinitions/GPIO_Defs_ESP32_BreakDanceV2.hpp" #elif defined (BOARD_ESP8266_D1MINI_LOLIN_SD) # include "platformDefinitions/GPIO_Defs_ESP8266_D1_mini_lolinsd.hpp" #elif defined (ARDUINO_ARCH_ESP32) diff --git a/ESPixelStick/src/WebMgr.cpp b/ESPixelStick/src/WebMgr.cpp index b22176d1b..36f2b509e 100644 --- a/ESPixelStick/src/WebMgr.cpp +++ b/ESPixelStick/src/WebMgr.cpp @@ -17,15 +17,13 @@ * */ -#include "ESPixelStick.h" +#include "WebMgr.hpp" +#include "FileMgr.hpp" -#include "output/OutputMgr.hpp" #include "input/InputMgr.hpp" #include "service/FPPDiscovery.h" #include "network/NetworkMgr.hpp" -#include "WebMgr.hpp" -#include "FileMgr.hpp" #include #include @@ -161,6 +159,7 @@ void c_WebMgr::init () // DEBUG_V(String("URL: ") + request->url()); if(HTTP_OPTIONS == request->method()) { + // DEBUG_V("Options request"); request->send (200); } else @@ -258,7 +257,7 @@ void c_WebMgr::init () } }); - webServer.serveStatic("/fseqfilelist", ESP_SDFS, "/fseqfilelist.json"); + webServer.on("/fseqfilelist", HTTP_GET, [](AsyncWebServerRequest *request){WebMgr.GetFseqFileListHandler(request);}); webServer.on ("/file/delete", HTTP_POST | HTTP_OPTIONS, [](AsyncWebServerRequest* request) { @@ -363,7 +362,7 @@ void c_WebMgr::init () ); // Firmware upload handler - webServer.on ("/updatefw", HTTP_POST, + webServer.on ("/updatefw", HTTP_POST, [](AsyncWebServerRequest* request) { RequestReboot(100000);; @@ -459,7 +458,7 @@ void c_WebMgr::init () request->send (404, CN_textSLASHplain, "Page Not found"); } ); - +/* webServer.on ("/download", HTTP_GET | HTTP_OPTIONS, [](AsyncWebServerRequest* request) { if(HTTP_OPTIONS == request->method()) @@ -479,7 +478,7 @@ void c_WebMgr::init () // DEBUG_V ("Send File Done"); } }); - +*/ webServer.onNotFound ([this](AsyncWebServerRequest* request) { if (request->method() == HTTP_OPTIONS) @@ -613,6 +612,108 @@ void c_WebMgr::CreateAdminInfoFile () // DEBUG_END; } // CreateAdminInfoFile +//----------------------------------------------------------------------------- +void c_WebMgr::GetFseqFileListHandler(AsyncWebServerRequest *request) +{ + // DEBUG_START; + + AsyncWebServerResponse *response = + request->beginChunkedResponse("application/json", + [this](uint8_t *buffer, size_t maxlen, size_t index) -> size_t + { + return GetFseqFileListChunk(buffer, maxlen, index); + }); + request->send(response); + + // DEBUG_END; +} // GetFseqfilelistHandler + +//----------------------------------------------------------------------------- +size_t c_WebMgr::GetFseqFileListChunk(uint8_t *buffer, size_t maxlen, size_t index) +{ + size_t response = 0; + // DEBUG_START; + + do // once + { + if(!FileMgr.SdCardIsInstalled()) + { + if(0 == index) + { + response = FileMgr.GetDefaultFseqFileList(buffer, maxlen); + } + else + { + response = 0; + } + break; + } + // is it a new request + if (index == 0) + { + NumberOfBytesTransfered = 0; // reset the log line index when we get a new request + TotalFileSizeToTransfer = 0; + buffer[0] = '\0'; + + // Try to open the file + if(!FileMgr.OpenSdFile(FSEQFILELIST, c_FileMgr::FileMode::FileRead, FileHandle)) + { + logcon(F("ERROR: Could not open List of Fseq files for reading")); + response = FileMgr.GetDefaultFseqFileList(buffer, maxlen); + FileMgr.BuildFseqList(); + + break; + } + + TotalFileSizeToTransfer = FileMgr.GetSdFileSize(FileHandle); + } + + // DEBUG_V(String(" index: ") + String(index)); + // DEBUG_V(String("TotalFileSizeToTransfer: ") + String(TotalFileSizeToTransfer)); + // DEBUG_V(String("NumberOfBytesTransfered: ") + String(NumberOfBytesTransfered)); + + if (TotalFileSizeToTransfer <= index) + { + FileMgr.CloseSdFile(FileHandle); + FileHandle = c_FileMgr::INVALID_FILE_HANDLE; + + // we close this request by sending a length of 0 + // DEBUG_V(String("file send complete")); + response = 0; + break; + } + + size_t BytesLeftToSend = TotalFileSizeToTransfer - NumberOfBytesTransfered; + size_t DataToSendThisChunk = min(BytesLeftToSend, maxlen); + // DEBUG_V(String(" BytesLeftToSend: ") + String(BytesLeftToSend)); + // DEBUG_V(String(" DataToSendThisChunk: ") + String(DataToSendThisChunk)); + + // is there space in the buffer to hold some data? + if(0 == DataToSendThisChunk) + { + // DEBUG_V("No data to send this chunk"); + response = 0; + break; + } + + memset(buffer, 0x0, maxlen-1); + FileMgr.ReadSdFile(FileHandle, + buffer, + DataToSendThisChunk); + // buffer[DataToSendThisChunk] = 'A'; + NumberOfBytesTransfered += DataToSendThisChunk; + response = DataToSendThisChunk; + // DEBUG_VV(String("buffer: ") + String((char*)buffer)); + + } while(false); + + // DEBUG_V(String(" response: ") + String(response)); + + // DEBUG_END; + return response; + +} // GetFseqFileListChunk + //----------------------------------------------------------------------------- void c_WebMgr::ProcessXJRequest (AsyncWebServerRequest* client) { @@ -670,12 +771,13 @@ void c_WebMgr::ProcessXJRequest (AsyncWebServerRequest* client) } // ProcessXJRequest //----------------------------------------------------------------------------- -void c_WebMgr::ProcessSetTimeRequest (time_t DateTime) +void c_WebMgr::ProcessSetTimeRequest (time_t EpochTime) { // DEBUG_START; - // DEBUG_V(String("DateTime: ") + String(DateTime)); - setTime(DateTime); + // DEBUG_V(String("EpochTime: ") + String(EpochTime)); + setTime(EpochTime); + // FileMgr.BuildFseqList(); // DEBUG_V(String("now: ") + String(now())); // DEBUG_END; diff --git a/ESPixelStick/src/WebMgr.hpp b/ESPixelStick/src/WebMgr.hpp index 15ca63445..94dc017a5 100644 --- a/ESPixelStick/src/WebMgr.hpp +++ b/ESPixelStick/src/WebMgr.hpp @@ -3,7 +3,7 @@ * WebMgr.hpp * * Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver -* Copyright (c) 2021, 2022 Shelby Merrick +* Copyright (c) 2021, 2024 Shelby Merrick * http://www.forkineye.com * * This program is provided free for you to use in any way that you wish, @@ -24,16 +24,6 @@ #include #include "output/OutputMgr.hpp" -#ifdef ARDUINO_ARCH_ESP32 -# if __has_include("SD.h") -# include -# endif // __has_include("SD.h") -#else -# if __has_include("SDFS.h") -# include -# endif // __has_include("SDFS.h") -#endif // def ARDUINO_ARCH_ESP32 - class c_WebMgr { public: @@ -51,6 +41,7 @@ class c_WebMgr void NetworkStateChanged (bool NewNetworkState); void GetDriverName (String & Name) { Name = "WebMgr"; } void CreateAdminInfoFile (); + void GetFseqFileListHandler(AsyncWebServerRequest *request); private: @@ -77,7 +68,7 @@ class c_WebMgr void ProcessXJRequest (AsyncWebServerRequest * client); void ProcessSetTimeRequest (time_t DateTime); - + void GetDeviceOptions (); void GetInputOptions (); void GetOutputOptions (); @@ -108,7 +99,10 @@ class c_WebMgr #endif // def BOARD_HAS_PSRAM WebJsonDocument *WebJsonDoc = nullptr; - + size_t GetFseqFileListChunk(uint8_t *buffer, size_t maxlen, size_t index); + c_FileMgr::FileId FileHandle = c_FileMgr::INVALID_FILE_HANDLE; + size_t TotalFileSizeToTransfer = 0; + size_t NumberOfBytesTransfered = 0; }; // c_WebMgr extern c_WebMgr WebMgr; diff --git a/ESPixelStick/src/memdebug.h b/ESPixelStick/src/memdebug.h index 79754c63a..7947dcba9 100644 --- a/ESPixelStick/src/memdebug.h +++ b/ESPixelStick/src/memdebug.h @@ -9,6 +9,10 @@ #define DEBUG_HW_END do {DEBUG_HW_CLEAR; pinMode(DEBUG_HW_PIN, INPUT);} while(0) */ +#ifndef LOG_PORT +#define LOG_PORT Serial +#endif // ndef LOG_PORT + #define MYFILE String (__FILE__).substring(String (__FILE__).lastIndexOf ("\\") + 1) #define DEBUG_V(v) {LOG_PORT.println(String("------ ") + String(FPSTR(__func__) ) + ":" + MYFILE + ":" + String(__LINE__ ) + ": " + String(v) + String(" ------")); LOG_PORT.flush();} diff --git a/ESPixelStick/src/network/NetworkMgr.cpp b/ESPixelStick/src/network/NetworkMgr.cpp index c3956536f..4a54ddc77 100644 --- a/ESPixelStick/src/network/NetworkMgr.cpp +++ b/ESPixelStick/src/network/NetworkMgr.cpp @@ -57,6 +57,7 @@ void c_NetworkMgr::AdvertiseNewState () PreviousState = IsConnected (); InputMgr.NetworkStateChanged (IsConnected ()); WebMgr.NetworkStateChanged (IsConnected ()); + FileMgr.NetworkStateChanged (IsConnected ()); FPPDiscovery.NetworkStateChanged (IsConnected ()); } diff --git a/ESPixelStick/src/network/WiFiDriver.cpp b/ESPixelStick/src/network/WiFiDriver.cpp index da2ebbbba..b0a915770 100644 --- a/ESPixelStick/src/network/WiFiDriver.cpp +++ b/ESPixelStick/src/network/WiFiDriver.cpp @@ -130,29 +130,26 @@ void c_WiFiDriver::Begin () if (FileMgr.SdCardIsInstalled()) { - if (ESP_SDFS.exists (F("wificonfig.json"))) + DynamicJsonDocument jsonConfigDoc(1024); + // DEBUG_V ("read the sdcard config"); + if (FileMgr.ReadSdFile (F("wificonfig.json"), jsonConfigDoc)) { - DynamicJsonDocument jsonConfigDoc(1024); - // DEBUG_V ("read the sdcard config"); - if (FileMgr.ReadSdFile (F("wificonfig.json"), jsonConfigDoc)) - { - // DEBUG_V ("Process the sdcard config"); - JsonObject jsonConfig = jsonConfigDoc.as (); + // DEBUG_V ("Process the sdcard config"); + JsonObject jsonConfig = jsonConfigDoc.as (); - // copy the fields of interest into the local structure - setFromJSON (ssid, jsonConfig, CN_ssid); - setFromJSON (passphrase, jsonConfig, CN_passphrase); - setFromJSON (ap_ssid, jsonConfig, CN_ap_ssid); - setFromJSON (ap_passphrase, jsonConfig, CN_ap_passphrase); + // copy the fields of interest into the local structure + setFromJSON (ssid, jsonConfig, CN_ssid); + setFromJSON (passphrase, jsonConfig, CN_passphrase); + setFromJSON (ap_ssid, jsonConfig, CN_ap_ssid); + setFromJSON (ap_passphrase, jsonConfig, CN_ap_passphrase); - ConfigSaveNeeded = true; + ConfigSaveNeeded = true; - FileMgr.DeleteSdFile (F ("wificonfig.json")); - } - else - { - // DEBUG_V ("ERROR: Could not read SD card config"); - } + FileMgr.DeleteSdFile (F ("wificonfig.json")); + } + else + { + // DEBUG_V ("ERROR: Could not read SD card config"); } } diff --git a/ESPixelStick/src/output/OutputRelay.cpp b/ESPixelStick/src/output/OutputRelay.cpp index a25e9457f..66ed7e84a 100644 --- a/ESPixelStick/src/output/OutputRelay.cpp +++ b/ESPixelStick/src/output/OutputRelay.cpp @@ -316,7 +316,7 @@ void c_OutputRelay::GetConfig (ArduinoJson::JsonObject & jsonConfig) JsonChannelData[OM_RELAY_CHANNEL_INVERT_NAME] = currentRelay.InvertOutput; JsonChannelData[OM_RELAY_CHANNEL_PWM_NAME] = currentRelay.Pwm; JsonChannelData[CN_trig] = currentRelay.OnOffTriggerLevel; - JsonChannelData[CN_gid] = currentRelay.GpioId; + JsonChannelData[CN_gid] = int(currentRelay.GpioId); #if defined(ARDUINO_ARCH_ESP32) JsonChannelData[CN_Frequency] = currentRelay.PwmFrequency; diff --git a/ESPixelStick/src/output/OutputSpi.hpp b/ESPixelStick/src/output/OutputSpi.hpp index e74b60fdc..dbce629ec 100644 --- a/ESPixelStick/src/output/OutputSpi.hpp +++ b/ESPixelStick/src/output/OutputSpi.hpp @@ -53,7 +53,7 @@ class c_OutputSpi #define SPI_NUM_TRANSACTIONS 2 #define SPI_NUM_INTENSITY_PER_TRANSACTION 128 #define SPI_BITS_PER_INTENSITY 8 -#define SPI_SPI_HOST VSPI_HOST +#define SPI_SPI_HOST DEFAULT_SPI_DEVICE #define SPI_SPI_DMA_CHANNEL 2 uint8_t NumIntensityValuesPerInterrupt = 0; diff --git a/ESPixelStick/src/output/OutputUart.cpp b/ESPixelStick/src/output/OutputUart.cpp index 2e541cc1e..0f988d6be 100644 --- a/ESPixelStick/src/output/OutputUart.cpp +++ b/ESPixelStick/src/output/OutputUart.cpp @@ -1162,7 +1162,7 @@ void c_OutputUart::TerminateSerialPortOperation() case UART_NUM_2: { // DEBUG_V ("UART_NUM_2"); - Serial2.end(true); + Serial2.end(); break; } #endif // def ARDUINO_ARCH_ESP32 diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_BreakDanceV2.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_BreakDanceV2.hpp new file mode 100644 index 000000000..1cb2e8edf --- /dev/null +++ b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_BreakDanceV2.hpp @@ -0,0 +1,59 @@ +#pragma once +/* + * GPIO_Defs_ESP32_BreakDanceV2.hpp - Output Management class + * + * Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver + * Copyright (c) 2021 - 2022 Shelby Merrick + * http://www.forkineye.com + * + * This program is provided free for you to use in any way that you wish, + * subject to the laws and regulations where you are using it. Due diligence + * is strongly suggested before using this code. Please give credit where due. + * + * The Author makes no warranty of any kind, express or implied, with regard + * to this program or the documentation contained in this document. The + * Author shall not be liable in any event for incidental or consequential + * damages in connection with, or arising out of, the furnishing, performance + * or use of these programs. + * + */ + +//Output Manager +#define DEFAULT_RMT_0_GPIO gpio_num_t::GPIO_NUM_2 +#define DEFAULT_RMT_1_GPIO gpio_num_t::GPIO_NUM_13 + +#define DEFAULT_RMT_2_GPIO gpio_num_t::GPIO_NUM_12 + +// SPI Output +#define SUPPORT_SPI_OUTPUT +#define DEFAULT_SPI_DATA_GPIO gpio_num_t::GPIO_NUM_27 +#define DEFAULT_SPI_CLOCK_GPIO gpio_num_t::GPIO_NUM_32 +#define DEFAULT_SPI_DEVICE HSPI_HOST + +#define DEFAULT_I2C_SDA gpio_num_t::GPIO_NUM_3 +#define DEFAULT_I2C_SCL gpio_num_t::GPIO_NUM_5 + +// File Manager +#define SUPPORT_SD +#define SD_CARD_MISO_PIN gpio_num_t::GPIO_NUM_19 +#define SD_CARD_MOSI_PIN gpio_num_t::GPIO_NUM_23 +#define SD_CARD_CLK_PIN gpio_num_t::GPIO_NUM_18 +#define SD_CARD_CS_PIN gpio_num_t::GPIO_NUM_4 + +#define DEFAULT_RELAY_GPIO gpio_num_t::GPIO_NUM_14 + +// Output Types +// 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_GS8208 // UART / RMT +#define SUPPORT_OutputType_Renard // UART / RMT +#define SUPPORT_OutputType_Serial // UART / RMT +#define SUPPORT_OutputType_TM1814 // UART / RMT +#define SUPPORT_OutputType_UCS1903 // UART / RMT +#define SUPPORT_OutputType_UCS8903 // UART / RMT +#define SUPPORT_OutputType_WS2801 // SPI +#define SUPPORT_OutputType_WS2811 // UART / RMT +#define SUPPORT_OutputType_Relay // GPIO +#define SUPPORT_OutputType_Servo_PCA9685 // I2C (default pins) diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_D1_MINI.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_D1_MINI.hpp index bbfc86d24..c8d04903a 100644 --- a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_D1_MINI.hpp +++ b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_D1_MINI.hpp @@ -3,7 +3,7 @@ * GPIO_Defs_ESP32_D1_MINI.hpp - Output Management class * * Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver -* Copyright (c) 2021 Shelby Merrick +* Copyright (c) 2024 Shelby Merrick * http://www.forkineye.com * * This program is provided free for you to use in any way that you wish, @@ -30,6 +30,7 @@ #define SUPPORT_SPI_OUTPUT #define DEFAULT_SPI_DATA_GPIO gpio_num_t::GPIO_NUM_15 #define DEFAULT_SPI_CLOCK_GPIO gpio_num_t::GPIO_NUM_25 +#define DEFAULT_SPI_DEVICE HSPI_HOST #define DEFAULT_I2C_SDA gpio_num_t::GPIO_NUM_21 #define DEFAULT_I2C_SCL gpio_num_t::GPIO_NUM_22 diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_D1_MINI_ETH.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_D1_MINI_ETH.hpp index 5b84fd522..4b4b1464a 100644 --- a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_D1_MINI_ETH.hpp +++ b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_D1_MINI_ETH.hpp @@ -41,6 +41,7 @@ #define SUPPORT_SPI_OUTPUT #define DEFAULT_SPI_DATA_GPIO gpio_num_t::GPIO_NUM_15 #define DEFAULT_SPI_CLOCK_GPIO gpio_num_t::GPIO_NUM_25 +#define DEFAULT_SPI_DEVICE HSPI_HOST #include diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_DevkitC.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_DevkitC.hpp index d90ece982..9b1cab120 100644 --- a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_DevkitC.hpp +++ b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_DevkitC.hpp @@ -3,7 +3,7 @@ * GPIO_Defs_ESP32_DevkitC.hpp - Output Management class * * Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver - * Copyright (c) 2022 Shelby Merrick + * Copyright (c) 2024 Shelby Merrick * http://www.forkineye.com * * This program is provided free for you to use in any way that you wish, @@ -31,6 +31,7 @@ #define SUPPORT_SPI_OUTPUT #define DEFAULT_SPI_DATA_GPIO gpio_num_t::GPIO_NUM_16 #define DEFAULT_SPI_CLOCK_GPIO gpio_num_t::GPIO_NUM_17 +#define DEFAULT_SPI_DEVICE HSPI_HOST #define DEFAULT_I2C_SDA gpio_num_t::GPIO_NUM_3 #define DEFAULT_I2C_SCL gpio_num_t::GPIO_NUM_5 diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_KA.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_KA.hpp new file mode 100644 index 000000000..be24e5759 --- /dev/null +++ b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_KA.hpp @@ -0,0 +1,57 @@ +#pragma once +/* +* GPIO_Defs_ESP32_KA.hpp - Output Management class +* +* Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver +* Copyright (c) 2024 Shelby Merrick +* http://www.forkineye.com +* +* This program is provided free for you to use in any way that you wish, +* subject to the laws and regulations where you are using it. Due diligence +* is strongly suggested before using this code. Please give credit where due. +* +* The Author makes no warranty of any kind, express or implied, with regard +* to this program or the documentation contained in this document. The +* Author shall not be liable in any event for incidental or consequential +* damages in connection with, or arising out of, the furnishing, performance +* or use of these programs. +* +*/ + +//Output Manager +#define DEFAULT_RMT_0_GPIO gpio_num_t::GPIO_NUM_2 +#define DEFAULT_RMT_1_GPIO gpio_num_t::GPIO_NUM_4 +#define DEFAULT_RMT_2_GPIO gpio_num_t::GPIO_NUM_0 +#define DEFAULT_RMT_3_GPIO gpio_num_t::GPIO_NUM_16 + +// SPI Output +#define SUPPORT_SPI_OUTPUT +#define DEFAULT_SPI_DATA_GPIO gpio_num_t::GPIO_NUM_15 +#define DEFAULT_SPI_CLOCK_GPIO gpio_num_t::GPIO_NUM_25 +#define DEFAULT_SPI_DEVICE HSPI_HOST + +#define DEFAULT_I2C_SDA gpio_num_t::GPIO_NUM_21 +#define DEFAULT_I2C_SCL gpio_num_t::GPIO_NUM_22 + +// File Manager +#define SUPPORT_SD +#define SD_CARD_MISO_PIN gpio_num_t::GPIO_NUM_19 +#define SD_CARD_MOSI_PIN gpio_num_t::GPIO_NUM_23 +#define SD_CARD_CLK_PIN gpio_num_t::GPIO_NUM_18 +#define SD_CARD_CS_PIN gpio_num_t::GPIO_NUM_5 + +// Output Types +// Not Finished - #define SUPPORT_OutputType_TLS3001 +#define SUPPORT_OutputType_APA102 // SPI +#define SUPPORT_OutputType_DMX // UART +#define SUPPORT_OutputType_GECE // UART +#define SUPPORT_OutputType_GS8208 // UART / RMT +#define SUPPORT_OutputType_Renard // UART +#define SUPPORT_OutputType_Serial // UART +#define SUPPORT_OutputType_TM1814 // UART / RMT +#define SUPPORT_OutputType_UCS1903 // UART / RMT +#define SUPPORT_OutputType_UCS8903 // UART / RMT +#define SUPPORT_OutputType_WS2801 // SPI +#define SUPPORT_OutputType_WS2811 // UART / RMT +#define SUPPORT_OutputType_Relay // GPIO +#define SUPPORT_OutputType_Servo_PCA9685 // I2C (default pins) diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_LoLin_D32_PRO.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_LoLin_D32_PRO.hpp index 2d066389b..542cf966e 100644 --- a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_LoLin_D32_PRO.hpp +++ b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_LoLin_D32_PRO.hpp @@ -28,6 +28,7 @@ #define SUPPORT_SPI_OUTPUT #define DEFAULT_SPI_DATA_GPIO gpio_num_t::GPIO_NUM_27 #define DEFAULT_SPI_CLOCK_GPIO gpio_num_t::GPIO_NUM_32 +#define DEFAULT_SPI_DEVICE HSPI_HOST #define DEFAULT_I2C_SDA gpio_num_t::GPIO_NUM_3 #define DEFAULT_I2C_SCL gpio_num_t::GPIO_NUM_5 diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_MH_ET_LIVE_MiniKit.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_MH_ET_LIVE_MiniKit.hpp index 905fbbcf8..bbd7eb69c 100644 --- a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_MH_ET_LIVE_MiniKit.hpp +++ b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_MH_ET_LIVE_MiniKit.hpp @@ -33,6 +33,7 @@ #define SUPPORT_SPI_OUTPUT #define DEFAULT_SPI_DATA_GPIO gpio_num_t::GPIO_NUM_16 #define DEFAULT_SPI_CLOCK_GPIO gpio_num_t::GPIO_NUM_17 +#define DEFAULT_SPI_DEVICE HSPI_HOST #define DEFAULT_I2C_SDA gpio_num_t::GPIO_NUM_21 #define DEFAULT_I2C_SCL gpio_num_t::GPIO_NUM_22 diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_Tetra2go.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_Tetra2go.hpp index f6fbef93b..e236a8b0b 100644 --- a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_Tetra2go.hpp +++ b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_Tetra2go.hpp @@ -28,6 +28,7 @@ #define SUPPORT_SPI_OUTPUT #define DEFAULT_SPI_DATA_GPIO gpio_num_t::GPIO_NUM_15 #define DEFAULT_SPI_CLOCK_GPIO gpio_num_t::GPIO_NUM_25 +#define DEFAULT_SPI_DEVICE HSPI_HOST #define DEFAULT_I2C_SDA gpio_num_t::GPIO_NUM_21 #define DEFAULT_I2C_SCL gpio_num_t::GPIO_NUM_22 diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_WT32ETH01_Wasatch.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_WT32ETH01_Wasatch.hpp index fe8323a89..d3ef79c63 100644 --- a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_WT32ETH01_Wasatch.hpp +++ b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_WT32ETH01_Wasatch.hpp @@ -29,7 +29,7 @@ #define DEFAULT_RMT_4_GPIO gpio_num_t::GPIO_NUM_15 #define DEFAULT_RMT_5_GPIO gpio_num_t::GPIO_NUM_17 #define DEFAULT_RMT_6_GPIO gpio_num_t::GPIO_NUM_5 -#define DEFAULT_RMT_7_GPIO gpio_num_t::GPIO_NUM_3 +#define DEFAULT_RMT_7_GPIO gpio_num_t::GPIO_NUM_33 // # define SUPPORT_SPI_OUTPUT // #define DEFAULT_SPI_DATA_GPIO gpio_num_t::GPIO_NUM_15 @@ -54,12 +54,12 @@ * ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720 * ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720 */ -#define DEFAULT_ETH_CLK_MODE eth_clock_mode_t::ETH_CLOCK_GPIO17_OUT +#define DEFAULT_ETH_CLK_MODE eth_clock_mode_t::ETH_CLOCK_GPIO0_IN // Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source) #define DEFAULT_ETH_POWER_PIN gpio_num_t::GPIO_NUM_16 #define ETH_POWER_PIN DEFAULT_ETH_POWER_PIN -#define DEFAULT_ETH_POWER_PIN_ACTIVE HIGH +#define DEFAULT_ETH_POWER_PIN_ACTIVE LOW // Type of the Ethernet PHY (LAN8720 or TLK110) #define DEFAULT_ETH_TYPE eth_phy_type_t::ETH_PHY_LAN8720 diff --git a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_WT32ETH0_Wasatch.hpp b/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_WT32ETH0_Wasatch.hpp deleted file mode 100644 index c3b25ceae..000000000 --- a/ESPixelStick/src/platformDefinitions/GPIO_Defs_ESP32_WT32ETH0_Wasatch.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once -/* -* GPIO_Defs_ESP32_WT32ETH01_Wasatch.hpp - Output Management class -* -* Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver -* Copyright (c) 2021 Shelby Merrick -* http://www.forkineye.com -* -* This program is provided free for you to use in any way that you wish, -* subject to the laws and regulations where you are using it. Due diligence -* is strongly suggested before using this code. Please give credit where due. -* -* The Author makes no warranty of any kind, express or implied, with regard -* to this program or the documentation contained in this document. The -* Author shall not be liable in any event for incidental or consequential -* damages in connection with, or arising out of, the furnishing, performance -* or use of these programs. -* -*/ - -#define SUPPORT_ETHERNET - -//Output Manager -#define DEFAULT_RMT_0_GPIO gpio_num_t::GPIO_NUM_2 -#define DEFAULT_RMT_1_GPIO gpio_num_t::GPIO_NUM_4 - -#define DEFAULT_RMT_2_GPIO gpio_num_t::GPIO_NUM_12 -#define DEFAULT_RMT_3_GPIO gpio_num_t::GPIO_NUM_14 -#define DEFAULT_RMT_4_GPIO gpio_num_t::GPIO_NUM_15 -#define DEFAULT_RMT_5_GPIO gpio_num_t::GPIO_NUM_17 -#define DEFAULT_RMT_6_GPIO gpio_num_t::GPIO_NUM_5 -#define DEFAULT_RMT_7_GPIO gpio_num_t::GPIO_NUM_2 - -// # define SUPPORT_SPI_OUTPUT -// #define DEFAULT_SPI_DATA_GPIO gpio_num_t::GPIO_NUM_15 -// #define DEFAULT_SPI_CLOCK_GPIO gpio_num_t::GPIO_NUM_25 - -#define DEFAULT_I2C_SDA gpio_num_t::GPIO_NUM_21 -#define DEFAULT_I2C_SCL gpio_num_t::GPIO_NUM_22 - -// File Manager -// #define SUPPORT_SD -#define SD_CARD_MISO_PIN gpio_num_t::GPIO_NUM_12 -#define SD_CARD_MOSI_PIN gpio_num_t::GPIO_NUM_13 -#define SD_CARD_CLK_PIN gpio_num_t::GPIO_NUM_14 -#define SD_CARD_CS_PIN gpio_num_t::GPIO_NUM_15 - -#include - - -/* - * ETH_CLOCK_GPIO0_IN - default: external clock from crystal oscillator - * ETH_CLOCK_GPIO0_OUT - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720 - * ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720 - * ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720 -*/ -#define DEFAULT_ETH_CLK_MODE eth_clock_mode_t::ETH_CLOCK_GPIO17_OUT - -// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source) -#define DEFAULT_ETH_POWER_PIN gpio_num_t::GPIO_NUM_16 -#define ETH_POWER_PIN DEFAULT_ETH_POWER_PIN -#define DEFAULT_ETH_POWER_PIN_ACTIVE HIGH - -// Type of the Ethernet PHY (LAN8720 or TLK110) -#define DEFAULT_ETH_TYPE eth_phy_type_t::ETH_PHY_LAN8720 - -// I2C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110) -#define ETH_ADDR_PHY_LAN8720 1 - -#define DEFAULT_ETH_ADDR ETH_ADDR_PHY_LAN8720 -#define DEFAULT_ETH_TXEN gpio_num_t::GPIO_NUM_21 -#define DEFAULT_ETH_TXD0 gpio_num_t::GPIO_NUM_19 -#define DEFAULT_ETH_TXD1 gpio_num_t::GPIO_NUM_22 -#define DEFAULT_ETH_CRSDV gpio_num_t::GPIO_NUM_27 -#define DEFAULT_ETH_RXD0 gpio_num_t::GPIO_NUM_25 -#define DEFAULT_ETH_RXD1 gpio_num_t::GPIO_NUM_26 -#define DEFAULT_ETH_MDC_PIN gpio_num_t::GPIO_NUM_23 -#define DEFAULT_ETH_MDIO_PIN gpio_num_t::GPIO_NUM_18 - -// Output Types -// Not Finished - #define SUPPORT_OutputType_TLS3001 -// #define SUPPORT_OutputType_APA102 // SPI -#define SUPPORT_OutputType_DMX // UART -#define SUPPORT_OutputType_GECE // UART -#define SUPPORT_OutputType_GS8208 // UART / RMT -#define SUPPORT_OutputType_Renard // UART -#define SUPPORT_OutputType_Serial // UART -#define SUPPORT_OutputType_TM1814 // UART / RMT -#define SUPPORT_OutputType_UCS1903 // UART / RMT -#define SUPPORT_OutputType_UCS8903 // UART / RMT -// #define SUPPORT_OutputType_WS2801 // SPI -#define SUPPORT_OutputType_WS2811 // UART / RMT -// #define SUPPORT_OutputType_Relay // GPIO -// #define SUPPORT_OutputType_Servo_PCA9685 // I2C (default pins) diff --git a/ESPixelStick/src/service/FPPDiscovery.cpp b/ESPixelStick/src/service/FPPDiscovery.cpp index bafae3819..e0ec8fe59 100644 --- a/ESPixelStick/src/service/FPPDiscovery.cpp +++ b/ESPixelStick/src/service/FPPDiscovery.cpp @@ -88,7 +88,7 @@ void c_FPPDiscovery::NetworkStateChanged (bool NewNetworkState) { Failed = false; logcon (String (F ("FPPDiscovery subscribed to broadcast messages on port: ")) + String(FPP_DISCOVERY_PORT)); - } + } if (!udp.listenMulticast (MulticastAddress, FPP_DISCOVERY_PORT)) { @@ -222,7 +222,7 @@ void c_FPPDiscovery::ProcessReceivedUdpPacket (AsyncUDPPacket UDPpacket) gettimeofday (&tv, NULL); MultiSyncStats.lastReceiveTime = tv.tv_sec; MultiSyncStats.pktLastCommand = fppPacket->packet_type; - + switch (fppPacket->packet_type) { case CTRL_PKT_CMD: // deprecated in favor of FPP Commands @@ -818,10 +818,16 @@ void c_FPPDiscovery::ProcessFile ( } // DEBUG_V(); - bool writeFinished = FileMgr.handleFileUpload (UploadFileName, index, data, len, final, ContentLength); + bool writeFailed = !FileMgr.handleFileUpload (UploadFileName, index, data, len, final, ContentLength); + + if(writeFailed) + { + // DEBUG_V("WriteFailed"); + request->send (500); + } // DEBUG_V(); - if (final || !writeFinished) + if (final || writeFailed) { inFileUpload = false; UploadFileName = ""; diff --git a/README.md b/README.md index d070b49ff..fc9db089f 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,11 @@ The recommended installation method is to download the latest [stable release](h If you are interested in bleeding edge / un-tested builds, automated CI builds are generated for every code push and are available as Artifact attachments to the [ESPixelStick CI](https://github.com/forkineye/ESPixelStick/actions/workflows/build.yaml) workflow runs. Just click on the latest successful run and look for **Release Archive** towards the bottom. Note to download Artifact attachments though, you will have to be logged into GitHub. +If you are interested in using the experimental web based flash tool, connect to: +HTTPS://espixelstickwebflasher.from-ct.com:5000 +This tool will always have a few of the most recent CI builds available for flashing to your device. + + If you would like to compile the project yourself and modify the source code, go down to [Build Requirements](#build-requirements). ## Hardware @@ -89,6 +94,9 @@ The current device configuration can be saved to a local drive using the Backup The current configuration can be over written from a file located on the local drive (in any directory you chose) by pressing the Restore button on the admin page. A popup will help you select the file to upload. NOTE: A restore is an OVER WRITE, not a merge. Any changes made since the backup file was created will be lost. +## SD File Management +The file management page is available on the UI when an SD card is detected by the ESP. You can add / remove files using the file management screen. It is known that the HTTP based file transfer used by the File Management screen can be very slow for large files. Alternativly, you can use your favorite FTP client (tested with FileZilla) to transfer files to the ESP. NOTE: You must configure the FTP client to run in single connection (port) mode. The ESP does not have enough resources to support concurrent command and data connections. + ## Resources - Firmware: [http://github.com/forkineye/ESPixelStick](http://github.com/forkineye/ESPixelStick) diff --git a/dist/README.md b/dist/README.md index 93ea6121d..9bfeb2a4a 100644 --- a/dist/README.md +++ b/dist/README.md @@ -6,4 +6,8 @@ How to use ---------- **ESPSFlashTool.jar** - This is a java based flash tool for flashing new modules or modules that can't be updated via the web interface. It will flash the ESP module with the ESPixelStick firmware to a default state and overwrite any previous settings. To launch the tool, you will need [Java 8](https://www.java.com) or greater. On Linux and macOS platforms, you will need launch the tool from a terminal within the extracted directory (```java -jar ESPSFlashTool.jar```). Additionally for macOS, you will have to jump through Apple's typical security hoops to allow non-Apple signed software to run. Once launched, simply fill in the boxes, select your harwdare and serial port, and click "Upload". -**espixelstick\*.efu** - These are web based firmware updates. Simply upload these via the web interface to flash your ESPixelStick. Your configuration will be saved and applied to the new firmware. Not that web upgrades between major releases, betas, and release candidates are not supported. \ No newline at end of file +**espixelstick\*.efu** - These are web based firmware updates. Simply upload these via the web interface to flash your ESPixelStick. Your configuration will be saved and applied to the new firmware. Not that web upgrades between major releases, betas, and release candidates are not supported. + +If you are interested in using the experimental web based flash tool, connect to: +HTTPS://espixelstickwebflasher.from-ct.com:5000 +This tool will always have a few of the most recent CI builds available for flashing to your device. This tool has only been tested with the Chrome browser. You do not need to install anything on your PC. Just connect the ESP using a USB cable and follow the instructions. \ No newline at end of file diff --git a/dist/firmware/firmware.json b/dist/firmware/firmware.json index ff99921fa..9ff023c6d 100644 --- a/dist/firmware/firmware.json +++ b/dist/firmware/firmware.json @@ -1101,7 +1101,7 @@ "name": "ESP32 KR Lights MSM", "description": "ESP32 based 5 port controller", "chip": "esp32", - "appbin": "esp32/esp32_kr_lights_msm32_tetra2go-app.bin", + "appbin": "esp32/esp32_kr_lights_msm-app.bin", "esptool": { "baudrate": "460800", "options": "", @@ -1113,7 +1113,7 @@ "offset": "0x01000" }, { - "name": "esp32/esp3esp32_kr_lights_msm2_tetra2go-partitions.bin", + "name": "esp32/esp32_kr_lights_msm-partitions.bin", "offset": "0x08000" }, { @@ -1131,6 +1131,76 @@ "size": "0x50000", "offset": "0x3B0000" } + }, + { + "name": "ESP32 KA", + "description": "ESP32 based 4 port + Relay controller", + "chip": "esp32", + "appbin": "esp32/esp32_ka-app.bin", + "esptool": { + "baudrate": "460800", + "options": "", + "flashcmd": "write_flash -z" + }, + "binfiles": [ + { + "name": "esp32/esp32_ka-bootloader.bin", + "offset": "0x01000" + }, + { + "name": "esp32/esp32_ka-partitions.bin", + "offset": "0x08000" + }, + { + "name": "esp32/boot_app0.bin", + "offset": "0x0e000" + }, + { + "name": "esp32/esp32_ka-app.bin", + "offset": "0x10000" + } + ], + "filesystem": { + "page": "256", + "block": "4096", + "size": "0x50000", + "offset": "0x3B0000" + } + }, + { + "name": "ESP32S Break Dance V2", + "description": "ESP32S based 4 port controller", + "chip": "esp32", + "appbin": "esp32/esp32_breakdancev2-app.bin", + "esptool": { + "baudrate": "460800", + "options": "", + "flashcmd": "write_flash -z" + }, + "binfiles": [ + { + "name": "esp32/esp32_breakdancev2-bootloader.bin", + "offset": "0x01000" + }, + { + "name": "esp32/esp32_breakdancev2-partitions.bin", + "offset": "0x08000" + }, + { + "name": "esp32/boot_app0.bin", + "offset": "0x0e000" + }, + { + "name": "esp32/esp32_breakdancev2-app.bin", + "offset": "0x10000" + } + ], + "filesystem": { + "page": "256", + "block": "4096", + "size": "0x50000", + "offset": "0x3B0000" + } } ] } diff --git a/html/index.html b/html/index.html index 16c2afb99..9811beb81 100644 --- a/html/index.html +++ b/html/index.html @@ -671,7 +671,27 @@
-
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+
+
+ .then(async webResponse => { const data = await webResponse.blob(); // console.info("RequestDiagData:webResponse.status: " + webResponse.status); @@ -604,7 +603,7 @@ function RequestDiagData() drawStream(streamData); } }) - .catch(async error => + .catch(async error => { console.error('SendCommand: Error: ', error); }); @@ -1307,6 +1306,9 @@ function ProcessReceivedJsonConfigMessage(JsonConfigData) { // console.info("Got System Config: " + JSON.stringify(System_Config) ); updateFromJSON(System_Config); + $('#ftpusername').val(System_Config.device.user); + $('#ftppassword').val(System_Config.device.password); + $('#ftp_enable').prop("checked", System_Config.device.enabled); if ({}.hasOwnProperty.call(System_Config.network, 'eth')) { $('#pg_network #network #eth').removeClass("hidden") @@ -1537,7 +1539,10 @@ function submitNetworkConfig() { System_Config.device.mosi_pin = $('#config #device #mosi_pin').val(); System_Config.device.clock_pin = $('#config #device #clock_pin').val(); System_Config.device.cs_pin = $('#config #device #cs_pin').val(); - + System_Config.device.user = $('#ftpusername').val(); + System_Config.device.password = $('#ftppassword').val(); + System_Config.device.enabled = $('#ftp_enable').prop('checked'); + if ({}.hasOwnProperty.call(System_Config, 'sensor')) { System_Config.sensor.units = parseInt($('#TemperatureSensorUnits').val()); } @@ -1767,15 +1772,6 @@ function submitDeviceConfig() { } // submitDeviceConfig -function convertUTCDateToLocalDate(date) { - date = new Date(date); - let localOffset = date.getTimezoneOffset() * 60000; - let localTime = date.getTime(); - date = localTime - localOffset; - - return date; -} // convertUTCDateToLocalDate - function int2ip(num) { let d = num % 256; for (let i = 3; i > 0; i--) { diff --git a/platformio.ini b/platformio.ini index 95d92c0bb..8ef5f5398 100644 --- a/platformio.ini +++ b/platformio.ini @@ -4,7 +4,7 @@ ; Local configuration should be done in platformio_user.ini [platformio] -default_envs = espsv3, d1_mini, d1_mini_pro, d32_pro, d32_pro_eth, esp32_cam, esp32_ttgo_t8, d1_mini32, d1_mini32_eth, esp32_bong69, esp32_wt32eth01, esp32_quinled_quad, esp32_quinled_quad_ae_plus, esp32_quinled_quad_ae_plus_8, esp32_quinled_quad_eth, esp32_quinled_uno, esp32_quinled_uno_ae_plus, esp32_quinled_uno_eth, esp32_quinled_dig_octa, esp01s, d1_mini_mhetesp32minikit, olimex_esp32_gw, d1_mini_twilightlord, d1_mini_twilightlord_eth, esp32_devkitc, esp32_quinled_uno_eth_espsv3, esp32_quinled_uno_espsv3, m5stack_atom, esp3deuxquatro_dmx, esp32_wasatch, esp32_tetra2go, esp32_kr_lights_msm, d1_mini_lolinsd +default_envs = espsv3, d1_mini, d1_mini_pro, d32_pro, d32_pro_eth, esp32_cam, esp32_ttgo_t8, d1_mini32, d1_mini32_eth, esp32_bong69, esp32_wt32eth01, esp32_quinled_quad, esp32_quinled_quad_ae_plus, esp32_quinled_quad_ae_plus_8, esp32_quinled_quad_eth, esp32_quinled_uno, esp32_quinled_uno_ae_plus, esp32_quinled_uno_eth, esp32_quinled_dig_octa, esp01s, d1_mini_mhetesp32minikit, olimex_esp32_gw, d1_mini_twilightlord, d1_mini_twilightlord_eth, esp32_devkitc, esp32_quinled_uno_eth_espsv3, esp32_quinled_uno_espsv3, m5stack_atom, esp3deuxquatro_dmx, esp32_wasatch, esp32_tetra2go, esp32_kr_lights_msm, d1_mini_lolinsd, esp32_ka, esp32_breakdancev2 src_dir = ./ESPixelStick data_dir = ./ESPixelStick/data build_cache_dir = ./.pio/.buildcache @@ -24,22 +24,25 @@ lib_compat_mode = strict lib_deps = adafruit/Adafruit PWM Servo Driver Library @ 2.4.0 bblanchon/ArduinoJson @ 6.18.5 - djgrrr/Int64String @ 1.1.1 https://github.com/esphome/ESPAsyncWebServer#4fd0a1fdf421664214a27373c0eb0247f94b7a79 - forkineye/ESPAsyncE131 @ 1.0.4 + https://github.com/MartinMueller2003/ESPAsyncE131 ottowinter/AsyncMqttClient-esphome @ 0.8.6 https://github.com/natcl/Artnet ; pull latest https://github.com/MartinMueller2003/Espalexa ; pull latest https://github.com/PaulStoffregen/Time - + https://github.com/greiman/SdFat + https://github.com/MartinMueller2003/SimpleFTPServer extra_scripts = .scripts/download_fs.py .scripts/CopyTargets.py pre:.scripts/pio-version.py -; build_type = debug -; upload_port = com6 - +build_flags = + -D SUPPORT_FTP +; -D FTP_SERVER_DEBUG +; -D FTP_ADDITIONAL_DEBUG + -D DISABLE_FS_H_WARNING=1 + -I ./ESPixelStick/src lib_ignore = ESP Async WebServer ; force the use of the esphome version AsyncTCP ; force the use of the esphome version @@ -50,34 +53,34 @@ lib_ignore = ; https://docs.platformio.org/en/latest/platforms/espressif8266.html ; ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; [esp8266] -; platform = espressif8266 @ 4.2.1 ; Arduino Core v3.0.2 -platform = espressif8266 @ 4.0.1 ; Arduino Core v3.0.2 +platform = espressif8266 @ 4.2.1 ; Arduino Core v3.0.2 board_build.f_cpu = 160000000L board_build.filesystem = littlefs board_build.ldscript = eagle.flash.4m2m.ld monitor_filters = esp8266_exception_decoder build_flags = ${env.build_flags} -; -D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190313 -; -D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 -; -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH -D NDEBUG ; https://github.com/esp8266/Arduino/issues/3978 -D FP_IN_IROM ; https://github.com/esp8266/Arduino/pull/7180 -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ; -D VTABLES_IN_IRAM -D VTABLES_IN_FLASH + -D DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP8266=2 + -D DEFAULT_STORAGE_TYPE_ESP8266=2 -Wl,-Map=firmware.map -Wl,--cref -; -DDEBUG_ESP_PORT=Serial -; -DDEBUG_ESP_OOM - +; -D DEBUG_ESP_PORT=Serial +; -D DEBUG_ESP_OOM lib_ignore = Ethernet ; Remove once Art-Net is fixed / replaced to not depend on Ethernet in lib config lib_deps = ${env.lib_deps} me-no-dev/ESPAsyncUDP @ 0.0.0-alpha+sha.697c75a025 ottowinter/ESPAsyncTCP-esphome @ 1.2.3 +extra_scripts = + ${env.extra_scripts} + pre:.scripts/deleteSD.py ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; ; ESP32 defaults for 4MB flash ; @@ -90,6 +93,8 @@ monitor_filters = esp32_exception_decoder ; monitor_filters = esp32_exception_decoder, time build_flags = ${env.build_flags} + -D DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP32=6 + -D DEFAULT_STORAGE_TYPE_ESP32=2 -Wl,-Map=firmware.map -Wl,--cref lib_deps = @@ -106,16 +111,9 @@ extra_scripts = ${env.extra_scripts} [esp32git] extends = esp32 build_flags = ${esp32.build_flags} -mtext-section-literals -; platform = https://github.com/platformio/platform-espressif32.git#48c4226e5240c873dae6b28adbb93ad8ca582b5d -; platform = https://github.com/platformio/platform-espressif32.git#eb7eba4 ; unstable 6.3.2 -; platform = https://github.com/platformio/platform-espressif32.git#8100ac5 ; works 6.3.1 -platform = https://github.com/platformio/platform-espressif32.git#b0a7f56bcde9fa332b40111b1423482d8f7cbc77 ; 6.5.0 -; platform_packages = -; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.11 ; uses a lot of ram -; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.3 ; -; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.2 ; runs real slow -; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.1 ; Has general issues -; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.0 ; SD card not stable on cam card +platform = espressif32 @ 6.6.0 +platform_packages = + framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.16 ; uses a lot of ram board_build.arduino.upstream_packages = no ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; @@ -436,7 +434,6 @@ build_flags = -D BOARD_NAME='"esp3deuxquatro_dmx"' -D BOARD_ESPS_ESP3DEUXQUATRO_DMX -;Quatro from CanadaPixelsCoro.ca [env:esp32_wasatch] extends = esp32git board = esp32dev @@ -467,3 +464,25 @@ build_unflags = -D BOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=memw + +; KA Relay board +[env:esp32_ka] +extends = esp32git +board = wemos_d1_mini32 +build_flags = + ${esp32git.build_flags} + -D BOARD_NAME='"esp32_ka"' + -D BOARD_ESP32_KA +build_unflags = + -U BOARD_HAS_PSRAM + +; Breakdance board +[env:esp32_breakdancev2] +extends = esp32git +board = nodemcu-32s +build_flags = + ${esp32git.build_flags} + -D BOARD_NAME='"esp32_breakdancev2"' + -D BOARD_ESP32_BREAKDANCEV2 +build_unflags = + -U BOARD_HAS_PSRAM