-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathLogger.ino
215 lines (163 loc) · 7.01 KB
/
Logger.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*
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 "logData" function simulates sensor data by reading reading a random value every 100ms and saving it in memory.
Afterwards, every 1000ms "moveDataToQSPI" moves those readings to a file in the Internal Storage of your board.
If a USB device is connected "performUpdate" function performs the update process every 10 seconds 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 you have "POSIXStorage" and "Arduino_UnifiedStorage" installed
- If you are using this sketch on an Arduino OPTA, use another board or an USB adaptor to view RS485 messages
- This sketch will log data, and check if there is any USB MSD Device connected to the USB Port of your board.
- Insert a USB Drive whenever you want
- Every 10 seconds data is transferred from the internal storage to the USB Mass storage device
- Unplug the USB device and inspect its contents.
NOTES: 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.
*/
#define ARDUINO_UNIFIED_STORAGE_DEBUG
#include "Arduino_UnifiedStorage.h"
#include <vector>
#if defined(ARDUINO_PORTENTA_H7_M7)
#define USB_MOUNTED_LED LED_BLUE
#elif defined(ARDUINO_PORTENTA_C33)
#define USB_MOUNTED_LED LEDB
#elif defined(ARDUINO_OPTA)
#define USB_MOUNTED_LED LED_D0
#endif
InternalStorage internalStorage;
USBStorage usbStorage;
Folder backupFolder = Folder();
bool usbIntialized = false;
std::vector<String> 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;
usbStorage.removeOnConnectCallback();
}
void disconnectionCallback(){
usbAvailable = false;
usbStorage.onConnect(connectionCallback);
}
// 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(random(9999));
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() {
UFile logFile = internalStorage.getRootFolder().createFile("log.txt", FileMode::READ);
UFile backupFile = backupFolder.createFile("backup_file.txt", FileMode::APPEND); // Create or open the backup file
UFile lastUpdateFile = backupFolder.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
Arduino_UnifiedStorage::debugPrint("Last update bytes: " + String(lastUpdateBytes));
if (lastUpdateBytes >= bytesWritten) {
Arduino_UnifiedStorage::debugPrint("No new data to copy. ");
backupFile.close();
lastUpdateFile.close();
backingUP = false;
return;
}
logFile.seek(lastUpdateBytes); // Move the file pointer to the last update position
unsigned long totalBytesToMove = bytesWritten - lastUpdateBytes;
Arduino_UnifiedStorage::debugPrint("New update bytes: " + String(totalBytesToMove));
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
Arduino_UnifiedStorage::debugPrint("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 && !usbIntialized){
usbStorage.begin();
Arduino_UnifiedStorage::debugPrint("First drive insertion, creating folders... ");
Folder usbRoot = usbStorage.getRootFolder();
String folderName = "LoggerBackup" + String(random(9999));
backupFolder = usbRoot.createSubfolder(folderName);
Arduino_UnifiedStorage::debugPrint("Successfully created backup folder: " + backupFolder.getPathAsString());
usbStorage.unmount();
usbIntialized = true;
}
else if(usbAvailable && usbIntialized) {
Arduino_UnifiedStorage::debugPrint("USB Mass storage is available ");
delay(100);
if (!usbStorage.isMounted()) {
Arduino_UnifiedStorage::debugPrint("Mounting USB Mass Storage ");
digitalWrite(USB_MOUNTED_LED, LOW);
if(usbStorage.begin()){
performUpdate();
}
} else if (usbStorage.isMounted()) {
Arduino_UnifiedStorage::debugPrint("USB Mass storage is connected, performing update ");
performUpdate();
}
} else {
Arduino_UnifiedStorage::debugPrint("USB Mass storage is not available ");
}
}
void setup() {
randomSeed(analogRead(A0));
#if !defined(ARDUINO_OPTA)
Serial.begin(115200);
while(!Serial);
#else
beginRS485(115200);
#endif
// toggle this to enable debugging output
Arduino_UnifiedStorage::debuggingModeEnabled = false;
usbStorage = USBStorage();
internalStorage = InternalStorage();
usbStorage.onConnect(connectionCallback);
usbStorage.onDisconnect(disconnectionCallback);
pinMode(USB_MOUNTED_LED, OUTPUT);
Arduino_UnifiedStorage::debugPrint("Formatting internal storage... ");
int formatted = internalStorage.format(FS_LITTLEFS);
Arduino_UnifiedStorage::debugPrint("QSPI Format status: " + String(formatted));
if (!internalStorage.begin()) {
Arduino_UnifiedStorage::debugPrint("Failed to initialize internal storage ");
return;
} else {
Arduino_UnifiedStorage::debugPrint("Initialized storage ");
}
}
void loop() {
runPeriodically(logDataToRAM, 100, &lastLog);
runPeriodically(moveDataToQSPI, 1000, &lastMove);
runPeriodically(backupToUSB, 10000, &lastBackup);
}