Skip to content

Commit 083b2ce

Browse files
added opta logger
1 parent 21e28f1 commit 083b2ce

File tree

12 files changed

+540
-135
lines changed

12 files changed

+540
-135
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The Arduino_UnifiedStorage library provides a unified interface to access differ
66

77

88
## Examples
9-
* [**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
9+
* [**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
1010
* [**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
1111
* [**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.
1212

@@ -40,9 +40,9 @@ The Arduino_UnifiedStorage library provides a unified interface to access differ
4040
## Compatibility
4141
This library has been tested with the following STM32 and Renesas based Arduino boards. The availability of storage mediums depends on the hardware interfaces:
4242
* Portenta Machine Control: USB and Internal QSPI Flash
43-
* Portenta H7 + Portenta Breakout: USB, SD, and QSPI
43+
* Portenta H7 + Portenta Breakout: USB, &sd, and QSPI
4444
* Portenta H7 + Vision Shield: SD and QSPI
45-
* Portenta C33 + Portenta Breakout: USB, SD, and QSPI
45+
* Portenta C33 + Portenta Breakout: USB, &sd, and QSPI
4646
* Portenta C33 + Vision Shield: SD and QSPI
4747
* Opta: Internal QSPI Flash and USB
4848

examples/OptaLogger/OptaLogger.ino

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*
2+
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.
3+
4+
The code defines two main functions: "logData" and "performUpdate".
5+
The "logData" function logs sensor data by reading an analog sensor and writing the data to the log file.
6+
7+
The "performUpdate" function performs the update process by:
8+
* reading the last update size from a file (number of bytes)
9+
* copying the new data from the log file to a backup file
10+
* and updating the last update size.
11+
12+
INSTRUCTIONS
13+
* Make sure the QSPI storage of your board is properly partitioned.
14+
* You can do that by flashing the QSPIFormat example that can be found in the STM32H747_System folder
15+
* Open the serial monitor and select answer with "Y" when this appears "Do you want to use partition scheme 1? Y/[n]"
16+
* Reboot the board
17+
* This sketch will log data, and check if there is any USB MSD Device connected to the USB Port of the Opta.
18+
The USB device is mounted and unmounted after every update operation. The first status LED is on when the USB drive is mounted.
19+
So as long as the status LED is off you can safely remove the drive.
20+
The sketch will log to internal storage in the meantime, and wait for the USB drive to be inserted again.
21+
*/
22+
23+
#include "Arduino_UnifiedStorage.h"
24+
#include <vector>
25+
#include <Output.h>
26+
27+
constexpr auto baudrate { 115200 };
28+
29+
30+
#define USB_MOUNTED_LED LED_D0
31+
32+
33+
34+
InternalStorage internalStorage = InternalStorage();
35+
USBStorage usbStorage = USBStorage();
36+
std::vector<String> sensorDataBuffer;
37+
38+
unsigned long bytesWritten = 0;
39+
unsigned long lastLog = 0;
40+
unsigned long lastMove = 0;
41+
unsigned long lastBackup = 0;
42+
43+
44+
volatile bool usbAvailable = false;
45+
bool backingUP = false;
46+
47+
void connectionCallback(){
48+
usbAvailable = true;
49+
}
50+
51+
void disconnectionCallback(){
52+
usbAvailable = false;
53+
}
54+
// Function to run a given method periodically
55+
void runPeriodically(void (*method)(), unsigned long interval, unsigned long* variable) {
56+
unsigned long currentMillis = millis();
57+
58+
if (currentMillis - *variable >= interval) {
59+
*variable = currentMillis;
60+
method(); // Call the provided method
61+
}
62+
}
63+
64+
// Function to log sensor data
65+
void logDataToRAM() {
66+
int timeStamp = millis();
67+
int sensorReading = analogRead(A0);
68+
String line = String(timeStamp) + "," + String(sensorReading) + "\n";
69+
sensorDataBuffer.push_back(line);
70+
}
71+
72+
void moveDataToQSPI() {
73+
if(!backingUP){
74+
UFile _logFile = internalStorage.getRootFolder().createFile("log.txt", FileMode::APPEND);
75+
for (const auto& line : sensorDataBuffer) {
76+
bytesWritten += _logFile.write(line); // Write the log line to the file
77+
}
78+
_logFile.close();
79+
sensorDataBuffer.clear();
80+
}
81+
}
82+
83+
84+
void performUpdate() {
85+
Folder usbRoot = usbStorage.getRootFolder(); // Get the root folder of the USB storage
86+
UFile logFile = internalStorage.getRootFolder().createFile("log.txt", FileMode::READ);
87+
UFile backupFile = usbRoot.createFile("backup_file.txt", FileMode::APPEND); // Create or open the backup file
88+
UFile lastUpdateFile = usbRoot.createFile("diff.txt", FileMode::READ); // Create or open the last update file
89+
90+
backingUP = true;
91+
unsigned lastUpdateBytes = lastUpdateFile.readAsString().toInt(); // Read the last update size from the file
92+
93+
printFormatted("Last update bytes: " + String(lastUpdateBytes) + "\n");
94+
95+
if (lastUpdateBytes >= bytesWritten) {
96+
printFormatted("No new data to copy. \n");
97+
backupFile.close();
98+
lastUpdateFile.close();
99+
backingUP = false;
100+
return;
101+
}
102+
103+
logFile.seek(lastUpdateBytes); // Move the file pointer to the last update position
104+
unsigned long totalBytesToMove = bytesWritten - lastUpdateBytes;
105+
printFormatted("New update bytes: " + String(totalBytesToMove) + "\n");
106+
107+
uint8_t* buffer = new uint8_t[totalBytesToMove];
108+
109+
size_t bytesRead = logFile.read(buffer, totalBytesToMove);
110+
size_t bytesMoved = backupFile.write(buffer, bytesRead); // Only write the bytes that haven't been backed up yet
111+
112+
printFormatted("Successfully copied " + String(bytesMoved) + " new bytes.");
113+
114+
lastUpdateFile.changeMode(FileMode::WRITE); // Open the last update file in write mode
115+
lastUpdateFile.write(String(lastUpdateBytes + bytesMoved)); // Update the last update size
116+
117+
backupFile.close();
118+
logFile.close();
119+
lastUpdateFile.close();
120+
121+
122+
usbStorage.unmount(); // Unmount the USB storage
123+
124+
digitalWrite(USB_MOUNTED_LED, HIGH);
125+
backingUP = false;
126+
delete[] buffer;
127+
}
128+
129+
130+
// Function to backup data to USB storage
131+
void backupToUSB() {
132+
if (usbAvailable) {
133+
printFormatted("USB Mass storage is available \n");
134+
delay(100);
135+
if (!usbStorage.isMounted()) {
136+
137+
printFormatted("Mounting USB Mass Storage \n");
138+
digitalWrite(USB_MOUNTED_LED, LOW);
139+
if(usbStorage.begin()){
140+
performUpdate();
141+
}
142+
143+
} else if (usbStorage.isMounted()) {
144+
printFormatted("USB Mass storage is connected, performing update \n");
145+
performUpdate();
146+
147+
}
148+
} else {
149+
printFormatted("USB Mass storage is not available \n");
150+
}
151+
152+
153+
}
154+
155+
156+
void setup() {
157+
beginRS485(baudrate);
158+
159+
160+
usbStorage.registerHotplugCallback(connectionCallback);
161+
usbStorage.registerUnplugCallback(disconnectionCallback);
162+
163+
pinMode(USB_MOUNTED_LED, OUTPUT);
164+
printFormatted("Formatting internal storage... \n");
165+
int formatted = internalStorage.format(FS_LITTLEFS);
166+
printFormatted("QSPI Format status: " + String(formatted) + "\n");
167+
168+
169+
170+
if (!internalStorage.begin()) {
171+
printFormatted("Failed to initialize internal storage \n");
172+
return;
173+
} else {
174+
printFormatted("Initialized storage \n");
175+
}
176+
177+
}
178+
179+
void loop() {
180+
181+
182+
runPeriodically(logDataToRAM, 100, &lastLog);
183+
runPeriodically(moveDataToQSPI, 1000, &lastMove);
184+
runPeriodically(backupToUSB, 10000, &lastBackup);
185+
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
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.
3+
4+
The code defines two main functions: "logData" and "performUpdate".
5+
The "logData" function logs sensor data by reading an analog sensor and writing the data to the log file.
6+
7+
The "performUpdate" function performs the update process by:
8+
* reading the last update size from a file (number of bytes)
9+
* copying the new data from the log file to a backup file
10+
* and updating the last update size.
11+
12+
INSTRUCTIONS
13+
* Make sure the QSPI storage of your board is properly partitioned.
14+
* You can do that by flashing the QSPIFormat example that can be found in the STM32H747_System folder
15+
* Open the serial monitor and select answer with "Y" when this appears "Do you want to use partition scheme 1? Y/[n]"
16+
* Reboot the board
17+
* This sketch will log data, and check if there is any USB MSD Device connected to the USB Port of the Opta.
18+
The USB device is mounted and unmounted after every update operation. The first status LED is on when the USB drive is mounted.
19+
So as long as the status LED is off you can safely remove the drive.
20+
The sketch will log to internal storage in the meantime, and wait for the USB drive to be inserted again.
21+
*/
22+
23+
#include "Arduino_UnifiedStorage.h"
24+
#include <vector>
25+
#include <Output.h>
26+
27+
constexpr auto baudrate { 115200 };
28+
29+
#if defined(ARDUINO_PORTENTA_H7_M7)
30+
#define USB_MOUNTED_LED LED_BLUE
31+
#elif defined(ARDUINO_PORTENTA_C33)
32+
#define USB_MOUNTED_LED LEDB
33+
#endif
34+
35+
36+
InternalStorage internalStorage = InternalStorage();
37+
USBStorage usbStorage = USBStorage();
38+
std::vector<String> sensorDataBuffer;
39+
40+
unsigned long bytesWritten = 0;
41+
unsigned long lastLog = 0;
42+
unsigned long lastMove = 0;
43+
unsigned long lastBackup = 0;
44+
45+
46+
volatile bool usbAvailable = false;
47+
bool backingUP = false;
48+
49+
void connectionCallback(){
50+
usbAvailable = true;
51+
}
52+
53+
void disconnectionCallback(){
54+
usbAvailable = false;
55+
}
56+
// Function to run a given method periodically
57+
void runPeriodically(void (*method)(), unsigned long interval, unsigned long* variable) {
58+
unsigned long currentMillis = millis();
59+
60+
if (currentMillis - *variable >= interval) {
61+
*variable = currentMillis;
62+
method(); // Call the provided method
63+
}
64+
}
65+
66+
// Function to log sensor data
67+
void logDataToRAM() {
68+
int timeStamp = millis();
69+
int sensorReading = analogRead(A0);
70+
String line = String(timeStamp) + "," + String(sensorReading) + "\n";
71+
sensorDataBuffer.push_back(line);
72+
}
73+
74+
void moveDataToQSPI() {
75+
if(!backingUP){
76+
UFile _logFile = internalStorage.getRootFolder().createFile("log.txt", FileMode::APPEND);
77+
for (const auto& line : sensorDataBuffer) {
78+
bytesWritten += _logFile.write(line); // Write the log line to the file
79+
}
80+
_logFile.close();
81+
sensorDataBuffer.clear();
82+
}
83+
}
84+
85+
86+
void performUpdate() {
87+
Folder usbRoot = usbStorage.getRootFolder(); // Get the root folder of the USB storage
88+
UFile logFile = internalStorage.getRootFolder().createFile("log.txt", FileMode::READ);
89+
UFile backupFile = usbRoot.createFile("backup_file.txt", FileMode::APPEND); // Create or open the backup file
90+
UFile lastUpdateFile = usbRoot.createFile("diff.txt", FileMode::READ); // Create or open the last update file
91+
92+
backingUP = true;
93+
unsigned lastUpdateBytes = lastUpdateFile.readAsString().toInt(); // Read the last update size from the file
94+
95+
Serial.print("Last update bytes: " + String(lastUpdateBytes) + "\n");
96+
97+
if (lastUpdateBytes >= bytesWritten) {
98+
Serial.print("No new data to copy. \n");
99+
backupFile.close();
100+
lastUpdateFile.close();
101+
backingUP = false;
102+
return;
103+
}
104+
105+
logFile.seek(lastUpdateBytes); // Move the file pointer to the last update position
106+
unsigned long totalBytesToMove = bytesWritten - lastUpdateBytes;
107+
Serial.print("New update bytes: " + String(totalBytesToMove) + "\n");
108+
109+
uint8_t* buffer = new uint8_t[totalBytesToMove];
110+
111+
size_t bytesRead = logFile.read(buffer, totalBytesToMove);
112+
size_t bytesMoved = backupFile.write(buffer, bytesRead); // Only write the bytes that haven't been backed up yet
113+
114+
Serial.print("Successfully copied " + String(bytesMoved) + " new bytes.");
115+
116+
lastUpdateFile.changeMode(FileMode::WRITE); // Open the last update file in write mode
117+
lastUpdateFile.write(String(lastUpdateBytes + bytesMoved)); // Update the last update size
118+
119+
backupFile.close();
120+
logFile.close();
121+
lastUpdateFile.close();
122+
123+
124+
usbStorage.unmount(); // Unmount the USB storage
125+
126+
digitalWrite(USB_MOUNTED_LED, HIGH);
127+
backingUP = false;
128+
delete[] buffer;
129+
}
130+
131+
132+
// Function to backup data to USB storage
133+
void backupToUSB() {
134+
if (usbAvailable) {
135+
Serial.print("USB Mass storage is available \n");
136+
delay(100);
137+
if (!usbStorage.isMounted()) {
138+
139+
Serial.print("Mounting USB Mass Storage \n");
140+
digitalWrite(USB_MOUNTED_LED, LOW);
141+
if(usbStorage.begin()){
142+
performUpdate();
143+
}
144+
145+
} else if (usbStorage.isMounted()) {
146+
Serial.print("USB Mass storage is connected, performing update \n");
147+
performUpdate();
148+
149+
}
150+
} else {
151+
Serial.print("USB Mass storage is not available \n");
152+
}
153+
154+
155+
}
156+
157+
158+
void setup() {
159+
//beginRS485(baudrate);
160+
Serial.begin(115200);
161+
while(!Serial);
162+
163+
usbStorage.registerHotplugCallback(connectionCallback);
164+
usbStorage.registerUnplugCallback(disconnectionCallback);
165+
166+
pinMode(USB_MOUNTED_LED, OUTPUT);
167+
Serial.print("Formatting internal storage... \n");
168+
int formatted = internalStorage.format(FS_LITTLEFS);
169+
Serial.print("QSPI Format status: " + String(formatted) + "\n");
170+
171+
172+
173+
if (!internalStorage.begin()) {
174+
Serial.print("Failed to initialize internal storage \n");
175+
return;
176+
} else {
177+
Serial.print("Initialized storage \n");
178+
}
179+
180+
}
181+
182+
void loop() {
183+
184+
185+
runPeriodically(logDataToRAM, 100, &lastLog);
186+
runPeriodically(moveDataToQSPI, 1000, &lastMove);
187+
runPeriodically(backupToUSB, 10000, &lastBackup);
188+
}

0 commit comments

Comments
 (0)