PaulStoffregen
Well-known member
Looks like the interface swap broken serial emulation on Linux, but only when using USB Type MTP. Windows and MacOS still work. I just fixed teensy_serialmon here.
Wonder why? Would make difference on Ubuntu?Looks like the interface swap broken serial emulation on Linux, but only when using USB Type MTP. Windows and MacOS still work. I just fixed teensy_serialmon here.
#define MTP_INTERFACE 1 // MTP Disk
#define SEREMU_INTERFACE 0 // Serial emulation
#define SEREMU_INTERFACE 0 // Serial emulation
#define AUDIO_INTERFACE 1 // Audio (uses 3 consecutive interfaces)
setSyncProvider - Would be nice if programs that use File system Dates and Times just worked without having to know about the time/date glue in the Time library.
That is the dates and times will be screwed up if something does not call setSyncProvider()...
Looking at the timestamp stuff today....
....
Agreed. I would like to bring more of this into the core library without any Time library dependency.
/*
LittleFS usuage from the LittleFS library
Starting with Teensyduino 1.54, support for LittleFS has been added.
LittleFS is a wrapper for the LittleFS File System for the Teensy family of microprocessors and provides support for RAM Disks, NOR and NAND Flash chips, and FRAM chips. For the NOR, NAND Flash support is provided for SPI and QSPI in the case of the Teensy 4.1. For FRAM only SPI is supported. It is also linked to SDFat so many of the same commands can be used as for an SD Card.
This example shows the use of some of the commands provided in LittleFS using a SPI Flash chip such as the W25Q128.
See the readme for the LittleFS library for more information: https://github.com/PaulStoffregen/LittleFS
*/
#include <LittleFS.h>
#include <SD.h>
// Some variables for later use
uint64_t fTot, totSize1;
// To use SPI flash we need to create a instance of the library telling it to use SPI flash.
/* Other options include:
LittleFS_QSPIFlash myfs;
LittleFS_Program myfs;
LittleFS_SPIFlash myfs;
LittleFS_SPIFram myfs;
LittleFS_SPINAND myfs;
LittleFS_QPINAND myfs;
LittleFS_RAM myfs;
*/
LittleFS_SPIFlash myfs;
time_t getTeensy3Time()
{
return Teensy3Clock.get();
}
// Since we are using SPI we need to tell the library what the chip select pin
#define chipSelect 6 // use for access flash on audio or prop shield
// Specifies that the file, file1 and file3 are File types, same as you would do for creating files
// on a SD Card
File file, file1, file2;
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(115200);
while (!Serial) {
// wait for serial port to connect.
}
Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
Serial.print("Initializing LittleFS ...");
setSyncProvider(getTeensy3Time);
// see if the Flash is present and can be initialized:
// Note: SPI is default so if you are using SPI and not SPI for instance
// you can just specify myfs.begin(chipSelect).
if (!myfs.begin(chipSelect, SPI)) {
Serial.printf("Error starting %s\n", "SPI FLASH");
while (1) {
// Error, so don't do anything more - stay stuck here
}
}
myfs.quickFormat();
Serial.println("LittleFS initialized.");
// To get the current space used and Filesystem size
Serial.println("\n---------------");
Serial.printf("Bytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
waitforInput();
// Now lets create a file and write some data. Note: basically the same usage for
// creating and writing to a file using SD library.
Serial.println("\n---------------");
Serial.println("Now lets create a file with some data in it");
Serial.println("---------------");
char someData[128];
memset( someData, 'z', 128 );
file = myfs.open("bigfile.txt", FILE_WRITE);
file.write(someData, sizeof(someData));
for (uint16_t j = 0; j < 100; j++)
file.write(someData, sizeof(someData));
file.close();
// We can also get the size of the file just created. Note we have to open and
// thes close the file unless we do file size before we close it in the previous step
file = myfs.open("bigfile.txt", FILE_WRITE);
Serial.printf("File Size of bigfile.txt (bytes): %u\n", file.size());
file.close();
// Now that we initialized the FS and created a file lets print the directory.
// Note: Since we are going to be doing print directory and getting disk usuage
// lets make it a function which can be copied and used in your own sketches.
listFiles();
waitforInput();
// Now lets rename the file
Serial.println("\n---------------");
Serial.println("Rename bigfile to file10");
myfs.rename("bigfile.txt", "file10.txt");
listFiles();
waitforInput();
// To delete the file
Serial.println("\n---------------");
Serial.println("Delete file10.txt");
//myfs.remove("file10.txt");
listFiles();
waitforInput();
Serial.println("\n---------------");
Serial.println("Create a directory and a subfile");
myfs.mkdir("structureData1");
file = myfs.open("structureData1/temp_test.txt", FILE_WRITE);
file.println("SOME DATA TO TEST");
file.close();
listFiles();
waitforInput();
Serial.println("\n---------------");
Serial.println("Rename directory");
myfs.rename("structureData1", "structuredData");
listFiles();
waitforInput();
Serial.println("\n---------------");
Serial.println("Lets remove them now...");
//Note have to remove directories files first
//myfs.remove("structuredData/temp_test.txt");
//myfs.rmdir("structuredData");
listFiles();
waitforInput();
Serial.println("\n---------------");
Serial.println("Now lets create a file and read the data back...");
// LittleFS also supports truncate function similar to SDFat. As shown in this
// example, you can truncate files.
//
Serial.println();
Serial.println("Writing to datalog.bin using LittleFS functions");
file1 = myfs.open("datalog.bin", FILE_WRITE);
unsigned int len = file1.size();
Serial.print("datalog.bin started with ");
Serial.print(len);
Serial.println(" bytes");
if (len > 0) {
// reduce the file to zero if it already had data
file1.truncate();
}
file1.print("Just some test data written to the file (by SdFat functions)");
file1.write((uint8_t) 0);
file1.close();
// You can also use regular SD type functions, even to access the same file. Just
// remember to close the file before opening as a regular SD File.
//
Serial.println();
Serial.println("Reading to datalog.bin using LittleFS functions");
file2 = myfs.open("datalog.bin");
if (file2) {
char mybuffer[100];
int index = 0;
while (file2.available()) {
char c = file2.read();
mybuffer[index] = c;
if (c == 0) break; // end of string
index = index + 1;
if (index == 99) break; // buffer full
}
mybuffer[index] = 0;
Serial.print(" Read from file: ");
Serial.println(mybuffer);
} else {
Serial.println("unable to open datalog.bin :(");
}
file2.close();
Serial.println("\nBasic Usage Example Finished");
}
void loop() {}
void listFiles()
{
Serial.println("---------------");
printDirectory(myfs);
Serial.printf("Bytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
}
void printDirectory(FS &fs) {
Serial.println("Directory\n---------");
printDirectory(fs.open("/"), 0);
Serial.println();
}
void printDirectory(File dir, int numSpaces) {
while(true) {
File entry = dir.openNextFile();
if (! entry) {
//Serial.println("** no more files **");
break;
}
printSpaces(numSpaces);
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numSpaces+2);
} else {
// files have sizes, directories do not
printSpaces(36 - numSpaces - strlen(entry.name()));
Serial.print(" ");
Serial.print(entry.size(), DEC);
uint16_t c_date; uint16_t c_time;
entry.getCreateDateTime(&c_date, &c_time);
Serial.printf(" %d-%02d-%02d %02d:%02d:%02d", FS_YEAR(c_date), FS_MONTH(c_date), FS_DAY(c_date), FS_HOUR(c_time), FS_MINUTE(c_time), FS_SECOND(c_time));
entry.getModifyDateTime(&c_date, &c_time);
Serial.printf(" %d-%02d-%02d %02d:%02d:%02d\n", FS_YEAR(c_date), FS_MONTH(c_date), FS_DAY(c_date), FS_HOUR(c_time), FS_MINUTE(c_time), FS_SECOND(c_time));
}
entry.close();
}
}
void printSpaces(int num) {
for (int i=0; i < num; i++) {
Serial.print(" ");
}
}
void waitforInput()
{
Serial.println("Press anykey to continue");
while (Serial.read() == -1) ;
while (Serial.read() != -1) ;
}
---------------
Directory
---------
FO Read:: directory
ONF:: next name = "file10.txt"
ONF:: pathname --- /file10.txt
/file10.txt 12928 2021-09-24 09:59:40 2021-09-24 09:59:40
ONF:: next name = "structuredData"
ONF:: pathname --- /structuredData
/structuredData/
ONF:: next name = "temp_test.txt"
ONF:: pathname --- /structuredData/temp_test.txt
/structuredData/temp_test.txt 19 2021-09-24 09:59:42 2021-09-24 09:59:42
Bytes Used: 32768, Bytes Total:67108864
Press anykey to continue
---------------
Directory
---------
FO Read:: directory
ONF:: next name = "file10.txt"
ONF:: pathname --- /file10.txt
file10.txt 12928 2021-09-24 10:13:36 2021-09-24 10:13:36
ONF:: next name = "structureData1"
ONF:: pathname --- /structureData1
structureData1/
ONF:: next name = "temp_test.txt"
ONF:: pathname --- /structureData1/temp_test.txt
temp_test.txt 19 1980-00-00 00:00:00GMT: Error value clearedtemp_test.txt
1980-00-00 00:00:00
Looks like you're storing 2 attributes for the 16 bit numbers of FAT filesystems?
time_t _now = now();
rcode = lfs_getattr(&lfs, filepath, 'c', (void *)&filetime, sizeof(filetime));
if(rcode != sizeof(filetime)) {
rcode = lfs_setattr(&lfs, filepath, 'c', (const void *) &_now, sizeof(_now));
if(rcode < 0)
Serial.println("FO:: set attribute creation failed");
}
rcode = lfs_setattr(&lfs, filepath, 'm', (const void *) &_now, sizeof(_now));
if(rcode < 0)
Serial.println("FO:: set attribute modified failed");
#ifdef FS_FILE_SUPPORT_DATES
// These will all return false as only some FS support it.
virtual bool getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
return (f) ? f->getAccessDateTime(pdate, ptime) : false;
}
virtual bool getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
return (f) ? f->getCreateDateTime(pdate, ptime) : false;
}
virtual bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
return (f) ? f->getModifyDateTime(pdate, ptime) : false;
}
virtual bool timestamp(uint8_t flags, uint16_t year, uint8_t month, uint8_t day,
uint8_t hour, uint8_t minute, uint8_t second) {
return (f) ? f->timestamp(flags, year, month, day, hour, minute, second) : false;
}
#endif
virtual bool setAccessDateTime(uint16_t date, uint16_t time) {
return (f) ? f->setAccessDateTime(date, time) : false;
}
virtual bool setCreateDateTime(uint16_t date, uint16_t time) {
return (f) ? f->setCreateDateTime(date, time) : false;
}
virtual bool setModifyDateTime(uint16_t date, uint16_t time) {
return (f) ? f->setModifyDateTime(date, time) : false;
}
void SDClass::dateTime(uint16_t *date, uint16_t *time)
{
time_t t = Teensy3Clock.get();
if (t < 315532800) {
// before 1980
*date = 0;
*time = 0;
return;
}
struct tm datetime;
gmtime_r(&t, &datetime);
// 15-9: year (0 = 1980)
// 8-5: month (1-12)
// 4-0: day (1-21)
*date = ((datetime.tm_year - 80) << 9) | ((datetime.tm_mon + 1) << 5) | datetime.tm_mday;
// 15-11: hours (0-23)
// 10-5: minutes (0-29)
// 4-0: seconds/2 (0-29)
*time = (datetime.tm_hour << 11) | (datetime.tm_min << 5) | (datetime.tm_sec >> 1);
}
/*
LittleFS usuage from the LittleFS library
Starting with Teensyduino 1.54, support for LittleFS has been added.
LittleFS is a wrapper for the LittleFS File System for the Teensy family of microprocessors and provides support for RAM Disks, NOR and NAND Flash chips, and FRAM chips. For the NOR, NAND Flash support is provided for SPI and QSPI in the case of the Teensy 4.1. For FRAM only SPI is supported. It is also linked to SDFat so many of the same commands can be used as for an SD Card.
This example shows the use of some of the commands provided in LittleFS using a SPI Flash chip such as the W25Q128.
See the readme for the LittleFS library for more information: https://github.com/PaulStoffregen/LittleFS
*/
#include <LittleFS.h>
#include <SD.h>
// Some variables for later use
uint64_t fTot, totSize1;
// To use SPI flash we need to create a instance of the library telling it to use SPI flash.
/* Other options include:
LittleFS_QSPIFlash myfs;
LittleFS_Program myfs;
LittleFS_SPIFlash myfs;
LittleFS_SPIFram myfs;
LittleFS_SPINAND myfs;
LittleFS_QPINAND myfs;
LittleFS_RAM myfs;
*/
LittleFS_SPIFlash myfs;
// Since we are using SPI we need to tell the library what the chip select pin
#define chipSelect 6 // use for access flash on audio or prop shield
// Specifies that the file, file1 and file3 are File types, same as you would do for creating files
// on a SD Card
File file, file1, file2;
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(115200);
while (!Serial) {
// wait for serial port to connect.
}
Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
Serial.print("Initializing LittleFS ...");
// see if the Flash is present and can be initialized:
// Note: SPI is default so if you are using SPI and not SPI for instance
// you can just specify myfs.begin(chipSelect).
if (!myfs.begin(chipSelect, SPI)) {
Serial.printf("Error starting %s\n", "SPI FLASH");
while (1) {
// Error, so don't do anything more - stay stuck here
}
}
myfs.quickFormat();
Serial.println("LittleFS initialized.");
// To get the current space used and Filesystem size
Serial.println("\n---------------");
Serial.printf("Bytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
waitforInput();
// Now lets create a file and write some data. Note: basically the same usage for
// creating and writing to a file using SD library.
Serial.println("\n---------------");
Serial.println("Now lets create a file with some data in it");
Serial.println("---------------");
char someData[128];
memset( someData, 'z', 128 );
file = myfs.open("bigfile.txt", FILE_WRITE);
file.write(someData, sizeof(someData));
for (uint16_t j = 0; j < 100; j++)
file.write(someData, sizeof(someData));
file.close();
// We can also get the size of the file just created. Note we have to open and
// thes close the file unless we do file size before we close it in the previous step
file = myfs.open("bigfile.txt", FILE_WRITE);
Serial.printf("File Size of bigfile.txt (bytes): %u\n", file.size());
file.close();
// Now that we initialized the FS and created a file lets print the directory.
// Note: Since we are going to be doing print directory and getting disk usuage
// lets make it a function which can be copied and used in your own sketches.
listFiles();
waitforInput();
// Now lets rename the file
Serial.println("\n---------------");
Serial.println("Rename bigfile to file10");
myfs.rename("bigfile.txt", "file10.txt");
listFiles();
waitforInput();
Serial.println("\n---------------");
Serial.println("Create a directory and a subfile");
myfs.mkdir("structureData1");
file = myfs.open("structureData1/temp_test.txt", FILE_WRITE);
file.println("SOME DATA TO TEST");
file.close();
listFiles();
waitforInput();
Serial.println("\n---------------");
Serial.println("Rename directory");
myfs.rename("structureData1", "structuredData");
listFiles();
waitforInput();
Serial.println("\n---------------");
Serial.println("Now lets create a file and read the data back...");
// LittleFS also supports truncate function similar to SDFat. As shown in this
// example, you can truncate files.
//
Serial.println();
Serial.println("Writing to datalog.bin using LittleFS functions");
file1 = myfs.open("datalog.bin", FILE_WRITE);
unsigned int len = file1.size();
Serial.print("datalog.bin started with ");
Serial.print(len);
Serial.println(" bytes");
if (len > 0) {
// reduce the file to zero if it already had data
file1.truncate();
}
file1.print("Just some test data written to the file (by SdFat functions)");
file1.write((uint8_t) 0);
file1.close();
// You can also use regular SD type functions, even to access the same file. Just
// remember to close the file before opening as a regular SD File.
//
Serial.println();
Serial.println("Reading to datalog.bin using LittleFS functions");
file2 = myfs.open("datalog.bin");
if (file2) {
char mybuffer[100];
int index = 0;
while (file2.available()) {
char c = file2.read();
mybuffer[index] = c;
if (c == 0) break; // end of string
index = index + 1;
if (index == 99) break; // buffer full
}
mybuffer[index] = 0;
Serial.print(" Read from file: ");
Serial.println(mybuffer);
} else {
Serial.println("unable to open datalog.bin :(");
}
file2.close();
Serial.println("\nBasic Usage Example Finished");
}
void loop() {}
void listFiles()
{
Serial.println("---------------");
printDirectory(myfs);
Serial.printf("Bytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
}
void printDirectory(FS &fs) {
Serial.println("Directory\n---------");
printDirectory(fs.open("/"), 0);
Serial.println();
}
void printDirectory(File dir, int numSpaces) {
while(true) {
File entry = dir.openNextFile();
if (! entry) {
//Serial.println("** no more files **");
break;
}
printSpaces(numSpaces);
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.print("/");
uint16_t c_date; uint16_t c_time;
entry.getCreateDateTime(&c_date, &c_time);
Serial.printf(" %d-%02d-%02d %02d:%02d:%02d", FS_YEAR(c_date), FS_MONTH(c_date), FS_DAY(c_date), FS_HOUR(c_time), FS_MINUTE(c_time), FS_SECOND(c_time));
entry.getModifyDateTime(&c_date, &c_time);
Serial.printf(" %d-%02d-%02d %02d:%02d:%02d\n", FS_YEAR(c_date), FS_MONTH(c_date), FS_DAY(c_date), FS_HOUR(c_time), FS_MINUTE(c_time), FS_SECOND(c_time));
Serial.println("--------------------------------------------------------------------");
printDirectory(entry, numSpaces+2);
} else {
// files have sizes, directories do not
printSpaces(36 - numSpaces - strlen(entry.name()));
Serial.print(" ");
Serial.print(entry.size(), DEC);
uint16_t c_date; uint16_t c_time;
entry.getCreateDateTime(&c_date, &c_time);
Serial.printf(" %d-%02d-%02d %02d:%02d:%02d", FS_YEAR(c_date), FS_MONTH(c_date), FS_DAY(c_date), FS_HOUR(c_time), FS_MINUTE(c_time), FS_SECOND(c_time));
entry.getModifyDateTime(&c_date, &c_time);
Serial.printf(" %d-%02d-%02d %02d:%02d:%02d\n", FS_YEAR(c_date), FS_MONTH(c_date), FS_DAY(c_date), FS_HOUR(c_time), FS_MINUTE(c_time), FS_SECOND(c_time));
}
entry.close();
}
}
void printSpaces(int num) {
for (int i=0; i < num; i++) {
Serial.print(" ");
}
}
void waitforInput()
{
Serial.println("Press anykey to continue");
while (Serial.read() == -1) ;
while (Serial.read() != -1) ;
}
time_t fileTime();
time_t fileCreationTime();
time_t getLastWrite();
time_t fileTime();
time_t fileCreationTime();
void fileTime(time_t t);
void fileCreationTime(time_t t);
There is an abstraction layer missing.
Is there a way to write a library that uses a file and/or uses open(), i.e. to write a new file? How to handle all the different media?
#include <SD.h>
#include <LittleFS.h>
LittleFS_SPIFlash myfs;
void myWrite(FS &filesystem, const char *filename) {
File myfile = filesystem.open(filename, FILE_WRITE_BEGIN);
if (myfile) {
myfile.println("This is test data written to a file.");
myfile.close();
Serial.println("file written");
} else {
Serial.println("error opening file for write");
}
}
void setup() {
Serial.begin(9600);
delay(1500);
if (SD.begin(BUILTIN_SDCARD)) { // SD card on Teensy 4.1 SD socket
myWrite(SD, "mytest1.txt");
} else {
Serial.println("Unable to access SD card");
}
if (myfs.begin(6)) { // SPI flash chip with CS on pin 6 (eg, audio shield)
myWrite(myfs, "mytest2.txt");
} else {
Serial.println("Unable to access flash memory chip card");
}
}
void loop() {
}
Is there a way to write a library that uses a file and/or uses open(), i.e. to write a new file? How to handle all the different media?
It looks like, that it is not possible. I could imagine a way which uses typeof or such - but there is no RTTI.
#include "Arduino.h"
#include "FS.h"
#include "LittleFS.h"
// library code ------------------------------------------------------
class MyClass
{
public:
MyClass(FS& fs) // user passes in the file system to use
: fileSystem(fs)
{}
void writeSomething()
{
File file = fileSystem.open("test", FILE_WRITE_BEGIN);
file.println("Bla bla");
file.write((uint8_t)0);
file.close();
}
String readSomething()
{
File file = fileSystem.open("test", FILE_READ);
return file.readString(); // file destructor automatically closes file
}
protected:
FS& fileSystem;
};
// usage -------------------------------------------
LittleFS_RAM lfs_ram;
MyClass myClass(lfs_ram); // use the library on e.g. LittleFS_RAM
void setup()
{
while (!Serial) {}
lfs_ram.begin(1024); // setup the filesystem
myClass.writeSomething(); // use the library class
Serial.println(myClass.readSomething());
}
void loop()
{
}