diff --git a/.vscode/settings.json b/.vscode/settings.json index 8b3f61d..fe561ae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,46 @@ "unordered_map": "cpp", "vector": "cpp", "string_view": "cpp", - "initializer_list": "cpp" + "initializer_list": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "ranges": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp" } } \ No newline at end of file diff --git a/README.md b/README.md index 7cc1bde..194d18d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The Arduino_UnifiedStorage library provides a unified interface to access differ ## Examples -* [**examples/SimpleStorageWriteRead**](https://github.com/arduino-libraries/Arduino_UnifiedStorage/blob/main/examples/SimpleStorageWriteRead/SimpleStorageWriteRead.ino) - Write/read simple data from SD, USB and internal storage +* [**examples/SimpleStorageWriteRead**](https://github.com/arduino-libraries/Arduino_UnifiedStorage/blob/main/examples/SimpleStorageWriteRead/SimpleStorageWriteRead.ino) - Write/read simple data from &sd, USB and internal storage * [**examples/AdvancedUSBInternalOperations**](https://github.com/arduino-libraries/Arduino_UnifiedStorage/blob/main/examples/AdvancedUSBInternalOperations/AdvancedUSBInternalOperations.ino) - Navigate file structure and demonstrate file operations between USB and internal storage * [**examples/BackupInternalPartitions**](https://github.com/arduino-libraries/Arduino_UnifiedStorage/blob/main/examples/BackupInternalPartitions/BackupInternalPartitions.ino) - Back up all partitions on the internal storage to a USB Mass Storage device. @@ -40,9 +40,9 @@ The Arduino_UnifiedStorage library provides a unified interface to access differ ## Compatibility This library has been tested with the following STM32 and Renesas based Arduino boards. The availability of storage mediums depends on the hardware interfaces: * Portenta Machine Control: USB and Internal QSPI Flash -* Portenta H7 + Portenta Breakout: USB, SD, and QSPI +* Portenta H7 + Portenta Breakout: USB, &sd, and QSPI * Portenta H7 + Vision Shield: SD and QSPI -* Portenta C33 + Portenta Breakout: USB, SD, and QSPI +* Portenta C33 + Portenta Breakout: USB, &sd, and QSPI * Portenta C33 + Vision Shield: SD and QSPI * Opta: Internal QSPI Flash and USB diff --git a/examples/AdvancedInternalStorage/AdvancedInternalStorage.ino b/examples/AdvancedInternalStorage/AdvancedInternalStorage.ino new file mode 100644 index 0000000..c96dc33 --- /dev/null +++ b/examples/AdvancedInternalStorage/AdvancedInternalStorage.ino @@ -0,0 +1,57 @@ +#include +#include + + + +void testWriting(Arduino_UnifiedStorage * storage){ + Folder root = storage->getRootFolder(); + UFile file = root.createFile("file.txt", FileMode::WRITE); + file.write("writing stuff to the file"); + file.changeMode(FileMode::READ); + Serial.println("Reading from file: " + file.readAsString()); + file.close(); + file.remove(); +} + +const char* createPartitionName(int i) { + char buffer[20]; // Adjust the size accordingly + snprintf(buffer, sizeof(buffer), "Part%d", i); + return buffer; +} + +void testAllPartitions(std::vector partitions){ + for (size_t i = 1; i < partitions.size() + 1; ++i) { + const char * partitionName = createPartitionName(i); + + InternalStorage thisPartition = InternalStorage(i, partitionName, partitions[i - 1].fs); + if(thisPartition.begin()){ + Serial.println("Succesfully initialised partition: " + String(partitionName)); + testWriting(&thisPartition); + } + } +} + +void setup(){ + + + + Serial.begin(115200); + while(!Serial); + + std::vector onePartition = {{16384, FS_LITTLEFS}}; + InternalStorage::partition(onePartition); + testAllPartitions(onePartition); + delay(5000); + + + std::vector fourPartitions = {{4096, FS_LITTLEFS}, {4096, FS_LITTLEFS}, {4096, FS_LITTLEFS}, {4096, FS_LITTLEFS}}; + InternalStorage::partition(fourPartitions); + testAllPartitions(fourPartitions); + delay(5000); + +} + +void loop(){ + + +} \ No newline at end of file diff --git a/examples/OptaLogger/OptaLogger.ino b/examples/OptaLogger/OptaLogger.ino new file mode 100644 index 0000000..2f56c61 --- /dev/null +++ b/examples/OptaLogger/OptaLogger.ino @@ -0,0 +1,184 @@ +/* +This example demonstrates the usage of the "Arduino_UnifiedStorage" library for logging and backing up data to USB storage in case a USB Mass Storage device is inserted. + +The code defines two main functions: "logData" and "performUpdate". +The "logData" function logs sensor data by reading an analog sensor and writing the data to the log file. + +The "performUpdate" function performs the update process by: +* reading the last update size from a file (number of bytes) +* copying the new data from the log file to a backup file +* and updating the last update size. + +INSTRUCTIONS +* Make sure the QSPI storage of your board is properly partitioned. + * You can do that by flashing the QSPIFormat example that can be found in the STM32H747_System folder + * Open the serial monitor and select answer with "Y" when this appears "Do you want to use partition scheme 1? Y/[n]" + * Reboot the board +* This sketch will log data, and check if there is any USB MSD Device connected to the USB Port of the Opta. + The USB device is mounted and unmounted after every update operation. The first status LED is on when the USB drive is mounted. + So as long as the status LED is off you can safely remove the drive. + The sketch will log to internal storage in the meantime, and wait for the USB drive to be inserted again. +*/ + +#include "Arduino_UnifiedStorage.h" +#include + +constexpr auto baudrate { 115200 }; + + +#define USB_MOUNTED_LED LED_D0 +#define SUCCESFULLY_COPIED_LED + + + +InternalStorage internalStorage = InternalStorage(true, "userData", FS_FAT); +USBStorage usbStorage = USBStorage(); +std::vector sensorDataBuffer; + +unsigned long bytesWritten = 0; +unsigned long lastLog = 0; +unsigned long lastMove = 0; +unsigned long lastBackup = 0; + + +volatile bool usbAvailable = false; +bool backingUP = false; + +void connectionCallback(){ + usbAvailable = true; +} + +void disconnectionCallback(){ + usbAvailable = false; +} +// Function to run a given method periodically +void runPeriodically(void (*method)(), unsigned long interval, unsigned long* variable) { + unsigned long currentMillis = millis(); + + if (currentMillis - *variable >= interval) { + *variable = currentMillis; + method(); // Call the provided method + } +} + +// Function to log sensor data +void logDataToRAM() { + int timeStamp = millis(); + int sensorReading = analogRead(A0); + String line = String(timeStamp) + "," + String(sensorReading) + "\n"; + sensorDataBuffer.push_back(line); +} + +void moveDataToQSPI() { + if(!backingUP){ + UFile _logFile = internalStorage.getRootFolder().createFile("log.txt", FileMode::APPEND); + for (const auto& line : sensorDataBuffer) { + bytesWritten += _logFile.write(line); // Write the log line to the file + } + _logFile.close(); + sensorDataBuffer.clear(); + } +} + + +void performUpdate() { + Folder usbRoot = usbStorage.getRootFolder(); // Get the root folder of the USB storage + UFile logFile = internalStorage.getRootFolder().createFile("log.txt", FileMode::READ); + UFile backupFile = usbRoot.createFile("backup_file.txt", FileMode::APPEND); // Create or open the backup file + UFile lastUpdateFile = usbRoot.createFile("diff.txt", FileMode::READ); // Create or open the last update file + + backingUP = true; + unsigned lastUpdateBytes = lastUpdateFile.readAsString().toInt(); // Read the last update size from the file + + printToSerialOrRS485("Last update bytes: " + String(lastUpdateBytes) + "\n"); + + if (lastUpdateBytes >= bytesWritten) { + printToSerialOrRS485("No new data to copy. \n"); + backupFile.close(); + lastUpdateFile.close(); + backingUP = false; + return; + } + + logFile.seek(lastUpdateBytes); // Move the file pointer to the last update position + unsigned long totalBytesToMove = bytesWritten - lastUpdateBytes; + printToSerialOrRS485("New update bytes: " + String(totalBytesToMove) + "\n"); + + uint8_t* buffer = new uint8_t[totalBytesToMove]; + + size_t bytesRead = logFile.read(buffer, totalBytesToMove); + size_t bytesMoved = backupFile.write(buffer, bytesRead); // Only write the bytes that haven't been backed up yet + + printToSerialOrRS485("Successfully copied " + String(bytesMoved) + " new bytes."); + + lastUpdateFile.changeMode(FileMode::WRITE); // Open the last update file in write mode + lastUpdateFile.write(String(lastUpdateBytes + bytesMoved)); // Update the last update size + + backupFile.close(); + logFile.close(); + lastUpdateFile.close(); + + + usbStorage.unmount(); // Unmount the USB storage + + digitalWrite(USB_MOUNTED_LED, HIGH); + backingUP = false; + delete[] buffer; +} + + +// Function to backup data to USB storage +void backupToUSB() { + if (usbAvailable) { + printToSerialOrRS485("USB Mass storage is available \n"); + delay(100); + if (!usbStorage.isMounted()) { + + printToSerialOrRS485("Mounting USB Mass Storage \n"); + digitalWrite(USB_MOUNTED_LED, LOW); + if(usbStorage.begin()){ + performUpdate(); + } + + } else if (usbStorage.isMounted()) { + printToSerialOrRS485("USB Mass storage is connected, performing update \n"); + performUpdate(); + + } + } else { + printToSerialOrRS485("USB Mass storage is not available \n"); + } + +} + + +void setup() { + beginRS485(baudrate); + + + usbStorage.onConnect(connectionCallback); + usbStorage.onDisconnect(disconnectionCallback); + + pinMode(USB_MOUNTED_LED, OUTPUT); + printToSerialOrRS485("Formatting internal storage... \n"); + int formatted = internalStorage.format(FS_LITTLEFS); + printToSerialOrRS485("QSPI Format status: " + String(formatted) + "\n"); + + + + if (!internalStorage.begin()) { + printToSerialOrRS485("Failed to initialize internal storage \n"); + return; + } else { + printToSerialOrRS485("Initialized storage \n"); + } + +} + +void loop() { + + + runPeriodically(logDataToRAM, 100, &lastLog); + runPeriodically(moveDataToQSPI, 1000, &lastMove); + runPeriodically(backupToUSB, 10000, &lastBackup); +} diff --git a/examples/PortentaH7Logger/PortentaH7Logger.ino b/examples/PortentaH7Logger/PortentaH7Logger.ino new file mode 100644 index 0000000..6ae0c04 --- /dev/null +++ b/examples/PortentaH7Logger/PortentaH7Logger.ino @@ -0,0 +1,188 @@ +/* +This example demonstrates the usage of the "Arduino_UnifiedStorage" library for logging and backing up data to USB storage in case a USB Mass Storage device is inserted. + +The code defines two main functions: "logData" and "performUpdate". +The "logData" function logs sensor data by reading an analog sensor and writing the data to the log file. + +The "performUpdate" function performs the update process by: +* reading the last update size from a file (number of bytes) +* copying the new data from the log file to a backup file +* and updating the last update size. + +INSTRUCTIONS +* Make sure the QSPI storage of your board is properly partitioned. + * You can do that by flashing the QSPIFormat example that can be found in the STM32H747_System folder + * Open the serial monitor and select answer with "Y" when this appears "Do you want to use partition scheme 1? Y/[n]" + * Reboot the board +* This sketch will log data, and check if there is any USB MSD Device connected to the USB Port of the Opta. + The USB device is mounted and unmounted after every update operation. The first status LED is on when the USB drive is mounted. + So as long as the status LED is off you can safely remove the drive. + The sketch will log to internal storage in the meantime, and wait for the USB drive to be inserted again. +*/ + +#include "Arduino_UnifiedStorage.h" +#include +#include + +constexpr auto baudrate { 115200 }; + +#if defined(ARDUINO_PORTENTA_H7_M7) +#define USB_MOUNTED_LED LED_BLUE +#elif defined(ARDUINO_PORTENTA_C33) +#define USB_MOUNTED_LED LEDB +#endif + + +InternalStorage internalStorage = InternalStorage(); +USBStorage usbStorage = USBStorage(); +std::vector sensorDataBuffer; + +unsigned long bytesWritten = 0; +unsigned long lastLog = 0; +unsigned long lastMove = 0; +unsigned long lastBackup = 0; + + +volatile bool usbAvailable = false; +bool backingUP = false; + +void connectionCallback(){ + usbAvailable = true; +} + +void disconnectionCallback(){ + usbAvailable = false; +} +// Function to run a given method periodically +void runPeriodically(void (*method)(), unsigned long interval, unsigned long* variable) { + unsigned long currentMillis = millis(); + + if (currentMillis - *variable >= interval) { + *variable = currentMillis; + method(); // Call the provided method + } +} + +// Function to log sensor data +void logDataToRAM() { + int timeStamp = millis(); + int sensorReading = analogRead(A0); + String line = String(timeStamp) + "," + String(sensorReading) + "\n"; + sensorDataBuffer.push_back(line); +} + +void moveDataToQSPI() { + if(!backingUP){ + UFile _logFile = internalStorage.getRootFolder().createFile("log.txt", FileMode::APPEND); + for (const auto& line : sensorDataBuffer) { + bytesWritten += _logFile.write(line); // Write the log line to the file + } + _logFile.close(); + sensorDataBuffer.clear(); + } +} + + +void performUpdate() { + Folder usbRoot = usbStorage.getRootFolder(); // Get the root folder of the USB storage + UFile logFile = internalStorage.getRootFolder().createFile("log.txt", FileMode::READ); + UFile backupFile = usbRoot.createFile("backup_file.txt", FileMode::APPEND); // Create or open the backup file + UFile lastUpdateFile = usbRoot.createFile("diff.txt", FileMode::READ); // Create or open the last update file + + backingUP = true; + unsigned lastUpdateBytes = lastUpdateFile.readAsString().toInt(); // Read the last update size from the file + + Serial.print("Last update bytes: " + String(lastUpdateBytes) + "\n"); + + if (lastUpdateBytes >= bytesWritten) { + Serial.print("No new data to copy. \n"); + backupFile.close(); + lastUpdateFile.close(); + backingUP = false; + return; + } + + logFile.seek(lastUpdateBytes); // Move the file pointer to the last update position + unsigned long totalBytesToMove = bytesWritten - lastUpdateBytes; + Serial.print("New update bytes: " + String(totalBytesToMove) + "\n"); + + uint8_t* buffer = new uint8_t[totalBytesToMove]; + + size_t bytesRead = logFile.read(buffer, totalBytesToMove); + size_t bytesMoved = backupFile.write(buffer, bytesRead); // Only write the bytes that haven't been backed up yet + + Serial.print("Successfully copied " + String(bytesMoved) + " new bytes."); + + lastUpdateFile.changeMode(FileMode::WRITE); // Open the last update file in write mode + lastUpdateFile.write(String(lastUpdateBytes + bytesMoved)); // Update the last update size + + backupFile.close(); + logFile.close(); + lastUpdateFile.close(); + + + usbStorage.unmount(); // Unmount the USB storage + + digitalWrite(USB_MOUNTED_LED, HIGH); + backingUP = false; + delete[] buffer; +} + + +// Function to backup data to USB storage +void backupToUSB() { + if (usbAvailable) { + Serial.print("USB Mass storage is available \n"); + delay(100); + if (!usbStorage.isMounted()) { + + Serial.print("Mounting USB Mass Storage \n"); + digitalWrite(USB_MOUNTED_LED, LOW); + if(usbStorage.begin()){ + performUpdate(); + } + + } else if (usbStorage.isMounted()) { + Serial.print("USB Mass storage is connected, performing update \n"); + performUpdate(); + + } + } else { + Serial.print("USB Mass storage is not available \n"); + } + + +} + + +void setup() { + //beginRS485(baudrate); + Serial.begin(115200); + while(!Serial); + + usbStorage.onConnect(connectionCallback); + usbStorage.onDisconnect(disconnectionCallback); + + pinMode(USB_MOUNTED_LED, OUTPUT); + Serial.print("Formatting internal storage... \n"); + int formatted = internalStorage.format(FS_LITTLEFS); + Serial.print("QSPI Format status: " + String(formatted) + "\n"); + + + + if (!internalStorage.begin()) { + Serial.print("Failed to initialize internal storage \n"); + return; + } else { + Serial.print("Initialized storage \n"); + } + +} + +void loop() { + + + runPeriodically(logDataToRAM, 100, &lastLog); + runPeriodically(moveDataToQSPI, 1000, &lastMove); + runPeriodically(backupToUSB, 10000, &lastBackup); +} diff --git a/extras/tests/TestExisting/TestExisting.ino b/extras/tests/TestExisting/TestExisting.ino index d9bef6f..965dc4b 100644 --- a/extras/tests/TestExisting/TestExisting.ino +++ b/extras/tests/TestExisting/TestExisting.ino @@ -1,54 +1,51 @@ #include -InternalStorage internalStorage = InternalStorage(); +InternalStorage internalStorage = InternalStorage(); void setup() { /* UNCOMMENT THIS PART IF YOU WANT TO ENABLE FORMATTING*/ + #if defined(ARDUINO_PORTENTA_C33) || defined(ARDUINO_PORTENTA_H7_M7) + Serial.begin(115200); + while(!Serial); + #elif defined(ARDUINO_OPTA) + beginRS485(115200); + #endif - Serial.begin(9600); - delay(1000); // Give time to open the Serial Monitor - while(!Serial); internalStorage.format(FS_LITTLEFS); internalStorage.begin(); - + c Folder root = internalStorage.getRootFolder(); - Serial.println(root.getPathAsString()); + // Test copyTo - Serial.println("Testing copyTo..."); + printToSerialOrRS485("Testing copyTo... \n"); Folder sourceFolder2 = root.createSubfolder("source_folder"); - Serial.println("Folder 1 created"); + printToSerialOrRS485("Folder 1 created \n"); - Serial.println("Trying to create a folder on top of an existing one... without overwrite"); + printToSerialOrRS485("Trying to create a folder on top of an existing one... without overwrite \n"); Folder sourceFolder3 = root.createSubfolder("source_folder"); - Serial.println("Trying to create a folder on top of an existing one... with overwrite"); + printToSerialOrRS485("Trying to create a folder on top of an existing one... with overwrite \n"); Folder sourceFolder4 = root.createSubfolder("source_folder", true); Folder destinationFolder2 = root.createSubfolder("destination_folder"); - Serial.println("Folder 2 created"); - - Serial.println(sourceFolder2.getPathAsString()); - Serial.println(destinationFolder2.getPathAsString()); + printToSerialOrRS485("Folder 2 created \n"); - Serial.println(); - Serial.println(); bool copyResult = sourceFolder2.copyTo(destinationFolder2, true); // Overwrite if exists if (copyResult) { - Serial.println("Copy successful"); + printToSerialOrRS485("Copy successful \n"); } else { - Serial.println("Copy failed"); + printToSerialOrRS485("Copy failed \n"); } - Serial.println(); @@ -57,15 +54,12 @@ void setup() { Folder sourceFolder = root.createSubfolder("source"); Folder destinationFolder = root.createSubfolder("destination"); - - Serial.println(); - Serial.println(); - Serial.println("Testing moveTo..."); + printToSerialOrRS485("Testing moveTo... \n"); bool moveResult = sourceFolder.moveTo(destinationFolder, true); // Overwrite if exists if (moveResult) { - Serial.println("Move successful"); + printToSerialOrRS485("Move successful \n"); } else { - Serial.println("Move failed"); + printToSerialOrRS485("Move failed \n"); } @@ -79,14 +73,10 @@ void setup() { bool success = someFile.copyTo(someOtherFolder); - Serial.println("trying to copy file without overwrite"); - Serial.println(success); + printToSerialOrRS485("trying to copy file without overwrite: %d\n", success); success = someFile.copyTo(someOtherFolder,true); - Serial.println("trying to copy file with overwrite"); - Serial.println(success); - - + printToSerialOrRS485("trying to copy file with overwrite: %d \n", success); } diff --git a/extras/tests/TestFileOperations/TestFileOperations.ino b/extras/tests/TestFileOperations/TestFileOperations.ino index 60ce5ee..97da9a6 100644 --- a/extras/tests/TestFileOperations/TestFileOperations.ino +++ b/extras/tests/TestFileOperations/TestFileOperations.ino @@ -22,30 +22,30 @@ InternalStorage internal = InternalStorage(); bool testFileCreationWithOpen(Folder root) { UFile file = UFile(); String path = root.getPathAsString() + "/test_open.txt"; - Serial.println(path); + printToSerialOrRS485(path); if (file.open(path, FileMode::WRITE)) { - Serial.println("\n--- Test creating file using file.open ---"); - Serial.println("Test creating file using file.open - Success"); + printToSerialOrRS485("\n--- Test creating file using file.open ---"); + printToSerialOrRS485("Test creating file using file.open - Success"); file.close(); file.remove(); return true; } else { - Serial.println("Test creating file using file.open - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test creating file using file.open - Failed. Error: " + String(getErrno())); return false; } } bool testFileCreationWithCreate(Folder root) { - Serial.println("\n--- Test creating file using root.createFile ---"); + printToSerialOrRS485("\n--- Test creating file using root.createFile ---"); UFile file = root.createFile("test_create.txt", FileMode::WRITE); if (file.exists()) { - Serial.println("Test creating file using root.createFile - Success"); + printToSerialOrRS485("Test creating file using root.createFile - Success"); file.close(); file.remove(); return true; } else { - Serial.println("Test creating file using root.createFile - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test creating file using root.createFile - Failed. Error: " + String(getErrno())); return false; } } @@ -53,14 +53,14 @@ bool testFileCreationWithCreate(Folder root) { bool testWritingCharBuffer(Folder root) { UFile file = root.createFile("test_write.txt", FileMode::WRITE); if (file.exists()) { - Serial.println("\n--- Test writing char * buffer ---"); + printToSerialOrRS485("\n--- Test writing char * buffer ---"); size_t bytesWritten = file.write(reinterpret_cast("Hello, World!"), 13); - Serial.println("Bytes written to file: " + String(bytesWritten)); + printToSerialOrRS485("Bytes written to file: " + String(bytesWritten)); file.close(); file.remove(); return bytesWritten == 13; } else { - Serial.println("Test writing char * buffer - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test writing char * buffer - Failed. Error: " + String(getErrno())); return false; } } @@ -68,16 +68,16 @@ bool testWritingCharBuffer(Folder root) { bool testWritingWithString(Folder root) { UFile file = root.createFile("test_write_string.txt", FileMode::WRITE); if (file.exists()) { - Serial.println("\n--- Test writing String ---"); + printToSerialOrRS485("\n--- Test writing String ---"); String data = " This is a test with String data."; size_t bytesWritten = file.write(data); - Serial.println("Bytes written to file (with String): " + String(bytesWritten)); + printToSerialOrRS485("Bytes written to file (with String): " + String(bytesWritten)); file.close(); file.remove(); return true; } else { - Serial.println("Test writing with String data type - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test writing with String data type - Failed. Error: " + String(getErrno())); return false; } @@ -86,15 +86,15 @@ bool testWritingWithString(Folder root) { bool testAppending(Folder root) { UFile file = root.createFile("test_append.txt", FileMode::WRITE); if (file.exists()) { - Serial.println("\n--- Test appending ---"); + printToSerialOrRS485("\n--- Test appending ---"); String data = " Appending some more data."; size_t bytesWritten = file.write(reinterpret_cast(data.c_str()), data.length()); - Serial.println("Bytes written to file (appending): " + String(bytesWritten)); + printToSerialOrRS485("Bytes written to file (appending): " + String(bytesWritten)); file.close(); file.remove(); return true; } else { - Serial.println("Test appending to the file - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test appending to the file - Failed. Error: " + String(getErrno())); return false; } } @@ -109,19 +109,19 @@ bool testReadingAll(Folder root) { char buffer[file.available()]; size_t bytesRead = file.read(reinterpret_cast(buffer), sizeof(buffer)); buffer[bytesRead] = '\0'; // Null-terminate the string - Serial.println("\n--- Test reading everything from the file ---"); - Serial.println("Read from file (test_read.txt): " + String(buffer)); + printToSerialOrRS485("\n--- Test reading everything from the file ---"); + printToSerialOrRS485("Read from file (test_read.txt): " + String(buffer)); file.close(); file.remove(); return true; } else { - Serial.println("Test reading everything from the file - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test reading everything from the file - Failed. Error: " + String(getErrno())); return false; } } else { - Serial.println("Test reading everything from the file - Failed to create file. Error: " + String(getErrno())); + printToSerialOrRS485("Test reading everything from the file - Failed to create file. Error: " + String(getErrno())); return false; } @@ -138,21 +138,21 @@ bool testSeeking(Folder root) { if (file.open(root.getPathAsString() + "/test_seek.txt", FileMode::READ)) { - Serial.println("\n--- Test seeking file ---"); + printToSerialOrRS485("\n--- Test seeking file ---"); file.seek(7); char buffer[20]; size_t bytesRead = file.read(reinterpret_cast(buffer), sizeof(buffer)); buffer[bytesRead] = '\0'; // Null-terminate the string - Serial.println("Read after seeking: " + String(buffer)); + printToSerialOrRS485("Read after seeking: " + String(buffer)); file.close(); file.remove(); return true; } else { - Serial.println("Test seeking in the file - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test seeking in the file - Failed. Error: " + String(getErrno())); return false; } } else { - Serial.println("Test seeking in the file - Failed to create file. Error: " + String(getErrno())); + printToSerialOrRS485("Test seeking in the file - Failed to create file. Error: " + String(getErrno())); return false; } @@ -165,18 +165,18 @@ bool testAvailableData(Folder root) { file.close(); if (file.open(root.getPathAsString() + "/test_available.txt", FileMode::READ)) { - Serial.println("\n--- Test available data ---"); + printToSerialOrRS485("\n--- Test available data ---"); int availableBytes = file.available(); - Serial.println("Available bytes in file (test_available.txt): " + String(availableBytes)); + printToSerialOrRS485("Available bytes in file (test_available.txt): " + String(availableBytes)); file.close(); file.remove(); return true; } else { - Serial.println("Test checking available data in the file - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test checking available data in the file - Failed. Error: " + String(getErrno())); return false; } } else { - Serial.println("Test checking available data in the file - Failed to create file. Error: " + String(getErrno())); + printToSerialOrRS485("Test checking available data in the file - Failed to create file. Error: " + String(getErrno())); return false; } @@ -193,26 +193,26 @@ bool testCopyingFile(Folder root) { Folder destinationFolder = root.createSubfolder("test_folder_copy"); if (destinationFolder.exists()) { - Serial.println("\n--- Test copying a file ---"); - Serial.println("Source file name: " + String(sourceFile.getPathAsString())); + printToSerialOrRS485("\n--- Test copying a file ---"); + printToSerialOrRS485("Source file name: " + String(sourceFile.getPathAsString())); if (sourceFile.copyTo(destinationFolder)) { - Serial.println("File copied successfully!"); + printToSerialOrRS485("File copied successfully!"); sourceFile.close(); sourceFile.remove(); destinationFolder.remove(); return true; } else { - Serial.println("File copying failed. Error: " + String(getErrno())); + printToSerialOrRS485("File copying failed. Error: " + String(getErrno())); return false; } } else { - Serial.println("Test copying a file - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test copying a file - Failed. Error: " + String(getErrno())); return false; } } else { - Serial.println("Test copying a file - Failed to create destination folder. Error: " + String(getErrno())); + printToSerialOrRS485("Test copying a file - Failed to create destination folder. Error: " + String(getErrno())); return false; } } @@ -227,11 +227,11 @@ bool testMovingFile(Folder root) { if (destinationFolder.exists()) { UFile movedFile = sourceFileMove; if (movedFile.exists()) { - Serial.println("\n--- Test moving a file ---"); - Serial.println("Source file name: " + String(sourceFileMove.getPathAsString())); - Serial.println("Destination file name: " + String(destinationFolder.getPathAsString()) + "/test_source_move.txt"); + printToSerialOrRS485("\n--- Test moving a file ---"); + printToSerialOrRS485("Source file name: " + String(sourceFileMove.getPathAsString())); + printToSerialOrRS485("Destination file name: " + String(destinationFolder.getPathAsString()) + "/test_source_move.txt"); if (sourceFileMove.moveTo(destinationFolder)) { - Serial.println("File moved successfully!"); + printToSerialOrRS485("File moved successfully!"); sourceFileMove.close(); movedFile.close(); movedFile.remove(); @@ -239,19 +239,19 @@ bool testMovingFile(Folder root) { sourceFileMove.remove(); return true; } else { - Serial.println("File moving failed. Error: " + String(getErrno())); + printToSerialOrRS485("File moving failed. Error: " + String(getErrno())); return false; } } else { - Serial.println("Test moving a file - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test moving a file - Failed. Error: " + String(getErrno())); return false; } } else { - Serial.println("Test moving a file - Failed to create destination folder. Error: " + String(getErrno())); + printToSerialOrRS485("Test moving a file - Failed to create destination folder. Error: " + String(getErrno())); return false; } } else { - Serial.println("Test moving a file - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test moving a file - Failed. Error: " + String(getErrno())); return false; } } @@ -263,20 +263,20 @@ void printFolderContents(Folder dir, int indentation = 0) { // Print directories for (Folder subdir : directories) { for (int i = 0; i < indentation; i++) { - Serial.print(" "); + printToSerialOrRS485(" "); } - Serial.print("[D] "); - Serial.println(subdir.getPath()); + printToSerialOrRS485("[D] "); + printToSerialOrRS485(subdir.getPath()); printFolderContents(subdir, indentation + 1); } // Print files for (UFile file : files) { for (int i = 0; i < indentation; i++) { - Serial.print(" "); + printToSerialOrRS485(" "); } - Serial.print("[F] "); - Serial.println(file.getPath()); + printToSerialOrRS485("[F] "); + printToSerialOrRS485(file.getPath()); } } @@ -284,8 +284,8 @@ void runTests(Arduino_UnifiedStorage * storage, String storageType) { if (storage->begin()) { Folder root = storage->getRootFolder(); - Serial.println("\n=== Testing " + storageType + " ==="); - Serial.println("========= File Tests ========="); + printToSerialOrRS485("\n=== Testing " + storageType + " ==="); + printToSerialOrRS485("========= File Tests ========="); testFileCreationWithOpen(root); testFileCreationWithCreate(root); @@ -298,30 +298,38 @@ void runTests(Arduino_UnifiedStorage * storage, String storageType) { testCopyingFile(root); testMovingFile(root); - Serial.println("\n========= FS Contents after File Tests ========="); - Serial.println("Should be empty if deletion was successful"); + printToSerialOrRS485("\n========= FS Contents after File Tests ========="); + printToSerialOrRS485("Should be empty if deletion was successful"); printFolderContents(root); - Serial.println("=============================\n"); + printToSerialOrRS485("=============================\n"); storage -> unmount(); } } void setup(){ - Serial.begin(115200); - while(!Serial); + + #if defined(ARDUINO_PORTENTA_C33) || defined(ARDUINO_PORTENTA_H7_M7) + Serial.begin(115200); + while(!Serial); + #elif defined(ARDUINO_OPTA) + beginRS485(115200); + #endif + #if defined(HAS_SD) - runTests(&sd, "SD"); + sd.format(FS_FAT); + runTests(&&sd, "SD"); #endif #if defined(HAS_USB) - + usb.format(FS_FAT); runTests(&usb, "USB"); #endif #if defined(HAS_QSPI) + internal.format(FS_FAT); runTests(&internal, "QSPI"); #endif diff --git a/extras/tests/TestFolderOperations/TestFolderOperations.ino b/extras/tests/TestFolderOperations/TestFolderOperations.ino index 303c322..e53aa83 100644 --- a/extras/tests/TestFolderOperations/TestFolderOperations.ino +++ b/extras/tests/TestFolderOperations/TestFolderOperations.ino @@ -28,20 +28,20 @@ void printFolderContents(Folder dir, int indentation = 0) { // Print directories for (Folder subdir : directories) { for (int i = 0; i < indentation; i++) { - Serial.print(" "); + printToSerialOrRS485(" "); } - Serial.print("[D] "); - Serial.println(subdir.getPath()); + printToSerialOrRS485("[D] "); + printToSerialOrRS485(subdir.getPath()); printFolderContents(subdir, indentation + 1); } // Print files for (UFile file : files) { for (int i = 0; i < indentation; i++) { - Serial.print(" "); + printToSerialOrRS485(" "); } - Serial.print("[F] "); - Serial.println(file.getPath()); + printToSerialOrRS485("[F] "); + printToSerialOrRS485(file.getPath()); } } @@ -49,12 +49,12 @@ void printFolderContents(Folder dir, int indentation = 0) { bool testFolderCreation(Folder root) { Folder subfolder = root.createSubfolder("test_folder"); if (subfolder.exists()) { - Serial.println("\n--- Test creating folder using root.createSubfolder ---"); - Serial.println("Test creating folder using root.createSubfolder - Success"); + printToSerialOrRS485("\n--- Test creating folder using root.createSubfolder ---"); + printToSerialOrRS485("Test creating folder using root.createSubfolder - Success"); subfolder.remove(); return true; } else { - Serial.println("Test creating folder using root.createSubfolder - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test creating folder using root.createSubfolder - Failed. Error: " + String(getErrno())); return false; } } @@ -62,18 +62,18 @@ bool testFolderCreation(Folder root) { bool testFolderRenaming(Folder root) { Folder sourceFolder = root.createSubfolder("source_folder"); if (sourceFolder.exists()) { - Serial.println("\n--- Test renaming folder ---"); - Serial.println("Source folder name: " + String(sourceFolder.getPathAsString())); + printToSerialOrRS485("\n--- Test renaming folder ---"); + printToSerialOrRS485("Source folder name: " + String(sourceFolder.getPathAsString())); if (sourceFolder.rename("renamed_folder")) { - Serial.println("Folder renamed to: " + String(sourceFolder.getPathAsString())); + printToSerialOrRS485("Folder renamed to: " + String(sourceFolder.getPathAsString())); sourceFolder.remove(); return true; } else { - Serial.println("Folder renaming failed. Error: " + String(getErrno())); + printToSerialOrRS485("Folder renaming failed. Error: " + String(getErrno())); return false; } } else { - Serial.println("Test folder renaming - Failed. Error: " + String(getErrno())); + printToSerialOrRS485("Test folder renaming - Failed. Error: " + String(getErrno())); return false; } } @@ -83,24 +83,24 @@ bool testCopyingFolder(Folder root) { Folder copyDestination = root.createSubfolder("copy_destination"); if (sourceFolder.exists()) { - Serial.println("\n--- Test copying a folder ---"); - Serial.println("Source folder name: " + String(sourceFolder.getPathAsString())); - Serial.println("Destination folder name: " + String(copyDestination.getPathAsString())); + printToSerialOrRS485("\n--- Test copying a folder ---"); + printToSerialOrRS485("Source folder name: " + String(sourceFolder.getPathAsString())); + printToSerialOrRS485("Destination folder name: " + String(copyDestination.getPathAsString())); if (sourceFolder.copyTo(copyDestination, true)) { - Serial.println("Folder copied successfully!"); + printToSerialOrRS485("Folder copied successfully!"); sourceFolder.remove(); copyDestination.remove(); return true; } else { - Serial.println("Folder copying failed. Error: " + String(getErrno())); + printToSerialOrRS485("Folder copying failed. Error: " + String(getErrno())); sourceFolder.remove(); return false; } } else { - Serial.println("Test copying a folder - Failed to create source folder. Error: " + String(getErrno())); + printToSerialOrRS485("Test copying a folder - Failed to create source folder. Error: " + String(getErrno())); return false; } } @@ -112,20 +112,20 @@ bool testMovingFolder(Folder root) { Folder moveDestination = root.createSubfolder("move_destination"); if (sourceFolderMove.exists()) { - Serial.println("\n--- Test moving a folder ---"); - Serial.println("Source folder name: " + String(sourceFolderMove.getPathAsString())); - Serial.println("Destination folder name: " + String(moveDestination.getPathAsString())); + printToSerialOrRS485("\n--- Test moving a folder ---"); + printToSerialOrRS485("Source folder name: " + String(sourceFolderMove.getPathAsString())); + printToSerialOrRS485("Destination folder name: " + String(moveDestination.getPathAsString())); if (sourceFolderMove.moveTo(moveDestination)) { - Serial.println("Folder moved successfully!"); + printToSerialOrRS485("Folder moved successfully!"); sourceFolderMove.remove(); moveDestination.remove(); return true; } else { - Serial.println("Folder moving failed. Error: " + String(getErrno())); + printToSerialOrRS485("Folder moving failed. Error: " + String(getErrno())); return false; } } else { - Serial.println("Test moving a folder - Failed to create source folder. Error: " + String(getErrno())); + printToSerialOrRS485("Test moving a folder - Failed to create source folder. Error: " + String(getErrno())); return false; } @@ -139,23 +139,28 @@ void runTests(Arduino_UnifiedStorage * storage, String storageType) { Folder root = storage->getRootFolder(); - Serial.println("========= Folder Tests ========="); + printToSerialOrRS485("========= Folder Tests ========="); testFolderCreation(root); testFolderRenaming(root); testCopyingFolder(root); testMovingFolder(root); - Serial.println("========= FS Contents after Folder Tests ========="); + printToSerialOrRS485("========= FS Contents after Folder Tests ========="); printFolderContents(root); storage->unmount(); - Serial.println(); + printToSerialOrRS485(""); } } void setup(){ - Serial.begin(115200); - while(!Serial); + #if defined(ARDUINO_PORTENTA_C33) || defined(ARDUINO_PORTENTA_H7_M7) + Serial.begin(115200); + while(!Serial); + #elif defined(ARDUINO_OPTA) + beginRS485(115200); + #endif + #if defined(HAS_USB) runTests(&usb, "USB"); @@ -166,7 +171,7 @@ void setup(){ #endif #if defined(HAS_SD) - runTests(&sd, "SD"); + runTests(&&sd, "SD"); #endif } diff --git a/extras/tests/TestRepeatedFormatMount/TestRepeatedFormatMount.ino b/extras/tests/TestRepeatedFormatMount/TestRepeatedFormatMount.ino index ce1e343..3ef0b71 100644 --- a/extras/tests/TestRepeatedFormatMount/TestRepeatedFormatMount.ino +++ b/extras/tests/TestRepeatedFormatMount/TestRepeatedFormatMount.ino @@ -20,81 +20,89 @@ InternalStorage internal = InternalStorage(); #endif void runRepeatedMountTest(Arduino_UnifiedStorage * storage, String storageType, int n = 10){ - Serial.println("Running repeated mount test for " + storageType); + printToSerialOrRS485("Running repeated mount test for " + storageType); printToSerialOrRS485("\n"); for(size_t i=0;ibegin(); - Serial.println("Mounting drive"); + printToSerialOrRS485("Mounting drive"); printToSerialOrRS485("\n"); if(mountResult != 1) { - Serial.println(mountResult); - Serial.println(getErrno()); + printToSerialOrRS485(mountResult); + printToSerialOrRS485(getErrno()); + printToSerialOrRS485("\n"); } Folder root = storage->getRootFolder(); UFile file = root.createFile("file.txt", FileMode::WRITE); file.write("writing stuff to the file"); file.changeMode(FileMode::READ); - Serial.println(file.readAsString()); + printToSerialOrRS485(file.readAsString()); printToSerialOrRS485("\n"); file.close(); file.remove(); int umountResult = storage->unmount(); if(!umountResult) { - Serial.println("Unmounting drive"); - Serial.println(umountResult); - Serial.println(getErrno()); + printToSerialOrRS485("Unmounting drive"); printToSerialOrRS485("\n"); + printToSerialOrRS485(umountResult); + printToSerialOrRS485(getErrno()); } else { - Serial.println("Successfully unmounted"); + printToSerialOrRS485("Successfully unmounted"); printToSerialOrRS485("\n"); } } } void setup(){ - Serial.begin(115200); - while(!Serial); + #if defined(ARDUINO_PORTENTA_C33) || defined(ARDUINO_PORTENTA_H7_M7) + Serial.begin(115200); + while(!Serial); + #elif defined(ARDUINO_OPTA) + beginRS485(115200); + #endif + #if defined(HAS_QSPI) + printToSerialOrRS485("RUNNING FORMAT AND REPEATED MOUNT - QSPI Storage \n"); printToSerialOrRS485("\n"); + printToSerialOrRS485("Formatting QSPI drive as LittleFS: " + String(internal.format(FS_LITTLEFS))); printToSerialOrRS485("\n"); + runRepeatedMountTest(&internal, "QSPI"); + printToSerialOrRS485("Formatting QSPI drive as FAT32: " + String(internal.format(FS_FAT))); printToSerialOrRS485("\n"); + runRepeatedMountTest(&internal, "QSPI"); + printToSerialOrRS485("Formatting SD drive as LittleFS again: " + String(internal.format(FS_LITTLEFS))); printToSerialOrRS485("\n"); + runRepeatedMountTest(&internal, "QSPI"); + printToSerialOrRS485("Formatting SD drive as FAT32 again: " + String(internal.format(FS_FAT))); printToSerialOrRS485("\n"); + runRepeatedMountTest(&internal, "QSPI"); + #endif + // format storage as FAT32 #if defined(HAS_USB) - Serial.println("RUNNING FORMAT AND REPEATED MOUNT - USB \n"); - Serial.println("Formatting USB drive as LittleFS: " + String(usb.format(FS_LITTLEFS))); + printToSerialOrRS485("RUNNING FORMAT AND REPEATED MOUNT - USB \n"); printToSerialOrRS485("\n"); + printToSerialOrRS485("Formatting USB drive as LittleFS: " + String(usb.format(FS_FAT))); printToSerialOrRS485("\n"); + printToSerialOrRS485("" + String(errno)); runRepeatedMountTest(&usb, "USB"); - Serial.println("Formatting USB drive as FAT32: " + String(usb.format(FS_FAT))); + printToSerialOrRS485("Formatting USB drive as FAT32: " + String(usb.format(FS_FAT))); printToSerialOrRS485("\n"); runRepeatedMountTest(&usb, "USB"); - Serial.println("Formatting USB drive as LittleFS again: " + String(usb.format(FS_LITTLEFS))); - runRepeatedMountTest(&usb, "USB"); - Serial.println("Formatting USB drive as FAT32 again: " + String(usb.format(FS_FAT))); + printToSerialOrRS485("Formatting USB drive as LittleFS again: " + String(usb.format(FS_LITTLEFS))); printToSerialOrRS485("\n"); runRepeatedMountTest(&usb, "USB"); + printToSerialOrRS485("Formatting USB drive as FAT32 again: " + String(usb.format(FS_FAT))); printToSerialOrRS485("\n"); + runRepeatedMountTest(&usb, "USB"); printToSerialOrRS485("\n"); #endif #if defined(HAS_SD) - Serial.println("RUNNING FORMAT AND REPEATED MOUNT - SD Card \n"); - Serial.println("Formatting SD drive as LittleFS: " + String(sd.format(FS_LITTLEFS))); - runRepeatedMountTest(&sd, "SD"); - Serial.println("Formatting SD drive as FAT32: " + String(sd.format(FS_FAT))); - runRepeatedMountTest(&sd, "SD"); - Serial.println("Formatting SD drive as LittleFS again: " + String(sd.format(FS_LITTLEFS))); - runRepeatedMountTest(&sd, "SD"); - Serial.println("Formatting SD drive as FAT32 again: " + String(sd.format(FS_FAT))); - runRepeatedMountTest(&sd, "SD"); + printToSerialOrRS485("RUNNING FORMAT AND REPEATED MOUNT - SD Card \n"); + printToSerialOrRS485("Formatting SD drive as LittleFS: " + String(sd.format(FS_LITTLEFS))); + runRepeatedMountTest(&&sd, "SD"); + printToSerialOrRS485("Formatting SD drive as FAT32: " + String(sd.format(FS_FAT))); + runRepeatedMountTest(&&sd, "SD"); + printToSerialOrRS485("Formatting SD drive as LittleFS again: " + String(sd.format(FS_LITTLEFS))); + runRepeatedMountTest(&&sd, "SD"); + printToSerialOrRS485("Formatting SD drive as FAT32 again: " + String(sd.format(FS_FAT))); + runRepeatedMountTest(&&sd, "SD"); #endif - #if defined(HAS_QSPI) - Serial.println("RUNNING FORMAT AND REPEATED MOUNT - QSPI Storage \n"); - Serial.println("Formatting QSPI drive as LittleFS: " + String(internal.format(FS_LITTLEFS))); - runRepeatedMountTest(&internal, "QSPI"); - Serial.println("Formatting QSPI drive as FAT32: " + String(internal.format(FS_FAT))); - runRepeatedMountTest(&internal, "QSPI"); - Serial.println("Formatting SD drive as LittleFS again: " + String(internal.format(FS_LITTLEFS))); - runRepeatedMountTest(&internal, "QSPI"); - Serial.println("Formatting SD drive as FAT32 again: " + String(internal.format(FS_FAT))); - runRepeatedMountTest(&internal, "QSPI"); - #endif + } diff --git a/extras/tests/TestUnified/TestUnified.ino b/extras/tests/TestUnified/TestUnified.ino index 7d48d6a..6123dea 100644 --- a/extras/tests/TestUnified/TestUnified.ino +++ b/extras/tests/TestUnified/TestUnified.ino @@ -8,27 +8,27 @@ #define HAS_QSPI #if defined(HAS_USB) -USBStorage * usb = new USBStorage(); +USBStorage usb = USBStorage(); #endif #if defined(HAS_SD) -SDStorage * sd = new SDStorage(); +SDStorage sd = SDStorage(); #endif #if defined(HAS_QSPI) -InternalStorage * qspi = new InternalStorage(); +InternalStorage qspi = InternalStorage(); #endif void test(String operation, Arduino_UnifiedStorage* sourceStorage, Arduino_UnifiedStorage* destinationStorage, const char* storageTypeA, const char* storageTypeB) { - Serial.println("----------------------------------------------------------"); - Serial.println("Running test for " + operation + " from " + String(storageTypeA) + " to " + String(storageTypeB) + "\n"); + printToSerialOrRS485("----------------------------------------------------------"); + printToSerialOrRS485("Running test for " + operation + " from " + String(storageTypeA) + " to " + String(storageTypeB) + "\n"); int mountSource = sourceStorage -> begin(); int mountDest = destinationStorage->begin(); - Serial.println("Mount " + String(storageTypeA) + ": " + mountSource); - Serial.println("Mount " + String(storageTypeB) + ": " + mountDest); + printToSerialOrRS485("Mount " + String(storageTypeA) + ": " + mountSource); printToSerialOrRS485("\n"); + printToSerialOrRS485("Mount " + String(storageTypeB) + ": " + mountDest); printToSerialOrRS485("\n"); if(mountSource && mountDest){ @@ -50,200 +50,208 @@ void test(String operation, Arduino_UnifiedStorage* sourceStorage, Arduino_Unifi } if (opperationResult) { - Serial.println(operation + " from " + String(storageTypeA) + " to " + String(storageTypeB) + " successful"); + printToSerialOrRS485(operation + " from " + String(storageTypeA) + " to " + String(storageTypeB) + " successful \n"); } - - Serial.println(); int unmountSource = sourceStorage->unmount(); int unmountDest = destinationStorage->unmount(); delay(1000); } else { - Serial.println("cannot execute test, fs not mounted"); + printToSerialOrRS485("cannot execute test, fs not mounted \n"); } } #if defined(HAS_USB) && defined(HAS_SD) void sd_and_usb(){ - Serial.println("TESTING SD AND USB \n\n\n\n"); + printToSerialOrRS485("TESTING SD AND USB \n\n\n\n"); - Serial.println("-----------------------------"); - Serial.println("Formatting USB to FAT: " + String(usb->format(FS_FAT))); - Serial.println("Formatting SD to FAT: " + String(sd->format(FS_FAT))); - Serial.println("-----------------------------"); + printToSerialOrRS485("-----------------------------"); printToSerialOrRS485("\n"); + printToSerialOrRS485("Formatting USB to FAT: " + String(usb.format(FS_FAT)));printToSerialOrRS485("\n"); + printToSerialOrRS485("Formatting SD to FAT: " + String(sd.format(FS_FAT)));printToSerialOrRS485("\n"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); - test("move", usb, sd, "USB FAT", "SD FAT"); - test("copy", usb, sd, "USB FAT", "SD FAT"); + test("move", &usb, &sd, "USB FAT", "SD FAT"); + test("copy", &usb, &sd, "USB FAT", "SD FAT"); - test("move", sd, usb, "SD FAT", "USB FAT"); - test("copy", sd, usb, "SD FAT", "USB FAT"); + test("move", &sd, &usb, "SD FAT", "USB FAT"); + test("copy", &sd, &usb, "SD FAT", "USB FAT"); - Serial.println("-----------------------------"); - Serial.println("Formatting USB to LittleFS:" + String(usb->format(FS_LITTLEFS))); - Serial.println("-----------------------------"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); + printToSerialOrRS485("Formatting USB to LittleFS:" + String(usb.format(FS_LITTLEFS)));printToSerialOrRS485("\n"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); - test("move", usb, sd, "USB LittleFS", "SD FAT "); - test("copy", usb, sd, "USB LittleFS", "SD FAT "); + test("move", &usb, &sd, "USB LittleFS", "SD FAT "); + test("copy", &usb, &sd, "USB LittleFS", "SD FAT "); - test("move", sd, usb, "SD FAT", "USB LittleFS"); - test("copy", sd, usb, "SD FAT", "USB LittleFS"); + test("move", &sd, &usb, "SD FAT", "USB LittleFS"); + test("copy", &sd, &usb, "SD FAT", "USB LittleFS"); - Serial.println("-----------------------------"); - Serial.println("Formatting SD to LittleFS: "+ String(sd->format(FS_LITTLEFS))); - Serial.println("-----------------------------"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); + printToSerialOrRS485("Formatting SD to LittleFS: "+ String(sd.format(FS_LITTLEFS)));printToSerialOrRS485("\n"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); - test("move", sd, usb, "SD LittleFS", "USB LittleFS"); - test("copy", sd, usb, "SD LittleFS", "USB LittleFS"); + test("move", &sd, &usb, "SD LittleFS", "USB LittleFS"); + test("copy", &sd, &usb, "SD LittleFS", "USB LittleFS"); - test("move", usb, sd, "USB LittleFS", "SD LittleFS"); - test("copy", usb, sd, "USB LittleFS", "SD LittleFS"); + test("move", &usb, &sd, "USB LittleFS", "SD LittleFS"); + test("copy", &usb, &sd, "USB LittleFS", "SD LittleFS"); - Serial.println("-----------------------------"); - Serial.println("Formatting USB to FAT: " + String(usb->format(FS_FAT))); - Serial.println("-----------------------------"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); + printToSerialOrRS485("Formatting USB to FAT: " + String(usb.format(FS_FAT)));printToSerialOrRS485("\n"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); - test("move", usb, sd, "USB FAT", "SD LittleFS"); - test("copy", usb, sd, "USB FAT", "SD LittleFS"); + test("move", &usb, &sd, "USB FAT", "SD LittleFS"); + test("copy", &usb, &sd, "USB FAT", "SD LittleFS"); - test("move", sd, usb, "SD LittleFS", "USB FAT"); - test("copy", sd, usb, "SD LittleFS", "USB FAT"); + test("move", &sd, &usb, "SD LittleFS", "USB FAT"); + test("copy", &sd, &usb, "SD LittleFS", "USB FAT"); } #endif #if defined(HAS_QSPI) && defined(HAS_SD) void qspi_and_sd() { - Serial.println("TESTING QSPI AND SD \n\n\n\n"); - Serial.println("-----------------------------"); - Serial.println("Formatting QSPI to FAT: " + String(qspi->format(FS_FAT))); - Serial.println("Formatting SD to FAT: " + String(sd->format(FS_FAT))); - Serial.println("-----------------------------"); - - test("move", qspi, sd, "QSPI FAT", "SD FAT"); - test("copy", qspi, sd, "QSPI FAT", "SD FAT"); + printToSerialOrRS485("TESTING QSPI AND SD \n\n\n\n"); + printToSerialOrRS485("-----------------------------"); + printToSerialOrRS485("Formatting QSPI to FAT: " + String(qspi.format(FS_FAT))); + printToSerialOrRS485("Formatting SD to FAT: " + String(sd.format(FS_FAT))); + printToSerialOrRS485("-----------------------------"); + + test("move", &qspi, &sd, "QSPI FAT", "SD FAT"); + test("copy", &qspi, &sd, "QSPI FAT", "SD FAT"); - test("move", sd, qspi, "SD FAT", "QSPI FAT"); - test("copy", sd, qspi, "SD FAT", "QSPI FAT"); + test("move", &sd, &qspi, "SD FAT", "QSPI FAT"); + test("copy", &sd, &qspi, "SD FAT", "QSPI FAT"); - Serial.println("-----------------------------"); - Serial.println("Formatting QSPI to LittleFS:" + String(qspi->format(FS_LITTLEFS))); - Serial.println("-----------------------------"); + printToSerialOrRS485("-----------------------------"); + printToSerialOrRS485("Formatting QSPI to LittleFS:" + String(qspi.format(FS_LITTLEFS))); + printToSerialOrRS485("-----------------------------"); - test("move", qspi, sd, "QSPI LittleFS", "SD FAT"); - test("copy", qspi, sd, "QSPI LittleFS", "SD FAT"); + test("move", &qspi, &sd, "QSPI LittleFS", "SD FAT"); + test("copy", &qspi, &sd, "QSPI LittleFS", "SD FAT"); - test("move", sd, qspi, "SD FAT", "QSPI LittleFS"); - test("copy", sd, qspi, "SD FAT", "QSPI LittleFS"); + test("move", &sd, &qspi, "SD FAT", "QSPI LittleFS"); + test("copy", &sd, &qspi, "SD FAT", "QSPI LittleFS"); - Serial.println("-----------------------------"); - Serial.println("Formatting SD to LittleFS: "+ String(sd->format(FS_LITTLEFS))); - Serial.println("-----------------------------"); + printToSerialOrRS485("-----------------------------"); + printToSerialOrRS485("Formatting SD to LittleFS: "+ String(sd.format(FS_LITTLEFS))); + printToSerialOrRS485("-----------------------------"); - test("move", qspi, sd, "QSPI LittleFS", "SD LittleFS"); - test("copy", qspi, sd, "QSPI LittleFS", "SD LittleFS"); + test("move", &qspi, &sd, "QSPI LittleFS", "SD LittleFS"); + test("copy", &qspi, &sd, "QSPI LittleFS", "SD LittleFS"); - test("move", sd, qspi, "SD LittleFS", "QSPI LittleFS"); - test("copy", sd, qspi, "SD LittleFS", "QSPI LittleFS"); + test("move", &sd, &qspi, "SD LittleFS", "QSPI LittleFS"); + test("copy", &sd, &qspi, "SD LittleFS", "QSPI LittleFS"); - Serial.println("-----------------------------"); - Serial.println("Formatting QSPI to FAT: " + String(qspi->format(FS_FAT))); - Serial.println("-----------------------------"); + printToSerialOrRS485("-----------------------------"); + printToSerialOrRS485("Formatting QSPI to FAT: " + String(qspi.format(FS_FAT))); + printToSerialOrRS485("-----------------------------"); - test("move", sd, qspi, "SD LittleFS", "QSPI FAT"); - test("copy", sd, qspi, "SD LittleFS", "QSPI FAT"); + test("move", &sd, &qspi, "SD LittleFS", "QSPI FAT"); + test("copy", &sd, &qspi, "SD LittleFS", "QSPI FAT"); - test("move", qspi, sd, "QSPI FAT", "SD LittleFS"); - test("copy", qspi, sd, "QSPI FAT", "SD LittleFS"); + test("move", &qspi, &sd, "QSPI FAT", "SD LittleFS"); + test("copy", &qspi, &sd, "QSPI FAT", "SD LittleFS"); } #endif #if defined(HAS_QSPI) && defined(HAS_USB) void qspi_and_usb() { - Serial.println("TESTING QSPI AND USB \n\n\n\n"); - Serial.println("-----------------------------"); - Serial.println("Formatting QSPI to FAT: " + String(qspi->format(FS_FAT))); - Serial.println("Formatting USB to FAT: " + String(usb->format(FS_FAT))); - Serial.println("-----------------------------"); - - test("move", qspi, usb, "QSPI FAT", "USB FAT"); - test("copy", qspi, usb, "QSPI FAT", "USB FAT"); + printToSerialOrRS485("TESTING QSPI AND USB \n\n\n\n"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); + qspi.begin(); + qspi.unmount(); + usb.begin(); + usb.unmount(); + + printToSerialOrRS485("Formatting USB to FAT: " + String(usb.format(FS_FAT)));printToSerialOrRS485("now formatting qspi"); + delay(1000); + printToSerialOrRS485("Formatting QSPI to FAT: " + String(qspi.format(FS_FAT)));printToSerialOrRS485("\n"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); + + test("move", &qspi, &usb, "QSPI FAT", "USB FAT"); + test("copy", &qspi, &usb, "QSPI FAT", "USB FAT"); - test("move", usb, qspi, "USB FAT", "QSPI FAT"); - test("copy", usb, qspi, "USB FAT", "QSPI FAT"); + test("move", &usb, &qspi, "USB FAT", "QSPI FAT"); + test("copy", &usb, &qspi, "USB FAT", "QSPI FAT"); - Serial.println("-----------------------------"); - Serial.println("Formatting QSPI to LittleFS:" + String(qspi->format(FS_LITTLEFS))); - Serial.println("-----------------------------"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); + printToSerialOrRS485("Formatting QSPI to LittleFS:" + String(qspi.format(FS_LITTLEFS)));printToSerialOrRS485("\n"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); - test("move", qspi, usb, "QSPI LittleFS", "USB FAT"); - test("copy", qspi, usb, "QSPI LittleFS", "USB FAT"); + test("move", &qspi, &usb, "QSPI LittleFS", "USB FAT"); + test("copy", &qspi, &usb, "QSPI LittleFS", "USB FAT"); - test("move", usb, qspi, "USB FAT", "QSPI LittleFS"); - test("copy", usb, qspi, "USB FAT", "QSPI LittleFS"); + test("move", &usb, &qspi, "USB FAT", "QSPI LittleFS"); + test("copy", &usb, &qspi, "USB FAT", "QSPI LittleFS"); - Serial.println("-----------------------------"); - Serial.println("Formatting USB to LittleFS: "+ String(usb->format(FS_LITTLEFS))); - Serial.println("-----------------------------"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); + printToSerialOrRS485("Formatting USB to LittleFS: "+ String(usb.format(FS_LITTLEFS)));printToSerialOrRS485("\n"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); - test("move", qspi, usb, "QSPI LittleFS", "USB LittleFS"); - test("copy", qspi, usb, "QSPI LittleFS", "USB LittleFS"); + test("move", &qspi, &usb, "QSPI LittleFS", "USB LittleFS"); + test("copy", &qspi, &usb, "QSPI LittleFS", "USB LittleFS"); - test("move", usb, qspi, "USB LittleFS", "QSPI LittleFS"); - test("copy", usb, qspi, "USB LittleFS", "QSPI LittleFS"); + test("move", &usb, &qspi, "USB LittleFS", "QSPI LittleFS"); + test("copy", &usb, &qspi, "USB LittleFS", "QSPI LittleFS"); - Serial.println("-----------------------------"); - Serial.println("Formatting QSPI to FAT:" + String(qspi->format(FS_FAT))); - Serial.println("-----------------------------"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); + printToSerialOrRS485("Formatting QSPI to FAT:" + String(qspi.format(FS_FAT)));printToSerialOrRS485("\n"); + printToSerialOrRS485("-----------------------------");printToSerialOrRS485("\n"); - test("move", usb, qspi, "USB LittleFS", "QSPI FAT"); - test("copy", usb, qspi, "USB LittleFS", "QSPI FAT"); + test("move", &usb, &qspi, "USB LittleFS", "QSPI FAT"); + test("copy", &usb, &qspi, "USB LittleFS", "QSPI FAT"); - test("move", qspi, usb, "QSPI FAT", "USB LittleFS"); - test("copy", qspi, usb, "QSPI FAT", "USB LittleFS"); + test("move", &qspi, &usb, "QSPI FAT", "USB LittleFS"); + test("copy", &qspi, &usb, "QSPI FAT", "USB LittleFS"); } #endif void setup(){ - Serial.begin(115200); - while(!Serial); + #if defined(ARDUINO_PORTENTA_C33) || defined(ARDUINO_PORTENTA_H7_M7) + Serial.begin(115200); + while(!Serial); + #elif defined(ARDUINO_OPTA) + beginRS485(115200); + #endif #if defined(HAS_USB) && defined(HAS_SD) && defined(HAS_QSPI) qspi_and_usb(); sd_and_usb(); qspi_and_sd(); - Serial.println("Tests finished, formatting all partitions back to FAT:"); - Serial.println("\t * Formatting QSPI to FAT: " + String(qspi->format(FS_FAT))); - Serial.println("\t * Formatting SD to FAT: " + String(sd->format(FS_FAT))); - Serial.println("\t * Formatting USB to FAT: " + String(usb->format(FS_FAT))); + printToSerialOrRS485("Tests finished, formatting all partitions back to FAT:"); + printToSerialOrRS485("\t * Formatting QSPI to FAT: " + String(qspi.format(FS_FAT))); + printToSerialOrRS485("\t * Formatting SD to FAT: " + String(sd.format(FS_FAT))); + printToSerialOrRS485("\t * Formatting USB to FAT: " + String(usb.format(FS_FAT))); #elif defined(HAS_USB) && defined(HAS_SD) sd_and_usb(); - Serial.println("\t * Formatting SD to FAT:" + String(sd->format(FS_FAT))); - Serial.println("\t * Formatting USB to FAT:" + String(usb->format(FS_FAT))); + printToSerialOrRS485("\t * Formatting SD to FAT:" + String(sd.format(FS_FAT))); + printToSerialOrRS485("\t * Formatting USB to FAT:" + String(usb.format(FS_FAT))); #elif defined(HAS_USB) && defined(HAS_QSPI) qspi_and_usb(); - Serial.println("Tests finished, formatting all partitions back to FAT:"); - Serial.println("\t * Formatting QSPI to FAT:" + String(qspi->format(FS_FAT))); - Serial.println("\t * Formatting USB to FAT:" + String(usb->format(FS_FAT))); + printToSerialOrRS485("Tests finished, formatting all partitions back to FAT:");printToSerialOrRS485("\n"); + printToSerialOrRS485("\t * Formatting QSPI to FAT:" + String(qspi.format(FS_FAT)));printToSerialOrRS485("\n"); + printToSerialOrRS485("\t * Formatting USB to FAT:" + String(usb.format(FS_FAT)));printToSerialOrRS485("\n"); #elif defined(HAS_SD) && defined(HAS_QSPI) qspi_and_sd(); - Serial.println("Tests finished, formatting all partitions back to FAT:"); - Serial.println("\t * Formatting QSPI to FAT:" + String(qspi->format(FS_FAT))); - Serial.println("\t * Formatting SD to FAT:" + String(sd->format(FS_FAT))); + printToSerialOrRS485("Tests finished, formatting all partitions back to FAT:"); + printToSerialOrRS485("\t * Formatting QSPI to FAT:" + String(qspi.format(FS_FAT))); + printToSerialOrRS485("\t * Formatting SD to FAT:" + String(sd.format(FS_FAT))); #elif defined(HAS_USB) - Serial.println("Cannot perform tests if only one storage type is selected"); + printToSerialOrRS485("Cannot perform tests if only one storage type is selected"); #elif defined(HAS_SD) - Serial.println("Cannot perform tests if only one storage type is selected"); + printToSerialOrRS485("Cannot perform tests if only one storage type is selected"); #elif defined(HAS_QSPI) - Serial.println("Cannot perform tests if only one storage type is selected"); + printToSerialOrRS485("Cannot perform tests if only one storage type is selected"); #else - Serial.println("Cannot perform tests if no storage type is selected"); + printToSerialOrRS485("Cannot perform tests if no storage type is selected"); #endif } diff --git a/library.properties b/library.properties index d81d519..f3f1e04 100644 --- a/library.properties +++ b/library.properties @@ -2,7 +2,7 @@ name=Arduino_UnifiedStorage version=1.0.0 author=Arduino maintainer=Arduino -sentence=Simplify cross-device storage management on Portenta platforms with a single library supporting SD, Flash, and USB storage access. +sentence=Simplify cross-device storage management on Portenta platforms with a single library supporting &sd, Flash, and USB storage access. paragraph=With this versatile library, you can seamlessly handle various storage types without the need for separate, device-specific libraries. Develop data logging, file storage, or data transfer applications, with a consistent interface. All while reducing development time and ensuring compatibility across the Portenta C33, Portenta H7, and Portenta Machine Control platforms. category=Data Storage url=https://github.com/arduino-libraries/Arduino_UnifiedStorage diff --git a/src/Arduino_UnifiedStorage.h b/src/Arduino_UnifiedStorage.h index ecb9f10..a87bac2 100644 --- a/src/Arduino_UnifiedStorage.h +++ b/src/Arduino_UnifiedStorage.h @@ -1,29 +1,22 @@ + #ifndef UnifiedStorage_H #define UnifiedStorage_H +#include "Arduino.h" +#include "Arduino_POSIXStorage.h" +#include "Boards.h" +#include "Utils.h" +#include "Types.h" +#include "Partitioning.h" + #include "Folder.h" #include "UFile.h" -#if defined(ARDUINO_PORTENTA_C33) -#include "Types.h" -#include "Arduino.h" -#include "Arduino_POSIXStorage.h" -#endif - #if defined(ARDUINO_PORTENTA_C33) - #include "QSPIFlashBlockDevice.h" - #include - #include - #include "FATFileSystem.h" - #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) || defined(ARDUINO_OPTA) - #include "QSPIFBlockDevice.h" - #include "MBRBlockDevice.h" - #include "FATFileSystem.h" - #endif /** @@ -66,15 +59,17 @@ class Arduino_UnifiedStorage { }; -#if defined(ARDUINO_PORTENTA_C33) || defined(ARDUINO_PORTENTA_H7_M7) - #include "USBStorage.h" - #include "SDStorage.h" - #include "InternalStorage.h" -#elif defined(ARDUINO_OPTA) - #include "USBStorage.h" - #include "InternalStorage.h" -#endif + #if defined(HAS_USB) + #include "USBStorage.h" + #endif + + #if defined(HAS_SD) + #include "SDStorage.h" + #endif + #if defined(HAS_QSPI) + #include "InternalStorage.h" + #endif #endif diff --git a/src/Boards.h b/src/Boards.h new file mode 100644 index 0000000..a9341f5 --- /dev/null +++ b/src/Boards.h @@ -0,0 +1,29 @@ +#if defined(ARDUINO_PORTENTA_C33) + #define HAS_SD + #define HAS_USB + #define HAS_QSPI + #define USES_RENESAS_CORE +#endif + +#if defined(ARDUINO_PORTENTA_H7_M7) + #define HAS_SD + #define HAS_USB + #define HAS_QSPI + #define USES_MBED_CORE +#endif + +#if defined(ARDUINO_OPTA) + #define HAS_USB + #define HAS_QSPI + #define USES_MBED_CORE +#endif + +#if defined(ARDUINO_NICLA_VISION) + #define HAS_QSPI + #define USES_MBED_CORE +#endif + + + + + diff --git a/src/Folder.h b/src/Folder.h index db3b5f9..f2c66f4 100644 --- a/src/Folder.h +++ b/src/Folder.h @@ -1,10 +1,10 @@ #ifndef Folder_H #define Folder_H -#include "Types.h" -#include "UFile.h" - +#include "Utils.h" +#include "UFile.h" +#include class UFile; /** diff --git a/src/InternalStorage.cpp b/src/InternalStorage.cpp index 2fa300f..ce763c6 100644 --- a/src/InternalStorage.cpp +++ b/src/InternalStorage.cpp @@ -1,16 +1,10 @@ #include "Arduino_UnifiedStorage.h" InternalStorage::InternalStorage(){ - - #if defined(ARDUINO_PORTENTA_C33) - this -> setQSPIPartition(2); - #elif defined(ARDUINO_PORTENTA_H7_M7) - this -> setQSPIPartition(3); - #endif - this -> setQSPIPartitionName("user"); } + InternalStorage::InternalStorage(int partition, const char * name, FileSystems fs){ this -> setQSPIPartition(partition); this -> setQSPIPartitionName(name); @@ -22,39 +16,24 @@ bool InternalStorage::begin(FileSystems fs){ return this -> begin(); } +bool InternalStorage::partition(std::vector partitions){ + Partitioning::partitionDrive(QSPIFBlockDeviceType::get_default_instance(), partitions); +} + + + bool InternalStorage::begin(){ - #if defined(ARDUINO_PORTENTA_C33) - this -> blockDevice = BlockDevice::get_default_instance(); - this -> userData = new MBRBlockDevice(this->blockDevice, this->partitionNumber); + this -> blockDevice = BlockDeviceType::get_default_instance(); + this -> userData = new MBRBlockDeviceType(this->blockDevice, this->partitionNumber); + if(this -> fileSystem == FS_FAT){ - this -> userDataFileSystem = new FATFileSystem(this->partitionName); + this -> userDataFileSystem = new FATFileSystemType(this->partitionName); } else { - this -> userDataFileSystem = new LittleFileSystem(this->partitionName); + this -> userDataFileSystem = new LittleFileSystemType(this->partitionName); } - int err = this -> userDataFileSystem -> mount(userData); - return err == 0; - #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_OPTA) - this -> blockDevice = QSPIFBlockDevice::get_default_instance(); - this -> userData = new mbed::MBRBlockDevice(this->blockDevice, this->partitionNumber); - if(this -> fileSystem == FS_FAT){ - - if(this -> userDataFileSystem != nullptr){ - delete(this -> userDataFileSystem); - } - this -> userDataFileSystem = new mbed::FATFileSystem(this->partitionName); - } else { - - if(this -> userDataFileSystem != nullptr){ - delete(this -> userDataFileSystem); - } - this -> userDataFileSystem = new mbed::LittleFileSystem(this->partitionName); - } - int err = this -> userDataFileSystem -> mount(this -> userData); + int err = this -> userDataFileSystem -> mount(userData); return err == 0; - #else - return false; // Unsupported board - #endif } bool InternalStorage::unmount(){ @@ -79,38 +58,18 @@ bool InternalStorage::format(FileSystems fs){ this -> unmount(); this -> fileSystem = fs; - if(fs == FS_FAT){ - #if defined(ARDUINO_PORTENTA_C33) - this -> userDataFileSystem = new FATFileSystem(this->partitionName); - return this -> userDataFileSystem -> reformat(this-> userData) == 0; - #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_OPTA) - this -> userDataFileSystem = new mbed::FATFileSystem(this->partitionName); + this -> userDataFileSystem = new FATFileSystemType(this->partitionName); return this -> userDataFileSystem -> reformat(this-> userData) == 0; - #endif } if (fs == FS_LITTLEFS) { - #if defined(ARDUINO_PORTENTA_C33) - this -> userDataFileSystem = new LittleFileSystem(this->partitionName); + this -> userDataFileSystem = new LittleFileSystemType(this->partitionName); return this -> userDataFileSystem -> reformat(this-> userData) == 0; - #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_OPTA) - this -> userDataFileSystem = new mbed::LittleFileSystem(this->partitionName); - return this -> userDataFileSystem -> reformat(this-> userData) == 0; - #endif } return false; } -#if defined(ARDUINO_PORTENTA_C33) -BlockDevice * InternalStorage::getBlockDevice(){ - return this -> blockDevice; -} -#endif - -#if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_OPTA) -mbed::BlockDevice * InternalStorage::getBlockDevice(){ +BlockDeviceType * InternalStorage::getBlockDevice(){ return this -> blockDevice; -} - -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/InternalStorage.h b/src/InternalStorage.h index 83e0f83..5a9ab8f 100644 --- a/src/InternalStorage.h +++ b/src/InternalStorage.h @@ -2,6 +2,8 @@ #define InternalStorage_H #include "Arduino_UnifiedStorage.h" +#include "Types.h" + /** * Represents internal storage using the Arduino Unified Storage library. @@ -78,30 +80,24 @@ class InternalStorage : public Arduino_UnifiedStorage { * * @return The block device as a BlockDevice object. */ - #if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_OPTA) - mbed::BlockDevice *getBlockDevice(); - #endif - #if defined(ARDUINO_PORTENTA_C33) - BlockDevice *getBlockDevice(); - #endif + BlockDeviceType *getBlockDevice(); + + static bool partition(std::vector partitions); + // partition() -> one Partition + // restoreDefaultPartitions(); private: - #if defined(ARDUINO_PORTENTA_C33) - BlockDevice * blockDevice; - MBRBlockDevice * userData; - FileSystem * userDataFileSystem; + BlockDeviceType * blockDevice; + MBRBlockDeviceType * userData; + FileSystemType * userDataFileSystem; int partitionNumber = 2; - #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_OPTA) - mbed::BlockDevice * blockDevice; - mbed::MBRBlockDevice * userData; - mbed::FileSystem * userDataFileSystem; - int partitionNumber = 3; - #endif - - char * partitionName; + + char * partitionName ; FileSystems fileSystem; + bool entireDrive = false; }; + #endif \ No newline at end of file diff --git a/src/Partitioning.cpp b/src/Partitioning.cpp new file mode 100644 index 0000000..b26cad5 --- /dev/null +++ b/src/Partitioning.cpp @@ -0,0 +1,99 @@ + +#include + + bool Partitioning::eraseMBRSector(BlockDeviceType * bd) +{ + #define MBR_BLOCK_SIZE 4096 + unsigned char buffer[MBR_BLOCK_SIZE]; + memset(buffer, 0xFF, sizeof(buffer)); + + if(bd-> program(buffer, 0, sizeof(buffer)) == 0){ + if(bd -> erase(0, MBR_BLOCK_SIZE) == 0){ + return true; + } else { + return false; + } + } else { + return false; + } +} + + bool Partitioning::isPartitionSchemeValid(BlockDeviceType * bd, std::vector partitions){ + size_t driveSize = bd -> size() / 1024; // + int totalSize = 0; + + for (size_t i = 1; i < partitions.size() + 1; ++i) { + Partition thisPartition = partitions[i - 1]; + totalSize += thisPartition.size; + } + + if(totalSize <= driveSize && partitions.size() <= 4){ + return true; + } else { + return false; + } +} + + bool Partitioning::formatPartition(BlockDeviceType * bd, int partitionNumber, FileSystems fs){ + #define DEFAULT_FS_LABEL "label" + MBRBlockDeviceType * thisPartition; + thisPartition = new MBRBlockDeviceType(bd, partitionNumber); + if(thisPartition != NULL){ + FileSystemType * thisFileSystem; + + if (fs == FS_FAT){ + thisFileSystem = new FATFileSystemType(DEFAULT_FS_LABEL); + } else if (fs == FS_LITTLEFS){ + thisFileSystem = new LittleFileSystemType(DEFAULT_FS_LABEL); + } + + if(thisFileSystem->reformat(thisPartition) == 0){ + delete(thisFileSystem); + delete(thisPartition); + return true; + } else { + return false; + } + } else { + return false; + } +} + + bool Partitioning::createAndFormatPartitions(BlockDeviceType * bd, std::vector partitions){ + + bool success = false; + int lastPartitionEnd = 0; + + for (size_t i = 1; i < partitions.size() + 1; ++i) { + int thisPartitionEnd = (partitions[i - 1].size * 1024) + lastPartitionEnd; + + if(MBRBlockDeviceType::partition(bd, i , 0x0B, lastPartitionEnd, thisPartitionEnd) == 0){ + success = formatPartition(bd, i, partitions[i - 1].fs); + } else { + success = false; + } + + lastPartitionEnd = thisPartitionEnd; + } + + return success; +} + + bool Partitioning::partitionDrive(BlockDeviceType * bd, std::vector partitions){ + bd -> init(); + + if(isPartitionSchemeValid(bd, partitions)){ + if(eraseMBRSector(bd)){ + if(createAndFormatPartitions(bd, partitions)){ + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } +} + \ No newline at end of file diff --git a/src/Partitioning.h b/src/Partitioning.h new file mode 100644 index 0000000..f0f76bf --- /dev/null +++ b/src/Partitioning.h @@ -0,0 +1,21 @@ + +#include "Arduino.h" +#include "Types.h" +#include "Arduino_POSIXStorage.h" +#include + +struct Partition { + int size; + FileSystems fs; +}; + +class Partitioning{ + public: + static bool eraseMBRSector(BlockDeviceType * bd); + static bool partitionDrive(BlockDeviceType * bd, std::vector partitions); + private: + static bool isPartitionSchemeValid(BlockDeviceType * bd, std::vector partitions); + static bool formatPartition(BlockDeviceType * bd, int partitionNumber, FileSystems fs); + static bool createAndFormatPartitions(BlockDeviceType * bd, std::vector partitions); + +}; diff --git a/src/SDStorage.h b/src/SDStorage.h index ab30b44..48f5ed6 100644 --- a/src/SDStorage.h +++ b/src/SDStorage.h @@ -5,7 +5,6 @@ #include "Arduino_UnifiedStorage.h" -#if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_C33) || !defined(ARDUINO_OPTA) /** * Represents an SD card storage using the Arduino Unified Storage library. @@ -59,5 +58,3 @@ class SDStorage: public Arduino_UnifiedStorage { }; #endif - -#endif \ No newline at end of file diff --git a/src/Types.h b/src/Types.h index 7377433..8c62402 100644 --- a/src/Types.h +++ b/src/Types.h @@ -1,150 +1,29 @@ - -#ifndef Types_H -#define Types_H -#define PATH_MAX 255 - -#include "Arduino.h" -#include "Arduino_POSIXStorage.h" -#include -#include - -[[gnu::unused]] static bool copyFolder(const char* source, const char* destination) { - DIR* dir = opendir(source); - if (dir == nullptr) { - printf("Failed to open source directory\n"); - return false; - } - - // Create destination directory if it doesn't exist - if (mkdir(destination, 0777) != 0 && errno != EEXIST) { - printf("Failed to create destination directory\n"); - closedir(dir); - return false; - } - - struct dirent* entry; - while ((entry = readdir(dir)) != nullptr) { - if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - char sourcePath[PATH_MAX]; - snprintf(sourcePath, PATH_MAX, "%s/%s", source, entry->d_name); - - char destinationPath[PATH_MAX]; - snprintf(destinationPath, PATH_MAX, "%s/%s", destination, entry->d_name); - - struct stat fileInfo; - if (stat(sourcePath, &fileInfo) != 0) { - closedir(dir); - return false; - } - - if (S_ISDIR(fileInfo.st_mode)) { - // Recursively copy subdirectories - if (!copyFolder(sourcePath, destinationPath)) { - closedir(dir); - return false; - } - } else { - // Copy regular files - FILE* sourceFile = fopen(sourcePath, "r"); - if (sourceFile == nullptr) { - - closedir(dir); - return false; - } - - FILE* destinationFile = fopen(destinationPath, "w"); - if (destinationFile == nullptr) { - fclose(sourceFile); - closedir(dir); - return false; - } - - int c; - while ((c = fgetc(sourceFile)) != EOF) { - fputc(c, destinationFile); - } - - fclose(sourceFile); - fclose(destinationFile); - } - } - } - - closedir(dir); - return true; -} - -[[gnu::unused]] static std::string replaceLastPathComponent(const std::string& path, const std::string& newComponent) { - size_t lastSlashIndex = path.find_last_of('/'); - if (lastSlashIndex != std::string::npos) { - std::string newPath = path.substr(0, lastSlashIndex + 1) + newComponent; - return newPath; - } - return path; -} - -// Helper function to get the last path component -[[gnu::unused]] static std::string getLastPathComponent(const std::string& path) { - size_t lastSlashIndex = path.find_last_of('/'); - if (lastSlashIndex != std::string::npos) { - return path.substr(lastSlashIndex + 1); - } - return path; -} - -// Helper function to replace the first path component with a new component -[[gnu::unused]] static std::string replaceFirstPathComponent(const std::string& path, const std::string& destinationPath) { - std::string fileName = getLastPathComponent(path); - std::string newPath = destinationPath + "/" + fileName; - return newPath; -} - - inline static String getErrno(){ - switch (errno) { - case ENOENT: - return "No such file or directory"; - case EEXIST: - return "File or directory already exists"; - case EIO: - return "Input/output error"; - case ENOTDIR: - return "Not a directory"; - case EISDIR: - return "Is a directory"; - case ENFILE: - return "Too many open files in system"; - case EMFILE: - return "Too many open files"; - case ENOSPC: - return "No space left on device"; - case ENAMETOOLONG: - return "File name too long"; - case EPERM: - return "Operation not permitted"; - case ENODEV: - return "No such device"; - case ENOTBLK: - return "Not a block device"; - case EBUSY: - return "Device or resource busy"; - case EAGAIN: - return "Resource temporarily unavailable"; - case ENXIO: - return "No such device or address"; - case ENOMEM: - return "Out of memory"; - case EACCES: - return "Permission denied"; - case EROFS: - return "Read-only file system"; - case EINVAL: - return "Invalid argument"; - default: - return "Undefined Error"; - } -} - -enum FileMode { READ, WRITE, APPEND }; - -#endif \ No newline at end of file +#include "Boards.h" + +#if defined(USES_RENESAS_CORE) + #include "BlockDevice.h" + #include "MBRBlockDevice.h" + #include "LittleFileSystem.h" + #include "FATFileSystem.h" + + typedef BlockDevice QSPIFBlockDeviceType; + typedef MBRBlockDevice MBRBlockDeviceType; + typedef BlockDevice BlockDeviceType; + typedef FATFileSystem FATFileSystemType; + typedef LittleFileSystem LittleFileSystemType; + typedef FileSystem FileSystemType; + +#elif defined(USES_MBED_CORE) + #include "QSPIFBlockDevice.h" + #include "MBRBlockDevice.h" + #include "LittleFileSystem.h" + #include "FATFileSystem.h" + + typedef QSPIFBlockDevice QSPIFBlockDeviceType; + typedef mbed::MBRBlockDevice MBRBlockDeviceType; + typedef mbed::BlockDevice BlockDeviceType; + typedef mbed::FATFileSystem FATFileSystemType; + typedef mbed::LittleFileSystem LittleFileSystemType; + typedef mbed::FileSystem FileSystemType; +#endif diff --git a/src/UFile.h b/src/UFile.h index b1679c1..7a1cf52 100644 --- a/src/UFile.h +++ b/src/UFile.h @@ -3,7 +3,8 @@ #include #include -#include "Types.h" +#include +#include "Utils.h" class Folder; #include "Folder.h" diff --git a/src/USBStorage.cpp b/src/USBStorage.cpp index 43ee1f8..e4289e5 100644 --- a/src/USBStorage.cpp +++ b/src/USBStorage.cpp @@ -1,6 +1,6 @@ #include "USBStorage.h" -#if defined(ARDUINO_PORTENTA_H7_M7) +#if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_OPTA) #include #endif @@ -16,6 +16,23 @@ bool USBStorage::begin(FileSystems fs){ return this -> begin(); } +void USBStorage::onConnect(void (* const callbackFunction)()){ + register_hotplug_callback(DEV_USB, callbackFunction); +} + +void USBStorage::removeOnConnectCallback(){ + deregister_hotplug_callback(DEV_USB); +} + +void USBStorage::onDisconnect(void (* const callbackFunction)()){ + register_unplug_callback(DEV_USB, callbackFunction); +} + +void USBStorage::removeOnDisconnectCallback(){ + deregister_unplug_callback(DEV_USB); +} + + bool USBStorage::begin(){ int attempts = 0; int err = mount(DEV_USB, this->fileSystem, MNT_DEFAULT); @@ -27,12 +44,14 @@ bool USBStorage::begin(){ } if(err == 0){ - this -> connected = true; + this -> mounted = true; } else { - this -> connected = false; + this -> mounted = false; } return err == 0; + + } bool USBStorage::unmount(){ @@ -40,7 +59,7 @@ bool USBStorage::unmount(){ if(unmountResult == 0){ - this -> connected = false; + this -> mounted = false; } return unmountResult == 0; @@ -51,12 +70,12 @@ Folder USBStorage::getRootFolder(){ } -bool USBStorage::isConnected(){ - return this -> connected; +bool USBStorage::isMounted(){ + return this -> mounted; } - bool USBStorage::format(FileSystems fs){ + if(fs == FS_FAT){ this -> begin(); this -> unmount(); diff --git a/src/USBStorage.h b/src/USBStorage.h index 3cd682f..e6ff3ff 100644 --- a/src/USBStorage.h +++ b/src/USBStorage.h @@ -1,8 +1,9 @@ -#include "Arduino_UnifiedStorage.h" + #ifndef USBStorage_H #define USBStorage_H +#include "Arduino_UnifiedStorage.h" /** * Represents a USB storage using the Arduino Unified Storage library. */ @@ -55,17 +56,22 @@ class USBStorage : public Arduino_UnifiedStorage { * * @return true if connected, false otherwise. */ - bool isConnected(); + bool isMounted(); + + void onConnect(void (* const callbackFunction)()); + void removeOnConnectCallback(); + void onDisconnect(void (* const callbackFunction)()); + void removeOnDisconnectCallback(); private: FileSystems fileSystem = FS_FAT; - bool connected = false; + bool mounted = false; unsigned long previousMillis; - unsigned int interval = 500; + unsigned int interval = 500; // document what this does too, make it constexp (mountRetryInterval) }; #endif diff --git a/src/Utils.h b/src/Utils.h new file mode 100644 index 0000000..0013544 --- /dev/null +++ b/src/Utils.h @@ -0,0 +1,177 @@ + + +#ifndef Utils_H +#define Utils_H +#define PATH_MAX 255 + +#include "Arduino.h" +#include "Arduino_POSIXStorage.h" +#include + + + +#if defined(ARDUINO_OPTA) +#include + +static void beginRS485(const int baudrate) +{ + const auto bitduration { 1.f / baudrate }; + const auto wordlen { 9.6f }; // OR 10.0f depending on the channel configuration + const auto preDelayBR { bitduration * wordlen * 3.5f * 1e6 }; + const auto postDelayBR { bitduration * wordlen * 3.5f * 1e6 }; + + RS485.begin(baudrate); + RS485.setDelays(preDelayBR, postDelayBR); + RS485.noReceive(); +} +#endif + +[[gnu::unused]] static int printToSerialOrRS485(String s){ + #if defined(ARDUINO_PORTENTA_C33) || defined(ARDUINO_PORTENTA_H7_M7) + Serial.print(s); + #elif defined(ARDUINO_OPTA) + RS485.beginTransmission(); + RS485.write(s.c_str(), strlen(s.c_str())); + RS485.endTransmission(); + #endif +} + +[[gnu::unused]] static bool copyFolder(const char* source, const char* destination) { + DIR* dir = opendir(source); + if (dir == nullptr) { + printf("Failed to open source directory\n"); + return false; + } + + // Create destination directory if it doesn't exist + if (mkdir(destination, 0777) != 0 && errno != EEXIST) { + printf("Failed to create destination directory\n"); + closedir(dir); + return false; + } + + struct dirent* entry; + while ((entry = readdir(dir)) != nullptr) { + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { + char sourcePath[PATH_MAX]; + snprintf(sourcePath, PATH_MAX, "%s/%s", source, entry->d_name); + + char destinationPath[PATH_MAX]; + snprintf(destinationPath, PATH_MAX, "%s/%s", destination, entry->d_name); + + struct stat fileInfo; + if (stat(sourcePath, &fileInfo) != 0) { + closedir(dir); + return false; + } + + if (S_ISDIR(fileInfo.st_mode)) { + // Recursively copy subdirectories + if (!copyFolder(sourcePath, destinationPath)) { + closedir(dir); + return false; + } + } else { + // Copy regular files + FILE* sourceFile = fopen(sourcePath, "r"); + if (sourceFile == nullptr) { + + closedir(dir); + return false; + } + + FILE* destinationFile = fopen(destinationPath, "w"); + if (destinationFile == nullptr) { + fclose(sourceFile); + closedir(dir); + return false; + } + + int c; + while ((c = fgetc(sourceFile)) != EOF) { + fputc(c, destinationFile); + } + + fclose(sourceFile); + fclose(destinationFile); + } + } + } + + closedir(dir); + return true; +} + +[[gnu::unused]] static std::string replaceLastPathComponent(const std::string& path, const std::string& newComponent) { + size_t lastSlashIndex = path.find_last_of('/'); + if (lastSlashIndex != std::string::npos) { + std::string newPath = path.substr(0, lastSlashIndex + 1) + newComponent; + return newPath; + } + return path; +} + +// Helper function to get the last path component +[[gnu::unused]] static std::string getLastPathComponent(const std::string& path) { + size_t lastSlashIndex = path.find_last_of('/'); + if (lastSlashIndex != std::string::npos) { + return path.substr(lastSlashIndex + 1); + } + return path; +} + +// Helper function to replace the first path component with a new component +[[gnu::unused]] static std::string replaceFirstPathComponent(const std::string& path, const std::string& destinationPath) { + std::string fileName = getLastPathComponent(path); + std::string newPath = destinationPath + "/" + fileName; + return newPath; +} + + inline static String getErrno(){ + switch (errno) { + case ENOENT: + return "No such file or directory"; + case EEXIST: + return "File or directory already exists"; + case EIO: + return "Input/output error"; + case ENOTDIR: + return "Not a directory"; + case EISDIR: + return "Is a directory"; + case ENFILE: + return "Too many open files in system"; + case EMFILE: + return "Too many open files"; + case ENOSPC: + return "No space left on device"; + case ENAMETOOLONG: + return "File name too long"; + case EPERM: + return "Operation not permitted"; + case ENODEV: + return "No such device"; + case ENOTBLK: + return "Not a block device"; + case EBUSY: + return "Device or resource busy"; + case EAGAIN: + return "Resource temporarily unavailable"; + case ENXIO: + return "No such device or address"; + case ENOMEM: + return "Out of memory"; + case EACCES: + return "Permission denied"; + case EROFS: + return "Read-only file system"; + case EINVAL: + return "Invalid argument"; + default: + return "Undefined Error"; + } +} + +enum FileMode { READ, WRITE, APPEND }; + +#endif \ No newline at end of file