/*
LittleFS datalogger
This example shows how to log data from three analog sensors
to an storage device such as a FLASH.
This example code is in the public domain.
*/
#include <LittleFS.h>
#include <MTP_Teensy.h>
// LittleFS supports creating file systems (FS) in multiple memory types.
// Depending on the
// memory type you want to use you would uncomment one of the following
// constructors
LittleFS_RAM lfsram;
LittleFS_SPIFlash sflash5; // https://github.com/PaulStoffregen/LittleFS#nand-flash
const int chipSelect = 5;
#ifdef ARDUINO_TEENSY41
extern "C" uint8_t external_psram_size;
uint32_t MEMFS_SIZE = 65536; // probably more than enough...
#endif
File dataFile; // Specifes that dataFile is of File type
int record_count = 0;
bool write_data = false;
uint32_t diskSize;
// Add in MTPD objects
MTPStorage storage;
MTPD mtpd(&storage);
FS *mtpDisk;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(115200);
// Serial4.begin(115200); // Use to echo stuff out for debug core.
while (!Serial && millis() < 5000) {
// wait for serial port to connect.
}
Serial.print(CrashReport);
Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
Serial.print("Initializing LittleFS ...");
// checks that the LittFS program has started with the disk size specified
if (!sflash5.begin(chipSelect, SPI)) {
Serial.printf("Error starting %s\n", "PROGRAM FLASH DISK");
while (1) {
// Error, so don't do anything more - stay stuck here
}
}
mtpd.begin();
// lets initialize a RAM drive.
#if defined ARDUINO_TEENSY41
if (external_psram_size)
MEMFS_SIZE = 4 * 1024 * 1024;
#endif
if (lfsram.begin(MEMFS_SIZE)) {
Serial.printf("Ram Drive of size: %u initialized\n", MEMFS_SIZE);
uint32_t istore = storage.addFilesystem(lfsram, "RAM");
Serial.printf("Set Storage Index drive to %u\n", istore);
}
mtpDisk = &lfsram; // so we don't start of with NULL pointer
storage.addFilesystem(sflash5, "sflash5");
Serial.println("LittleFS initialized.");
menu();
}
void loop() {
mtpd.loop();
if (Serial.available()) {
uint8_t command = Serial.read();
int ch = Serial.read();
uint32_t drive_index = CommandLineReadNextNumber(ch, 0);
while (ch == ' ')
ch = Serial.read();
switch (command) {
case 'l':
listFiles();
break;
case 'e':
eraseFiles();
break;
case 's': {
Serial.println("\nLogging Data!!!");
write_data = true; // sets flag to continue to write data until new
// command is received
// opens a file or creates a file if not present, FILE_WRITE will append
// data to
// to the file created.
dataFile = mtpDisk->open("datalog.txt", FILE_WRITE);
logData();
} break;
case 'x':
stopLogging();
break;
case '1': {
// first dump list of storages:
uint32_t fsCount = storage.getFSCount();
Serial.printf("\nDump Storage list(%u)\n", fsCount);
for (uint32_t ii = 0; ii < fsCount; ii++) {
Serial.printf("store:%u storage:%x name:%s fs:%x\n", ii,
mtpd.Store2Storage(ii), storage.getStoreName(ii),
(uint32_t)storage.getStoreFS(ii));
}
Serial.println("\nDump Index List");
storage.dumpIndexList();
} break;
case '2':
Serial.printf("Drive # %d Selected\n", drive_index);
mtpDisk = storage.getStoreFS(drive_index);
break;
case 'd':
dumpLog();
break;
case 'r':
Serial.println("Send Device Reset Event");
mtpd.send_DeviceResetEvent();
break;
case 'R':
Serial.print(" RESTART Teensy ...");
delay(100);
SCB_AIRCR = 0x05FA0004;
break;
case '\r':
case '\n':
case 'h':
menu();
break;
default:
menu();
break;
}
while (Serial.read() != -1)
; // remove rest of characters.
}
if (write_data)
logData();
}
void logData() {
// make a string for assembling the data to log:
String dataString = "";
// read three sensors and append to the string:
for (int analogPin = 0; analogPin < 3; analogPin++) {
int sensor = analogRead(analogPin);
dataString += String(sensor);
if (analogPin < 2) {
dataString += ",";
}
}
// if the file is available, write to it:
if (dataFile) {
dataFile.println(dataString);
// print to the serial port too:
Serial.println(dataString);
record_count += 1;
} else {
// if the file isn't open, pop up an error:
Serial.println("error opening datalog.txt");
}
delay(100); // run at a reasonable not-too-fast speed for testing
}
void stopLogging() {
Serial.println("\nStopped Logging Data!!!");
write_data = false;
// Closes the data file.
dataFile.close();
Serial.printf("Records written = %d\n", record_count);
mtpd.send_DeviceResetEvent();
}
void dumpLog() {
Serial.println("\nDumping Log!!!");
// open the file.
dataFile = mtpDisk->open("datalog.txt");
// if the file is available, write to it:
if (dataFile) {
while (dataFile.available()) {
Serial.write(dataFile.read());
}
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
}
}
void menu() {
Serial.println();
Serial.println("Menu Options:");
Serial.println("\t1 - List USB Drives (Step 1)");
Serial.println("\t2 - Select USB Drive for Logging (Step 2)");
Serial.println("\tl - List files on disk");
Serial.println("\te - Erase files on disk");
Serial.println("\ts - Start Logging data (Restarting logger will append "
"records to existing log)");
Serial.println("\tx - Stop Logging data");
Serial.println("\td - Dump Log");
Serial.println("\tr - reset MTP");
Serial.println("\tR - restart Teensy");
Serial.println("\th - Menu");
Serial.println();
}
void listFiles() {
Serial.print("\n Space Used = ");
Serial.println(mtpDisk->usedSize());
Serial.print("Filesystem Size = ");
Serial.println(mtpDisk->totalSize());
File root = mtpDisk->open("/");
printDirectory(root, 0);
root.close();
}
void eraseFiles() {
//DBGSerial.println("Formating not supported at this time");
Serial.println("\n*** Erase/Format started ***");
mtpDisk->format(1, '.', Serial);
Serial.println("Completed, sending device reset event");
mtpd.send_DeviceResetEvent();
}
void printDirectory(File dir, int numSpaces) {
DateTimeFields dtf;
while (true) {
File entry = dir.openNextFile();
if (!entry) {
// Serial.println("** no more files **");
break;
}
printSpaces(numSpaces);
Serial.print(entry.name());
printSpaces(36 - numSpaces - strlen(entry.name()));
if (entry.getCreateTime(dtf)) {
Serial.printf(" C: %02u/%02u/%04u %02u:%02u", dtf.mon + 1, dtf.mday, dtf.year + 1900, dtf.hour, dtf.min );
}
if (entry.getModifyTime(dtf)) {
Serial.printf(" M: %02u/%02u/%04u %02u:%02u", dtf.mon + 1, dtf.mday, dtf.year + 1900, dtf.hour, dtf.min );
}
if (entry.isDirectory()) {
Serial.println(" /");
printDirectory(entry, numSpaces + 2);
} else {
// files have sizes, directories do not
Serial.print(" ");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
void printSpaces(int num) {
for (int i = 0; i < num; i++) {
Serial.print(" ");
}
}
uint32_t CommandLineReadNextNumber(int &ch, uint32_t default_num) {
while (ch == ' ')
ch = Serial.read();
if ((ch < '0') || (ch > '9'))
return default_num;
uint32_t return_value = 0;
while ((ch >= '0') && (ch <= '9')) {
return_value = return_value * 10 + ch - '0';
ch = Serial.read();
}
return return_value;
}