Browse Source

Timestamp fix, edit src for cplint errors

Add time st
Bill Greiman 4 years ago
parent
commit
1535ac2b03
100 changed files with 1737 additions and 1096 deletions
  1. 28 16
      examples/AvrAdcLogger/AvrAdcLogger.ino
  2. 4 4
      examples/BackwardCompatibility/BackwardCompatibility.ino
  3. 14 8
      examples/ExFatFormatter/ExFatFormatter.ino
  4. 29 15
      examples/ExFatLogger/ExFatLogger.ino
  5. 5 5
      examples/OpenNext/OpenNext.ino
  6. 12 6
      examples/QuickStart/QuickStart.ino
  7. 15 15
      examples/ReadCsvFile/ReadCsvFile.ino
  8. 106 14
      examples/RtcTimestampTest/RtcTimestampTest.ino
  9. 6 6
      examples/STM32Test/STM32Test.ino
  10. 12 6
      examples/SdFormatter/SdFormatter.ino
  11. 10 3
      examples/SdInfo/SdInfo.ino
  12. 2 2
      examples/SoftwareSpi/SoftwareSpi.ino
  13. 9 9
      examples/TeensyRtcTimestamp/TeensyRtcTimestamp.ino
  14. 19 12
      examples/TeensySdioDemo/TeensySdioDemo.ino
  15. 3 3
      examples/UserChipSelectFunction/UserChipSelectFunction.ino
  16. 2 2
      examples/UserSPIDriver/UserSPIDriver.ino
  17. 10 4
      examples/bench/bench.ino
  18. 1 1
      examples/examplesV1/#attic/AnalogLogger/AnalogLogger.ino
  19. 2 2
      examples/examplesV1/#attic/BaseExtCaseTest/BaseExtCaseTest.ino
  20. 1 1
      examples/examplesV1/#attic/HelloWorld/HelloWorld.ino
  21. 3 3
      examples/examplesV1/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino
  22. 2 2
      examples/examplesV1/#attic/SD_Size/SD_Size.ino
  23. 3 3
      examples/examplesV1/#attic/SdFatSize/SdFatSize.ino
  24. 1 1
      examples/examplesV1/#attic/StreamParseInt/StreamParseInt.ino
  25. 2 2
      examples/examplesV1/#attic/append/append.ino
  26. 2 2
      examples/examplesV1/#attic/average/average.ino
  27. 3 3
      examples/examplesV1/#attic/benchSD/benchSD.ino
  28. 2 2
      examples/examplesV1/#attic/bufstream/bufstream.ino
  29. 1 1
      examples/examplesV1/#attic/cin_cout/cin_cout.ino
  30. 1 1
      examples/examplesV1/#attic/eventlog/eventlog.ino
  31. 2 2
      examples/examplesV1/#attic/fgetsRewrite/fgetsRewrite.ino
  32. 2 2
      examples/examplesV1/#attic/readlog/readlog.ino
  33. 4 4
      examples/examplesV1/LowLatencyLoggerADXL345/UserFunctions.cpp
  34. 2 2
      examples/examplesV1/LowLatencyLoggerMPU6050/UserFunctions.cpp
  35. 3 3
      examples/examplesV1/OpenNext/OpenNext.ino
  36. 1 1
      examples/examplesV1/PrintBenchmark/PrintBenchmark.ino
  37. 4 4
      examples/examplesV1/RawWrite/RawWrite.ino
  38. 7 7
      examples/examplesV1/ReadCsv/ReadCsv.ino
  39. 5 5
      examples/examplesV1/ReadCsvArray/ReadCsvArray.ino
  40. 3 3
      examples/examplesV1/ReadCsvStream/ReadCsvStream.ino
  41. 2 2
      examples/examplesV1/STM32Test/STM32Test.ino
  42. 7 7
      examples/examplesV1/SdFormatter/SdFormatter.ino
  43. 6 6
      examples/examplesV1/SdInfo/SdInfo.ino
  44. 2 2
      examples/examplesV1/SoftwareSpi/SoftwareSpi.ino
  45. 3 3
      examples/examplesV1/StdioBench/StdioBench.ino
  46. 12 12
      examples/examplesV1/TeensySdioDemo/TeensySdioDemo.ino
  47. 2 2
      examples/examplesV1/Timestamp/Timestamp.ino
  48. 2 2
      examples/examplesV1/TwoCards/TwoCards.ino
  49. 3 3
      examples/examplesV1/dataLogger/dataLogger.ino
  50. 2 2
      examples/examplesV1/fgets/fgets.ino
  51. 1 1
      examples/examplesV1/formatting/formatting.ino
  52. 2 2
      examples/examplesV1/getline/getline.ino
  53. 3 3
      examples/examplesV1/wipe/wipe.ino
  54. 153 32
      extras/cpplint.py
  55. 0 7
      extras/cpplint.txt
  56. 1 1
      library.properties
  57. 1 1
      src/DigitalIO/SoftSPI.h
  58. 242 238
      src/ExFatLib/ExFatDbg.cpp
  59. 90 54
      src/ExFatLib/ExFatFile.cpp
  60. 51 12
      src/ExFatLib/ExFatFile.h
  61. 80 55
      src/ExFatLib/ExFatFilePrint.cpp
  62. 18 20
      src/ExFatLib/ExFatFileWrite.cpp
  63. 7 7
      src/ExFatLib/ExFatFormatter.cpp
  64. 76 76
      src/ExFatLib/ExFatPartition.cpp
  65. 12 12
      src/ExFatLib/ExFatPartition.h
  66. 2 2
      src/ExFatLib/ExFatVolume.cpp
  67. 1 1
      src/ExFatLib/ExFatVolume.h
  68. 48 49
      src/ExFatLib/upcase.cpp
  69. 0 1
      src/FatLib/FatDbg.cpp
  70. 101 53
      src/FatLib/FatFile.cpp
  71. 54 9
      src/FatLib/FatFile.h
  72. 24 19
      src/FatLib/FatFileLFN.cpp
  73. 11 21
      src/FatLib/FatFilePrint.cpp
  74. 17 12
      src/FatLib/FatFileSFN.cpp
  75. 6 6
      src/FatLib/FatFormatter.cpp
  76. 10 10
      src/FatLib/FatPartition.cpp
  77. 1 1
      src/FatLib/FatPartition.h
  78. 2 2
      src/FatLib/FatVolume.cpp
  79. 63 2
      src/FsLib/FsFile.h
  80. 1 1
      src/FsLib/FsVolume.h
  81. 110 111
      src/SdCard/SdSpiCard.cpp
  82. 1 1
      src/SdCard/SdSpiCard.h
  83. 1 1
      src/SdCard/SdioCard.h
  84. 3 3
      src/SdCard/SdioTeensy.cpp
  85. 1 1
      src/SdCard/SdioTeensy.h
  86. 11 5
      src/SdFat.h
  87. 22 1
      src/SdFatConfig.h
  88. 2 2
      src/SpiDriver/SdSpiArtemis.cpp
  89. 1 1
      src/SpiDriver/SdSpiBaseClass.h
  90. 4 4
      src/common/BlockDeviceInterface.h
  91. 74 0
      src/common/CompileDateTime.h
  92. 1 1
      src/common/FmtNumber.cpp
  93. 1 1
      src/common/FsDateTime.cpp
  94. 30 16
      src/common/FsDateTime.h
  95. 2 2
      src/common/PrintBasic.h
  96. 4 1
      src/common/SysCall.h
  97. 2 2
      src/iostream/StdioStream.cpp
  98. 1 1
      src/iostream/StreamBaseClass.cpp
  99. 2 2
      src/iostream/bufstream.h
  100. 2 2
      src/iostream/fstream.h

+ 28 - 16
examples/AvrAdcLogger/AvrAdcLogger.ino

@@ -44,10 +44,16 @@ MinimumSerial MinSerial;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // Set USE_RTC nonzero for file timestamps.
 // Set USE_RTC nonzero for file timestamps.
 // RAM use will be marginal on Uno with RTClib.
 // RAM use will be marginal on Uno with RTClib.
+// Set USE_RTC nonzero for file timestamps.
+// RAM use will be marginal on Uno with RTClib.
+// 0 - RTC not used
+// 1 - DS1307
+// 2 - DS3231
+// 3 - PCF8523
 #define USE_RTC 0
 #define USE_RTC 0
 #if USE_RTC
 #if USE_RTC
 #include "RTClib.h"
 #include "RTClib.h"
-#endif
+#endif  // USE_RTC
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // Pin definitions.
 // Pin definitions.
 //
 //
@@ -141,7 +147,7 @@ const uint16_t MIN_ADC_CYCLES = 15;
 // Extra cpu cycles to setup ADC with more than one pin per sample.
 // Extra cpu cycles to setup ADC with more than one pin per sample.
 const uint16_t ISR_SETUP_ADC = PIN_COUNT > 1 ? 100 : 0;
 const uint16_t ISR_SETUP_ADC = PIN_COUNT > 1 ? 100 : 0;
 
 
-// Maximum cycles for timer0 system interrupt, millis, micros.
+// Maximum cycles for timer0 system interrupt.
 const uint16_t ISR_TIMER0 = 160;
 const uint16_t ISR_TIMER0 = 160;
 //==============================================================================
 //==============================================================================
 const uint32_t MAX_FILE_SIZE = MAX_FILE_SIZE_MiB << 20;
 const uint32_t MAX_FILE_SIZE = MAX_FILE_SIZE_MiB << 20;
@@ -303,8 +309,15 @@ void printUnusedStack() {
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 #if USE_RTC
 #if USE_RTC
+#if USE_RTC == 1
 RTC_DS1307 rtc;
 RTC_DS1307 rtc;
-
+#elif USE_RTC == 2
+RTC_DS3231 rtc;
+#elif USE_RTC == 3
+RTC_PCF8523 rtc;
+#else  // USE_RTC == type
+#error USE_RTC type not implemented.
+#endif  // USE_RTC == type
 // Call back for file timestamps.  Only called for file create and sync().
 // Call back for file timestamps.  Only called for file create and sync().
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
   DateTime now = rtc.now();
   DateTime now = rtc.now();
@@ -553,6 +566,15 @@ void binaryToCsv() {
   Serial.println(F(" Seconds"));
   Serial.println(F(" Seconds"));
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+//------------------------------------------------------------------------------
 void createBinFile() {
 void createBinFile() {
   binFile.close();
   binFile.close();
   while (sd.exists(binName)) {
   while (sd.exists(binName)) {
@@ -719,7 +741,7 @@ void logData() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void openBinFile() {
 void openBinFile() {
   char name[NAME_DIM];
   char name[NAME_DIM];
-  serialClearInput();
+  clearSerialInput();
   Serial.println(F("Enter file name"));
   Serial.println(F("Enter file name"));
   if (!serialReadLine(name, sizeof(name))) {
   if (!serialReadLine(name, sizeof(name))) {
     return;
     return;
@@ -772,12 +794,6 @@ void printData() {
   Serial.println(F("Done"));
   Serial.println(F("Done"));
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-void serialClearInput() {
-  do {
-    delay(10);
-  } while (Serial.read() >= 0);
-}
-//------------------------------------------------------------------------------
 bool serialReadLine(char* str, size_t size) {
 bool serialReadLine(char* str, size_t size) {
   size_t n = 0;
   size_t n = 0;
   while(!Serial.available()) {
   while(!Serial.available()) {
@@ -840,9 +856,7 @@ void setup(void) {
 void loop(void) {
 void loop(void) {
   printUnusedStack();
   printUnusedStack();
   // Read any Serial data.
   // Read any Serial data.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
   Serial.println();
   Serial.println();
   Serial.println(F("type:"));
   Serial.println(F("type:"));
   Serial.println(F("b - open existing bin file"));
   Serial.println(F("b - open existing bin file"));
@@ -860,9 +874,7 @@ void loop(void) {
     digitalWrite(ERROR_LED_PIN, LOW);
     digitalWrite(ERROR_LED_PIN, LOW);
   }
   }
   // Read any Serial data.
   // Read any Serial data.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
 
 
   if (c == 'b') {
   if (c == 'b') {
     openBinFile();
     openBinFile();

+ 4 - 4
examples/BackwardCompatibility/BackwardCompatibility.ino

@@ -1,6 +1,6 @@
 // A simple read/write example for SD.h.
 // A simple read/write example for SD.h.
 // Mostly from the SD.h ReadWrite example.
 // Mostly from the SD.h ReadWrite example.
-// 
+//
 // Your SD must be formatted FAT16/FAT32.
 // Your SD must be formatted FAT16/FAT32.
 //
 //
 // Set USE_SD_H nonzero to use SD.h.
 // Set USE_SD_H nonzero to use SD.h.
@@ -28,14 +28,14 @@ void setup() {
 #if USE_SD_H
 #if USE_SD_H
   Serial.println(F("Using SD.h. Set USE_SD_H zero to use SdFat.h."));
   Serial.println(F("Using SD.h. Set USE_SD_H zero to use SdFat.h."));
 #else  // USE_SD_H
 #else  // USE_SD_H
-  Serial.println(F("Using SdFat.h. Set USE_SD_H nonzero to use SD.h."));  
-#endif  // USE_SD_H  
+  Serial.println(F("Using SdFat.h. Set USE_SD_H nonzero to use SD.h."));
+#endif  // USE_SD_H
   Serial.println(F("\nType any character to begin."));
   Serial.println(F("\nType any character to begin."));
   while (!Serial.available()) {
   while (!Serial.available()) {
     yield();
     yield();
   }
   }
   Serial.print("Initializing SD card...");
   Serial.print("Initializing SD card...");
-  
+
   if (!SD.begin(SD_CS_PIN)) {
   if (!SD.begin(SD_CS_PIN)) {
     Serial.println("initialization failed!");
     Serial.println("initialization failed!");
     return;
     return;

+ 14 - 8
examples/ExFatFormatter/ExFatFormatter.ino

@@ -3,7 +3,7 @@
 
 
 /*
 /*
   Change the value of SD_CS_PIN if you are using SPI and
   Change the value of SD_CS_PIN if you are using SPI and
-  your hardware does not use the default value, SS.  
+  your hardware does not use the default value, SS.
   Common values are:
   Common values are:
   Arduino Ethernet shield: pin 4
   Arduino Ethernet shield: pin 4
   Sparkfun SD shield: pin 8
   Sparkfun SD shield: pin 8
@@ -31,6 +31,15 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
 
 
 SdExFat sd;
 SdExFat sd;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+//------------------------------------------------------------------------------
 void errorHalt() {
 void errorHalt() {
   sd.printSdError(&Serial);
   sd.printSdError(&Serial);
   SysCall::halt();
   SysCall::halt();
@@ -41,20 +50,17 @@ void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
   while (!Serial) {}
   while (!Serial) {}
   Serial.println(F("Type any character to begin"));
   Serial.println(F("Type any character to begin"));
-  
+
   while (!Serial.available()) {
   while (!Serial.available()) {
     yield();
     yield();
   }
   }
-  do {
-    delay(10);
-  } while(Serial.read() >= 0);
-  
+  clearSerialInput();
   Serial.println();
   Serial.println();
   Serial.println(F(
   Serial.println(F(
     "Your SD will be formated exFAT.\r\n"
     "Your SD will be formated exFAT.\r\n"
     "All data on the SD will be lost.\r\n"
     "All data on the SD will be lost.\r\n"
     "Type 'Y' to continue.\r\n"));
     "Type 'Y' to continue.\r\n"));
-    
+
   while (!Serial.available()) {
   while (!Serial.available()) {
     yield();
     yield();
   }
   }
@@ -64,7 +70,7 @@ void setup() {
   }
   }
   if (!sd.cardBegin(SD_CONFIG)) {
   if (!sd.cardBegin(SD_CONFIG)) {
     error("cardBegin failed");
     error("cardBegin failed");
-  }    
+  }
   if(!sd.format(&Serial)) {
   if(!sd.format(&Serial)) {
     error("format failed");
     error("format failed");
   }
   }

+ 29 - 15
examples/ExFatLogger/ExFatLogger.ino

@@ -24,6 +24,10 @@ const uint32_t LOG_INTERVAL_USEC = 2000;
 
 
 // Set USE_RTC nonzero for file timestamps.
 // Set USE_RTC nonzero for file timestamps.
 // RAM use will be marginal on Uno with RTClib.
 // RAM use will be marginal on Uno with RTClib.
+// 0 - RTC not used
+// 1 - DS1307
+// 2 - DS3231
+// 3 - PCF8523
 #define USE_RTC 0
 #define USE_RTC 0
 #if USE_RTC
 #if USE_RTC
 #include "RTClib.h"
 #include "RTClib.h"
@@ -151,8 +155,15 @@ file_t csvFile;
 char binName[] = "ExFatLogger00.bin";
 char binName[] = "ExFatLogger00.bin";
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 #if USE_RTC
 #if USE_RTC
+#if USE_RTC == 1
 RTC_DS1307 rtc;
 RTC_DS1307 rtc;
-
+#elif USE_RTC == 2
+RTC_DS3231 rtc;
+#elif USE_RTC == 3
+RTC_PCF8523 rtc;
+#else  // USE_RTC == type
+#error USE_RTC type not implemented.
+#endif  // USE_RTC == type
 // Call back for file timestamps.  Only called for file create and sync().
 // Call back for file timestamps.  Only called for file create and sync().
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
   DateTime now = rtc.now();
   DateTime now = rtc.now();
@@ -211,6 +222,15 @@ void binaryToCsv() {
   Serial.print(0.001*(millis() - t0));
   Serial.print(0.001*(millis() - t0));
   Serial.println(F(" Seconds"));
   Serial.println(F(" Seconds"));
 }
 }
+//------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
 //-------------------------------------------------------------------------------
 //-------------------------------------------------------------------------------
 void createBinFile() {
 void createBinFile() {
   binFile.close();
   binFile.close();
@@ -261,7 +281,7 @@ bool createCsvFile() {
   if (!csvFile.open(csvName, O_WRONLY | O_CREAT | O_TRUNC)) {
   if (!csvFile.open(csvName, O_WRONLY | O_CREAT | O_TRUNC)) {
     error("open csvFile failed");
     error("open csvFile failed");
   }
   }
-  serialClearInput();
+  clearSerialInput();
   Serial.print(F("Writing: "));
   Serial.print(F("Writing: "));
   Serial.print(csvName);
   Serial.print(csvName);
   Serial.println(F(" - type any character to stop"));
   Serial.println(F(" - type any character to stop"));
@@ -289,7 +309,7 @@ void logData() {
   if (binFile.write(fifoBuf, 512) != 512) {
   if (binFile.write(fifoBuf, 512) != 512) {
     error("write first sector failed");
     error("write first sector failed");
   }
   }
-  serialClearInput();
+  clearSerialInput();
   Serial.println(F("Type any character to stop"));
   Serial.println(F("Type any character to stop"));
 
 
   // Wait until SD is not busy.
   // Wait until SD is not busy.
@@ -397,7 +417,7 @@ void logData() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void openBinFile() {
 void openBinFile() {
   char name[FILE_NAME_DIM];
   char name[FILE_NAME_DIM];
-  serialClearInput();
+  clearSerialInput();
   Serial.println(F("Enter file name"));
   Serial.println(F("Enter file name"));
   if (!serialReadLine(name, sizeof(name))) {
   if (!serialReadLine(name, sizeof(name))) {
     return;
     return;
@@ -425,7 +445,7 @@ void printData() {
   if (!binFile.seekSet(512)) {
   if (!binFile.seekSet(512)) {
     error("seek failed");
     error("seek failed");
   }
   }
-  serialClearInput();
+  clearSerialInput();
   Serial.println(F("type any character to stop\n"));
   Serial.println(F("type any character to stop\n"));
   delay(1000);
   delay(1000);
   printRecord(&Serial, nullptr);
   printRecord(&Serial, nullptr);
@@ -439,16 +459,10 @@ void printData() {
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void printUnusedStack() {
 void printUnusedStack() {
-#if HAS_UNUSED_STACK  
+#if HAS_UNUSED_STACK
   Serial.print(F("\nUnused stack: "));
   Serial.print(F("\nUnused stack: "));
   Serial.println(UnusedStack());
   Serial.println(UnusedStack());
-#endif  // HAS_UNUSED_STACK 
-}
-//------------------------------------------------------------------------------
-void serialClearInput() {
-  do {
-    delay(10);
-  } while (Serial.read() >= 0);
+#endif  // HAS_UNUSED_STACK
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 bool serialReadLine(char* str, size_t size) {
 bool serialReadLine(char* str, size_t size) {
@@ -476,7 +490,7 @@ void testSensor() {
   const uint32_t interval = 200000;
   const uint32_t interval = 200000;
   int32_t diff;
   int32_t diff;
   data_t data;
   data_t data;
-  serialClearInput();
+  clearSerialInput();
   Serial.println(F("\nTesting - type any character to stop\n"));
   Serial.println(F("\nTesting - type any character to stop\n"));
   delay(1000);
   delay(1000);
   printRecord(&Serial, nullptr);
   printRecord(&Serial, nullptr);
@@ -538,7 +552,7 @@ void setup() {
 void loop() {
 void loop() {
   printUnusedStack();
   printUnusedStack();
   // Read any Serial data.
   // Read any Serial data.
-  serialClearInput();
+  clearSerialInput();
 
 
   if (ERROR_LED_PIN >= 0) {
   if (ERROR_LED_PIN >= 0) {
     digitalWrite(ERROR_LED_PIN, LOW);
     digitalWrite(ERROR_LED_PIN, LOW);

+ 5 - 5
examples/OpenNext/OpenNext.ino

@@ -8,7 +8,7 @@
 #define SD_FAT_TYPE 0
 #define SD_FAT_TYPE 0
 /*
 /*
   Change the value of SD_CS_PIN if you are using SPI and
   Change the value of SD_CS_PIN if you are using SPI and
-  your hardware does not use the default value, SS.  
+  your hardware does not use the default value, SS.
   Common values are:
   Common values are:
   Arduino Ethernet shield: pin 4
   Arduino Ethernet shield: pin 4
   Sparkfun SD shield: pin 8
   Sparkfun SD shield: pin 8
@@ -57,12 +57,12 @@ FsFile file;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
-  
+
   Serial.println("Type any character to start");
   Serial.println("Type any character to start");
   while (!Serial.available()) {
   while (!Serial.available()) {
     SysCall::yield();
     SysCall::yield();
@@ -72,7 +72,7 @@ void setup() {
   if (!sd.begin(SD_CONFIG)) {
   if (!sd.begin(SD_CONFIG)) {
     sd.initErrorHalt(&Serial);
     sd.initErrorHalt(&Serial);
   }
   }
-  // Open root directory 
+  // Open root directory
   if (!dir.open("/")){
   if (!dir.open("/")){
     error("dir.open failed");
     error("dir.open failed");
   }
   }

+ 12 - 6
examples/QuickStart/QuickStart.ino

@@ -48,6 +48,15 @@ void cardOrSpeed() {
   cout << F("Edit SPI_SPEED in this program to change it.\n");
   cout << F("Edit SPI_SPEED in this program to change it.\n");
 }
 }
 
 
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+
 void reformatMsg() {
 void reformatMsg() {
   cout << F("Try reformatting the card.  For best results use\n");
   cout << F("Try reformatting the card.  For best results use\n");
   cout << F("the SdFormatter program in SdFat/examples or download\n");
   cout << F("the SdFormatter program in SdFat/examples or download\n");
@@ -88,9 +97,7 @@ void setup() {
 bool firstTry = true;
 bool firstTry = true;
 void loop() {
 void loop() {
   // Read any existing Serial data.
   // Read any existing Serial data.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
 
 
   if (!firstTry) {
   if (!firstTry) {
     cout << F("\nRestarting\n");
     cout << F("\nRestarting\n");
@@ -171,9 +178,8 @@ void loop() {
     return;
     return;
   }
   }
   // Read any extra Serial data.
   // Read any extra Serial data.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
+
   cout << F("\nSuccess!  Type any character to restart.\n");
   cout << F("\nSuccess!  Type any character to restart.\n");
   while (!Serial.available()) {
   while (!Serial.available()) {
     SysCall::yield();
     SysCall::yield();

+ 15 - 15
examples/ReadCsvFile/ReadCsvFile.ino

@@ -5,7 +5,7 @@
 #define SD_FAT_TYPE 0
 #define SD_FAT_TYPE 0
 /*
 /*
   Change the value of SD_CS_PIN if you are using SPI and
   Change the value of SD_CS_PIN if you are using SPI and
-  your hardware does not use the default value, SS.  
+  your hardware does not use the default value, SS.
   Common values are:
   Common values are:
   Arduino Ethernet shield: pin 4
   Arduino Ethernet shield: pin 4
   Sparkfun SD shield: pin 8
   Sparkfun SD shield: pin 8
@@ -63,25 +63,25 @@ bool parseLine(char* str) {
   // Set strtok start of line.
   // Set strtok start of line.
   str = strtok(str, ",");
   str = strtok(str, ",");
   if (!str) return false;
   if (!str) return false;
-  
+
   // Print text field.
   // Print text field.
   Serial.println(str);
   Serial.println(str);
-  
+
   // Subsequent calls to strtok expects a null pointer.
   // Subsequent calls to strtok expects a null pointer.
   str = strtok(nullptr, ",");
   str = strtok(nullptr, ",");
   if (!str) return false;
   if (!str) return false;
-  
+
   // Convert string to long integer.
   // Convert string to long integer.
   int32_t i32 = strtol(str, &ptr, 0);
   int32_t i32 = strtol(str, &ptr, 0);
   if (str == ptr || *skipSpace(ptr)) return false;
   if (str == ptr || *skipSpace(ptr)) return false;
   Serial.println(i32);
   Serial.println(i32);
-  
+
   str = strtok(nullptr, ",");
   str = strtok(nullptr, ",");
   if (!str) return false;
   if (!str) return false;
-  
+
   // strtoul accepts a leading minus with unexpected results.
   // strtoul accepts a leading minus with unexpected results.
   if (*skipSpace(str) == '-') return false;
   if (*skipSpace(str) == '-') return false;
-  
+
   // Convert string to unsigned long integer.
   // Convert string to unsigned long integer.
   uint32_t u32 = strtoul(str, &ptr, 0);
   uint32_t u32 = strtoul(str, &ptr, 0);
   if (str == ptr || *skipSpace(ptr)) return false;
   if (str == ptr || *skipSpace(ptr)) return false;
@@ -89,20 +89,20 @@ bool parseLine(char* str) {
 
 
   str = strtok(nullptr, ",");
   str = strtok(nullptr, ",");
   if (!str) return false;
   if (!str) return false;
-  
+
   // Convert string to double.
   // Convert string to double.
   double d = strtod(str, &ptr);
   double d = strtod(str, &ptr);
   if (str == ptr || *skipSpace(ptr)) return false;
   if (str == ptr || *skipSpace(ptr)) return false;
   Serial.println(d);
   Serial.println(d);
-  
+
   // Check for extra fields.
   // Check for extra fields.
   return strtok(nullptr, ",") == nullptr;
   return strtok(nullptr, ",") == nullptr;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     yield();
     yield();
   }
   }
@@ -117,7 +117,7 @@ void setup() {
   }
   }
   // Remove any existing file.
   // Remove any existing file.
   if (sd.exists("ReadCsvDemo.csv")) {
   if (sd.exists("ReadCsvDemo.csv")) {
-    sd.remove("ReadCsvDemo.csv"); 
+    sd.remove("ReadCsvDemo.csv");
   }
   }
   // Create the file.
   // Create the file.
   if (!file.open("ReadCsvDemo.csv", FILE_WRITE)) {
   if (!file.open("ReadCsvDemo.csv", FILE_WRITE)) {
@@ -128,14 +128,14 @@ void setup() {
     "abc,123,456,7.89\r\n"
     "abc,123,456,7.89\r\n"
     "def,-321,654,-9.87\r\n"
     "def,-321,654,-9.87\r\n"
     "ghi,333,0xff,5.55"));
     "ghi,333,0xff,5.55"));
-    
+
   // Rewind file for read.
   // Rewind file for read.
   file.rewind();
   file.rewind();
-  
+
   while (file.available()) {
   while (file.available()) {
     int n = file.fgets(line, sizeof(line));
     int n = file.fgets(line, sizeof(line));
     if (n <= 0) {
     if (n <= 0) {
-      error("fgets failed"); 
+      error("fgets failed");
     }
     }
     if (line[n-1] != '\n' && n == (sizeof(line) - 1)) {
     if (line[n-1] != '\n' && n == (sizeof(line) - 1)) {
       error("line too long");
       error("line too long");

+ 106 - 14
examples/RtcTimestampTest/RtcTimestampTest.ino

@@ -4,13 +4,19 @@
 #include "SdFat.h"
 #include "SdFat.h"
 // https://github.com/adafruit/RTClib
 // https://github.com/adafruit/RTClib
 #include "RTClib.h"
 #include "RTClib.h"
+// Set RTC_TYPE for file timestamps.
+// 0 - millis()
+// 1 - DS1307
+// 2 - DS3231
+// 3 - PCF8523
+#define RTC_TYPE 3
 
 
 // SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
 // SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
 // 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
 // 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
 #define SD_FAT_TYPE 0
 #define SD_FAT_TYPE 0
 /*
 /*
   Change the value of SD_CS_PIN if you are using SPI and
   Change the value of SD_CS_PIN if you are using SPI and
-  your hardware does not use the default value, SS.  
+  your hardware does not use the default value, SS.
   Common values are:
   Common values are:
   Arduino Ethernet shield: pin 4
   Arduino Ethernet shield: pin 4
   Sparkfun SD shield: pin 8
   Sparkfun SD shield: pin 8
@@ -50,7 +56,19 @@ FsFile file;
 #error Invalid SD_FAT_TYPE
 #error Invalid SD_FAT_TYPE
 #endif  // SD_FAT_TYPE
 #endif  // SD_FAT_TYPE
 
 
+
+#if RTC_TYPE == 0
+RTC_Millis rtc;
+#elif RTC_TYPE == 1
 RTC_DS1307 rtc;
 RTC_DS1307 rtc;
+#elif RTC_TYPE == 2
+RTC_DS3231 rtc;
+#elif RTC_TYPE == 3
+RTC_PCF8523 rtc;
+#else  // RTC_TYPE == type
+#error RTC_TYPE type not implemented.
+#endif  // RTC_TYPE == type
+
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // Call back for file timestamps.  Only called for file create and sync().
 // Call back for file timestamps.  Only called for file create and sync().
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
@@ -61,46 +79,111 @@ void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
 
 
   // Return time using FS_TIME macro to format fields.
   // Return time using FS_TIME macro to format fields.
   *time = FS_TIME(now.hour(), now.minute(), now.second());
   *time = FS_TIME(now.hour(), now.minute(), now.second());
-  
+
   // Return low time bits in units of 10 ms, 0 <= ms10 <= 199.
   // Return low time bits in units of 10 ms, 0 <= ms10 <= 199.
   *ms10 = now.second() & 1 ? 100 : 0;
   *ms10 = now.second() & 1 ? 100 : 0;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+#define error(msg) (Serial.println(F("error " msg)), false)
+//------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+//------------------------------------------------------------------------------
+void getLine(char* line, size_t size) {
+  size_t i = 0;
+  uint32_t t;
+  line[0] = '\0';
+  while (!Serial.available()) {
+    yield();
+  }
+  while (true) {
+    t = millis() + 10;
+    while (!Serial.available()) {
+      if (millis() > t){
+        return;
+      }
+    }
+    int c = Serial.read();
+    if (i >= (size - 1) || c == '\r' || c == '\n' ) {
+      return;
+    }
+    line[i++] = c;
+    line[i] = '\0';
+  }
+}
+//------------------------------------------------------------------------------
 void printField(Print* pr, char sep, uint8_t v) {
 void printField(Print* pr, char sep, uint8_t v) {
   if (sep) {
   if (sep) {
     pr->write(sep);
     pr->write(sep);
-  }  
+  }
   if (v < 10) {
   if (v < 10) {
     pr->write('0');
     pr->write('0');
   }
   }
   pr->print(v);
   pr->print(v);
 }
 }
-//------------------------------------------------------------------------------  
+//------------------------------------------------------------------------------
 void printNow(Print* pr) {
 void printNow(Print* pr) {
   DateTime now = rtc.now();
   DateTime now = rtc.now();
   pr->print(now.year());
   pr->print(now.year());
   printField(pr, '-',now.month());
   printField(pr, '-',now.month());
-  printField(pr, '-',now.day());  
+  printField(pr, '-',now.day());
   printField(pr, ' ',now.hour());
   printField(pr, ' ',now.hour());
   printField(pr, ':',now.minute());
   printField(pr, ':',now.minute());
   printField(pr, ':',now.second());
   printField(pr, ':',now.second());
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+bool setRtc() {
+  uint16_t y;
+  uint8_t m, d, hh, mm, ss;
+  char line[30];
+  char* ptr;
+
+  clearSerialInput();
+  Serial.println(F("Enter: YYYY-MM-DD hh:mm:ss"));
+  getLine(line, sizeof(line));
+  Serial.print(F("Input: "));
+  Serial.println(line);
+
+  y = strtol(line, &ptr, 0);
+  if (*ptr++ != '-' || y < 2000 || y > 2099) return error("year");
+  m = strtol(ptr, &ptr, 0);
+  if (*ptr++ != '-' || m < 1 || m > 12) return error("month");
+  d = strtol(ptr, &ptr, 0);
+  if (d < 1 || d > 31) return error("day");
+  hh = strtol(ptr, &ptr, 0);
+  if (*ptr++ != ':' || hh > 23) return error("hour");
+  mm = strtol(ptr, &ptr, 0);
+  if (*ptr++ != ':' || mm > 59) return error("minute");
+  ss = strtol(ptr, &ptr, 0);
+  if (ss > 59) return error("second");
+
+  rtc.adjust(DateTime(y, m, d, hh, mm, ss));
+  Serial.print(F("RTC set to "));
+  printNow(&Serial);
+  Serial.println();
+  return true;
+}
+//------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
   while (!Serial) {
   while (!Serial) {
     yield();
     yield();
   }
   }
-  Serial.println(F("Type any character to begin"));
-  while (!Serial.available()) {
-    yield();
-  }
+#if RTC_TYPE == 0
+  rtc.begin(DateTime(F(__DATE__), F(__TIME__)));
+#else  // RTC_TYPE
   if (!rtc.begin()) {
   if (!rtc.begin()) {
     Serial.println(F("rtc.begin failed"));
     Serial.println(F("rtc.begin failed"));
     return;
     return;
   }
   }
   if (!rtc.isrunning()) {
   if (!rtc.isrunning()) {
-    Serial.println("RTC is NOT running!");
+    Serial.println(F("RTC is NOT running!"));
     return;
     return;
     // following line sets the RTC to the date & time this sketch was compiled
     // following line sets the RTC to the date & time this sketch was compiled
     // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
     // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
@@ -108,13 +191,22 @@ void setup() {
     // January 21, 2014 at 3am you would call:
     // January 21, 2014 at 3am you would call:
     // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
     // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
   }
   }
-  Serial.print(F("DateTime::now "));
-  printNow(&Serial);
+#endif  // RTC_TYPE
+  while (true) {
+    Serial.print(F("DateTime::now "));
+    printNow(&Serial);
+    Serial.println();
+    clearSerialInput();
+    Serial.println(F("Type Y to set RTC, any other character to continue"));
+    while (!Serial.available()) {}
+    if (Serial.read() != 'Y') break;
+    if (setRtc()) break;
+  }
   Serial.println();
   Serial.println();
 
 
   // Set callback
   // Set callback
   FsDateTime::setCallback(dateTime);
   FsDateTime::setCallback(dateTime);
-  
+
   if (!sd.begin(SD_CONFIG)) {
   if (!sd.begin(SD_CONFIG)) {
     sd.initErrorHalt(&Serial);
     sd.initErrorHalt(&Serial);
   }
   }
@@ -130,7 +222,7 @@ void setup() {
   file.print(F("Test file at: "));
   file.print(F("Test file at: "));
   printNow(&file);
   printNow(&file);
   file.println();
   file.println();
-  
+
   file.close();
   file.close();
   // List files in SD root.
   // List files in SD root.
   sd.ls(LS_DATE | LS_SIZE);
   sd.ls(LS_DATE | LS_SIZE);

+ 6 - 6
examples/STM32Test/STM32Test.ino

@@ -7,7 +7,7 @@
 #include "FreeStack.h"
 #include "FreeStack.h"
 
 
 // Chip select PA4, shared SPI, 18 MHz, port 1.
 // Chip select PA4, shared SPI, 18 MHz, port 1.
-#define SD1_CONFIG SdSpiConfig(PA4, SHARED_SPI, SD_SCK_MHZ(18), &SPI) 
+#define SD1_CONFIG SdSpiConfig(PA4, SHARED_SPI, SD_SCK_MHZ(18), &SPI)
 SdFs sd1;
 SdFs sd1;
 FsFile file1;
 FsFile file1;
 
 
@@ -36,7 +36,7 @@ void errorHalt() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
@@ -65,7 +65,7 @@ void setup() {
   }
   }
   // Make Dir1 the working directory on sd1.
   // Make Dir1 the working directory on sd1.
   if (!sd1.chdir("Dir1")) {
   if (!sd1.chdir("Dir1")) {
-     error("dsd1.chdir");   
+     error("dsd1.chdir");
   }
   }
   // initialize the second card
   // initialize the second card
   if (!sd2.begin(SD2_CONFIG)) {
   if (!sd2.begin(SD2_CONFIG)) {
@@ -79,8 +79,8 @@ void setup() {
   }
   }
   // Make Dir2 the working directory on sd2.
   // Make Dir2 the working directory on sd2.
   if (!sd2.chdir("Dir2")) {
   if (!sd2.chdir("Dir2")) {
-     error("sd2.chdir");   
-  }  
+     error("sd2.chdir");
+  }
   // remove test.bin from /Dir1 directory of sd1
   // remove test.bin from /Dir1 directory of sd1
   if (sd1.exists("test.bin")) {
   if (sd1.exists("test.bin")) {
     if (!sd1.remove("test.bin")) {
     if (!sd1.remove("test.bin")) {
@@ -144,7 +144,7 @@ void setup() {
   // close test.bin
   // close test.bin
   file1.close();
   file1.close();
   // sync copy.bin so ls works.
   // sync copy.bin so ls works.
-  file2.close(); 
+  file2.close();
   // list directories.
   // list directories.
   Serial.println(F("------sd1 -------"));
   Serial.println(F("------sd1 -------"));
   sd1.ls("/", LS_R | LS_SIZE);
   sd1.ls("/", LS_R | LS_SIZE);

+ 12 - 6
examples/SdFormatter/SdFormatter.ino

@@ -73,6 +73,15 @@ void sdErrorHalt() {
   SysCall::halt();
   SysCall::halt();
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+//------------------------------------------------------------------------------
 // flash erase all data
 // flash erase all data
 uint32_t const ERASE_SIZE = 262144L;
 uint32_t const ERASE_SIZE = 262144L;
 void eraseCard() {
 void eraseCard() {
@@ -154,9 +163,8 @@ void setup() {
     SysCall::yield();
     SysCall::yield();
   }
   }
   // Discard any extra characters.
   // Discard any extra characters.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
+
   cout << F(
   cout << F(
          "\n"
          "\n"
          "This program can erase and/or format SD/SDHC/SDXC cards.\n"
          "This program can erase and/or format SD/SDHC/SDXC cards.\n"
@@ -181,9 +189,7 @@ void setup() {
     return;
     return;
   }
   }
   // Read any existing Serial data.
   // Read any existing Serial data.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
 
 
   // Select and initialize proper card driver.
   // Select and initialize proper card driver.
   m_card = cardFactory.newCard(SD_CONFIG);
   m_card = cardFactory.newCard(SD_CONFIG);

+ 10 - 3
examples/SdInfo/SdInfo.ino

@@ -59,6 +59,15 @@ bool cidDmp() {
   return true;
   return true;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+//------------------------------------------------------------------------------
 bool csdDmp() {
 bool csdDmp() {
   bool eraseSingleBlock;
   bool eraseSingleBlock;
   if (m_csd.v1.csd_ver == 0) {
   if (m_csd.v1.csd_ver == 0) {
@@ -206,9 +215,7 @@ void setup() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void loop() {
 void loop() {
   // Read any existing Serial data.
   // Read any existing Serial data.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
 
 
   // F stores strings in flash to save RAM
   // F stores strings in flash to save RAM
   cout << F("\ntype any character to start\n");
   cout << F("\ntype any character to start\n");

+ 2 - 2
examples/SoftwareSpi/SoftwareSpi.ino

@@ -41,7 +41,7 @@ FsFile file;
 
 
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
@@ -60,7 +60,7 @@ void setup() {
   file.println(F("This line was printed using software SPI."));
   file.println(F("This line was printed using software SPI."));
 
 
   file.rewind();
   file.rewind();
-  
+
   while (file.available()) {
   while (file.available()) {
     Serial.write(file.read());
     Serial.write(file.read());
   }
   }

+ 9 - 9
examples/TeensyRtcTimestamp/TeensyRtcTimestamp.ino

@@ -9,7 +9,7 @@
 #define SD_FAT_TYPE 3
 #define SD_FAT_TYPE 3
 /*
 /*
   Change the value of SD_CS_PIN if you are using SPI and
   Change the value of SD_CS_PIN if you are using SPI and
-  your hardware does not use the default value, SS.  
+  your hardware does not use the default value, SS.
   Common values are:
   Common values are:
   Arduino Ethernet shield: pin 4
   Arduino Ethernet shield: pin 4
   Sparkfun SD shield: pin 8
   Sparkfun SD shield: pin 8
@@ -52,13 +52,13 @@ FsFile file;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // Call back for file timestamps.  Only called for file create and sync().
 // Call back for file timestamps.  Only called for file create and sync().
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
-  
+
   // Return date using FS_DATE macro to format fields.
   // Return date using FS_DATE macro to format fields.
   *date = FS_DATE(year(), month(), day());
   *date = FS_DATE(year(), month(), day());
 
 
   // Return time using FS_TIME macro to format fields.
   // Return time using FS_TIME macro to format fields.
   *time = FS_TIME(hour(), minute(), second());
   *time = FS_TIME(hour(), minute(), second());
-  
+
   // Return low time bits in units of 10 ms.
   // Return low time bits in units of 10 ms.
   *ms10 = second() & 1 ? 100 : 0;
   *ms10 = second() & 1 ? 100 : 0;
 }
 }
@@ -71,17 +71,17 @@ time_t getTeensy3Time()
 void printField(Print* pr, char sep, uint8_t v) {
 void printField(Print* pr, char sep, uint8_t v) {
   if (sep) {
   if (sep) {
     pr->write(sep);
     pr->write(sep);
-  }  
+  }
   if (v < 10) {
   if (v < 10) {
     pr->write('0');
     pr->write('0');
   }
   }
   pr->print(v);
   pr->print(v);
 }
 }
-//------------------------------------------------------------------------------  
+//------------------------------------------------------------------------------
 void printNow(Print* pr) {
 void printNow(Print* pr) {
   pr->print(year());
   pr->print(year());
   printField(pr, '-', month());
   printField(pr, '-', month());
-  printField(pr, '-', day());  
+  printField(pr, '-', day());
   printField(pr, ' ', hour());
   printField(pr, ' ', hour());
   printField(pr, ':', minute());
   printField(pr, ':', minute());
   printField(pr, ':', second());
   printField(pr, ':', second());
@@ -90,7 +90,7 @@ void printNow(Print* pr) {
 void setup() {
 void setup() {
   // set the Time library to use Teensy 3.0's RTC to keep time
   // set the Time library to use Teensy 3.0's RTC to keep time
   setSyncProvider(getTeensy3Time);
   setSyncProvider(getTeensy3Time);
-  
+
   Serial.begin(9600);
   Serial.begin(9600);
   while (!Serial) {
   while (!Serial) {
     yield();
     yield();
@@ -109,7 +109,7 @@ void setup() {
 
 
   // Set callback
   // Set callback
   FsDateTime::setCallback(dateTime);
   FsDateTime::setCallback(dateTime);
-  
+
   if (!sd.begin(SD_CONFIG)) {
   if (!sd.begin(SD_CONFIG)) {
     sd.initErrorHalt(&Serial);
     sd.initErrorHalt(&Serial);
   }
   }
@@ -125,7 +125,7 @@ void setup() {
   file.print(F("Test file at: "));
   file.print(F("Test file at: "));
   printNow(&file);
   printNow(&file);
   file.println();
   file.println();
-  
+
   file.close();
   file.close();
   // List files in SD root.
   // List files in SD root.
   sd.ls(LS_DATE | LS_SIZE);
   sd.ls(LS_DATE | LS_SIZE);

+ 19 - 12
examples/TeensySdioDemo/TeensySdioDemo.ino

@@ -52,6 +52,15 @@ uint32_t yieldCalls = 0;
 // Max busy time for single yield call.
 // Max busy time for single yield call.
 uint32_t yieldMaxUsec = 0;
 uint32_t yieldMaxUsec = 0;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+//------------------------------------------------------------------------------
 void errorHalt(const char* msg) {
 void errorHalt(const char* msg) {
   Serial.print("Error: ");
   Serial.print("Error: ");
   Serial.println(msg);
   Serial.println(msg);
@@ -63,7 +72,7 @@ void errorHalt(const char* msg) {
     Serial.print(", ErrorData: 0X");
     Serial.print(", ErrorData: 0X");
     Serial.println(sd.sdErrorData(), HEX);
     Serial.println(sd.sdErrorData(), HEX);
   }
   }
-  while (true) {} 
+  while (true) {}
 }
 }
 bool ready = false;
 bool ready = false;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -94,14 +103,14 @@ void runTest() {
   totalMicros = 0;
   totalMicros = 0;
   yieldMicros = 0;
   yieldMicros = 0;
   yieldCalls = 0;
   yieldCalls = 0;
-  yieldMaxUsec = 0; 
+  yieldMaxUsec = 0;
   if (!file.open("TeensyDemo.bin", O_RDWR | O_CREAT)) {
   if (!file.open("TeensyDemo.bin", O_RDWR | O_CREAT)) {
     errorHalt("open failed");
     errorHalt("open failed");
   }
   }
   Serial.println("\nsize,write,read");
   Serial.println("\nsize,write,read");
   Serial.println("bytes,KB/sec,KB/sec");
   Serial.println("bytes,KB/sec,KB/sec");
   for (size_t nb = 512; nb <= BUF_DIM; nb *= 2) {
   for (size_t nb = 512; nb <= BUF_DIM; nb *= 2) {
-    uint32_t nRdWr = FILE_SIZE/nb;   
+    uint32_t nRdWr = FILE_SIZE/nb;
     if (!file.truncate(0)) {
     if (!file.truncate(0)) {
       errorHalt("truncate failed");
       errorHalt("truncate failed");
     }
     }
@@ -123,19 +132,19 @@ void runTest() {
     Serial.print(',');
     Serial.print(',');
     file.rewind();
     file.rewind();
     t = micros();
     t = micros();
-    
+
     for (uint32_t n = 0; n < nRdWr; n++) {
     for (uint32_t n = 0; n < nRdWr; n++) {
       if ((int)nb != file.read(buf, nb)) {
       if ((int)nb != file.read(buf, nb)) {
         errorHalt("read failed");
         errorHalt("read failed");
       }
       }
-      // crude check of data.     
+      // crude check of data.
       if (buf32[0] != n || buf32[nb/4 - 1] != n) {
       if (buf32[0] != n || buf32[nb/4 - 1] != n) {
         errorHalt("data check");
         errorHalt("data check");
       }
       }
     }
     }
     t = micros() - t;
     t = micros() - t;
-    totalMicros += t;   
-    Serial.println(1000.0*FILE_SIZE/t);    
+    totalMicros += t;
+    Serial.println(1000.0*FILE_SIZE/t);
   }
   }
   file.close();
   file.close();
   Serial.print("\ntotalMicros  ");
   Serial.print("\ntotalMicros  ");
@@ -145,7 +154,7 @@ void runTest() {
   Serial.print("yieldCalls   ");
   Serial.print("yieldCalls   ");
   Serial.println(yieldCalls);
   Serial.println(yieldCalls);
   Serial.print("yieldMaxUsec ");
   Serial.print("yieldMaxUsec ");
-  Serial.println(yieldMaxUsec); 
+  Serial.println(yieldMaxUsec);
 //  Serial.print("kHzSdClk     ");
 //  Serial.print("kHzSdClk     ");
 //  Serial.println(kHzSdClk());
 //  Serial.println(kHzSdClk());
   Serial.println("Done");
   Serial.println("Done");
@@ -166,9 +175,7 @@ void loop() {
       "SPI mode so do SDIO tests first.\n"
       "SPI mode so do SDIO tests first.\n"
       "\nCycle power on the card if an error occurs.");
       "\nCycle power on the card if an error occurs.");
   }
   }
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read());
+  clearSerialInput();
 
 
   Serial.println(
   Serial.println(
     "\nType '1' for FIFO SDIO"
     "\nType '1' for FIFO SDIO"
@@ -198,7 +205,7 @@ void loop() {
     if (!sd.begin(SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(50)))) {
     if (!sd.begin(SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(50)))) {
       errorHalt("begin failed");
       errorHalt("begin failed");
     }
     }
-    Serial.println("\nShared SPI mode - slow for small transfers.");    
+    Serial.println("\nShared SPI mode - slow for small transfers.");
   } else {
   } else {
     Serial.println("Invalid input");
     Serial.println("Invalid input");
     return;
     return;

+ 3 - 3
examples/UserChipSelectFunction/UserChipSelectFunction.ino

@@ -5,7 +5,7 @@
 
 
 // SD_CHIP_SELECT_MODE must be set to one or two in SdFat/SdFatConfig.h.
 // SD_CHIP_SELECT_MODE must be set to one or two in SdFat/SdFatConfig.h.
 // A value of one allows optional replacement and two requires replacement.
 // A value of one allows optional replacement and two requires replacement.
-#if SD_CHIP_SELECT_MODE == 1 || SD_CHIP_SELECT_MODE == 2  
+#if SD_CHIP_SELECT_MODE == 1 || SD_CHIP_SELECT_MODE == 2
 
 
 // SD chip select pin.
 // SD chip select pin.
 #define SD_CS_PIN SS
 #define SD_CS_PIN SS
@@ -34,11 +34,11 @@ void setup() {
     sd.initErrorHalt(&Serial);
     sd.initErrorHalt(&Serial);
   }
   }
   sd.ls(&Serial, LS_SIZE);
   sd.ls(&Serial, LS_SIZE);
-  
+
   Serial.print(F("sdCsInit calls: "));
   Serial.print(F("sdCsInit calls: "));
   Serial.println(initCalls);
   Serial.println(initCalls);
   Serial.print(F("sdCsWrite calls: "));
   Serial.print(F("sdCsWrite calls: "));
-  Serial.println(writeCalls); 
+  Serial.println(writeCalls);
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void loop() {}
 void loop() {}

+ 2 - 2
examples/UserSPIDriver/UserSPIDriver.ino

@@ -21,7 +21,7 @@ class MySpiClass : public SdSpiBaseClass {
   }
   }
   // Initialize the SPI bus.
   // Initialize the SPI bus.
   void begin(SdSpiConfig config) {
   void begin(SdSpiConfig config) {
-    (void)config; 
+    (void)config;
     SPI.begin();
     SPI.begin();
   }
   }
   // Deactivate SPI hardware.
   // Deactivate SPI hardware.
@@ -32,7 +32,7 @@ class MySpiClass : public SdSpiBaseClass {
   uint8_t receive() {
   uint8_t receive() {
     return SPI.transfer(0XFF);
     return SPI.transfer(0XFF);
   }
   }
-  // Receive multiple bytes.  
+  // Receive multiple bytes.
   // Replace this function if your board has multiple byte receive.
   // Replace this function if your board has multiple byte receive.
   uint8_t receive(uint8_t* buf, size_t count) {
   uint8_t receive(uint8_t* buf, size_t count) {
     for (size_t i = 0; i < count; i++) {
     for (size_t i = 0; i < count; i++) {

+ 10 - 4
examples/bench/bench.ino

@@ -108,6 +108,15 @@ void cidDmp() {
   cout << endl;
   cout << endl;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+//------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
 
 
@@ -122,7 +131,6 @@ void setup() {
       "\nSet ENABLE_DEDICATED_SPI nonzero in\n"
       "\nSet ENABLE_DEDICATED_SPI nonzero in\n"
       "SdFatConfig.h for best SPI performance.\n");
       "SdFatConfig.h for best SPI performance.\n");
   }
   }
-
   // use uppercase in hex and use 0X base prefix
   // use uppercase in hex and use 0X base prefix
   cout << uppercase << showbase << endl;
   cout << uppercase << showbase << endl;
 }
 }
@@ -136,9 +144,7 @@ void loop() {
   bool skipLatency;
   bool skipLatency;
 
 
   // Discard any input.
   // Discard any input.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
 
 
   // F() stores strings in flash to save RAM
   // F() stores strings in flash to save RAM
   cout << F("Type any character to start\n");
   cout << F("Type any character to start\n");

+ 1 - 1
examples/examplesV1/#attic/AnalogLogger/AnalogLogger.ino

@@ -66,7 +66,7 @@ ostream& operator << (ostream& os, DateTime& dt) {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
+
   // Wait for USB Serial.
   // Wait for USB Serial.
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();

+ 2 - 2
examples/examplesV1/#attic/BaseExtCaseTest/BaseExtCaseTest.ino

@@ -17,8 +17,8 @@ const char* name[] = {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 1 - 1
examples/examplesV1/#attic/HelloWorld/HelloWorld.ino

@@ -8,7 +8,7 @@ ArduinoOutStream cout(Serial);
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
 
 
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 3 - 3
examples/examplesV1/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino

@@ -24,8 +24,8 @@ void error(const char* s) {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     yield();
     yield();
   }
   }
@@ -51,7 +51,7 @@ void loop() {
   if (!SD.begin(chipSelect)) {
   if (!SD.begin(chipSelect)) {
     error("begin");
     error("begin");
   }
   }
-  
+
   Serial.println(F("Starting print test.  Please wait.\n"));
   Serial.println(F("Starting print test.  Please wait.\n"));
 
 
   // do write test
   // do write test

+ 2 - 2
examples/examplesV1/#attic/SD_Size/SD_Size.ino

@@ -9,8 +9,8 @@ File file;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     yield();
     yield();
   }
   }

+ 3 - 3
examples/examplesV1/#attic/SdFatSize/SdFatSize.ino

@@ -12,12 +12,12 @@ SdFile file;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
-  
+
   if (!sd.begin()) {
   if (!sd.begin()) {
     Serial.println("begin failed");
     Serial.println("begin failed");
     return;
     return;

+ 1 - 1
examples/examplesV1/#attic/StreamParseInt/StreamParseInt.ino

@@ -17,7 +17,7 @@ void setup() {
   }
   }
   Serial.println(F("Type any character to start"));
   Serial.println(F("Type any character to start"));
   while (!Serial.available()) {
   while (!Serial.available()) {
-    SysCall::yield(); 
+    SysCall::yield();
   }
   }
   // Initialize the SD.
   // Initialize the SD.
   if (!SD.begin(csPin)) {
   if (!SD.begin(csPin)) {

+ 2 - 2
examples/examplesV1/#attic/append/append.ino

@@ -26,8 +26,8 @@ void setup() {
   char name[] = "append.txt";
   char name[] = "append.txt";
 
 
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 2 - 2
examples/examplesV1/#attic/average/average.ino

@@ -55,8 +55,8 @@ void calcAverage() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 3 - 3
examples/examplesV1/#attic/benchSD/benchSD.ino

@@ -27,8 +27,8 @@ void error(const char* s) {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     yield();
     yield();
   }
   }
@@ -46,7 +46,7 @@ void loop() {
 
 
   // F() stores strings in flash to save RAM
   // F() stores strings in flash to save RAM
   Serial.println(F("Type any character to start"));
   Serial.println(F("Type any character to start"));
-  
+
   while (!Serial.available()) {
   while (!Serial.available()) {
     yield();
     yield();
   }
   }

+ 2 - 2
examples/examplesV1/#attic/bufstream/bufstream.ino

@@ -13,8 +13,8 @@ void setup() {
   int i, j, k;    // values from parsed line
   int i, j, k;    // values from parsed line
 
 
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 1 - 1
examples/examplesV1/#attic/cin_cout/cin_cout.ino

@@ -16,7 +16,7 @@ ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 1 - 1
examples/examplesV1/#attic/eventlog/eventlog.ino

@@ -36,7 +36,7 @@ void logEvent(const char *msg) {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 2 - 2
examples/examplesV1/#attic/fgetsRewrite/fgetsRewrite.ino

@@ -86,8 +86,8 @@ void makeTestFile() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 2 - 2
examples/examplesV1/#attic/readlog/readlog.ino

@@ -18,8 +18,8 @@ ArduinoOutStream cout(Serial);
 void setup() {
 void setup() {
   int c;
   int c;
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 4 - 4
examples/examplesV1/LowLatencyLoggerADXL345/UserFunctions.cpp

@@ -17,12 +17,12 @@ const uint8_t DATAZ1 = 0x37; //Z-Axis Data 1
 
 
 void writeADXL345Register(const uint8_t registerAddress, const uint8_t value) {
 void writeADXL345Register(const uint8_t registerAddress, const uint8_t value) {
   // Max SPI clock frequency is 5 MHz with CPOL = 1 and CPHA = 1.
   // Max SPI clock frequency is 5 MHz with CPOL = 1 and CPHA = 1.
-  SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE3));  
+  SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE3));
   digitalWrite(ADXL345_CS, LOW);
   digitalWrite(ADXL345_CS, LOW);
   SPI.transfer(registerAddress);
   SPI.transfer(registerAddress);
   SPI.transfer(value);
   SPI.transfer(value);
   digitalWrite(ADXL345_CS, HIGH);
   digitalWrite(ADXL345_CS, HIGH);
-  SPI.endTransaction();  
+  SPI.endTransaction();
 }
 }
 
 
 void userSetup() {
 void userSetup() {
@@ -32,7 +32,7 @@ void userSetup() {
   //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
   //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
   writeADXL345Register(DATA_FORMAT, 0x01);
   writeADXL345Register(DATA_FORMAT, 0x01);
   //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
   //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
-  writeADXL345Register(POWER_CTL, 0x08);  //Measurement mode  
+  writeADXL345Register(POWER_CTL, 0x08);  //Measurement mode
 }
 }
 
 
 // Acquire a data record.
 // Acquire a data record.
@@ -45,7 +45,7 @@ void acquireData(data_t* data) {
   SPI.transfer(DATAX0 | 0XC0);
   SPI.transfer(DATAX0 | 0XC0);
   data->accel[0] = SPI.transfer(0) | (SPI.transfer(0) << 8);
   data->accel[0] = SPI.transfer(0) | (SPI.transfer(0) << 8);
   data->accel[1] = SPI.transfer(0) | (SPI.transfer(0) << 8);
   data->accel[1] = SPI.transfer(0) | (SPI.transfer(0) << 8);
-  data->accel[2] = SPI.transfer(0) | (SPI.transfer(0) << 8); 
+  data->accel[2] = SPI.transfer(0) | (SPI.transfer(0) << 8);
   digitalWrite(ADXL345_CS, HIGH);
   digitalWrite(ADXL345_CS, HIGH);
   SPI.endTransaction();
   SPI.endTransaction();
 }
 }

+ 2 - 2
examples/examplesV1/LowLatencyLoggerMPU6050/UserFunctions.cpp

@@ -9,7 +9,7 @@ static uint32_t startMicros;
 // Acquire a data record.
 // Acquire a data record.
 void acquireData(data_t* data) {
 void acquireData(data_t* data) {
   data->time = micros();
   data->time = micros();
-  mpu.getMotion6(&data->ax, &data->ay, &data->az, 
+  mpu.getMotion6(&data->ax, &data->ay, &data->az,
                  &data->gx, &data->gy, &data->gz);
                  &data->gx, &data->gy, &data->gz);
 }
 }
 
 
@@ -21,7 +21,7 @@ void userSetup() {
 #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
 #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
   Fastwire::setup(400, true);
   Fastwire::setup(400, true);
 #endif
 #endif
-  mpu.initialize();  
+  mpu.initialize();
 }
 }
 
 
 // Print a data record.
 // Print a data record.

+ 3 - 3
examples/examplesV1/OpenNext/OpenNext.ino

@@ -15,12 +15,12 @@ SdFile file;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
-  
+
   Serial.println("Type any character to start");
   Serial.println("Type any character to start");
   while (!Serial.available()) {
   while (!Serial.available()) {
     SysCall::yield();
     SysCall::yield();

+ 1 - 1
examples/examplesV1/PrintBenchmark/PrintBenchmark.ino

@@ -26,7 +26,7 @@ ArduinoOutStream cout(Serial);
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 4 - 4
examples/examplesV1/RawWrite/RawWrite.ino

@@ -45,8 +45,8 @@ ArduinoOutStream cout(Serial);
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup(void) {
 void setup(void) {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
@@ -101,7 +101,7 @@ void loop(void) {
   cout << F("Start raw write of ") << file.fileSize()/1000UL << F(" KB\n");
   cout << F("Start raw write of ") << file.fileSize()/1000UL << F(" KB\n");
   cout << F("Target rate: ") << RATE_KB_PER_SEC << F(" KB/sec\n");
   cout << F("Target rate: ") << RATE_KB_PER_SEC << F(" KB/sec\n");
   cout << F("Target time: ") << TEST_TIME_SEC << F(" seconds\n");
   cout << F("Target time: ") << TEST_TIME_SEC << F(" seconds\n");
-  
+
   // tell card to setup for multiple block write with pre-erase
   // tell card to setup for multiple block write with pre-erase
   if (!sd.card()->writeStart(bgnBlock, BLOCK_COUNT)) {
   if (!sd.card()->writeStart(bgnBlock, BLOCK_COUNT)) {
     error("writeStart failed");
     error("writeStart failed");
@@ -173,7 +173,7 @@ void loop(void) {
   cout << F(" seconds\n");
   cout << F(" seconds\n");
   cout << F("Min block write time: ") << minWriteTime << F(" micros\n");
   cout << F("Min block write time: ") << minWriteTime << F(" micros\n");
   cout << F("Max block write time: ") << maxWriteTime << F(" micros\n");
   cout << F("Max block write time: ") << maxWriteTime << F(" micros\n");
-  cout << F("Avg block write time: ") << avgWriteTime << F(" micros\n");  
+  cout << F("Avg block write time: ") << avgWriteTime << F(" micros\n");
   // close file for next pass of loop
   // close file for next pass of loop
   file.close();
   file.close();
   Serial.println();
   Serial.println();

+ 7 - 7
examples/examplesV1/ReadCsv/ReadCsv.ino

@@ -30,7 +30,7 @@ File file;
  * delim - csv delimiter.
  * delim - csv delimiter.
  *
  *
  * return - negative value for failure.
  * return - negative value for failure.
- *          delimiter, '\n' or zero(EOF) for success.           
+ *          delimiter, '\n' or zero(EOF) for success.
  */
  */
 int csvReadText(File* file, char* str, size_t size, char delim) {
 int csvReadText(File* file, char* str, size_t size, char delim) {
   char ch;
   char ch;
@@ -129,8 +129,8 @@ int csvReadFloat(File* file, float* num, char delim) {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     yield();
     yield();
   }
   }
@@ -144,8 +144,8 @@ void setup() {
     return;
     return;
   }
   }
   // Remove existing file.
   // Remove existing file.
-   SD.remove("READTEST.TXT"); 
-   
+   SD.remove("READTEST.TXT");
+
   // Create the file.
   // Create the file.
   file = SD.open("READTEST.TXT", FILE_WRITE);
   file = SD.open("READTEST.TXT", FILE_WRITE);
   if (!file) {
   if (!file) {
@@ -169,7 +169,7 @@ void setup() {
   file.seek(0);
   file.seek(0);
 
 
   // Read the file and print fields.
   // Read the file and print fields.
-  int16_t tcalc; 
+  int16_t tcalc;
   float t1, t2, h1, h2;
   float t1, t2, h1, h2;
   // Must be dim 9 to allow for zero byte.
   // Must be dim 9 to allow for zero byte.
   char timeS[9], dateS[9];
   char timeS[9], dateS[9];
@@ -188,7 +188,7 @@ void setup() {
       while ((ch = file.read()) > 0 && nr++ < 100) {
       while ((ch = file.read()) > 0 && nr++ < 100) {
         Serial.write(ch);
         Serial.write(ch);
       }
       }
-      break;            
+      break;
     }
     }
     Serial.print(tcalc);
     Serial.print(tcalc);
     Serial.print(CSV_DELIM);
     Serial.print(CSV_DELIM);

+ 5 - 5
examples/examplesV1/ReadCsvArray/ReadCsvArray.ino

@@ -51,8 +51,8 @@ size_t readField(File* file, char* str, size_t size, const char* delim) {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
@@ -63,7 +63,7 @@ void setup() {
   // Initialize the SD.
   // Initialize the SD.
   if (!SD.begin(CS_PIN)) {
   if (!SD.begin(CS_PIN)) {
     errorHalt("begin failed");
     errorHalt("begin failed");
-  } 
+  }
   // Create or open the file.
   // Create or open the file.
   file = SD.open("READNUM.TXT", FILE_WRITE);
   file = SD.open("READNUM.TXT", FILE_WRITE);
   if (!file) {
   if (!file) {
@@ -93,7 +93,7 @@ void setup() {
   char *ptr;     // Test for valid field.
   char *ptr;     // Test for valid field.
 
 
   // Read the file and store the data.
   // Read the file and store the data.
-  
+
   for (i = 0; i < ROW_DIM; i++) {
   for (i = 0; i < ROW_DIM; i++) {
     for (j = 0; j < COL_DIM; j++) {
     for (j = 0; j < COL_DIM; j++) {
       n = readField(&file, str, sizeof(str), ",\n");
       n = readField(&file, str, sizeof(str), ",\n");
@@ -117,7 +117,7 @@ void setup() {
     // Allow missing endl at eof.
     // Allow missing endl at eof.
     if (str[n-1] != '\n' && file.available()) {
     if (str[n-1] != '\n' && file.available()) {
       errorHalt("missing endl");
       errorHalt("missing endl");
-    }    
+    }
   }
   }
 
 
   // Print the array.
   // Print the array.

+ 3 - 3
examples/examplesV1/ReadCsvStream/ReadCsvStream.ino

@@ -92,14 +92,14 @@ void writeFile() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
   cout << F("Type any character to start\n");
   cout << F("Type any character to start\n");
   while (!Serial.available()) {
   while (!Serial.available()) {
-    SysCall::yield();  
+    SysCall::yield();
   }
   }
 
 
   // Initialize at the highest speed supported by the board that is
   // Initialize at the highest speed supported by the board that is

+ 2 - 2
examples/examplesV1/STM32Test/STM32Test.ino

@@ -33,7 +33,7 @@ const uint16_t NWRITE = FILE_SIZE/BUF_DIM;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
   }
   }
 
 
@@ -151,7 +151,7 @@ void setup() {
   Serial.println(F(" millis"));
   Serial.println(F(" millis"));
   // close test.bin
   // close test.bin
   file1.close();
   file1.close();
-  file2.close(); 
+  file2.close();
   // list current directory on both cards
   // list current directory on both cards
   Serial.println(F("------sd1 -------"));
   Serial.println(F("------sd1 -------"));
   sd1.ls("/", LS_R | LS_DATE | LS_SIZE);
   sd1.ls("/", LS_R | LS_DATE | LS_SIZE);

+ 7 - 7
examples/examplesV1/SdFormatter/SdFormatter.ino

@@ -12,7 +12,7 @@
  * and SDFormatter uses FAT12.
  * and SDFormatter uses FAT12.
  */
  */
 #error  use new Version 2 SdFormatter
 #error  use new Version 2 SdFormatter
-// Set USE_SDIO to zero for SPI card access. 
+// Set USE_SDIO to zero for SPI card access.
 #define USE_SDIO 0
 #define USE_SDIO 0
 //
 //
 // Change the value of chipSelect if your hardware does
 // Change the value of chipSelect if your hardware does
@@ -45,7 +45,7 @@ SdioCardEX card;
 #else  // USE_SDIO
 #else  // USE_SDIO
 Sd2Card card;
 Sd2Card card;
 #endif  // USE_SDIO
 #endif  // USE_SDIO
- 
+
 uint32_t cardSizeBlocks;
 uint32_t cardSizeBlocks;
 uint32_t cardCapacityMB;
 uint32_t cardCapacityMB;
 
 
@@ -171,10 +171,10 @@ void clearFatDir(uint32_t bgn, uint32_t count) {
   for (uint32_t i = 0; i < count; i++) {
   for (uint32_t i = 0; i < count; i++) {
     if (!card.writeBlock(bgn + i, cache.data)) {
     if (!card.writeBlock(bgn + i, cache.data)) {
        sdError("Clear FAT/DIR writeBlock failed");
        sdError("Clear FAT/DIR writeBlock failed");
-    }     
+    }
     if ((i & 0XFF) == 0) {
     if ((i & 0XFF) == 0) {
       cout << '.';
       cout << '.';
-    }    
+    }
   }
   }
 #else  // USE_SDIO
 #else  // USE_SDIO
   if (!card.writeStart(bgn, count)) {
   if (!card.writeStart(bgn, count)) {
@@ -461,7 +461,7 @@ void formatCard() {
 void setup() {
 void setup() {
   char c;
   char c;
   Serial.begin(9600);
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
@@ -521,7 +521,7 @@ void setup() {
   }
   }
 #if USE_SDIO
 #if USE_SDIO
   if (!card.begin()) {
   if (!card.begin()) {
-    sdError("card.begin failed");  
+    sdError("card.begin failed");
   }
   }
 #else  // USE_SDIO
 #else  // USE_SDIO
   if (!card.begin(chipSelect, SPI_SPEED)) {
   if (!card.begin(chipSelect, SPI_SPEED)) {
@@ -531,7 +531,7 @@ void setup() {
            "Is chip select correct at the top of this program?\n");
            "Is chip select correct at the top of this program?\n");
     sdError("card.begin failed");
     sdError("card.begin failed");
   }
   }
-#endif  
+#endif
   cardSizeBlocks = card.cardSize();
   cardSizeBlocks = card.cardSize();
   if (cardSizeBlocks == 0) {
   if (cardSizeBlocks == 0) {
     sdError("cardSize");
     sdError("cardSize");

+ 6 - 6
examples/examplesV1/SdInfo/SdInfo.ino

@@ -5,7 +5,7 @@
 #include "SdFat.h"
 #include "SdFat.h"
 #include "sdios.h"
 #include "sdios.h"
 #error Use new Version 2 SdInfo
 #error Use new Version 2 SdInfo
-// Set USE_SDIO to zero for SPI card access. 
+// Set USE_SDIO to zero for SPI card access.
 #define USE_SDIO 0
 #define USE_SDIO 0
 /*
 /*
  * SD chip select pin.  Common values are:
  * SD chip select pin.  Common values are:
@@ -143,8 +143,8 @@ void volDmp() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
@@ -154,7 +154,7 @@ void setup() {
 
 
   // F stores strings in flash to save RAM
   // F stores strings in flash to save RAM
   cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
   cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
-#if !USE_SDIO  
+#if !USE_SDIO
   if (DISABLE_CHIP_SELECT < 0) {
   if (DISABLE_CHIP_SELECT < 0) {
     cout << F(
     cout << F(
            "\nAssuming the SD is the only SPI device.\n"
            "\nAssuming the SD is the only SPI device.\n"
@@ -167,7 +167,7 @@ void setup() {
   }
   }
   cout << F("\nAssuming the SD chip select pin is: ") <<int(SD_CHIP_SELECT);
   cout << F("\nAssuming the SD chip select pin is: ") <<int(SD_CHIP_SELECT);
   cout << F("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
   cout << F("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
-#endif  // !USE_SDIO  
+#endif  // !USE_SDIO
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void loop() {
 void loop() {
@@ -195,7 +195,7 @@ void loop() {
     sdErrorMsg("cardBegin failed");
     sdErrorMsg("cardBegin failed");
     return;
     return;
   }
   }
- #endif  // USE_SDIO 
+ #endif  // USE_SDIO
   t = millis() - t;
   t = millis() - t;
 
 
   cardSize = sd.card()->cardSize();
   cardSize = sd.card()->cardSize();

+ 2 - 2
examples/examplesV1/SoftwareSpi/SoftwareSpi.ino

@@ -24,7 +24,7 @@ SdFile file;
 
 
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
@@ -43,7 +43,7 @@ void setup() {
   file.println(F("This line was printed using software SPI."));
   file.println(F("This line was printed using software SPI."));
 
 
   file.rewind();
   file.rewind();
-  
+
   while (file.available()) {
   while (file.available()) {
     Serial.write(file.read());
     Serial.write(file.read());
   }
   }

+ 3 - 3
examples/examplesV1/StdioBench/StdioBench.ino

@@ -42,7 +42,7 @@ void setup() {
   Serial.println(F("Starting test"));
   Serial.println(F("Starting test"));
 
 
   // Initialize at the highest speed supported by the board that is
   // Initialize at the highest speed supported by the board that is
-  // not over 50 MHz. Try a lower speed if SPI errors occur.  
+  // not over 50 MHz. Try a lower speed if SPI errors occur.
   if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
   if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
     sd.errorHalt();
     sd.errorHalt();
   }
   }
@@ -146,7 +146,7 @@ void setup() {
             stdioFile.printField(n, '\n');
             stdioFile.printField(n, '\n');
 #else  // PRINT_FIELD
 #else  // PRINT_FIELD
             stdioFile.println(n);
             stdioFile.println(n);
-#endif  // PRINT_FIELD      
+#endif  // PRINT_FIELD
           }
           }
           break;
           break;
 
 
@@ -157,7 +157,7 @@ void setup() {
               stdioFile.printField(f[i], '\n', 4);
               stdioFile.printField(f[i], '\n', 4);
 #else  // PRINT_FIELD
 #else  // PRINT_FIELD
               stdioFile.println(f[i], 4);
               stdioFile.println(f[i], 4);
-#endif  // PRINT_FIELD                            
+#endif  // PRINT_FIELD
             }
             }
           }
           }
           break;
           break;

+ 12 - 12
examples/examplesV1/TeensySdioDemo/TeensySdioDemo.ino

@@ -1,7 +1,7 @@
 // Simple performance test for Teensy 3.5/3.6 SDHC.
 // Simple performance test for Teensy 3.5/3.6 SDHC.
 // Demonstrates yield() efficiency.
 // Demonstrates yield() efficiency.
 
 
-// Warning SdFatSdio and SdFatSdioEX normally should 
+// Warning SdFatSdio and SdFatSdioEX normally should
 // not both be used in a program.
 // not both be used in a program.
 // Each has its own cache and member variables.
 // Each has its own cache and member variables.
 
 
@@ -48,8 +48,8 @@ void errorHalt(const char* msg) {
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 uint32_t kHzSdClk() {
 uint32_t kHzSdClk() {
-  return useEx ? sdEx.card()->kHzSdClk() : sd.card()->kHzSdClk(); 
-}  
+  return useEx ? sdEx.card()->kHzSdClk() : sd.card()->kHzSdClk();
+}
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // Replace "weak" system yield() function.
 // Replace "weak" system yield() function.
 void yield() {
 void yield() {
@@ -74,7 +74,7 @@ void runTest() {
   totalMicros = 0;
   totalMicros = 0;
   yieldMicros = 0;
   yieldMicros = 0;
   yieldCalls = 0;
   yieldCalls = 0;
-  yieldMaxUsec = 0; 
+  yieldMaxUsec = 0;
   if (!file.open("TeensyDemo.bin", O_RDWR | O_CREAT)) {
   if (!file.open("TeensyDemo.bin", O_RDWR | O_CREAT)) {
     errorHalt("open failed");
     errorHalt("open failed");
   }
   }
@@ -100,19 +100,19 @@ void runTest() {
     Serial.print(',');
     Serial.print(',');
     file.rewind();
     file.rewind();
     t = micros();
     t = micros();
-    
+
     for (uint32_t n = 0; n < nRdWr; n++) {
     for (uint32_t n = 0; n < nRdWr; n++) {
       if ((int)nb != file.read(buf, nb)) {
       if ((int)nb != file.read(buf, nb)) {
         errorHalt("read failed");
         errorHalt("read failed");
       }
       }
-      // crude check of data.     
+      // crude check of data.
       if (buf32[0] != n || buf32[nb/4 - 1] != n) {
       if (buf32[0] != n || buf32[nb/4 - 1] != n) {
         errorHalt("data check");
         errorHalt("data check");
       }
       }
     }
     }
     t = micros() - t;
     t = micros() - t;
-    totalMicros += t;   
-    Serial.println(1000.0*FILE_SIZE/t);    
+    totalMicros += t;
+    Serial.println(1000.0*FILE_SIZE/t);
   }
   }
   file.close();
   file.close();
   Serial.print("\ntotalMicros  ");
   Serial.print("\ntotalMicros  ");
@@ -122,7 +122,7 @@ void runTest() {
   Serial.print("yieldCalls   ");
   Serial.print("yieldCalls   ");
   Serial.println(yieldCalls);
   Serial.println(yieldCalls);
   Serial.print("yieldMaxUsec ");
   Serial.print("yieldMaxUsec ");
-  Serial.println(yieldMaxUsec); 
+  Serial.println(yieldMaxUsec);
   Serial.print("kHzSdClk     ");
   Serial.print("kHzSdClk     ");
   Serial.println(kHzSdClk());
   Serial.println(kHzSdClk());
   Serial.println("Done");
   Serial.println("Done");
@@ -133,8 +133,8 @@ void setup() {
   while (!Serial) {
   while (!Serial) {
   }
   }
   Serial.println("SdFatSdioEX uses extended multi-block transfers without DMA.");
   Serial.println("SdFatSdioEX uses extended multi-block transfers without DMA.");
-  Serial.println("SdFatSdio uses a traditional DMA SDIO implementation."); 
-  Serial.println("Note the difference is speed and busy yield time.\n"); 
+  Serial.println("SdFatSdio uses a traditional DMA SDIO implementation.");
+  Serial.println("Note the difference is speed and busy yield time.\n");
 }
 }
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 void loop() {
 void loop() {
@@ -163,7 +163,7 @@ void loop() {
       sd.initErrorHalt("SdFatSdio begin() failed");
       sd.initErrorHalt("SdFatSdio begin() failed");
     }
     }
     // make sd the current volume.
     // make sd the current volume.
-    sd.chvol();  
+    sd.chvol();
   }
   }
   runTest();
   runTest();
 }
 }

+ 2 - 2
examples/examplesV1/Timestamp/Timestamp.ino

@@ -53,7 +53,7 @@ void dateTime(uint16_t* date, uint16_t* time) {
 void printTimestamps(SdFile& f) {
 void printTimestamps(SdFile& f) {
   cout << F("Creation: ");
   cout << F("Creation: ");
   f.printCreateDateTime(&Serial);
   f.printCreateDateTime(&Serial);
-  cout << endl << F("Modify: ");  
+  cout << endl << F("Modify: ");
   f.printModifyDateTime(&Serial);
   f.printModifyDateTime(&Serial);
   cout << endl << F("Access: ");
   cout << endl << F("Access: ");
   f.printAccessDateTime(&Serial);
   f.printAccessDateTime(&Serial);
@@ -68,7 +68,7 @@ void setup(void) {
   }
   }
   cout << F("Type any character to start\n");
   cout << F("Type any character to start\n");
   while (!Serial.available()) {
   while (!Serial.available()) {
-    SysCall::yield();  
+    SysCall::yield();
   }
   }
   // Initialize at the highest speed supported by the board that is
   // Initialize at the highest speed supported by the board that is
   // not over 50 MHz. Try a lower speed if SPI errors occur.
   // not over 50 MHz. Try a lower speed if SPI errors occur.

+ 2 - 2
examples/examplesV1/TwoCards/TwoCards.ino

@@ -25,7 +25,7 @@ const uint32_t NWRITE = FILE_SIZE/BUF_DIM;
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup() {
 void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
@@ -146,7 +146,7 @@ void setup() {
   Serial.println(F(" millis"));
   Serial.println(F(" millis"));
   // close test.bin
   // close test.bin
   file1.close();
   file1.close();
-  file2.close(); 
+  file2.close();
   // list current directory on both cards
   // list current directory on both cards
   Serial.println(F("------sd1 -------"));
   Serial.println(F("------sd1 -------"));
   sd1.ls("/", LS_R | LS_DATE | LS_SIZE);
   sd1.ls("/", LS_R | LS_DATE | LS_SIZE);

+ 3 - 3
examples/examplesV1/dataLogger/dataLogger.ino

@@ -67,8 +67,8 @@ void setup() {
   char fileName[13] = FILE_BASE_NAME "00.csv";
   char fileName[13] = FILE_BASE_NAME "00.csv";
 
 
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
@@ -78,7 +78,7 @@ void setup() {
   while (!Serial.available()) {
   while (!Serial.available()) {
     SysCall::yield();
     SysCall::yield();
   }
   }
-  
+
   // Initialize at the highest speed supported by the board that is
   // Initialize at the highest speed supported by the board that is
   // not over 50 MHz. Try a lower speed if SPI errors occur.
   // not over 50 MHz. Try a lower speed if SPI errors occur.
   if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
   if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {

+ 2 - 2
examples/examplesV1/fgets/fgets.ino

@@ -61,8 +61,8 @@ void makeTestFile() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup(void) {
 void setup(void) {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 1 - 1
examples/examplesV1/formatting/formatting.ino

@@ -43,7 +43,7 @@ void showDate(int m, int d, int y) {
 void setup(void) {
 void setup(void) {
   Serial.begin(9600);
   Serial.begin(9600);
 
 
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 2 - 2
examples/examplesV1/getline/getline.ino

@@ -55,8 +55,8 @@ void testGetline() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 void setup(void) {
 void setup(void) {
   Serial.begin(9600);
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }

+ 3 - 3
examples/examplesV1/wipe/wipe.ino

@@ -9,7 +9,7 @@ SdFat sd;
 void setup() {
 void setup() {
   int c;
   int c;
   Serial.begin(9600);
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   while (!Serial) {
     SysCall::yield();
     SysCall::yield();
   }
   }
@@ -22,7 +22,7 @@ void setup() {
     sd.errorHalt("Quitting, you did not type 'Y'.");
     sd.errorHalt("Quitting, you did not type 'Y'.");
   }
   }
   // Initialize at the highest speed supported by the board that is
   // Initialize at the highest speed supported by the board that is
-  // not over 50 MHz. Try a lower speed if SPI errors occur. 
+  // not over 50 MHz. Try a lower speed if SPI errors occur.
   if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
   if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
     sd.initErrorHalt();
     sd.initErrorHalt();
   }
   }
@@ -32,7 +32,7 @@ void setup() {
   }
   }
   // Must reinitialize after wipe.
   // Must reinitialize after wipe.
   // Initialize at the highest speed supported by the board that is
   // Initialize at the highest speed supported by the board that is
-  // not over 50 MHz. Try a lower speed if SPI errors occur.  
+  // not over 50 MHz. Try a lower speed if SPI errors occur.
   if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
   if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
     sd.errorHalt("Second init failed.");
     sd.errorHalt("Second init failed.");
   }
   }

+ 153 - 32
extras/cpplint.py

@@ -51,12 +51,19 @@ import sre_compile
 import string
 import string
 import sys
 import sys
 import unicodedata
 import unicodedata
+import sysconfig
+
+try:
+  xrange          # Python 2
+except NameError:
+  xrange = range  # Python 3
 
 
 
 
 _USAGE = """
 _USAGE = """
 Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
 Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
                    [--counting=total|toplevel|detailed] [--root=subdir]
                    [--counting=total|toplevel|detailed] [--root=subdir]
                    [--linelength=digits] [--headers=x,y,...]
                    [--linelength=digits] [--headers=x,y,...]
+                   [--quiet]
         <file> [file] ...
         <file> [file] ...
 
 
   The style guidelines this tries to follow are those in
   The style guidelines this tries to follow are those in
@@ -83,6 +90,9 @@ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
     verbose=#
     verbose=#
       Specify a number 0-5 to restrict errors to certain verbosity levels.
       Specify a number 0-5 to restrict errors to certain verbosity levels.
 
 
+    quiet
+      Don't print anything if no errors are found.
+
     filter=-x,+y,...
     filter=-x,+y,...
       Specify a comma-separated list of category-filters to apply: only
       Specify a comma-separated list of category-filters to apply: only
       error messages whose category names pass the filters will be printed.
       error messages whose category names pass the filters will be printed.
@@ -114,12 +124,13 @@ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
       ignored.
       ignored.
 
 
       Examples:
       Examples:
-        Assuming that src/.git exists, the header guard CPP variables for
-        src/chrome/browser/ui/browser.h are:
+        Assuming that top/src/.git exists (and cwd=top/src), the header guard
+        CPP variables for top/src/chrome/browser/ui/browser.h are:
 
 
         No flag => CHROME_BROWSER_UI_BROWSER_H_
         No flag => CHROME_BROWSER_UI_BROWSER_H_
         --root=chrome => BROWSER_UI_BROWSER_H_
         --root=chrome => BROWSER_UI_BROWSER_H_
         --root=chrome/browser => UI_BROWSER_H_
         --root=chrome/browser => UI_BROWSER_H_
+        --root=.. => SRC_CHROME_BROWSER_UI_BROWSER_H_
 
 
     linelength=digits
     linelength=digits
       This is the allowed line length for the project. The default value is
       This is the allowed line length for the project. The default value is
@@ -168,9 +179,9 @@ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
     "linelength" allows to specify the allowed line length for the project.
     "linelength" allows to specify the allowed line length for the project.
 
 
     The "root" option is similar in function to the --root flag (see example
     The "root" option is similar in function to the --root flag (see example
-    above).
-    
-    The "headers" option is similar in function to the --headers flag 
+    above). Paths are relative to the directory of the CPPLINT.cfg.
+
+    The "headers" option is similar in function to the --headers flag
     (see example above).
     (see example above).
 
 
     CPPLINT.cfg has an effect on files in the same directory and all
     CPPLINT.cfg has an effect on files in the same directory and all
@@ -539,6 +550,7 @@ _error_suppressions = {}
 # The root directory used for deriving header guard CPP variable.
 # The root directory used for deriving header guard CPP variable.
 # This is set by --root flag.
 # This is set by --root flag.
 _root = None
 _root = None
+_root_debug = False
 
 
 # The allowed line length of files.
 # The allowed line length of files.
 # This is set by --linelength flag.
 # This is set by --linelength flag.
@@ -563,7 +575,7 @@ def ProcessHppHeadersOption(val):
     # Automatically append to extensions list so it does not have to be set 2 times
     # Automatically append to extensions list so it does not have to be set 2 times
     _valid_extensions.update(_hpp_headers)
     _valid_extensions.update(_hpp_headers)
   except ValueError:
   except ValueError:
-    PrintUsage('Header extensions must be comma seperated list.')
+    PrintUsage('Header extensions must be comma separated list.')
 
 
 def IsHeaderExtension(file_extension):
 def IsHeaderExtension(file_extension):
   return file_extension in _hpp_headers
   return file_extension in _hpp_headers
@@ -859,6 +871,7 @@ class _CppLintState(object):
     self._filters_backup = self.filters[:]
     self._filters_backup = self.filters[:]
     self.counting = 'total'  # In what way are we counting errors?
     self.counting = 'total'  # In what way are we counting errors?
     self.errors_by_category = {}  # string to int dict storing error counts
     self.errors_by_category = {}  # string to int dict storing error counts
+    self.quiet = False  # Suppress non-error messagess?
 
 
     # output format:
     # output format:
     # "emacs" - format that emacs can parse (default)
     # "emacs" - format that emacs can parse (default)
@@ -869,6 +882,12 @@ class _CppLintState(object):
     """Sets the output format for errors."""
     """Sets the output format for errors."""
     self.output_format = output_format
     self.output_format = output_format
 
 
+  def SetQuiet(self, quiet):
+    """Sets the module's quiet settings, and returns the previous setting."""
+    last_quiet = self.quiet
+    self.quiet = quiet
+    return last_quiet
+
   def SetVerboseLevel(self, level):
   def SetVerboseLevel(self, level):
     """Sets the module's verbosity, and returns the previous setting."""
     """Sets the module's verbosity, and returns the previous setting."""
     last_verbose_level = self.verbose_level
     last_verbose_level = self.verbose_level
@@ -950,6 +969,14 @@ def _SetOutputFormat(output_format):
   """Sets the module's output format."""
   """Sets the module's output format."""
   _cpplint_state.SetOutputFormat(output_format)
   _cpplint_state.SetOutputFormat(output_format)
 
 
+def _Quiet():
+  """Return's the module's quiet setting."""
+  return _cpplint_state.quiet
+
+def _SetQuiet(quiet):
+  """Set the module's quiet status, and return previous setting."""
+  return _cpplint_state.SetQuiet(quiet)
+
 
 
 def _VerboseLevel():
 def _VerboseLevel():
   """Returns the module's verbosity setting."""
   """Returns the module's verbosity setting."""
@@ -1356,7 +1383,7 @@ def FindNextMultiLineCommentEnd(lines, lineix):
 
 
 def RemoveMultiLineCommentsFromRange(lines, begin, end):
 def RemoveMultiLineCommentsFromRange(lines, begin, end):
   """Clears a range of lines for multi-line comments."""
   """Clears a range of lines for multi-line comments."""
-  # Having // dummy comments makes the lines non-empty, so we will not get
+  # Having // <empty> comments makes the lines non-empty, so we will not get
   # unnecessary blank line warnings later in the code.
   # unnecessary blank line warnings later in the code.
   for i in range(begin, end):
   for i in range(begin, end):
     lines[i] = '/**/'
     lines[i] = '/**/'
@@ -1730,7 +1757,7 @@ def CheckForCopyright(filename, lines, error):
   """Logs an error if no Copyright message appears at the top of the file."""
   """Logs an error if no Copyright message appears at the top of the file."""
 
 
   # We'll say it should occur by line 10. Don't forget there's a
   # We'll say it should occur by line 10. Don't forget there's a
-  # dummy line at the front.
+  # placeholder line at the front.
   for line in xrange(1, min(len(lines), 11)):
   for line in xrange(1, min(len(lines), 11)):
     if re.search(r'Copyright', lines[line], re.I): break
     if re.search(r'Copyright', lines[line], re.I): break
   else:                       # means no copyright line was found
   else:                       # means no copyright line was found
@@ -1754,6 +1781,30 @@ def GetIndentLevel(line):
   else:
   else:
     return 0
     return 0
 
 
+def PathSplitToList(path):
+  """Returns the path split into a list by the separator.
+
+  Args:
+    path: An absolute or relative path (e.g. '/a/b/c/' or '../a')
+
+  Returns:
+    A list of path components (e.g. ['a', 'b', 'c]).
+  """
+  lst = []
+  while True:
+    (head, tail) = os.path.split(path)
+    if head == path: # absolute paths end
+      lst.append(head)
+      break
+    if tail == path: # relative paths end
+      lst.append(tail)
+      break
+
+    path = head
+    lst.append(tail)
+
+  lst.reverse()
+  return lst
 
 
 def GetHeaderGuardCPPVariable(filename):
 def GetHeaderGuardCPPVariable(filename):
   """Returns the CPP variable that should be used as a header guard.
   """Returns the CPP variable that should be used as a header guard.
@@ -1776,13 +1827,58 @@ def GetHeaderGuardCPPVariable(filename):
 
 
   fileinfo = FileInfo(filename)
   fileinfo = FileInfo(filename)
   file_path_from_root = fileinfo.RepositoryName()
   file_path_from_root = fileinfo.RepositoryName()
-  if _root:
-    suffix = os.sep
-    # On Windows using directory separator will leave us with
-    # "bogus escape error" unless we properly escape regex.
-    if suffix == '\\':
-      suffix += '\\'
-    file_path_from_root = re.sub('^' + _root + suffix, '', file_path_from_root)
+
+  def FixupPathFromRoot():
+    if _root_debug:
+      sys.stderr.write("\n_root fixup, _root = '%s', repository name = '%s'\n"
+          %(_root, fileinfo.RepositoryName()))
+
+    # Process the file path with the --root flag if it was set.
+    if not _root:
+      if _root_debug:
+        sys.stderr.write("_root unspecified\n")
+      return file_path_from_root
+
+    def StripListPrefix(lst, prefix):
+      # f(['x', 'y'], ['w, z']) -> None  (not a valid prefix)
+      if lst[:len(prefix)] != prefix:
+        return None
+      # f(['a, 'b', 'c', 'd'], ['a', 'b']) -> ['c', 'd']
+      return lst[(len(prefix)):]
+
+    # root behavior:
+    #   --root=subdir , lstrips subdir from the header guard
+    maybe_path = StripListPrefix(PathSplitToList(file_path_from_root),
+                                 PathSplitToList(_root))
+
+    if _root_debug:
+      sys.stderr.write(("_root lstrip (maybe_path=%s, file_path_from_root=%s," +
+          " _root=%s)\n") %(maybe_path, file_path_from_root, _root))
+
+    if maybe_path:
+      return os.path.join(*maybe_path)
+
+    #   --root=.. , will prepend the outer directory to the header guard
+    full_path = fileinfo.FullName()
+    root_abspath = os.path.abspath(_root)
+
+    maybe_path = StripListPrefix(PathSplitToList(full_path),
+                                 PathSplitToList(root_abspath))
+
+    if _root_debug:
+      sys.stderr.write(("_root prepend (maybe_path=%s, full_path=%s, " +
+          "root_abspath=%s)\n") %(maybe_path, full_path, root_abspath))
+
+    if maybe_path:
+      return os.path.join(*maybe_path)
+
+    if _root_debug:
+      sys.stderr.write("_root ignore, returning %s\n" %(file_path_from_root))
+
+    #   --root=FAKE_DIR is ignored
+    return file_path_from_root
+
+  file_path_from_root = FixupPathFromRoot()
   return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_'
   return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_'
 
 
 
 
@@ -3187,8 +3283,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
   line = clean_lines.elided[linenum]
   line = clean_lines.elided[linenum]
 
 
   # You shouldn't have spaces before your brackets, except maybe after
   # You shouldn't have spaces before your brackets, except maybe after
-  # 'delete []' or 'return []() {};'
-  if Search(r'\w\s+\[', line) and not Search(r'(?:delete|return)\s+\[', line):
+  # 'delete []', 'return []() {};', or 'auto [abc, ...] = ...;'.
+  if Search(r'\w\s+\[', line) and not Search(r'(?:auto&?|delete|return)\s+\[', line):
     error(filename, linenum, 'whitespace/braces', 5,
     error(filename, linenum, 'whitespace/braces', 5,
           'Extra space before [')
           'Extra space before [')
 
 
@@ -3770,9 +3866,9 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
 
 
   # Block bodies should not be followed by a semicolon.  Due to C++11
   # Block bodies should not be followed by a semicolon.  Due to C++11
   # brace initialization, there are more places where semicolons are
   # brace initialization, there are more places where semicolons are
-  # required than not, so we use a whitelist approach to check these
-  # rather than a blacklist.  These are the places where "};" should
-  # be replaced by just "}":
+  # required than not, so we explicitly list the allowed rules rather
+  # than listing the disallowed ones.  These are the places where "};"
+  # should be replaced by just "}":
   # 1. Some flavor of block following closing parenthesis:
   # 1. Some flavor of block following closing parenthesis:
   #    for (;;) {};
   #    for (;;) {};
   #    while (...) {};
   #    while (...) {};
@@ -3828,11 +3924,11 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
     #  - INTERFACE_DEF
     #  - INTERFACE_DEF
     #  - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED:
     #  - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED:
     #
     #
-    # We implement a whitelist of safe macros instead of a blacklist of
+    # We implement a list of safe macros instead of a list of
     # unsafe macros, even though the latter appears less frequently in
     # unsafe macros, even though the latter appears less frequently in
     # google code and would have been easier to implement.  This is because
     # google code and would have been easier to implement.  This is because
-    # the downside for getting the whitelist wrong means some extra
-    # semicolons, while the downside for getting the blacklist wrong
+    # the downside for getting the allowed checks wrong means some extra
+    # semicolons, while the downside for getting disallowed checks wrong
     # would result in compile errors.
     # would result in compile errors.
     #
     #
     # In addition to macros, we also don't want to warn on
     # In addition to macros, we also don't want to warn on
@@ -4196,6 +4292,16 @@ def GetLineWidth(line):
       if unicodedata.east_asian_width(uc) in ('W', 'F'):
       if unicodedata.east_asian_width(uc) in ('W', 'F'):
         width += 2
         width += 2
       elif not unicodedata.combining(uc):
       elif not unicodedata.combining(uc):
+        # Issue 337
+        # https://mail.python.org/pipermail/python-list/2012-August/628809.html
+        if (sys.version_info.major, sys.version_info.minor) <= (3, 2):
+          # https://github.com/python/cpython/blob/2.7/Include/unicodeobject.h#L81
+          is_wide_build = sysconfig.get_config_var("Py_UNICODE_SIZE") >= 4
+          # https://github.com/python/cpython/blob/2.7/Objects/unicodeobject.c#L564
+          is_low_surrogate = 0xDC00 <= ord(uc) <= 0xDFFF
+          if not is_wide_build and is_low_surrogate:
+            width -= 1
+          
         width += 1
         width += 1
     return width
     return width
   else:
   else:
@@ -5018,19 +5124,19 @@ def CheckForNonConstReference(filename, clean_lines, linenum,
   #
   #
   # We also accept & in static_assert, which looks like a function but
   # We also accept & in static_assert, which looks like a function but
   # it's actually a declaration expression.
   # it's actually a declaration expression.
-  whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|'
+  allowed_functions = (r'(?:[sS]wap(?:<\w:+>)?|'
                            r'operator\s*[<>][<>]|'
                            r'operator\s*[<>][<>]|'
                            r'static_assert|COMPILE_ASSERT'
                            r'static_assert|COMPILE_ASSERT'
                            r')\s*\(')
                            r')\s*\(')
-  if Search(whitelisted_functions, line):
+  if Search(allowed_functions, line):
     return
     return
   elif not Search(r'\S+\([^)]*$', line):
   elif not Search(r'\S+\([^)]*$', line):
-    # Don't see a whitelisted function on this line.  Actually we
+    # Don't see an allowed function on this line.  Actually we
     # didn't see any function name on this line, so this is likely a
     # didn't see any function name on this line, so this is likely a
     # multi-line parameter list.  Try a bit harder to catch this case.
     # multi-line parameter list.  Try a bit harder to catch this case.
     for i in xrange(2):
     for i in xrange(2):
       if (linenum > i and
       if (linenum > i and
-          Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])):
+          Search(allowed_functions, clean_lines.elided[linenum - i - 1])):
         return
         return
 
 
   decls = ReplaceAll(r'{[^}]*}', ' ', line)  # exclude function body
   decls = ReplaceAll(r'{[^}]*}', ' ', line)  # exclude function body
@@ -5884,6 +5990,9 @@ def ProcessConfigOverrides(filename):
             if base_name:
             if base_name:
               pattern = re.compile(val)
               pattern = re.compile(val)
               if pattern.match(base_name):
               if pattern.match(base_name):
+                if _cpplint_state.quiet:
+                  # Suppress "Ignoring file" warning when using --quiet.
+                  return False
                 sys.stderr.write('Ignoring "%s": file excluded by "%s". '
                 sys.stderr.write('Ignoring "%s": file excluded by "%s". '
                                  'File path component "%s" matches '
                                  'File path component "%s" matches '
                                  'pattern "%s"\n' %
                                  'pattern "%s"\n' %
@@ -5897,7 +6006,8 @@ def ProcessConfigOverrides(filename):
                 sys.stderr.write('Line length must be numeric.')
                 sys.stderr.write('Line length must be numeric.')
           elif name == 'root':
           elif name == 'root':
             global _root
             global _root
-            _root = val
+            # root directories are specified relative to CPPLINT.cfg dir.
+            _root = os.path.join(os.path.dirname(cfg_file), val)
           elif name == 'headers':
           elif name == 'headers':
             ProcessHppHeadersOption(val)
             ProcessHppHeadersOption(val)
           else:
           else:
@@ -5934,6 +6044,7 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
 
 
   _SetVerboseLevel(vlevel)
   _SetVerboseLevel(vlevel)
   _BackupFilters()
   _BackupFilters()
+  old_errors = _cpplint_state.error_count
 
 
   if not ProcessConfigOverrides(filename):
   if not ProcessConfigOverrides(filename):
     _RestoreFilters()
     _RestoreFilters()
@@ -6002,7 +6113,10 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
         Error(filename, linenum, 'whitespace/newline', 1,
         Error(filename, linenum, 'whitespace/newline', 1,
               'Unexpected \\r (^M) found; better to use only \\n')
               'Unexpected \\r (^M) found; better to use only \\n')
 
 
-  sys.stdout.write('Done processing %s\n' % filename)
+  # Suppress printing anything if --quiet was passed unless the error
+  # count has increased after processing this file.
+  if not _cpplint_state.quiet or old_errors != _cpplint_state.error_count:
+    sys.stdout.write('Done processing %s\n' % filename)
   _RestoreFilters()
   _RestoreFilters()
 
 
 
 
@@ -6046,13 +6160,15 @@ def ParseArguments(args):
                                                  'root=',
                                                  'root=',
                                                  'linelength=',
                                                  'linelength=',
                                                  'extensions=',
                                                  'extensions=',
-                                                 'headers='])
+                                                 'headers=',
+                                                 'quiet'])
   except getopt.GetoptError:
   except getopt.GetoptError:
     PrintUsage('Invalid arguments.')
     PrintUsage('Invalid arguments.')
 
 
   verbosity = _VerboseLevel()
   verbosity = _VerboseLevel()
   output_format = _OutputFormat()
   output_format = _OutputFormat()
   filters = ''
   filters = ''
+  quiet = _Quiet()
   counting_style = ''
   counting_style = ''
 
 
   for (opt, val) in opts:
   for (opt, val) in opts:
@@ -6062,6 +6178,8 @@ def ParseArguments(args):
       if val not in ('emacs', 'vs7', 'eclipse'):
       if val not in ('emacs', 'vs7', 'eclipse'):
         PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
         PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
       output_format = val
       output_format = val
+    elif opt == '--quiet':
+      quiet = True
     elif opt == '--verbose':
     elif opt == '--verbose':
       verbosity = int(val)
       verbosity = int(val)
     elif opt == '--filter':
     elif opt == '--filter':
@@ -6086,7 +6204,7 @@ def ParseArguments(args):
       try:
       try:
           _valid_extensions = set(val.split(','))
           _valid_extensions = set(val.split(','))
       except ValueError:
       except ValueError:
-          PrintUsage('Extensions must be comma seperated list.')
+          PrintUsage('Extensions must be comma separated list.')
     elif opt == '--headers':
     elif opt == '--headers':
       ProcessHppHeadersOption(val)
       ProcessHppHeadersOption(val)
 
 
@@ -6094,6 +6212,7 @@ def ParseArguments(args):
     PrintUsage('No files were specified.')
     PrintUsage('No files were specified.')
 
 
   _SetOutputFormat(output_format)
   _SetOutputFormat(output_format)
+  _SetQuiet(quiet)
   _SetVerboseLevel(verbosity)
   _SetVerboseLevel(verbosity)
   _SetFilters(filters)
   _SetFilters(filters)
   _SetCountingStyle(counting_style)
   _SetCountingStyle(counting_style)
@@ -6114,7 +6233,9 @@ def main():
   _cpplint_state.ResetErrorCounts()
   _cpplint_state.ResetErrorCounts()
   for filename in filenames:
   for filename in filenames:
     ProcessFile(filename, _cpplint_state.verbose_level)
     ProcessFile(filename, _cpplint_state.verbose_level)
-  _cpplint_state.PrintErrorCounts()
+  # If --quiet is passed, suppress printing error count unless there are errors.
+  if not _cpplint_state.quiet or _cpplint_state.error_count > 0:
+    _cpplint_state.PrintErrorCounts()
 
 
   sys.exit(_cpplint_state.error_count > 0)
   sys.exit(_cpplint_state.error_count > 0)
 
 

+ 0 - 7
extras/cpplint.txt

@@ -1,7 +0,0 @@
-Ignoring ../src/DigitalIO/readme.txt; not a valid file name (cc, h, cpp, cu, cuh)
-Ignoring ../src/SdCard/CPPLINT.cfg; not a valid file name (cc, h, cpp, cu, cuh)
-Ignoring "../src/SdCard/SdioTeensy.h": file excluded by "C:\Users\bill\Documents\ArduinoSdFat\libraries\SdFat\src\SdCard\CPPLINT.cfg". File path component "SdioTeensy.h" matches pattern "SdioTeensy.h"
-Ignoring ../src/common/CPPLINT.cfg; not a valid file name (cc, h, cpp, cu, cuh)
-Ignoring "../src/common/PrintBasic.cpp": file excluded by "C:\Users\bill\Documents\ArduinoSdFat\libraries\SdFat\src\common\CPPLINT.cfg". File path component "PrintBasic.cpp" matches pattern "PrintBasic.cpp"
-Ignoring "../src/common/PrintBasic.h": file excluded by "C:\Users\bill\Documents\ArduinoSdFat\libraries\SdFat\src\common\CPPLINT.cfg". File path component "PrintBasic.h" matches pattern "PrintBasic.h"
-Ignoring "../src/common/PrintTemplates.h": file excluded by "C:\Users\bill\Documents\ArduinoSdFat\libraries\SdFat\src\common\CPPLINT.cfg". File path component "PrintTemplates.h" matches pattern "PrintTemplates.h"

+ 1 - 1
library.properties

@@ -1,5 +1,5 @@
 name=SdFat
 name=SdFat
-version=2.0.1
+version=2.0.2
 license=MIT
 license=MIT
 author=Bill Greiman <fat16lib@sbcglobal.net>
 author=Bill Greiman <fat16lib@sbcglobal.net>
 maintainer=Bill Greiman <fat16lib@sbcglobal.net>
 maintainer=Bill Greiman <fat16lib@sbcglobal.net>

+ 1 - 1
src/DigitalIO/SoftSPI.h

@@ -18,7 +18,7 @@
  * <http://www.gnu.org/licenses/>.
  * <http://www.gnu.org/licenses/>.
  */
  */
 /**
 /**
- * @file 
+ * @file
  * @brief  Software SPI.
  * @brief  Software SPI.
  *
  *
  * @defgroup softSPI Software SPI
  * @defgroup softSPI Software SPI

+ 242 - 238
src/ExFatLib/ExFatDbg.cpp

@@ -25,31 +25,118 @@
 #include "ExFatVolume.h"
 #include "ExFatVolume.h"
 #include "upcase.h"
 #include "upcase.h"
 #include "ExFatFile.h"
 #include "ExFatFile.h"
-#include "../common/FsDateTime.h"
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-static void printHex64(print_t* pr, uint64_t n) {
-  char buf[17];
-  char *str = &buf[sizeof(buf) - 1];
-  *str = '\0';
-  do {
-    uint8_t h = n & 15;
-    *--str = h < 10 ? h + '0' : h + 'A' - 10;
-    n >>= 4;
-  } while (n);
-  pr->println(str);
+static void printHex(print_t* pr, uint8_t h);
+static void printHex(print_t* pr, uint16_t val);
+static void printHex(print_t* pr, uint32_t val);
+static void printHex64(print_t* pr, uint64_t n);
+static void println64(print_t* pr, uint64_t n);
+//------------------------------------------------------------------------------
+static void dmpDirData(print_t* pr, DirGeneric_t* dir) {
+  for (uint8_t k = 0; k < 31; k++) {
+    if (k) {
+      pr->write(' ');
+    }
+    printHex(pr, dir->data[k]);
+  }
+  pr->println();
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-static void println64(print_t* pr, uint64_t n) {
-  char buf[21];
-  char *str = &buf[sizeof(buf) - 1];
-  *str = '\0';
-  do {
-    uint64_t m = n;
-    n /= 10;
-    *--str = m - 10*n + '0';
-  } while (n);
-  pr->println(str);
+static uint16_t exFatDirChecksum(const void* dir, uint16_t checksum) {
+  const uint8_t* data = reinterpret_cast<const uint8_t*>(dir);
+  bool skip = data[0] == EXFAT_TYPE_FILE;
+  for (size_t i = 0; i < 32; i += (i == 1 && skip ? 3 : 1)) {
+    checksum = ((checksum << 15) | (checksum >> 1)) + data[i];
+  }
+  return checksum;
+}
+//------------------------------------------------------------------------------
+static void printDateTime(print_t* pr,
+                          uint32_t timeDate, uint8_t ms, int8_t tz) {
+  fsPrintDateTime(pr, timeDate, ms, tz);
+  pr->println();
+}
+//------------------------------------------------------------------------------
+static void printDirBitmap(print_t* pr, DirBitmap_t* dir) {
+  pr->print(F("dirBitmap: 0x"));
+  pr->println(dir->type, HEX);
+  pr->print(F("flags: 0x"));
+  pr->println(dir->flags, HEX);
+  pr->print(F("firstCluster: "));
+  pr->println(getLe32(dir->firstCluster));
+  pr->print(F("size: "));
+  println64(pr, getLe64(dir->size));
+}
+//------------------------------------------------------------------------------
+static void printDirFile(print_t* pr, DirFile_t* dir) {
+  pr->print(F("dirFile: 0x"));
+  pr->println(dir->type, HEX);
+  pr->print(F("setCount: "));
+  pr->println(dir->setCount);
+  pr->print(F("setChecksum: 0x"));
+  pr->println(getLe16(dir->setChecksum), HEX);
+  pr->print(F("attributes: 0x"));
+  pr->println(getLe16(dir->attributes), HEX);
+  pr->print(F("createTime: "));
+  printDateTime(pr, getLe32(dir->createTime),
+                dir->createTimeMs, dir->createTimezone);
+  pr->print(F("modifyTime: "));
+  printDateTime(pr, getLe32(dir->modifyTime),
+                dir->modifyTimeMs, dir->modifyTimezone);
+  pr->print(F("accessTime: "));
+  printDateTime(pr, getLe32(dir->accessTime), 0, dir->accessTimezone);
+}
+//------------------------------------------------------------------------------
+static void printDirLabel(print_t* pr, DirLabel_t* dir) {
+  pr->print(F("dirLabel: 0x"));
+  pr->println(dir->type, HEX);
+  pr->print(F("labelLength: "));
+  pr->println(dir->labelLength);
+  pr->print(F("unicode: "));
+  for (size_t i = 0; i < dir->labelLength; i++) {
+    pr->write(dir->unicode[2*i]);
+  }
+  pr->println();
+}
+//------------------------------------------------------------------------------
+static void printDirName(print_t* pr, DirName_t* dir) {
+  pr->print(F("dirName: 0x"));
+  pr->println(dir->type, HEX);
+  pr->print(F("unicode: "));
+  for (size_t i = 0; i < 30; i += 2) {
+    if (dir->unicode[i] == 0) break;
+    pr->write(dir->unicode[i]);
+  }
+  pr->println();
+}
+//------------------------------------------------------------------------------
+static void printDirStream(print_t* pr, DirStream_t* dir) {
+  pr->print(F("dirStream: 0x"));
+  pr->println(dir->type, HEX);
+  pr->print(F("flags: 0x"));
+  pr->println(dir->flags, HEX);
+  pr->print(F("nameLength: "));
+  pr->println(dir->nameLength);
+  pr->print(F("nameHash: 0x"));
+  pr->println(getLe16(dir->nameHash), HEX);
+  pr->print(F("validLength: "));
+  println64(pr, getLe64(dir->validLength));
+  pr->print(F("firstCluster: "));
+  pr->println(getLe32(dir->firstCluster));
+  pr->print(F("dataLength: "));
+  println64(pr, getLe64(dir->dataLength));
+}
+//------------------------------------------------------------------------------
+static void printDirUpcase(print_t* pr, DirUpcase_t* dir) {
+  pr->print(F("dirUpcase: 0x"));
+  pr->println(dir->type, HEX);
+    pr->print(F("checksum: 0x"));
+  pr->println(getLe32(dir->checksum), HEX);
+  pr->print(F("firstCluster: "));
+  pr->println(getLe32(dir->firstCluster));
+  pr->print(F("size: "));
+  println64(pr, getLe64(dir->size));
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 static void printExFatBoot(print_t* pr, pbs_t* pbs) {
 static void printExFatBoot(print_t* pr, pbs_t* pbs) {
@@ -104,28 +191,6 @@ static void printHex(print_t* pr, uint8_t h) {
   pr->print(h, HEX);
   pr->print(h, HEX);
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-static void printMbr(print_t* pr, MbrSector_t* mbr) {
-  pr->print(F("mbrSig: 0x"));
-  pr->println(getLe16(mbr->signature), HEX);
-  for (int i = 0; i < 4; i++) {
-    printHex(pr, mbr->part[i].boot);
-    pr->write(' ');
-    for (int k = 0; k < 3; k++) {
-      printHex(pr, mbr->part[i].beginCHS[k]);
-      pr->write(' ');
-    }
-    printHex(pr, mbr->part[i].type);
-    pr->write(' ');
-    for (int k = 0; k < 3; k++) {
-      printHex(pr, mbr->part[i].endCHS[k]);
-      pr->write(' ');
-    }
-    pr->print(getLe32(mbr->part[i].relativeSectors), HEX);
-    pr->print(' ');
-    pr->println(getLe32(mbr->part[i].totalSectors), HEX);
-  }
-}
-//------------------------------------------------------------------------------
 static void printHex(print_t* pr, uint16_t val) {
 static void printHex(print_t* pr, uint16_t val) {
   bool space = true;
   bool space = true;
   for (uint8_t i = 0; i < 4; i++) {
   for (uint8_t i = 0; i < 4; i++) {
@@ -156,210 +221,52 @@ static void printHex(print_t* pr, uint32_t val) {
   }
   }
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-void ExFatPartition::dmpCluster(print_t* pr, uint32_t cluster,
-                                uint32_t offset, uint32_t count) {
-  uint32_t sector = clusterStartSector(cluster) + offset;
-  for (uint32_t i = 0; i < count; i++) {
-    pr->print(F("\nSector: "));
-    pr->println(sector + i, HEX);
-    dmpSector(pr, sector + i);
-  }
-}
-//------------------------------------------------------------------------------
-void ExFatPartition::dmpSector(print_t* pr, uint32_t sector) {
-  uint8_t* cache = dataCacheGet(sector, FsCache::CACHE_FOR_READ);
-  if (!cache) {
-    pr->println(F("dmpSector failed"));
-    return;
-  }
-  for (uint16_t i = 0; i < 512; i++) {
-    if (i%32 == 0) {
-      if (i) {
-        pr->println();
-      }
-      printHex(pr, i);
-    }
-    pr->write(' ');
-    printHex(pr, cache[i]);
-  }
-  pr->println();
-}
-//------------------------------------------------------------------------------
-void ExFatPartition::dmpBitmap(print_t* pr) {
-  pr->println(F("bitmap:"));
-  dmpSector(pr, m_clusterHeapStartSector);
+static void printHex64(print_t* pr, uint64_t n) {
+  char buf[17];
+  char *str = &buf[sizeof(buf) - 1];
+  *str = '\0';
+  do {
+    uint8_t h = n & 15;
+    *--str = h < 10 ? h + '0' : h + 'A' - 10;
+    n >>= 4;
+  } while (n);
+  pr->println(str);
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-static void dmpDirData(print_t* pr, DirGeneric_t* dir) {
-  for (uint8_t k = 0; k < 31; k++) {
-    if (k) {
-      pr->write(' ');
-    }
-    printHex(pr, dir->data[k]);
-  }
-  pr->println();
+static void println64(print_t* pr, uint64_t n) {
+  char buf[21];
+  char *str = &buf[sizeof(buf) - 1];
+  *str = '\0';
+  do {
+    uint64_t m = n;
+    n /= 10;
+    *--str = m - 10*n + '0';
+  } while (n);
+  pr->println(str);
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-void ExFatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
-  uint32_t sector = m_fatStartSector + start;
-  uint32_t cluster = 128*start;
-  pr->println(F("FAT:"));
-  for (uint32_t i = 0; i < count; i++) {
-    uint8_t* cache = dataCacheGet(sector + i, FsCache::CACHE_FOR_READ);
-    if (!cache) {
-      pr->println(F("cache read failed"));
-      return;
-    }
-    uint32_t* fat = reinterpret_cast<uint32_t*>(cache);
-    for (size_t k = 0; k < 128; k++) {
-      if (0 == cluster%8) {
-        if (k) {
-          pr->println();
-        }
-        printHex(pr, cluster);
-      }
-      cluster++;
+static void printMbr(print_t* pr, MbrSector_t* mbr) {
+  pr->print(F("mbrSig: 0x"));
+  pr->println(getLe16(mbr->signature), HEX);
+  for (int i = 0; i < 4; i++) {
+    printHex(pr, mbr->part[i].boot);
+    pr->write(' ');
+    for (int k = 0; k < 3; k++) {
+      printHex(pr, mbr->part[i].beginCHS[k]);
       pr->write(' ');
       pr->write(' ');
-      printHex(pr, fat[k]);
     }
     }
-    pr->println();
-  }
-}
-//------------------------------------------------------------------------------
-void ExFatPartition::printFat(print_t* pr) {
-  uint32_t next;
-  int8_t status;
-  pr->println(F("FAT:"));
-  for (uint32_t cluster = 0; cluster < 16; cluster++) {
-    status = fatGet(cluster, &next);
-    pr->print(cluster, HEX);
+    printHex(pr, mbr->part[i].type);
     pr->write(' ');
     pr->write(' ');
-    if (status == 0) {
-      next = EXFAT_EOC;
+    for (int k = 0; k < 3; k++) {
+      printHex(pr, mbr->part[i].endCHS[k]);
+      pr->write(' ');
     }
     }
-    pr->println(next, HEX);
-  }
-}
-//------------------------------------------------------------------------------
-bool ExFatPartition::printVolInfo(print_t* pr) {
-  uint8_t* cache = dataCacheGet(0, FsCache::CACHE_FOR_READ);
-  if (!cache) {
-    pr->println(F("read mbr failed"));
-    return false;
-  }
-  MbrSector_t* mbr = reinterpret_cast<MbrSector_t*>(cache);
-  printMbr(pr, mbr);
-  uint32_t volStart = getLe32(mbr->part->relativeSectors);
-  uint32_t volSize = getLe32(mbr->part->totalSectors);
-  if (volSize == 0) {
-    pr->print(F("bad partition size"));
-    return false;
-  }
-  cache = dataCacheGet(volStart, FsCache::CACHE_FOR_READ);
-  if (!cache) {
-    pr->println(F("read pbs failed"));
-    return false;
-  }
-  printExFatBoot(pr, reinterpret_cast<pbs_t*>(cache));
-  return true;
-}
-//------------------------------------------------------------------------------
-static void printDateTime(print_t* pr,
-                          uint32_t timeDate, uint8_t ms, int8_t tz) {
-  fsPrintDateTime(pr, timeDate, ms, tz);
-  pr->println();
-}
-//------------------------------------------------------------------------------
-static void printDirBitmap(print_t* pr, DirBitmap_t* dir) {
-  pr->print(F("dirBitmap: 0x"));
-  pr->println(dir->type, HEX);
-  pr->print(F("flags: 0x"));
-  pr->println(dir->flags, HEX);
-  pr->print(F("firstCluster: "));
-  pr->println(getLe32(dir->firstCluster));
-  pr->print(F("size: "));
-  println64(pr, getLe64(dir->size));
-}
-//------------------------------------------------------------------------------
-static void printDirUpcase(print_t* pr, DirUpcase_t* dir) {
-  pr->print(F("dirUpcase: 0x"));
-  pr->println(dir->type, HEX);
-    pr->print(F("checksum: 0x"));
-  pr->println(getLe32(dir->checksum), HEX);
-  pr->print(F("firstCluster: "));
-  pr->println(getLe32(dir->firstCluster));
-  pr->print(F("size: "));
-  println64(pr, getLe64(dir->size));
-}
-//------------------------------------------------------------------------------
-static void printDirLabel(print_t* pr, DirLabel_t* dir) {
-  pr->print(F("dirLabel: 0x"));
-  pr->println(dir->type, HEX);
-  pr->print(F("labelLength: "));
-  pr->println(dir->labelLength);
-  pr->print(F("unicode: "));
-  for (size_t i = 0; i < dir->labelLength; i++) {
-    pr->write(dir->unicode[2*i]);
-  }
-  pr->println();
-}
-//------------------------------------------------------------------------------
-static void printDirFile(print_t* pr, DirFile_t* dir) {
-  pr->print(F("dirFile: 0x"));
-  pr->println(dir->type, HEX);
-  pr->print(F("setCount: "));
-  pr->println(dir->setCount);
-  pr->print(F("setChecksum: 0x"));
-  pr->println(getLe16(dir->setChecksum), HEX);
-  pr->print(F("attributes: 0x"));
-  pr->println(getLe16(dir->attributes), HEX);
-  pr->print(F("createTime: "));
-  printDateTime(pr, getLe32(dir->createTime),
-                dir->createTimeMs, dir->createTimezone);
-  pr->print(F("modifyTime: "));
-  printDateTime(pr, getLe32(dir->modifyTime),
-                dir->modifyTimeMs, dir->modifyTimezone);
-  pr->print(F("accessTime: "));
-  printDateTime(pr, getLe32(dir->accessTime), 0, dir->accessTimezone);
-}
-//------------------------------------------------------------------------------
-static void printDirStream(print_t* pr, DirStream_t* dir) {
-  pr->print(F("dirStream: 0x"));
-  pr->println(dir->type, HEX);
-  pr->print(F("flags: 0x"));
-  pr->println(dir->flags, HEX);
-  pr->print(F("nameLength: "));
-  pr->println(dir->nameLength);
-  pr->print(F("nameHash: 0x"));
-  pr->println(getLe16(dir->nameHash), HEX);
-  pr->print(F("validLength: "));
-  println64(pr, getLe64(dir->validLength));
-  pr->print(F("firstCluster: "));
-  pr->println(getLe32(dir->firstCluster));
-  pr->print(F("dataLength: "));
-  println64(pr, getLe64(dir->dataLength));
-}
-//------------------------------------------------------------------------------
-static void printDirName(print_t* pr, DirName_t* dir) {
-  pr->print(F("dirName: 0x"));
-  pr->println(dir->type, HEX);
-  pr->print(F("unicode: "));
-  for (size_t i = 0; i < 30; i += 2) {
-    if (dir->unicode[i] == 0) break;
-    pr->write(dir->unicode[i]);
-  }
-  pr->println();
-}
-//------------------------------------------------------------------------------
-static uint16_t exFatDirChecksum(const void* dir, uint16_t checksum) {
-  const uint8_t* data = reinterpret_cast<const uint8_t*>(dir);
-  bool skip = data[0] == EXFAT_TYPE_FILE;
-  for (size_t i = 0; i < 32; i += (i == 1 && skip ? 3 : 1)) {
-    checksum = ((checksum << 15) | (checksum >> 1)) + data[i];
+    pr->print(getLe32(mbr->part[i].relativeSectors), HEX);
+    pr->print(' ');
+    pr->println(getLe32(mbr->part[i].totalSectors), HEX);
   }
   }
-  return checksum;
 }
 }
-//------------------------------------------------------------------------------
+//==============================================================================
 void ExFatPartition::checkUpcase(print_t* pr) {
 void ExFatPartition::checkUpcase(print_t* pr) {
   bool skip = false;
   bool skip = false;
   uint16_t u = 0;
   uint16_t u = 0;
@@ -430,6 +337,66 @@ void ExFatPartition::checkUpcase(print_t* pr) {
   pr->println(F("Done checkUpcase"));
   pr->println(F("Done checkUpcase"));
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+void ExFatPartition::dmpBitmap(print_t* pr) {
+  pr->println(F("bitmap:"));
+  dmpSector(pr, m_clusterHeapStartSector);
+}
+//------------------------------------------------------------------------------
+void ExFatPartition::dmpCluster(print_t* pr, uint32_t cluster,
+                                uint32_t offset, uint32_t count) {
+  uint32_t sector = clusterStartSector(cluster) + offset;
+  for (uint32_t i = 0; i < count; i++) {
+    pr->print(F("\nSector: "));
+    pr->println(sector + i, HEX);
+    dmpSector(pr, sector + i);
+  }
+}
+//------------------------------------------------------------------------------
+void ExFatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) {
+  uint32_t sector = m_fatStartSector + start;
+  uint32_t cluster = 128*start;
+  pr->println(F("FAT:"));
+  for (uint32_t i = 0; i < count; i++) {
+    uint8_t* cache = dataCacheGet(sector + i, FsCache::CACHE_FOR_READ);
+    if (!cache) {
+      pr->println(F("cache read failed"));
+      return;
+    }
+    uint32_t* fat = reinterpret_cast<uint32_t*>(cache);
+    for (size_t k = 0; k < 128; k++) {
+      if (0 == cluster%8) {
+        if (k) {
+          pr->println();
+        }
+        printHex(pr, cluster);
+      }
+      cluster++;
+      pr->write(' ');
+      printHex(pr, fat[k]);
+    }
+    pr->println();
+  }
+}
+//------------------------------------------------------------------------------
+void ExFatPartition::dmpSector(print_t* pr, uint32_t sector) {
+  uint8_t* cache = dataCacheGet(sector, FsCache::CACHE_FOR_READ);
+  if (!cache) {
+    pr->println(F("dmpSector failed"));
+    return;
+  }
+  for (uint16_t i = 0; i < 512; i++) {
+    if (i%32 == 0) {
+      if (i) {
+        pr->println();
+      }
+      printHex(pr, i);
+    }
+    pr->write(' ');
+    printHex(pr, cache[i]);
+  }
+  pr->println();
+}
+//------------------------------------------------------------------------------
 bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
 bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
   DirGeneric_t* dir = nullptr;
   DirGeneric_t* dir = nullptr;
   DirFile_t* dirFile;
   DirFile_t* dirFile;
@@ -547,6 +514,21 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
   return true;
   return true;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+void ExFatPartition::printFat(print_t* pr) {
+  uint32_t next;
+  int8_t status;
+  pr->println(F("FAT:"));
+  for (uint32_t cluster = 0; cluster < 16; cluster++) {
+    status = fatGet(cluster, &next);
+    pr->print(cluster, HEX);
+    pr->write(' ');
+    if (status == 0) {
+      next = EXFAT_EOC;
+    }
+    pr->println(next, HEX);
+  }
+}
+//------------------------------------------------------------------------------
 void ExFatPartition::printUpcase(print_t* pr) {
 void ExFatPartition::printUpcase(print_t* pr) {
   uint8_t* upcase = nullptr;
   uint8_t* upcase = nullptr;
   uint32_t sector;
   uint32_t sector;
@@ -593,5 +575,27 @@ void ExFatPartition::printUpcase(print_t* pr) {
   printHex(pr, checksum);
   printHex(pr, checksum);
   pr->println();
   pr->println();
 }
 }
+//------------------------------------------------------------------------------
+bool ExFatPartition::printVolInfo(print_t* pr) {
+  uint8_t* cache = dataCacheGet(0, FsCache::CACHE_FOR_READ);
+  if (!cache) {
+    pr->println(F("read mbr failed"));
+    return false;
+  }
+  MbrSector_t* mbr = reinterpret_cast<MbrSector_t*>(cache);
+  printMbr(pr, mbr);
+  uint32_t volStart = getLe32(mbr->part->relativeSectors);
+  uint32_t volSize = getLe32(mbr->part->totalSectors);
+  if (volSize == 0) {
+    pr->print(F("bad partition size"));
+    return false;
+  }
+  cache = dataCacheGet(volStart, FsCache::CACHE_FOR_READ);
+  if (!cache) {
+    pr->println(F("read pbs failed"));
+    return false;
+  }
+  printExFatBoot(pr, reinterpret_cast<pbs_t*>(cache));
+  return true;
+}
 #endif  // DOXYGEN_SHOULD_SKIP_THIS
 #endif  // DOXYGEN_SHOULD_SKIP_THIS
-

+ 90 - 54
src/ExFatLib/ExFatFile.cpp

@@ -27,7 +27,7 @@
 #include "ExFatFile.h"
 #include "ExFatFile.h"
 #include "ExFatVolume.h"
 #include "ExFatVolume.h"
 #include "upcase.h"
 #include "upcase.h"
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::close() {
 bool ExFatFile::close() {
   bool rtn = sync();
   bool rtn = sync();
   m_attributes = FILE_ATTR_CLOSED;
   m_attributes = FILE_ATTR_CLOSED;
@@ -35,6 +35,20 @@ bool ExFatFile::close() {
   return rtn;
   return rtn;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+bool ExFatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
+  if (!isContiguous()) {
+    return false;
+  }
+  if (bgnSector) {
+    *bgnSector = firstSector();
+  }
+  if (endSector) {
+    *endSector = firstSector() +
+                 ((m_validLength - 1) >> m_vol->bytesPerSectorShift());
+  }
+  return true;
+}
+//------------------------------------------------------------------------------
 void ExFatFile::fgetpos(fspos_t* pos) {
 void ExFatFile::fgetpos(fspos_t* pos) {
   pos->position = m_curPosition;
   pos->position = m_curPosition;
   pos->cluster = m_curCluster;
   pos->cluster = m_curCluster;
@@ -68,12 +82,61 @@ int ExFatFile::fgets(char* str, int num, char* delim) {
   return n;
   return n;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+uint32_t ExFatFile::firstSector() {
+  return m_firstCluster ? m_vol->clusterStartSector(m_firstCluster) : 0;
+}
+//------------------------------------------------------------------------------
 void ExFatFile::fsetpos(const fspos_t* pos) {
 void ExFatFile::fsetpos(const fspos_t* pos) {
   m_curPosition = pos->position;
   m_curPosition = pos->position;
   m_curCluster = pos->cluster;
   m_curCluster = pos->cluster;
 }
 }
-//-----------------------------------------------------------------------------
-size_t ExFatFile::getName(ExChar_t *name, size_t length) {
+//------------------------------------------------------------------------------
+bool ExFatFile::getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
+  DirFile_t* df = reinterpret_cast<DirFile_t*>
+                 (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
+  if (!df) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  *pdate = getLe16(df->accessDate);
+  *ptime = getLe16(df->accessTime);
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+bool ExFatFile::getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
+  DirFile_t* df = reinterpret_cast<DirFile_t*>
+                 (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
+  if (!df) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  *pdate = getLe16(df->createDate);
+  *ptime = getLe16(df->createTime);
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+bool ExFatFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
+  DirFile_t* df = reinterpret_cast<DirFile_t*>
+                 (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
+  if (!df) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  *pdate = getLe16(df->modifyDate);
+  *ptime = getLe16(df->modifyTime);
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+size_t ExFatFile::getName(ExChar_t* name, size_t length) {
   DirName_t* dn;
   DirName_t* dn;
   DirPos_t pos = m_dirPos;
   DirPos_t pos = m_dirPos;
   size_t n = 0;
   size_t n = 0;
@@ -108,11 +171,11 @@ size_t ExFatFile::getName(ExChar_t *name, size_t length) {
   *name = 0;
   *name = 0;
   return 0;
   return 0;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::open(const ExChar_t* path, int oflag) {
 bool ExFatFile::open(const ExChar_t* path, int oflag) {
   return open(ExFatVolume::cwv(), path, oflag);
   return open(ExFatVolume::cwv(), path, oflag);
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::open(ExFatVolume* vol, const ExChar_t* path, int oflag) {
 bool ExFatFile::open(ExFatVolume* vol, const ExChar_t* path, int oflag) {
   return vol && open(vol->vwd(), path, oflag);
   return vol && open(vol->vwd(), path, oflag);
 }
 }
@@ -156,7 +219,7 @@ bool ExFatFile::open(ExFatFile* dirFile, const ExChar_t* path, oflag_t oflag) {
   }
   }
   return open(dirFile, &fname, oflag);
   return open(dirFile, &fname, oflag);
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -170,7 +233,7 @@ bool ExFatFile::open(ExFatFile* dirFile, uint32_t index, oflag_t oflag) {
   }
   }
   return false;
   return false;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::openNext(ExFatFile* dir, oflag_t oflag) {
 bool ExFatFile::openNext(ExFatFile* dir, oflag_t oflag) {
   if (isOpen() || !dir->isDir() || (dir->curPosition() & 0X1F)) {
   if (isOpen() || !dir->isDir() || (dir->curPosition() & 0X1F)) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
@@ -400,13 +463,23 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name,
       dirFile->type = EXFAT_TYPE_FILE;
       dirFile->type = EXFAT_TYPE_FILE;
       m_setCount = freeNeed - 1;
       m_setCount = freeNeed - 1;
       dirFile->setCount = m_setCount;
       dirFile->setCount = m_setCount;
+
       if (FsDateTime::callback) {
       if (FsDateTime::callback) {
         uint16_t date, time;
         uint16_t date, time;
         uint8_t ms10;
         uint8_t ms10;
         FsDateTime::callback(&date, &time, &ms10);
         FsDateTime::callback(&date, &time, &ms10);
-        dirFile->createTimeMs = ms10;
-        setLe16(dirFile->createTime, time);
         setLe16(dirFile->createDate, date);
         setLe16(dirFile->createDate, date);
+        setLe16(dirFile->createTime, time);
+        dirFile->createTimeMs = ms10;
+      } else {
+        setLe16(dirFile->createDate, FS_DEFAULT_DATE);
+        setLe16(dirFile->modifyDate, FS_DEFAULT_DATE);
+        setLe16(dirFile->accessDate, FS_DEFAULT_DATE);
+       if (FS_DEFAULT_TIME) {
+         setLe16(dirFile->createTime, FS_DEFAULT_TIME);
+         setLe16(dirFile->modifyTime, FS_DEFAULT_TIME);
+         setLe16(dirFile->accessTime, FS_DEFAULT_TIME);
+       }
       }
       }
     } else if (i == 1) {
     } else if (i == 1) {
       dirStream = reinterpret_cast<DirStream_t*>(cache);
       dirStream = reinterpret_cast<DirStream_t*>(cache);
@@ -438,7 +511,7 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name,
   m_flags = 0;
   m_flags = 0;
   return false;
   return false;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::openRoot(ExFatVolume* vol) {
 bool ExFatFile::openRoot(ExFatVolume* vol) {
   if (isOpen()) {
   if (isOpen()) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
@@ -494,7 +567,7 @@ bool ExFatFile::parsePathName(const ExChar_t* path,
   fname->len = len;
   fname->len = len;
   return true;
   return true;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 int ExFatFile::peek() {
 int ExFatFile::peek() {
   uint64_t curPosition = m_curPosition;
   uint64_t curPosition = m_curPosition;
   uint32_t curCluster = m_curCluster;
   uint32_t curCluster = m_curCluster;
@@ -503,44 +576,7 @@ int ExFatFile::peek() {
   m_curCluster = curCluster;
   m_curCluster = curCluster;
   return c;
   return c;
 }
 }
-//-----------------------------------------------------------------------------
-size_t ExFatFile::printName(print_t* pr) {
-  DirName_t* dn;
-  DirPos_t pos = m_dirPos;
-  size_t n = 0;
-  uint8_t in;
-  uint8_t buf[15];
-  if (!isOpen()) {
-      DBG_FAIL_MACRO;
-      goto fail;
-  }
-  for (uint8_t is = 1; is < m_setCount; is++) {
-    if (m_vol->dirSeek(&pos, is == 1 ? 64: 32) != 1) {
-      DBG_FAIL_MACRO;
-      goto fail;
-    }
-    dn = reinterpret_cast<DirName_t*>
-         (m_vol->dirCache(&pos, FsCache::CACHE_FOR_READ));
-    if (!dn || dn->type != EXFAT_TYPE_NAME) {
-      DBG_FAIL_MACRO;
-      goto fail;
-    }
-    for (in = 0; in < 15; in++) {
-      uint16_t c = getLe16(dn->unicode + 2*in);
-      if (!c) {
-        break;;
-      }
-      buf[in] = c < 0X7f ? c : '?';
-      n++;
-    }
-    pr->write(buf, in);
-  }
-  return n;
-
- fail:
-  return 0;
-}
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 int ExFatFile::read(void* buf, size_t count) {
 int ExFatFile::read(void* buf, size_t count) {
   uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
   uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
   int8_t fg;
   int8_t fg;
@@ -604,7 +640,7 @@ int ExFatFile::read(void* buf, size_t count) {
 #if USE_MULTI_SECTOR_IO
 #if USE_MULTI_SECTOR_IO
     } else if (toRead >= 2*m_vol->bytesPerSector()) {
     } else if (toRead >= 2*m_vol->bytesPerSector()) {
       uint32_t ns = toRead >> m_vol->bytesPerSectorShift();
       uint32_t ns = toRead >> m_vol->bytesPerSectorShift();
-      // Limit writes to current cluster.
+      // Limit reads to current cluster.
       uint32_t maxNs = m_vol->sectorsPerCluster()
       uint32_t maxNs = m_vol->sectorsPerCluster()
                        - (clusterOffset >> m_vol->bytesPerSectorShift());
                        - (clusterOffset >> m_vol->bytesPerSectorShift());
       if (ns > maxNs) {
       if (ns > maxNs) {
@@ -639,7 +675,7 @@ int ExFatFile::read(void* buf, size_t count) {
   }
   }
   return count - toRead;
   return count - toRead;
 
 
-fail:
+ fail:
   m_error |= READ_ERROR;
   m_error |= READ_ERROR;
   return -1;
   return -1;
 }
 }
@@ -652,7 +688,7 @@ bool ExFatFile::remove(const ExChar_t* path) {
   }
   }
   return file.remove();
   return file.remove();
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -702,11 +738,11 @@ bool ExFatFile::seekSet(uint64_t pos) {
     }
     }
   }
   }
 
 
-done:
+ done:
   m_curPosition = pos;
   m_curPosition = pos;
   return true;
   return true;
 
 
-fail:
+ fail:
   m_curCluster = tmp;
   m_curCluster = tmp;
   return false;
   return false;
 }
 }

+ 51 - 12
src/ExFatLib/ExFatFile.h

@@ -118,7 +118,7 @@ class ExFatFile {
   /** \return The number of bytes available from the current position
   /** \return The number of bytes available from the current position
    * to EOF for normal files.  INT_MAX is returned for very large files.
    * to EOF for normal files.  INT_MAX is returned for very large files.
    *
    *
-   * available64() is recomended for very large files.
+   * available64() is recommended for very large files.
    *
    *
    * Zero is returned for directory files.
    * Zero is returned for directory files.
    *
    *
@@ -133,6 +133,16 @@ class ExFatFile {
    * \return true for success or false for failure.
    * \return true for success or false for failure.
    */
    */
   bool close();
   bool close();
+  /** Check for contiguous file and return its raw sector range.
+   *
+   * \param[out] bgnSector the first sector address for the file.
+   * \param[out] endSector the last  sector address for the file.
+   *
+   * Parameters may be nullptr.
+   *
+   * \return true for success or false for failure.
+   */
+  bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector);
   /** \return The current position for a file or directory. */
   /** \return The current position for a file or directory. */
   uint64_t curPosition() const {return m_curPosition;}
   uint64_t curPosition() const {return m_curPosition;}
 
 
@@ -163,8 +173,8 @@ class ExFatFile {
    * Get a string from a file.
    * Get a string from a file.
    *
    *
    * fgets() reads bytes from a file into the array pointed to by \a str, until
    * fgets() reads bytes from a file into the array pointed to by \a str, until
-   * \a num - 1 bytes are read, or a delimiter is read and transferred to \a str,
-   * or end-of-file is encountered. The string is then terminated
+   * \a num - 1 bytes are read, or a delimiter is read and transferred to
+   * \a str, or end-of-file is encountered. The string is then terminated
    * with a null byte.
    * with a null byte.
    *
    *
    * fgets() deletes CR, '\\r', from the string.  This insures only a '\\n'
    * fgets() deletes CR, '\\r', from the string.  This insures only a '\\n'
@@ -177,12 +187,15 @@ class ExFatFile {
    * \param[in] delim Optional set of delimiters. The default is "\n".
    * \param[in] delim Optional set of delimiters. The default is "\n".
    *
    *
    * \return For success fgets() returns the length of the string in \a str.
    * \return For success fgets() returns the length of the string in \a str.
-   * If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
+   * If no data is read, fgets() returns zero for EOF or -1 if an error
+   * occurred.
    */
    */
   int fgets(char* str, int num, char* delim = nullptr);
   int fgets(char* str, int num, char* delim = nullptr);
   /** \return The total number of bytes in a file. */
   /** \return The total number of bytes in a file. */
   uint64_t fileSize() {return m_validLength;}
   uint64_t fileSize() {return m_validLength;}
-  /** set position for streams
+  /** \return Address of first sector or zero for empty file. */
+  uint32_t firstSector();
+  /** Set position for streams
    * \param[in] pos struct with value for new position
    * \param[in] pos struct with value for new position
    */
    */
   void fsetpos(const fspos_t* pos);
   void fsetpos(const fspos_t* pos);
@@ -195,19 +208,43 @@ class ExFatFile {
    * \param[in] size The size of the array in characters.
    * \param[in] size The size of the array in characters.
    * \return the name length.
    * \return the name length.
    */
    */
-  size_t getName(ExChar_t *name, size_t size);
+  size_t getName(ExChar_t* name, size_t size);
   /** Clear all error bits. */
   /** Clear all error bits. */
   void clearError() {
   void clearError() {
     m_error = 0;
     m_error = 0;
   }
   }
-  /** Set writeError to zero */
+  /** Clear writeError. */
   void clearWriteError() {
   void clearWriteError() {
     m_error &= ~WRITE_ERROR;
     m_error &= ~WRITE_ERROR;
   }
   }
+  /** Get a file's access date and time.
+   *
+   * \param[out] pdate Packed date for directory entry.
+   * \param[out] ptime Packed time for directory entry.
+   *
+   * \return true for success or false for failure.
+   */
+  bool getAccessDateTime(uint16_t* pdate, uint16_t* ptime);
+  /** Get a file's create date and time.
+   *
+   * \param[out] pdate Packed date for directory entry.
+   * \param[out] ptime Packed time for directory entry.
+   *
+   * \return true for success or false for failure.
+   */
+  bool getCreateDateTime(uint16_t* pdate, uint16_t* ptime);
   /** \return All error bits. */
   /** \return All error bits. */
   uint8_t getError() {
   uint8_t getError() {
     return isOpen() ? m_error : 0XFF;
     return isOpen() ? m_error : 0XFF;
   }
   }
+  /** Get a file's modify date and time.
+   *
+   * \param[out] pdate Packed date for directory entry.
+   * \param[out] ptime Packed time for directory entry.
+   *
+   * \return true for success or false for failure.
+   */
+  bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime);
   /** \return value of writeError */
   /** \return value of writeError */
   bool getWriteError() {
   bool getWriteError() {
     return isOpen() ? m_error & WRITE_ERROR : true;
     return isOpen() ? m_error & WRITE_ERROR : true;
@@ -297,10 +334,12 @@ class ExFatFile {
    * O_CREAT - If the file exists, this flag has no effect except as noted
    * O_CREAT - If the file exists, this flag has no effect except as noted
    * under O_EXCL below. Otherwise, the file shall be created
    * under O_EXCL below. Otherwise, the file shall be created
    *
    *
-   * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
+   * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file
+   * exists.
    *
    *
    * O_TRUNC - If the file exists and is a regular file, and the file is
    * O_TRUNC - If the file exists and is a regular file, and the file is
-   * successfully opened and is not read only, its length shall be truncated to 0.
+   * successfully opened and is not read only, its length shall be truncated
+   * to 0.
    *
    *
    * WARNING: A given file must not be opened by more than one file object
    * WARNING: A given file must not be opened by more than one file object
    * or file corruption may occur.
    * or file corruption may occur.
@@ -586,10 +625,10 @@ class ExFatFile {
    */
    */
   /** Set a file's timestamps in its directory entry.
   /** Set a file's timestamps in its directory entry.
    *
    *
-   * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
-   * OR of flags from the following list
+   * \param[in] flags Values for \a flags are constructed by a
+   * bitwise-inclusive OR of flags from the following list
    *
    *
-   * T_ACCESS - Set the file's last access date.
+   * T_ACCESS - Set the file's last access date and time.
    *
    *
    * T_CREATE - Set the file's creation date and time.
    * T_CREATE - Set the file's creation date and time.
    *
    *

+ 80 - 55
src/ExFatLib/ExFatFilePrint.cpp

@@ -27,59 +27,6 @@
 #include "ExFatFile.h"
 #include "ExFatFile.h"
 #include "upcase.h"
 #include "upcase.h"
 #include "ExFatVolume.h"
 #include "ExFatVolume.h"
-//-----------------------------------------------------------------------------
-size_t ExFatFile::printFileSize(print_t* pr) {
-  uint64_t n = m_validLength;
-  char buf[21];
-  char *str = &buf[sizeof(buf) - 1];
-  char *bgn = str - 12;
-  *str = '\0';
-  do {
-    uint64_t m = n;
-    n /= 10;
-    *--str = m - 10*n + '0';
-  } while (n);
-  while (str > bgn) {
-    *--str = ' ';
-  }
-  return pr->write(str);
-}
-//-----------------------------------------------------------------------------
-size_t ExFatFile::printAccessDateTime(print_t* pr) {
-  DirFile_t* df = reinterpret_cast<DirFile_t*>
-                 (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
-  if (!df) {
-    DBG_FAIL_MACRO;
-    goto fail;
-  }
-  return fsPrintDateTime(pr, getLe32(df->accessTime));
-fail:
-  return 0;
-}
-//-----------------------------------------------------------------------------
-size_t ExFatFile::printCreateDateTime(print_t* pr) {
-  DirFile_t* df = reinterpret_cast<DirFile_t*>
-                 (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
-  if (!df) {
-    DBG_FAIL_MACRO;
-    goto fail;
-  }
-  return fsPrintDateTime(pr, getLe32(df->createTime));
-fail:
-  return 0;
-}
-//-----------------------------------------------------------------------------
-size_t ExFatFile::printModifyDateTime(print_t* pr) {
-  DirFile_t* df = reinterpret_cast<DirFile_t*>
-                 (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_READ));
-  if (!df) {
-    DBG_FAIL_MACRO;
-    goto fail;
-  }
-  return fsPrintDateTime(pr, getLe32(df->modifyTime));
-fail:
-  return 0;
-}
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 bool ExFatFile::ls(print_t* pr) {
 bool ExFatFile::ls(print_t* pr) {
   ExFatFile file;
   ExFatFile file;
@@ -151,6 +98,84 @@ bool ExFatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) {
  fail:
  fail:
   return false;
   return false;
 }
 }
+//------------------------------------------------------------------------------
+size_t ExFatFile::printAccessDateTime(print_t* pr) {
+  uint16_t date;
+  uint16_t time;
+  if (getAccessDateTime(&date, &time)) {
+    return fsPrintDateTime(pr, date, time);
+  }
+  return 0;
+}
+//------------------------------------------------------------------------------
+size_t ExFatFile::printCreateDateTime(print_t* pr) {
+  uint16_t date;
+  uint16_t time;
+  if (getCreateDateTime(&date, &time)) {
+    return fsPrintDateTime(pr, date, time);
+  }
+  return 0;
+}
+//------------------------------------------------------------------------------
+size_t ExFatFile::printFileSize(print_t* pr) {
+  uint64_t n = m_validLength;
+  char buf[21];
+  char *str = &buf[sizeof(buf) - 1];
+  char *bgn = str - 12;
+  *str = '\0';
+  do {
+    uint64_t m = n;
+    n /= 10;
+    *--str = m - 10*n + '0';
+  } while (n);
+  while (str > bgn) {
+    *--str = ' ';
+  }
+  return pr->write(str);
+}
+//------------------------------------------------------------------------------
+size_t ExFatFile::printModifyDateTime(print_t* pr) {
+  uint16_t date;
+  uint16_t time;
+  if (getModifyDateTime(&date, &time)) {
+    return fsPrintDateTime(pr, date, time);
+  }
+  return 0;
+}
+//------------------------------------------------------------------------------
+size_t ExFatFile::printName(print_t* pr) {
+  DirName_t* dn;
+  DirPos_t pos = m_dirPos;
+  size_t n = 0;
+  uint8_t in;
+  uint8_t buf[15];
+  if (!isOpen()) {
+      DBG_FAIL_MACRO;
+      goto fail;
+  }
+  for (uint8_t is = 1; is < m_setCount; is++) {
+    if (m_vol->dirSeek(&pos, is == 1 ? 64: 32) != 1) {
+      DBG_FAIL_MACRO;
+      goto fail;
+    }
+    dn = reinterpret_cast<DirName_t*>
+         (m_vol->dirCache(&pos, FsCache::CACHE_FOR_READ));
+    if (!dn || dn->type != EXFAT_TYPE_NAME) {
+      DBG_FAIL_MACRO;
+      goto fail;
+    }
+    for (in = 0; in < 15; in++) {
+      uint16_t c = getLe16(dn->unicode + 2*in);
+      if (!c) {
+        break;;
+      }
+      buf[in] = c < 0X7f ? c : '?';
+      n++;
+    }
+    pr->write(buf, in);
+  }
+  return n;
 
 
-
-
+ fail:
+  return 0;
+}

+ 18 - 20
src/ExFatLib/ExFatFileWrite.cpp

@@ -27,11 +27,8 @@
 #include "ExFatFile.h"
 #include "ExFatFile.h"
 #include "ExFatVolume.h"
 #include "ExFatVolume.h"
 #include "upcase.h"
 #include "upcase.h"
-//=============================================================================
+//==============================================================================
 #if READ_ONLY
 #if READ_ONLY
-bool ExFatFile::sync() {
-  return false;
-}
 bool ExFatFile::mkdir(ExFatFile* parent, const ExChar_t* path, bool pFlag) {
 bool ExFatFile::mkdir(ExFatFile* parent, const ExChar_t* path, bool pFlag) {
   (void) parent;
   (void) parent;
   (void)path;
   (void)path;
@@ -51,18 +48,20 @@ bool ExFatFile::rename(ExFatFile* dirFile, const ExChar_t* newPath) {
   (void)newPath;
   (void)newPath;
   return false;
   return false;
 }
 }
+bool ExFatFile::sync() {
+  return false;
+}
 bool ExFatFile::truncate() {
 bool ExFatFile::truncate() {
   return false;
   return false;
 }
 }
-
 size_t ExFatFile::write(const void* buf, size_t nbyte) {
 size_t ExFatFile::write(const void* buf, size_t nbyte) {
   (void)buf;
   (void)buf;
   (void)nbyte;
   (void)nbyte;
   return false;
   return false;
 }
 }
-//=============================================================================
+//==============================================================================
 #else  // READ_ONLY
 #else  // READ_ONLY
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 static uint16_t exFatDirChecksum(const uint8_t* data, uint16_t checksum) {
 static uint16_t exFatDirChecksum(const uint8_t* data, uint16_t checksum) {
   bool skip = data[0] == EXFAT_TYPE_FILE;
   bool skip = data[0] == EXFAT_TYPE_FILE;
   for (size_t i = 0; i < 32; i += i == 1 && skip ? 3 : 1) {
   for (size_t i = 0; i < 32; i += i == 1 && skip ? 3 : 1) {
@@ -70,7 +69,7 @@ static uint16_t exFatDirChecksum(const uint8_t* data, uint16_t checksum) {
   }
   }
   return checksum;
   return checksum;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::addCluster() {
 bool ExFatFile::addCluster() {
   uint32_t find = m_vol->bitmapFind(m_curCluster ?  m_curCluster + 1 : 0, 1);
   uint32_t find = m_vol->bitmapFind(m_curCluster ?  m_curCluster + 1 : 0, 1);
   if (find < 2) {
   if (find < 2) {
@@ -119,7 +118,7 @@ bool ExFatFile::addCluster() {
  fail:
  fail:
   return false;
   return false;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::addDirCluster() {
 bool ExFatFile::addDirCluster() {
   uint32_t sector;
   uint32_t sector;
   uint32_t dl = isRoot() ? m_vol->rootLength() : m_dataLength;
   uint32_t dl = isRoot() ? m_vol->rootLength() : m_dataLength;
@@ -195,7 +194,7 @@ bool ExFatFile::mkdir(ExFatFile* parent, const ExChar_t* path, bool pFlag) {
   }
   }
   return mkdir(parent, &fname);
   return mkdir(parent, &fname);
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -225,7 +224,7 @@ bool ExFatFile::mkdir(ExFatFile* parent, ExName_t* fname) {
   m_flags = FILE_FLAG_READ | FILE_FLAG_CONTIGUOUS | FILE_FLAG_DIR_DIRTY;
   m_flags = FILE_FLAG_READ | FILE_FLAG_CONTIGUOUS | FILE_FLAG_DIR_DIRTY;
   return sync();
   return sync();
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -342,7 +341,7 @@ bool ExFatFile::rename(ExFatFile* dirFile, const ExChar_t* newPath) {
   oldFile.m_attributes = FILE_ATTR_FILE;
   oldFile.m_attributes = FILE_ATTR_FILE;
   return oldFile.remove();
   return oldFile.remove();
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -375,10 +374,10 @@ bool ExFatFile::rmdir() {
   m_flags |= FILE_FLAG_WRITE;
   m_flags |= FILE_FLAG_WRITE;
   return remove();
   return remove();
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::sync() {
 bool ExFatFile::sync() {
   if (!isOpen()) {
   if (!isOpen()) {
     return true;
     return true;
@@ -420,7 +419,6 @@ bool ExFatFile::syncDir() {
         setCount = df->setCount;
         setCount = df->setCount;
         setLe16(df->attributes, m_attributes & FILE_ATTR_COPY);
         setLe16(df->attributes, m_attributes & FILE_ATTR_COPY);
         if (FsDateTime::callback) {
         if (FsDateTime::callback) {
-          m_vol->dataCacheDirty();
           uint16_t date, time;
           uint16_t date, time;
           uint8_t ms10;
           uint8_t ms10;
           FsDateTime::callback(&date, &time, &ms10);
           FsDateTime::callback(&date, &time, &ms10);
@@ -430,6 +428,7 @@ bool ExFatFile::syncDir() {
           setLe16(df->accessTime, time);
           setLe16(df->accessTime, time);
           setLe16(df->accessDate, date);
           setLe16(df->accessDate, date);
         }
         }
+        m_vol->dataCacheDirty();
         break;
         break;
 
 
       case EXFAT_TYPE_STREAM:
       case EXFAT_TYPE_STREAM:
@@ -460,7 +459,7 @@ bool ExFatFile::syncDir() {
       goto fail;
       goto fail;
     }
     }
   }
   }
-  df = reinterpret_cast<DirFile_t *>
+  df = reinterpret_cast<DirFile_t*>
        (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE));
        (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE));
   if (!df) {
   if (!df) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
@@ -559,7 +558,7 @@ bool ExFatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
       goto fail;
       goto fail;
     }
     }
   }
   }
-  df = reinterpret_cast<DirFile_t *>
+  df = reinterpret_cast<DirFile_t*>
        (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE));
        (m_vol->dirCache(&m_dirPos, FsCache::CACHE_FOR_WRITE));
   if (!df) {
   if (!df) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
@@ -778,10 +777,9 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) {
       m_validLength = m_curPosition;
       m_validLength = m_curPosition;
     }
     }
   }
   }
-
   if (m_curPosition > m_dataLength) {
   if (m_curPosition > m_dataLength) {
     m_dataLength = m_curPosition;
     m_dataLength = m_curPosition;
-    // update fileSize and insure sync will update dir entr
+    // update fileSize and insure sync will update dir entry
     m_flags |= FILE_FLAG_DIR_DIRTY;
     m_flags |= FILE_FLAG_DIR_DIRTY;
   } else if (FsDateTime::callback) {
   } else if (FsDateTime::callback) {
     // insure sync will update modified date and time
     // insure sync will update modified date and time
@@ -789,7 +787,7 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) {
   }
   }
   return nbyte;
   return nbyte;
 
 
-fail:
+ fail:
   // return for write error
   // return for write error
   m_error |= WRITE_ERROR;
   m_error |= WRITE_ERROR;
   return -1;
   return -1;

+ 7 - 7
src/ExFatLib/ExFatFormatter.cpp

@@ -25,7 +25,7 @@
 #define DBG_FILE "ExFatFormatter.cpp"
 #define DBG_FILE "ExFatFormatter.cpp"
 #include "../common/DebugMacros.h"
 #include "../common/DebugMacros.h"
 #include "ExFatFormatter.h"
 #include "ExFatFormatter.h"
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 // Formatter assumes 512 byte sectors.
 // Formatter assumes 512 byte sectors.
 const uint32_t BOOT_BACKUP_OFFSET = 12;
 const uint32_t BOOT_BACKUP_OFFSET = 12;
 const uint16_t BYTES_PER_SECTOR = 512;
 const uint16_t BYTES_PER_SECTOR = 512;
@@ -35,7 +35,7 @@ const uint16_t MINIMUM_UPCASE_SKIP = 512;
 const uint32_t BITMAP_CLUSTER = 2;
 const uint32_t BITMAP_CLUSTER = 2;
 const uint32_t UPCASE_CLUSTER = 3;
 const uint32_t UPCASE_CLUSTER = 3;
 const uint32_t ROOT_CLUSTER = 4;
 const uint32_t ROOT_CLUSTER = 4;
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 #define PRINT_FORMAT_PROGRESS 1
 #define PRINT_FORMAT_PROGRESS 1
 #if !PRINT_FORMAT_PROGRESS
 #if !PRINT_FORMAT_PROGRESS
 #define writeMsg(pr, str)
 #define writeMsg(pr, str)
@@ -44,7 +44,7 @@ const uint32_t ROOT_CLUSTER = 4;
 #else  // PRINT_FORMAT_PROGRESS
 #else  // PRINT_FORMAT_PROGRESS
 #define writeMsg(pr, str) if (pr) pr->write(str)
 #define writeMsg(pr, str) if (pr) pr->write(str)
 #endif  // PRINT_FORMAT_PROGRESS
 #endif  // PRINT_FORMAT_PROGRESS
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) {
 bool ExFatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) {
 #if !PRINT_FORMAT_PROGRESS
 #if !PRINT_FORMAT_PROGRESS
 (void)pr;
 (void)pr;
@@ -287,7 +287,7 @@ bool ExFatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) {
   writeMsg(pr, "Format failed\r\n");
   writeMsg(pr, "Format failed\r\n");
   return false;
   return false;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFormatter::syncUpcase() {
 bool ExFatFormatter::syncUpcase() {
   uint16_t index = m_upcaseSize & SECTOR_MASK;
   uint16_t index = m_upcaseSize & SECTOR_MASK;
   if (!index) {
   if (!index) {
@@ -298,7 +298,7 @@ bool ExFatFormatter::syncUpcase() {
   }
   }
   return m_dev->writeSector(m_upcaseSector, m_secBuf);
   return m_dev->writeSector(m_upcaseSector, m_secBuf);
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFormatter::writeUpcaseByte(uint8_t b) {
 bool ExFatFormatter::writeUpcaseByte(uint8_t b) {
   uint16_t index = m_upcaseSize & SECTOR_MASK;
   uint16_t index = m_upcaseSize & SECTOR_MASK;
   m_secBuf[index] = b;
   m_secBuf[index] = b;
@@ -309,11 +309,11 @@ bool ExFatFormatter::writeUpcaseByte(uint8_t b) {
   }
   }
   return true;
   return true;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFormatter::writeUpcaseUnicode(uint16_t unicode) {
 bool ExFatFormatter::writeUpcaseUnicode(uint16_t unicode) {
   return writeUpcaseByte(unicode) && writeUpcaseByte(unicode >> 8);
   return writeUpcaseByte(unicode) && writeUpcaseByte(unicode >> 8);
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFormatter::writeUpcase(uint32_t sector) {
 bool ExFatFormatter::writeUpcase(uint32_t sector) {
   uint32_t n;
   uint32_t n;
   uint32_t ns;
   uint32_t ns;

+ 76 - 76
src/ExFatLib/ExFatPartition.cpp

@@ -26,12 +26,7 @@
 #include "../common/DebugMacros.h"
 #include "../common/DebugMacros.h"
 #include "ExFatVolume.h"
 #include "ExFatVolume.h"
 #include "../common/FsStructs.h"
 #include "../common/FsStructs.h"
-//-----------------------------------------------------------------------------
-void FsCache::invalidate() {
-  m_status = 0;
-  m_sector = 0XFFFFFFFF;
-}
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint8_t* FsCache::get(uint32_t sector, uint8_t option) {
 uint8_t* FsCache::get(uint32_t sector, uint8_t option) {
   if (!m_blockDev) {
   if (!m_blockDev) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
@@ -54,10 +49,15 @@ uint8_t* FsCache::get(uint32_t sector, uint8_t option) {
   m_status |= option & CACHE_STATUS_MASK;
   m_status |= option & CACHE_STATUS_MASK;
   return m_cacheBuffer;
   return m_cacheBuffer;
 
 
-fail:
+ fail:
   return nullptr;
   return nullptr;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+void FsCache::invalidate() {
+  m_status = 0;
+  m_sector = 0XFFFFFFFF;
+}
+//------------------------------------------------------------------------------
 bool FsCache::sync() {
 bool FsCache::sync() {
   if (m_status & CACHE_STATUS_DIRTY) {
   if (m_status & CACHE_STATUS_DIRTY) {
     if (!m_blockDev->writeSector(m_sector, m_cacheBuffer)) {
     if (!m_blockDev->writeSector(m_sector, m_cacheBuffer)) {
@@ -68,68 +68,10 @@ bool FsCache::sync() {
   }
   }
   return true;
   return true;
 
 
-fail:
-  return false;
-}
-//=============================================================================
-bool ExFatPartition::init(BlockDevice* dev, uint8_t part) {
-  uint32_t volStart = 0;
-  uint8_t *cache;
-  pbs_t* pbs;
-  BpbExFat_t* bpb;
-  MbrSector_t* mbr;
-  MbrPart_t* mp;
-
-  m_fatType = 0;
-  m_blockDev = dev;
-  cacheInit(m_blockDev);
-  cache = dataCacheGet(0, FsCache::CACHE_FOR_READ);
-  if (part > 4 || !cache) {
-    DBG_FAIL_MACRO;
-    goto fail;
-  }
-  if (part >= 1) {
-    mbr = reinterpret_cast<MbrSector_t*>(cache);
-    mp = &mbr->part[part - 1];
-    if ((mp->boot != 0 && mp->boot != 0X80) || mp->type == 0) {
-      DBG_FAIL_MACRO;
-      goto fail;
-    }
-    volStart = getLe32(mp->relativeSectors);
-    cache = dataCacheGet(volStart, FsCache::CACHE_FOR_READ);
-    if (!cache) {
-      DBG_FAIL_MACRO;
-      goto fail;
-    }
-  }
-  pbs = reinterpret_cast<pbs_t*>(cache);
-  if (strncmp(pbs->oemName, "EXFAT", 5)) {
-    DBG_FAIL_MACRO;
-    goto fail;
-  }
-  bpb = reinterpret_cast<BpbExFat_t*>(pbs->bpb);
-  if (bpb->bytesPerSectorShift != m_bytesPerSectorShift) {
-    DBG_FAIL_MACRO;
-    goto fail;
-  }
-  m_fatStartSector = volStart + getLe32(bpb->fatOffset);
-  m_fatLength = getLe32(bpb->fatLength);
-  m_clusterHeapStartSector = volStart + getLe32(bpb->clusterHeapOffset);
-  m_clusterCount = getLe32(bpb->clusterCount);
-  m_rootDirectoryCluster = getLe32(bpb->rootDirectoryCluster);
-  m_sectorsPerClusterShift = bpb->sectorsPerClusterShift;
-  m_bytesPerCluster = 1UL << (m_bytesPerSectorShift + m_sectorsPerClusterShift);
-  m_clusterMask = m_bytesPerCluster - 1;
-  // Set m_bitmapStart to first free cluster.
-  m_bitmapStart = 0;
-  bitmapFind(0, 1);
-  m_fatType = FAT_TYPE_EXFAT;
-  return true;
-
  fail:
  fail:
   return false;
   return false;
 }
 }
-//-----------------------------------------------------------------------------
+//==============================================================================
 // return 0 if error, 1 if no space, else start cluster.
 // return 0 if error, 1 if no space, else start cluster.
 uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
 uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
   uint32_t start = cluster ? cluster - 2 : m_bitmapStart;
   uint32_t start = cluster ? cluster - 2 : m_bitmapStart;
@@ -178,7 +120,7 @@ uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
   }
   }
   return 0;
   return 0;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatPartition::bitmapModify(uint32_t cluster,
 bool ExFatPartition::bitmapModify(uint32_t cluster,
                                   uint32_t count, bool value) {
                                   uint32_t count, bool value) {
   uint32_t sector;
   uint32_t sector;
@@ -229,7 +171,7 @@ bool ExFatPartition::bitmapModify(uint32_t cluster,
  fail:
  fail:
   return false;
   return false;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint32_t ExFatPartition::chainSize(uint32_t cluster) {
 uint32_t ExFatPartition::chainSize(uint32_t cluster) {
   uint32_t n = 0;
   uint32_t n = 0;
   int8_t status;
   int8_t status;
@@ -240,14 +182,14 @@ uint32_t ExFatPartition::chainSize(uint32_t cluster) {
   } while (status);
   } while (status);
   return n;
   return n;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint8_t* ExFatPartition::dirCache(DirPos_t* pos, uint8_t options) {
 uint8_t* ExFatPartition::dirCache(DirPos_t* pos, uint8_t options) {
   uint32_t sector = clusterStartSector(pos->cluster);
   uint32_t sector = clusterStartSector(pos->cluster);
   sector += (m_clusterMask & pos->position) >> m_bytesPerSectorShift;
   sector += (m_clusterMask & pos->position) >> m_bytesPerSectorShift;
   uint8_t* cache = dataCacheGet(sector, options);
   uint8_t* cache = dataCacheGet(sector, options);
   return cache ? cache + (pos->position & m_sectorMask) : nullptr;
   return cache ? cache + (pos->position & m_sectorMask) : nullptr;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 // return -1 error, 0 EOC, 1 OK
 // return -1 error, 0 EOC, 1 OK
 int8_t ExFatPartition::dirSeek(DirPos_t* pos, uint32_t offset) {
 int8_t ExFatPartition::dirSeek(DirPos_t* pos, uint32_t offset) {
   int8_t status;
   int8_t status;
@@ -266,10 +208,10 @@ int8_t ExFatPartition::dirSeek(DirPos_t* pos, uint32_t offset) {
   }
   }
   return 1;
   return 1;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint8_t ExFatPartition::fatGet(uint32_t cluster, uint32_t* value) {
 uint8_t ExFatPartition::fatGet(uint32_t cluster, uint32_t* value) {
   uint8_t* cache;
   uint8_t* cache;
-uint32_t next;
+  uint32_t next;
   uint32_t sector;
   uint32_t sector;
 
 
   if (cluster > (m_clusterCount + 1)) {
   if (cluster > (m_clusterCount + 1)) {
@@ -290,7 +232,7 @@ uint32_t next;
   *value = next;
   *value = next;
   return 1;
   return 1;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatPartition::fatPut(uint32_t cluster, uint32_t value) {
 bool ExFatPartition::fatPut(uint32_t cluster, uint32_t value) {
   uint32_t sector;
   uint32_t sector;
   uint8_t* cache;
   uint8_t* cache;
@@ -310,7 +252,7 @@ bool ExFatPartition::fatPut(uint32_t cluster, uint32_t value) {
  fail:
  fail:
   return false;
   return false;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatPartition::freeChain(uint32_t cluster) {
 bool ExFatPartition::freeChain(uint32_t cluster) {
   uint32_t next;
   uint32_t next;
   uint32_t start = cluster;
   uint32_t start = cluster;
@@ -340,7 +282,7 @@ bool ExFatPartition::freeChain(uint32_t cluster) {
  fail:
  fail:
   return false;
   return false;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint32_t ExFatPartition::freeClusterCount() {
 uint32_t ExFatPartition::freeClusterCount() {
   uint32_t nc = 0;
   uint32_t nc = 0;
   uint32_t sector = m_clusterHeapStartSector;
   uint32_t sector = m_clusterHeapStartSector;
@@ -369,7 +311,65 @@ uint32_t ExFatPartition::freeClusterCount() {
     }
     }
   }
   }
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+bool ExFatPartition::init(BlockDevice* dev, uint8_t part) {
+  uint32_t volStart = 0;
+  uint8_t* cache;
+  pbs_t* pbs;
+  BpbExFat_t* bpb;
+  MbrSector_t* mbr;
+  MbrPart_t* mp;
+
+  m_fatType = 0;
+  m_blockDev = dev;
+  cacheInit(m_blockDev);
+  cache = dataCacheGet(0, FsCache::CACHE_FOR_READ);
+  if (part > 4 || !cache) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  if (part >= 1) {
+    mbr = reinterpret_cast<MbrSector_t*>(cache);
+    mp = &mbr->part[part - 1];
+    if ((mp->boot != 0 && mp->boot != 0X80) || mp->type == 0) {
+      DBG_FAIL_MACRO;
+      goto fail;
+    }
+    volStart = getLe32(mp->relativeSectors);
+    cache = dataCacheGet(volStart, FsCache::CACHE_FOR_READ);
+    if (!cache) {
+      DBG_FAIL_MACRO;
+      goto fail;
+    }
+  }
+  pbs = reinterpret_cast<pbs_t*>(cache);
+  if (strncmp(pbs->oemName, "EXFAT", 5)) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  bpb = reinterpret_cast<BpbExFat_t*>(pbs->bpb);
+  if (bpb->bytesPerSectorShift != m_bytesPerSectorShift) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  m_fatStartSector = volStart + getLe32(bpb->fatOffset);
+  m_fatLength = getLe32(bpb->fatLength);
+  m_clusterHeapStartSector = volStart + getLe32(bpb->clusterHeapOffset);
+  m_clusterCount = getLe32(bpb->clusterCount);
+  m_rootDirectoryCluster = getLe32(bpb->rootDirectoryCluster);
+  m_sectorsPerClusterShift = bpb->sectorsPerClusterShift;
+  m_bytesPerCluster = 1UL << (m_bytesPerSectorShift + m_sectorsPerClusterShift);
+  m_clusterMask = m_bytesPerCluster - 1;
+  // Set m_bitmapStart to first free cluster.
+  m_bitmapStart = 0;
+  bitmapFind(0, 1);
+  m_fatType = FAT_TYPE_EXFAT;
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
 uint32_t ExFatPartition::rootLength() {
 uint32_t ExFatPartition::rootLength() {
   uint32_t nc = chainSize(m_rootDirectoryCluster);
   uint32_t nc = chainSize(m_rootDirectoryCluster);
   return nc << bytesPerClusterShift();
   return nc << bytesPerClusterShift();

+ 12 - 12
src/ExFatLib/ExFatPartition.h

@@ -110,7 +110,7 @@ class FsCache {
   uint32_t m_sector;
   uint32_t m_sector;
   uint8_t m_cacheBuffer[512];
   uint8_t m_cacheBuffer[512];
 };
 };
-//=============================================================================
+//==============================================================================
 /**
 /**
  * \class ExFatPartition
  * \class ExFatPartition
  * \brief Access exFat partitions on raw file devices.
  * \brief Access exFat partitions on raw file devices.
@@ -119,15 +119,15 @@ class ExFatPartition {
  public:
  public:
   ExFatPartition() : m_fatType(0) {}
   ExFatPartition() : m_fatType(0) {}
   /** \return the number of bytes in a cluster. */
   /** \return the number of bytes in a cluster. */
-  uint32_t bytesPerCluster() {return m_bytesPerCluster;}
+  uint32_t bytesPerCluster() const {return m_bytesPerCluster;}
   /** \return the power of two for bytesPerCluster. */
   /** \return the power of two for bytesPerCluster. */
-  uint8_t bytesPerClusterShift() {
+  uint8_t bytesPerClusterShift() const {
     return m_bytesPerSectorShift + m_sectorsPerClusterShift;
     return m_bytesPerSectorShift + m_sectorsPerClusterShift;
   }
   }
   /** \return the number of bytes in a sector. */
   /** \return the number of bytes in a sector. */
-  uint16_t bytesPerSector() {return m_bytesPerSector;}
+  uint16_t bytesPerSector() const {return m_bytesPerSector;}
   /** \return the power of two for bytesPerSector. */
   /** \return the power of two for bytesPerSector. */
-  uint8_t bytesPerSectorShift() {return m_bytesPerSectorShift;}
+  uint8_t bytesPerSectorShift() const {return m_bytesPerSectorShift;}
 
 
   /** Clear the cache and returns a pointer to the cache.  Not for normal apps.
   /** Clear the cache and returns a pointer to the cache.  Not for normal apps.
    * \return A pointer to the cache buffer or zero if an error occurs.
    * \return A pointer to the cache buffer or zero if an error occurs.
@@ -136,13 +136,13 @@ class ExFatPartition {
     return m_dataCache.clear();
     return m_dataCache.clear();
   }
   }
   /** \return the cluster count for the partition. */
   /** \return the cluster count for the partition. */
-  uint32_t clusterCount() {return m_clusterCount;}
+  uint32_t clusterCount() const {return m_clusterCount;}
   /** \return the cluster heap start sector. */
   /** \return the cluster heap start sector. */
-  uint32_t clusterHeapStartSector() {return m_clusterHeapStartSector;}
+  uint32_t clusterHeapStartSector() const {return m_clusterHeapStartSector;}
   /** \return the FAT length in sectors */
   /** \return the FAT length in sectors */
-  uint32_t fatLength() {return m_fatLength;}
+  uint32_t fatLength() const {return m_fatLength;}
   /** \return the FAT start sector number. */
   /** \return the FAT start sector number. */
-  uint32_t fatStartSector() {return m_fatStartSector;}
+  uint32_t fatStartSector() const {return m_fatStartSector;}
   /** \return Type FAT_TYPE_EXFAT for exFAT partition or zero for error. */
   /** \return Type FAT_TYPE_EXFAT for exFAT partition or zero for error. */
   uint8_t fatType() const {return m_fatType;}
   uint8_t fatType() const {return m_fatType;}
   /** \return the free cluster count. */
   /** \return the free cluster count. */
@@ -158,17 +158,17 @@ class ExFatPartition {
    */
    */
   bool init(BlockDevice* dev, uint8_t part);
   bool init(BlockDevice* dev, uint8_t part);
   /** \return the root directory start cluster number. */
   /** \return the root directory start cluster number. */
-  uint32_t rootDirectoryCluster() {return m_rootDirectoryCluster;}
+  uint32_t rootDirectoryCluster() const {return m_rootDirectoryCluster;}
   /** \return the root directory length. */
   /** \return the root directory length. */
   uint32_t rootLength();
   uint32_t rootLength();
   /** \return the number of sectors in a cluster. */
   /** \return the number of sectors in a cluster. */
-  uint32_t sectorsPerCluster() {return 1UL << m_sectorsPerClusterShift;}
+  uint32_t sectorsPerCluster() const {return 1UL << m_sectorsPerClusterShift;}
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
   // Use sectorsPerCluster(). blocksPerCluster() will be removed in the future.
   // Use sectorsPerCluster(). blocksPerCluster() will be removed in the future.
   uint32_t blocksPerCluster() __attribute__ ((deprecated)) {return sectorsPerCluster();} //NOLINT
   uint32_t blocksPerCluster() __attribute__ ((deprecated)) {return sectorsPerCluster();} //NOLINT
 #endif  // DOXYGEN_SHOULD_SKIP_THIS
 #endif  // DOXYGEN_SHOULD_SKIP_THIS
   /** \return the power of two for sectors per cluster. */
   /** \return the power of two for sectors per cluster. */
-  uint8_t  sectorsPerClusterShift() {return m_sectorsPerClusterShift;}
+  uint8_t  sectorsPerClusterShift() const {return m_sectorsPerClusterShift;}
   //----------------------------------------------------------------------------
   //----------------------------------------------------------------------------
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
   void checkUpcase(print_t* pr);
   void checkUpcase(print_t* pr);

+ 2 - 2
src/ExFatLib/ExFatVolume.cpp

@@ -24,7 +24,7 @@
  */
  */
 #include "ExFatVolume.h"
 #include "ExFatVolume.h"
 ExFatVolume* ExFatVolume::m_cwv = nullptr;
 ExFatVolume* ExFatVolume::m_cwv = nullptr;
-//----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 bool ExFatVolume::chdir(const ExChar_t* path) {
 bool ExFatVolume::chdir(const ExChar_t* path) {
   ExFatFile dir;
   ExFatFile dir;
   if (!dir.open(vwd(), path, O_RDONLY)) {
   if (!dir.open(vwd(), path, O_RDONLY)) {
@@ -36,6 +36,6 @@ bool ExFatVolume::chdir(const ExChar_t* path) {
   m_vwd = dir;
   m_vwd = dir;
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }

+ 1 - 1
src/ExFatLib/ExFatVolume.h

@@ -26,7 +26,7 @@
 #define ExFatVolume_h
 #define ExFatVolume_h
 #include "ExFatPartition.h"
 #include "ExFatPartition.h"
 #include "ExFatFile.h"
 #include "ExFatFile.h"
-//=============================================================================
+//==============================================================================
 /**
 /**
  * \class ExFatVolume
  * \class ExFatVolume
  * \brief exFAT volume.
  * \brief exFAT volume.

+ 48 - 49
src/ExFatLib/upcase.cpp

@@ -47,7 +47,7 @@ struct pair16 {
   uint16_t val;
   uint16_t val;
 };
 };
 typedef struct pair16 pair16_t;
 typedef struct pair16 pair16_t;
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 static const map16_t mapTable[] TABLE_MEM = {
 static const map16_t mapTable[] TABLE_MEM = {
   {0X0061, -32,  26},
   {0X0061, -32,  26},
   {0X00E0, -32,  23},
   {0X00E0, -32,  23},
@@ -104,7 +104,7 @@ static const map16_t mapTable[] TABLE_MEM = {
   {0XFF41, -32,  26},
   {0XFF41, -32,  26},
 };
 };
 const size_t MAP_DIM = sizeof(mapTable)/sizeof(map16_t);
 const size_t MAP_DIM = sizeof(mapTable)/sizeof(map16_t);
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 static const pair16_t lookupTable[] TABLE_MEM = {
 static const pair16_t lookupTable[] TABLE_MEM = {
   {0X00FF, 0X0178},
   {0X00FF, 0X0178},
   {0X0180, 0X0243},
   {0X0180, 0X0243},
@@ -183,17 +183,7 @@ static const pair16_t lookupTable[] TABLE_MEM = {
   {0X2C76, 0X2C75},
   {0X2C76, 0X2C75},
 };
 };
 const size_t LOOKUP_DIM = sizeof(lookupTable)/sizeof(pair16_t);
 const size_t LOOKUP_DIM = sizeof(lookupTable)/sizeof(pair16_t);
-
-//-----------------------------------------------------------------------------
-uint16_t exFatHashName(const ExChar16_t* name, size_t n, uint16_t hash) {
-  for (size_t i = 0; i < n; i++) {
-    uint16_t c = toUpcase(name[i]);
-    hash = ((hash << 15) | (hash >> 1)) + (c & 0XFF);
-    hash = ((hash << 15) | (hash >> 1)) + (c >> 8);
-  }
-  return hash;
-}
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 static size_t searchPair16(const pair16_t* table, size_t size, uint16_t key) {
 static size_t searchPair16(const pair16_t* table, size_t size, uint16_t key) {
   size_t left = 0;
   size_t left = 0;
   size_t right = size;
   size_t right = size;
@@ -208,29 +198,11 @@ static size_t searchPair16(const pair16_t* table, size_t size, uint16_t key) {
   }
   }
   return left;
   return left;
 }
 }
-//-----------------------------------------------------------------------------
-uint16_t toUpcase(uint16_t chr) {
-  uint16_t i, first;
-  // Optimize for simple ASCII.
-  if (chr < 127) {
-    return chr - ('a' <= chr && chr <= 'z' ? 'a' - 'A' : 0);
-  }
-  i = searchPair16(reinterpret_cast<const pair16_t*>(mapTable), MAP_DIM, chr);
-  first = readTable16(mapTable[i].base);
-  if (first <= chr && (chr - first)  < readTable8(mapTable[i].count)) {
-    int8_t off = readTable8(mapTable[i].off);
-    if (off == 1) {
-      return chr - ((chr - first) & 1);
-    }
-    return chr + (off ? off : -0x1C60);
-  }
-  i = searchPair16(lookupTable, LOOKUP_DIM, chr);
-  if (readTable16(lookupTable[i].key) == chr) {
-    return readTable16(lookupTable[i].val);
-  }
-  return chr;
+//------------------------------------------------------------------------------
+static char toUpper(char c) {
+  return c - ('a' <= c && c <= 'z' ? 'a' - 'A' : 0);
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool exFatCmpName(const DirName_t* unicode,
 bool exFatCmpName(const DirName_t* unicode,
                   const ExChar16_t* name, size_t offset, size_t n) {
                   const ExChar16_t* name, size_t offset, size_t n) {
   uint16_t u;
   uint16_t u;
@@ -242,11 +214,28 @@ bool exFatCmpName(const DirName_t* unicode,
   }
   }
   return true;
   return true;
 }
 }
-//-----------------------------------------------------------------------------
-static char toUpper(char c) {
-  return c - ('a' <= c && c <= 'z' ? 'a' - 'A' : 0);
+//------------------------------------------------------------------------------
+bool exFatCmpName(const DirName_t* unicode,
+                  const char* name, size_t offset, size_t n) {
+  uint16_t u;
+  for (size_t i = 0; i < n; i++) {
+    u = getLe16(unicode->unicode + 2*i);
+    if (u >= 0x7F  || toUpper(name[i + offset]) != toUpper(u)) {
+      return false;
+    }
+  }
+  return true;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+uint16_t exFatHashName(const ExChar16_t* name, size_t n, uint16_t hash) {
+  for (size_t i = 0; i < n; i++) {
+    uint16_t c = toUpcase(name[i]);
+    hash = ((hash << 15) | (hash >> 1)) + (c & 0XFF);
+    hash = ((hash << 15) | (hash >> 1)) + (c >> 8);
+  }
+  return hash;
+}
+//------------------------------------------------------------------------------
 uint16_t exFatHashName(const char* name, size_t n, uint16_t hash) {
 uint16_t exFatHashName(const char* name, size_t n, uint16_t hash) {
   for (size_t i = 0; i < n; i++) {
   for (size_t i = 0; i < n; i++) {
     uint8_t c = name[i];
     uint8_t c = name[i];
@@ -258,19 +247,29 @@ uint16_t exFatHashName(const char* name, size_t n, uint16_t hash) {
   }
   }
   return hash;
   return hash;
 }
 }
-//-----------------------------------------------------------------------------
-bool exFatCmpName(const DirName_t* unicode,
-                  const char* name, size_t offset, size_t n) {
-  uint16_t u;
-  for (size_t i = 0; i < n; i++) {
-    u = getLe16(unicode->unicode + 2*i);
-    if (u >= 0x7F  || toUpper(name[i + offset]) != toUpper(u)) {
-      return false;
+//------------------------------------------------------------------------------
+uint16_t toUpcase(uint16_t chr) {
+  uint16_t i, first;
+  // Optimize for simple ASCII.
+  if (chr < 127) {
+    return chr - ('a' <= chr && chr <= 'z' ? 'a' - 'A' : 0);
+  }
+  i = searchPair16(reinterpret_cast<const pair16_t*>(mapTable), MAP_DIM, chr);
+  first = readTable16(mapTable[i].base);
+  if (first <= chr && (chr - first)  < readTable8(mapTable[i].count)) {
+    int8_t off = readTable8(mapTable[i].off);
+    if (off == 1) {
+      return chr - ((chr - first) & 1);
     }
     }
+    return chr + (off ? off : -0x1C60);
   }
   }
-  return true;
+  i = searchPair16(lookupTable, LOOKUP_DIM, chr);
+  if (readTable16(lookupTable[i].key) == chr) {
+    return readTable16(lookupTable[i].val);
+  }
+  return chr;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint32_t upcaseChecksum(uint16_t uc, uint32_t sum) {
 uint32_t upcaseChecksum(uint16_t uc, uint32_t sum) {
   sum = (sum << 31) + (sum >> 1) + (uc & 0XFF);
   sum = (sum << 31) + (sum >> 1) + (uc & 0XFF);
   sum = (sum << 31) + (sum >> 1) + (uc >> 8);
   sum = (sum << 31) + (sum >> 1) + (uc >> 8);

+ 0 - 1
src/FatLib/FatDbg.cpp

@@ -24,7 +24,6 @@
  */
  */
 #include "FatVolume.h"
 #include "FatVolume.h"
 #include "FatFile.h"
 #include "FatFile.h"
-#include "../common/FsDateTime.h"
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 static void printHex(print_t* pr, uint8_t h) {
 static void printHex(print_t* pr, uint8_t h) {

+ 101 - 53
src/FatLib/FatFile.cpp

@@ -88,7 +88,7 @@ bool FatFile::addDirCluster() {
   m_curPosition += m_vol->bytesPerCluster();
   m_curPosition += m_vol->bytesPerCluster();
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -103,7 +103,7 @@ DirFat_t* FatFile::cacheDirEntry(uint8_t action) {
   }
   }
   return pc->dir + (m_dirIndex & 0XF);
   return pc->dir + (m_dirIndex & 0XF);
 
 
-fail:
+ fail:
   return nullptr;
   return nullptr;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -116,7 +116,7 @@ bool FatFile::close() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 bool FatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
 bool FatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
   // error if no clusters
   // error if no clusters
-  if (m_firstCluster == 0) {
+  if (!isFile() || m_firstCluster == 0) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
     goto fail;
     goto fail;
   }
   }
@@ -148,7 +148,7 @@ bool FatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
     }
     }
   }
   }
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -161,7 +161,7 @@ bool FatFile::createContiguous(const char* path, uint32_t size) {
     return true;
     return true;
   }
   }
   close();
   close();
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -175,33 +175,6 @@ bool FatFile::createContiguous(FatFile* dirFile,
     return true;
     return true;
   }
   }
   close();
   close();
-fail:
-  return false;
-}
-//------------------------------------------------------------------------------
-bool FatFile::preAllocate(uint32_t length) {
-  uint32_t need;
-  if (!length || !isWritable() || m_firstCluster) {
-    DBG_FAIL_MACRO;
-    goto fail;
-  }
-  need = 1 + ((length - 1) >> m_vol->bytesPerClusterShift());
-  // allocate clusters
-  if (!m_vol->allocContiguous(need, &m_firstCluster)) {
-    DBG_FAIL_MACRO;
-    goto fail;
-  }
-  m_fileSize = length;
-
-#if USE_FAT_FILE_FLAG_CONTIGUOUS
-  // Mark contiguous and insure sync() will update dir entry
-  m_flags |= FILE_FLAG_PREALLOCATE | FILE_FLAG_CONTIGUOUS | FILE_FLAG_DIR_DIRTY;
-#else  // USE_FAT_FILE_FLAG_CONTIGUOUS
-  // insure sync() will update dir entry
-  m_flags |= FILE_FLAG_DIR_DIRTY;
-#endif  // USE_FAT_FILE_FLAG_CONTIGUOUS
-  return sync();
-
  fail:
  fail:
   return false;
   return false;
 }
 }
@@ -223,7 +196,7 @@ bool FatFile::dirEntry(DirFat_t* dst) {
   memcpy(dst, dir, sizeof(DirFat_t));
   memcpy(dst, dir, sizeof(DirFat_t));
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -289,6 +262,47 @@ void FatFile::fsetpos(const fspos_t* pos) {
   m_curCluster = pos->cluster;
   m_curCluster = pos->cluster;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+bool FatFile::getAccessDate(uint16_t* pdate) {
+  DirFat_t dir;
+  if (!dirEntry(&dir)) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  *pdate = getLe16(dir.accessDate);
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+bool FatFile::getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
+  DirFat_t dir;
+  if (!dirEntry(&dir)) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  *pdate = getLe16(dir.createDate);
+  *ptime = getLe16(dir.createTime);
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+bool FatFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
+  DirFat_t dir;
+  if (!dirEntry(&dir)) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  *pdate = getLe16(dir.modifyDate);
+  *ptime = getLe16(dir.modifyTime);
+  return true;
+
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
 bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
 bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
   fname_t fname;
   fname_t fname;
   FatFile tmpDir;
   FatFile tmpDir;
@@ -327,7 +341,7 @@ bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
   }
   }
   return mkdir(parent, &fname);
   return mkdir(parent, &fname);
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -397,10 +411,10 @@ bool FatFile::mkdir(FatFile* parent, fname_t* fname) {
   // write first sector
   // write first sector
   return m_vol->cacheSync();
   return m_vol->cacheSync();
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatFile::open(const char* path, oflag_t oflag) {
 bool FatFile::open(const char* path, oflag_t oflag) {
   return open(FatVolume::cwv(), path, oflag);
   return open(FatVolume::cwv(), path, oflag);
 }
 }
@@ -449,7 +463,7 @@ bool FatFile::open(FatFile* dirFile, const char* path, oflag_t oflag) {
   }
   }
   return open(dirFile, &fname, oflag);
   return open(dirFile, &fname, oflag);
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -574,7 +588,7 @@ bool FatFile::openCachedEntry(FatFile* dirFile, uint16_t dirIndex,
   }
   }
   return true;
   return true;
 
 
-fail:
+ fail:
   m_attributes = FILE_ATTR_CLOSED;
   m_attributes = FILE_ATTR_CLOSED;
   m_flags = 0;
   m_flags = 0;
   return false;
   return false;
@@ -629,7 +643,7 @@ bool FatFile::openNext(FatFile* dirFile, oflag_t oflag) {
     }
     }
   }
   }
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -662,7 +676,34 @@ bool FatFile::openRoot(FatVolume* vol) {
   m_flags = FILE_FLAG_READ;
   m_flags = FILE_FLAG_READ;
   return true;
   return true;
 
 
-fail:
+ fail:
+  return false;
+}
+//------------------------------------------------------------------------------
+bool FatFile::preAllocate(uint32_t length) {
+  uint32_t need;
+  if (!length || !isWritable() || m_firstCluster) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  need = 1 + ((length - 1) >> m_vol->bytesPerClusterShift());
+  // allocate clusters
+  if (!m_vol->allocContiguous(need, &m_firstCluster)) {
+    DBG_FAIL_MACRO;
+    goto fail;
+  }
+  m_fileSize = length;
+
+#if USE_FAT_FILE_FLAG_CONTIGUOUS
+  // Mark contiguous and insure sync() will update dir entry
+  m_flags |= FILE_FLAG_PREALLOCATE | FILE_FLAG_CONTIGUOUS | FILE_FLAG_DIR_DIRTY;
+#else  // USE_FAT_FILE_FLAG_CONTIGUOUS
+  // insure sync() will update dir entry
+  m_flags |= FILE_FLAG_DIR_DIRTY;
+#endif  // USE_FAT_FILE_FLAG_CONTIGUOUS
+  return sync();
+
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -790,7 +831,7 @@ int FatFile::read(void* buf, size_t nbyte) {
   }
   }
   return nbyte - toRead;
   return nbyte - toRead;
 
 
-fail:
+ fail:
   m_error |= READ_ERROR;
   m_error |= READ_ERROR;
   return -1;
   return -1;
 }
 }
@@ -842,7 +883,7 @@ DirFat_t* FatFile::readDirCache(bool skipReadOk) {
   // return pointer to entry
   // return pointer to entry
   return reinterpret_cast<DirFat_t*>(m_vol->cacheAddress()) + i;
   return reinterpret_cast<DirFat_t*>(m_vol->cacheAddress()) + i;
 
 
-fail:
+ fail:
   return nullptr;
   return nullptr;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -854,7 +895,7 @@ bool FatFile::remove(const char* path) {
   }
   }
   return file.remove();
   return file.remove();
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -966,7 +1007,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) {
   }
   }
   return m_vol->cacheSync();
   return m_vol->cacheSync();
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -1008,7 +1049,7 @@ bool FatFile::rmdir() {
   m_flags |= FILE_FLAG_WRITE;
   m_flags |= FILE_FLAG_WRITE;
   return remove();
   return remove();
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -1083,7 +1124,7 @@ bool FatFile::rmRfStar() {
   }
   }
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -1117,9 +1158,16 @@ bool FatFile::seekSet(uint32_t pos) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
     goto fail;
     goto fail;
   }
   }
-  // calculate cluster index for cur and new position
-  nCur = (m_curPosition - 1) >> (m_vol->bytesPerClusterShift());
+  // calculate cluster index for new position
   nNew = (pos - 1) >> (m_vol->bytesPerClusterShift());
   nNew = (pos - 1) >> (m_vol->bytesPerClusterShift());
+#if USE_FAT_FILE_FLAG_CONTIGUOUS
+  if (isContiguous()) {
+    m_curCluster = m_firstCluster + nNew;
+    goto done;
+  }
+#endif  // USE_FAT_FILE_FLAG_CONTIGUOUS
+  // calculate cluster index for current position
+  nCur = (m_curPosition - 1) >> (m_vol->bytesPerClusterShift());
 
 
   if (nNew < nCur || m_curPosition == 0) {
   if (nNew < nCur || m_curPosition == 0) {
     // must follow chain from first cluster
     // must follow chain from first cluster
@@ -1135,12 +1183,12 @@ bool FatFile::seekSet(uint32_t pos) {
     }
     }
   }
   }
 
 
-done:
+ done:
   m_curPosition = pos;
   m_curPosition = pos;
   m_flags &= ~FILE_FLAG_PREALLOCATE;
   m_flags &= ~FILE_FLAG_PREALLOCATE;
   return true;
   return true;
 
 
-fail:
+ fail:
   m_curCluster = tmp;
   m_curCluster = tmp;
   return false;
   return false;
 }
 }
@@ -1182,7 +1230,7 @@ bool FatFile::sync() {
   }
   }
   DBG_FAIL_MACRO;
   DBG_FAIL_MACRO;
 
 
-fail:
+ fail:
   m_error |= WRITE_ERROR;
   m_error |= WRITE_ERROR;
   return false;
   return false;
 }
 }
@@ -1233,7 +1281,7 @@ bool FatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
   }
   }
   return m_vol->cacheSync();
   return m_vol->cacheSync();
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -1436,7 +1484,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
   }
   }
   return nbyte;
   return nbyte;
 
 
-fail:
+ fail:
   // return for write error
   // return for write error
   m_error |= WRITE_ERROR;
   m_error |= WRITE_ERROR;
   return -1;
   return -1;

+ 54 - 9
src/FatLib/FatFile.h

@@ -151,10 +151,49 @@ class FatFile {
   }
   }
   /** \return Directory entry index. */
   /** \return Directory entry index. */
   uint16_t dirIndex() {return m_dirIndex;}
   uint16_t dirIndex() {return m_dirIndex;}
+  /** Get a file's access date.
+   *
+   * \param[out] pdate Packed date for directory entry.
+   *
+   * \return true for success or false for failure.
+   */
+  bool getAccessDate(uint16_t* pdate);
+  /** Get a file's access date and time.
+   *
+   * \param[out] pdate Packed date for directory entry.
+   * \param[out] ptime return zero since FAT has no time.
+   *
+   * This function is for comparability in FsFile.
+   *
+   * \return true for success or false for failure.
+   */
+  bool getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
+    if (!getAccessDate(pdate)) {
+      return false;
+    }
+    *ptime = 0;
+    return true;
+  }
+  /** Get a file's create date and time.
+   *
+   * \param[out] pdate Packed date for directory entry.
+   * \param[out] ptime Packed time for directory entry.
+   *
+   * \return true for success or false for failure.
+   */
+  bool getCreateDateTime(uint16_t* pdate, uint16_t* ptime);
   /** \return All error bits. */
   /** \return All error bits. */
   uint8_t getError() {
   uint8_t getError() {
     return m_error;
     return m_error;
   }
   }
+  /** Get a file's modify date and time.
+   *
+   * \param[out] pdate Packed date for directory entry.
+   * \param[out] ptime Packed time for directory entry.
+   *
+   * \return true for success or false for failure.
+   */
+  bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime);
   /** \return value of writeError */
   /** \return value of writeError */
   bool getWriteError() {
   bool getWriteError() {
     return isOpen() ? m_error & WRITE_ERROR : true;
     return isOpen() ? m_error & WRITE_ERROR : true;
@@ -196,6 +235,8 @@ class FatFile {
    * \param[out] bgnSector the first sector address for the file.
    * \param[out] bgnSector the first sector address for the file.
    * \param[out] endSector the last  sector address for the file.
    * \param[out] endSector the last  sector address for the file.
    *
    *
+   * Set the contiguous flag if the file is contiguous.
+   * The parameters may be nullptr to only set the flag.
    * \return true for success or false for failure.
    * \return true for success or false for failure.
    */
    */
   bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector);
   bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector);
@@ -203,7 +244,7 @@ class FatFile {
   /** Create and open a new contiguous file of a specified size.
   /** Create and open a new contiguous file of a specified size.
    *
    *
    * \param[in] dirFile The directory where the file will be created.
    * \param[in] dirFile The directory where the file will be created.
-   * \param[in] path A path with a validfile name.
+   * \param[in] path A path with a valid file name.
    * \param[in] size The desired file size.
    * \param[in] size The desired file size.
    *
    *
    * \return true for success or false for failure.
    * \return true for success or false for failure.
@@ -212,7 +253,7 @@ class FatFile {
                         const char* path, uint32_t size);
                         const char* path, uint32_t size);
   /** Create and open a new contiguous file of a specified size.
   /** Create and open a new contiguous file of a specified size.
    *
    *
-   * \param[in] path A path with a validfile name.
+   * \param[in] path A path with a valid file name.
    * \param[in] size The desired file size.
    * \param[in] size The desired file size.
    *
    *
    * \return true for success or false for failure.
    * \return true for success or false for failure.
@@ -263,8 +304,8 @@ class FatFile {
    * Get a string from a file.
    * Get a string from a file.
    *
    *
    * fgets() reads bytes from a file into the array pointed to by \a str, until
    * fgets() reads bytes from a file into the array pointed to by \a str, until
-   * \a num - 1 bytes are read, or a delimiter is read and transferred to \a str,
-   * or end-of-file is encountered. The string is then terminated
+   * \a num - 1 bytes are read, or a delimiter is read and transferred to
+   * \a str, or end-of-file is encountered. The string is then terminated
    * with a null byte.
    * with a null byte.
    *
    *
    * fgets() deletes CR, '\\r', from the string.  This insures only a '\\n'
    * fgets() deletes CR, '\\r', from the string.  This insures only a '\\n'
@@ -277,7 +318,8 @@ class FatFile {
    * \param[in] delim Optional set of delimiters. The default is "\n".
    * \param[in] delim Optional set of delimiters. The default is "\n".
    *
    *
    * \return For success fgets() returns the length of the string in \a str.
    * \return For success fgets() returns the length of the string in \a str.
-   * If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
+   * If no data is read, fgets() returns zero for EOF or -1 if an error
+   * occurred.
    */
    */
   int fgets(char* str, int num, char* delim = nullptr);
   int fgets(char* str, int num, char* delim = nullptr);
 
 
@@ -287,7 +329,7 @@ class FatFile {
   }
   }
   /** \return first sector of file or zero for empty file. */
   /** \return first sector of file or zero for empty file. */
   uint32_t firstBlock() const {return firstSector();}
   uint32_t firstBlock() const {return firstSector();}
-  /** \return first sector of file or zero for empty file. */
+  /** \return Address of first sector or zero for empty file. */
   uint32_t firstSector() const;
   uint32_t firstSector() const;
   /**
   /**
    * Get a file's name followed by a zero byte.
    * Get a file's name followed by a zero byte.
@@ -472,10 +514,12 @@ class FatFile {
    * O_CREAT - If the file exists, this flag has no effect except as noted
    * O_CREAT - If the file exists, this flag has no effect except as noted
    * under O_EXCL below. Otherwise, the file shall be created
    * under O_EXCL below. Otherwise, the file shall be created
    *
    *
-   * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
+   * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file
+   * exists.
    *
    *
    * O_TRUNC - If the file exists and is a regular file, and the file is
    * O_TRUNC - If the file exists and is a regular file, and the file is
-   * successfully opened and is not read only, its length shall be truncated to 0.
+   * successfully opened and is not read only, its length shall be truncated
+   * to 0.
    *
    *
    * WARNING: A given file must not be opened by more than one FatFile object
    * WARNING: A given file must not be opened by more than one FatFile object
    * or file corruption may occur.
    * or file corruption may occur.
@@ -873,7 +917,8 @@ class FatFile {
    * \return For success write() returns the number of bytes written, always
    * \return For success write() returns the number of bytes written, always
    * \a count.  If an error occurs, write() returns -1.  Possible errors
    * \a count.  If an error occurs, write() returns -1.  Possible errors
    * include write() is called before a file has been opened, write is called
    * include write() is called before a file has been opened, write is called
-   * for a read-only file, device is full, a corrupt file system or an I/O error.
+   * for a read-only file, device is full, a corrupt file system or an I/O
+   * error.
    *
    *
    */
    */
   size_t write(const void* buf, size_t count);
   size_t write(const void* buf, size_t count);

+ 24 - 19
src/FatLib/FatFileLFN.cpp

@@ -59,7 +59,7 @@ static uint16_t Bernstein(uint16_t hash, const char *str, size_t len) {
  * \param[in] i Index of character.
  * \param[in] i Index of character.
  * \return The 16-bit character.
  * \return The 16-bit character.
  */
  */
-static uint16_t lfnGetChar(DirLfn_t *ldir, uint8_t i) {
+static uint16_t lfnGetChar(DirLfn_t* ldir, uint8_t i) {
   if (i < 5) {
   if (i < 5) {
     return getLe16(ldir->unicode1 + 2*i);
     return getLe16(ldir->unicode1 + 2*i);
   } else if (i < 11) {
   } else if (i < 11) {
@@ -70,7 +70,7 @@ static uint16_t lfnGetChar(DirLfn_t *ldir, uint8_t i) {
   return 0;
   return 0;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-static bool lfnGetName(DirLfn_t *ldir, char* name, size_t n) {
+static bool lfnGetName(DirLfn_t* ldir, char* name, size_t n) {
   uint8_t i;
   uint8_t i;
   size_t k = 13*((ldir->order & 0X1F) - 1);
   size_t k = 13*((ldir->order & 0X1F) - 1);
   for (i = 0; i < 13; i++) {
   for (i = 0; i < 13; i++) {
@@ -104,7 +104,7 @@ inline bool lfnLegalChar(uint8_t c) {
  * \param[in] i Index of character.
  * \param[in] i Index of character.
  * \param[in] c  The 16-bit character.
  * \param[in] c  The 16-bit character.
  */
  */
-static void lfnPutChar(DirLfn_t *ldir, uint8_t i, uint16_t c) {
+static void lfnPutChar(DirLfn_t* ldir, uint8_t i, uint16_t c) {
   if (i < 5) {
   if (i < 5) {
     setLe16(ldir->unicode1 + 2*i, c);
     setLe16(ldir->unicode1 + 2*i, c);
   } else if (i < 11) {
   } else if (i < 11) {
@@ -114,7 +114,7 @@ static void lfnPutChar(DirLfn_t *ldir, uint8_t i, uint16_t c) {
   }
   }
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-static void lfnPutName(DirLfn_t *ldir, const char* name, size_t n) {
+static void lfnPutName(DirLfn_t* ldir, const char* name, size_t n) {
   size_t k = 13*((ldir->order & 0X1F) - 1);
   size_t k = 13*((ldir->order & 0X1F) - 1);
   for (uint8_t i = 0; i < 13; i++, k++) {
   for (uint8_t i = 0; i < 13; i++, k++) {
     uint16_t c = k < n ? name[k] : k == n ? 0 : 0XFFFF;
     uint16_t c = k < n ? name[k] : k == n ? 0 : 0XFFFF;
@@ -165,7 +165,7 @@ bool FatFile::getName(char* name, size_t size) {
   // Fall into fail.
   // Fall into fail.
   DBG_FAIL_MACRO;
   DBG_FAIL_MACRO;
 
 
-fail:
+ fail:
   name[0] = 0;
   name[0] = 0;
   return false;
   return false;
 }
 }
@@ -404,7 +404,7 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) {
     }
     }
   }
   }
 
 
-found:
+ found:
   // Don't open if create only.
   // Don't open if create only.
   if (oflag & O_EXCL) {
   if (oflag & O_EXCL) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
@@ -412,7 +412,7 @@ found:
   }
   }
   goto open;
   goto open;
 
 
-create:
+ create:
   // don't create unless O_CREAT and write mode
   // don't create unless O_CREAT and write mode
   if (!(oflag & O_CREAT) || !isWriteMode(oflag)) {
   if (!(oflag & O_CREAT) || !isWriteMode(oflag)) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
@@ -484,21 +484,26 @@ create:
   // Set base-name and extension lower case bits.
   // Set base-name and extension lower case bits.
   dir->caseFlags =  (FAT_CASE_LC_BASE | FAT_CASE_LC_EXT) & fname->flags;
   dir->caseFlags =  (FAT_CASE_LC_BASE | FAT_CASE_LC_EXT) & fname->flags;
 
 
-  // set timestamps
+  // Set timestamps.
   if (FsDateTime::callback) {
   if (FsDateTime::callback) {
     // call user date/time function
     // call user date/time function
     FsDateTime::callback(&date, &time, &ms10);
     FsDateTime::callback(&date, &time, &ms10);
-    dir->createTimeMs = ms10;
     setLe16(dir->createDate, date);
     setLe16(dir->createDate, date);
     setLe16(dir->createTime, time);
     setLe16(dir->createTime, time);
-    setLe16(dir->accessDate, date);
-    setLe16(dir->modifyDate, date);
-    setLe16(dir->modifyTime, time);;
+    dir->createTimeMs = ms10;
+  } else {
+    setLe16(dir->createDate, FS_DEFAULT_DATE);
+    setLe16(dir->modifyDate, FS_DEFAULT_DATE);
+    setLe16(dir->accessDate, FS_DEFAULT_DATE);
+    if (FS_DEFAULT_TIME) {
+      setLe16(dir->createTime, FS_DEFAULT_TIME);
+      setLe16(dir->modifyTime, FS_DEFAULT_TIME);
+    }
   }
   }
   // Force write of entry to device.
   // Force write of entry to device.
   dirFile->m_vol->cacheDirty();
   dirFile->m_vol->cacheDirty();
 
 
-open:
+ open:
   // open entry in cache.
   // open entry in cache.
   if (!openCachedEntry(dirFile, curIndex, oflag, lfnOrd)) {
   if (!openCachedEntry(dirFile, curIndex, oflag, lfnOrd)) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
@@ -506,7 +511,7 @@ open:
   }
   }
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -553,7 +558,7 @@ size_t FatFile::printName(print_t* pr) {
   }
   }
   return n;
   return n;
 
 
-fail:
+ fail:
   return 0;
   return 0;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -632,14 +637,14 @@ bool FatFile::remove() {
   // Fall into fail.
   // Fall into fail.
   DBG_FAIL_MACRO;
   DBG_FAIL_MACRO;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 bool FatFile::lfnUniqueSfn(fname_t* fname) {
 bool FatFile::lfnUniqueSfn(fname_t* fname) {
   const uint8_t FIRST_HASH_SEQ = 2;  // min value is 2
   const uint8_t FIRST_HASH_SEQ = 2;  // min value is 2
   uint8_t pos = fname->seqPos;;
   uint8_t pos = fname->seqPos;;
-  DirFat_t *dir;
+  DirFat_t* dir;
   uint16_t hex;
   uint16_t hex;
 
 
   DBG_HALT_IF(!(fname->flags & FNAME_FLAG_LOST_CHARS));
   DBG_HALT_IF(!(fname->flags & FNAME_FLAG_LOST_CHARS));
@@ -685,10 +690,10 @@ bool FatFile::lfnUniqueSfn(fname_t* fname) {
   // fall inti fail - too many tries.
   // fall inti fail - too many tries.
   DBG_FAIL_MACRO;
   DBG_FAIL_MACRO;
 
 
-fail:
+ fail:
   return false;
   return false;
 
 
-done:
+ done:
   return true;
   return true;
 }
 }
 #endif  // #if USE_LONG_FILE_NAMES
 #endif  // #if USE_LONG_FILE_NAMES

+ 11 - 21
src/FatLib/FatFilePrint.cpp

@@ -121,38 +121,28 @@ bool FatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) {
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 size_t FatFile::printAccessDate(print_t* pr) {
 size_t FatFile::printAccessDate(print_t* pr) {
-  DirFat_t dir;
-  if (!dirEntry(&dir)) {
-    DBG_FAIL_MACRO;
-    goto fail;
+  uint16_t date;
+  if (getAccessDate(&date)) {
+    return fsPrintDate(pr, date);
   }
   }
-  return fsPrintDate(pr, getLe16(dir.accessDate));
-
-fail:
   return 0;
   return 0;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 size_t FatFile::printCreateDateTime(print_t* pr) {
 size_t FatFile::printCreateDateTime(print_t* pr) {
-  DirFat_t dir;
-  if (!dirEntry(&dir)) {
-    DBG_FAIL_MACRO;
-    goto fail;
+  uint16_t date;
+  uint16_t time;
+  if (getCreateDateTime(&date, &time)) {
+    return fsPrintDateTime(pr, date, time);
   }
   }
-  return fsPrintDateTime(pr, getLe16(dir.createDate), getLe16(dir.createTime));
-
-fail:
   return 0;
   return 0;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 size_t FatFile::printModifyDateTime(print_t* pr) {
 size_t FatFile::printModifyDateTime(print_t* pr) {
-  DirFat_t dir;
-  if (!dirEntry(&dir)) {
-    DBG_FAIL_MACRO;
-    goto fail;
+  uint16_t date;
+  uint16_t time;
+  if (getModifyDateTime(&date, &time)) {
+    return fsPrintDateTime(pr, date, time);
   }
   }
-  return fsPrintDateTime(pr, getLe16(dir.modifyDate), getLe16(dir.modifyTime));
-
-fail:
   return 0;
   return 0;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------

+ 17 - 12
src/FatLib/FatFileSFN.cpp

@@ -31,7 +31,7 @@
 bool FatFile::getSFN(char* name) {
 bool FatFile::getSFN(char* name) {
   uint8_t j = 0;
   uint8_t j = 0;
   uint8_t lcBit = FAT_CASE_LC_BASE;
   uint8_t lcBit = FAT_CASE_LC_BASE;
-  DirFat_t *dir;
+  DirFat_t* dir;
 
 
   if (!isOpen()) {
   if (!isOpen()) {
     DBG_FAIL_MACRO;
     DBG_FAIL_MACRO;
@@ -67,7 +67,7 @@ bool FatFile::getSFN(char* name) {
   name[j] = 0;
   name[j] = 0;
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -79,7 +79,7 @@ size_t FatFile::printSFN(print_t* pr) {
   }
   }
   return pr->write(name);
   return pr->write(name);
 
 
-fail:
+ fail:
   return 0;
   return 0;
 }
 }
 #if !USE_LONG_FILE_NAMES
 #if !USE_LONG_FILE_NAMES
@@ -138,7 +138,7 @@ bool FatFile::parsePathName(const char* path, fname_t* fname,
   *ptr = path;
   *ptr = path;
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -242,16 +242,21 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) {
   // Set base-name and extension lower case bits.
   // Set base-name and extension lower case bits.
   dir->caseFlags = (FAT_CASE_LC_BASE | FAT_CASE_LC_EXT) & fname->flags;
   dir->caseFlags = (FAT_CASE_LC_BASE | FAT_CASE_LC_EXT) & fname->flags;
 
 
-  // set timestamps
+  // Set timestamps.
   if (FsDateTime::callback) {
   if (FsDateTime::callback) {
     // call user date/time function
     // call user date/time function
     FsDateTime::callback(&date, &time, &ms10);
     FsDateTime::callback(&date, &time, &ms10);
-    dir->createTimeMs = ms10;
-    setLe16(dir->createTime, time);
-    setLe16(dir->modifyTime, time);
-    setLe16(dir->accessDate, date);
     setLe16(dir->createDate, date);
     setLe16(dir->createDate, date);
-    setLe16(dir->modifyDate, date);
+    setLe16(dir->createTime, time);
+    dir->createTimeMs = ms10;
+  } else {
+    setLe16(dir->createDate, FS_DEFAULT_DATE);
+    setLe16(dir->modifyDate, FS_DEFAULT_DATE);
+    setLe16(dir->accessDate, FS_DEFAULT_DATE);
+    if (FS_DEFAULT_TIME) {
+      setLe16(dir->createTime, FS_DEFAULT_TIME);
+      setLe16(dir->modifyTime, FS_DEFAULT_TIME);
+    }
   }
   }
   // Force write of entry to device.
   // Force write of entry to device.
   dirFile->m_vol->cacheDirty();
   dirFile->m_vol->cacheDirty();
@@ -259,7 +264,7 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) {
   // open entry in cache.
   // open entry in cache.
   return openCachedEntry(dirFile, index, oflag, 0);
   return openCachedEntry(dirFile, index, oflag, 0);
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -295,7 +300,7 @@ bool FatFile::remove() {
   // Write entry to device.
   // Write entry to device.
   return m_vol->cacheSync();
   return m_vol->cacheSync();
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 #endif  // !USE_LONG_FILE_NAMES
 #endif  // !USE_LONG_FILE_NAMES

+ 6 - 6
src/FatLib/FatFormatter.cpp

@@ -35,7 +35,7 @@ const uint16_t SECTORS_PER_MB = 0X100000/BYTES_PER_SECTOR;
 const uint16_t FAT16_ROOT_ENTRY_COUNT = 512;
 const uint16_t FAT16_ROOT_ENTRY_COUNT = 512;
 const uint16_t FAT16_ROOT_SECTOR_COUNT =
 const uint16_t FAT16_ROOT_SECTOR_COUNT =
                32*FAT16_ROOT_ENTRY_COUNT/BYTES_PER_SECTOR;
                32*FAT16_ROOT_ENTRY_COUNT/BYTES_PER_SECTOR;
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 #define PRINT_FORMAT_PROGRESS 1
 #define PRINT_FORMAT_PROGRESS 1
 #if !PRINT_FORMAT_PROGRESS
 #if !PRINT_FORMAT_PROGRESS
 #define writeMsg(str)
 #define writeMsg(str)
@@ -44,7 +44,7 @@ const uint16_t FAT16_ROOT_SECTOR_COUNT =
 #else  // PRINT_FORMAT_PROGRESS
 #else  // PRINT_FORMAT_PROGRESS
 #define writeMsg(str) if (m_pr) m_pr->write(str)
 #define writeMsg(str) if (m_pr) m_pr->write(str)
 #endif  // PRINT_FORMAT_PROGRESS
 #endif  // PRINT_FORMAT_PROGRESS
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) {
 bool FatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) {
   bool rtn;
   bool rtn;
   m_dev = dev;
   m_dev = dev;
@@ -80,7 +80,7 @@ bool FatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) {
   }
   }
   return rtn;
   return rtn;
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatFormatter::initFatDir(uint8_t fatType, uint32_t sectorCount) {
 bool FatFormatter::initFatDir(uint8_t fatType, uint32_t sectorCount) {
   size_t n;
   size_t n;
   memset(m_secBuf, 0, BYTES_PER_SECTOR);
   memset(m_secBuf, 0, BYTES_PER_SECTOR);
@@ -103,7 +103,7 @@ bool FatFormatter::initFatDir(uint8_t fatType, uint32_t sectorCount) {
   return m_dev->writeSector(m_fatStart, m_secBuf) &&
   return m_dev->writeSector(m_fatStart, m_secBuf) &&
          m_dev->writeSector(m_fatStart + m_fatSize, m_secBuf);
          m_dev->writeSector(m_fatStart + m_fatSize, m_secBuf);
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 void FatFormatter::initPbs() {
 void FatFormatter::initPbs() {
   PbsFat_t* pbs = reinterpret_cast<PbsFat_t*>(m_secBuf);
   PbsFat_t* pbs = reinterpret_cast<PbsFat_t*>(m_secBuf);
   memset(m_secBuf, 0, BYTES_PER_SECTOR);
   memset(m_secBuf, 0, BYTES_PER_SECTOR);
@@ -128,7 +128,7 @@ void FatFormatter::initPbs() {
   // skip rest of bpb
   // skip rest of bpb
   setLe16(pbs->signature, PBR_SIGNATURE);
   setLe16(pbs->signature, PBR_SIGNATURE);
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatFormatter::makeFat16() {
 bool FatFormatter::makeFat16() {
   uint32_t nc;
   uint32_t nc;
   uint32_t r;
   uint32_t r;
@@ -180,7 +180,7 @@ bool FatFormatter::makeFat16() {
   }
   }
   return initFatDir(16, m_dataStart - m_fatStart);
   return initFatDir(16, m_dataStart - m_fatStart);
 }
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatFormatter::makeFat32() {
 bool FatFormatter::makeFat32() {
   uint32_t nc;
   uint32_t nc;
   uint32_t r;
   uint32_t r;

+ 10 - 10
src/FatLib/FatPartition.cpp

@@ -46,7 +46,7 @@ cache_t* FatCache::read(uint32_t sector, uint8_t option) {
   m_status |= option & CACHE_STATUS_MASK;
   m_status |= option & CACHE_STATUS_MASK;
   return &m_buffer;
   return &m_buffer;
 
 
-fail:
+ fail:
 
 
   return nullptr;
   return nullptr;
 }
 }
@@ -69,7 +69,7 @@ bool FatCache::sync() {
   }
   }
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -130,7 +130,7 @@ bool FatPartition::allocateCluster(uint32_t current, uint32_t* next) {
   *next = find;
   *next = find;
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -195,7 +195,7 @@ bool FatPartition::allocContiguous(uint32_t count, uint32_t* firstCluster) {
   *firstCluster = bgnCluster;
   *firstCluster = bgnCluster;
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -266,7 +266,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) {
   *value = next;
   *value = next;
   return 1;
   return 1;
 
 
-fail:
+ fail:
   return -1;
   return -1;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -343,7 +343,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) {
     goto fail;
     goto fail;
   }
   }
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -372,7 +372,7 @@ bool FatPartition::freeChain(uint32_t cluster) {
 
 
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -434,7 +434,7 @@ int32_t FatPartition::freeClusterCount() {
   setFreeClusterCount(free);
   setFreeClusterCount(free);
   return free;
   return free;
 
 
-fail:
+ fail:
   return -1;
   return -1;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -462,7 +462,7 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) {
     }
     }
     mbr = reinterpret_cast<MbrSector_t*>
     mbr = reinterpret_cast<MbrSector_t*>
           (cacheFetchData(0, FatCache::CACHE_FOR_READ));
           (cacheFetchData(0, FatCache::CACHE_FOR_READ));
-    MbrPart_t *mp = mbr->part + part - 1;
+    MbrPart_t* mp = mbr->part + part - 1;
 
 
     if (!mbr || mp->type == 0 || (mp->boot != 0 && mp->boot != 0X80)) {
     if (!mbr || mp->type == 0 || (mp->boot != 0 && mp->boot != 0X80)) {
       DBG_FAIL_MACRO;
       DBG_FAIL_MACRO;
@@ -533,6 +533,6 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) {
   }
   }
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }

+ 1 - 1
src/FatLib/FatPartition.h

@@ -339,7 +339,7 @@ class FatPartition {
   bool cacheSyncData() {
   bool cacheSyncData() {
     return m_cache.sync();
     return m_cache.sync();
   }
   }
-  cache_t *cacheAddress() {
+  cache_t* cacheAddress() {
     return m_cache.buffer();
     return m_cache.buffer();
   }
   }
   uint32_t cacheSectorNumber() {
   uint32_t cacheSectorNumber() {

+ 2 - 2
src/FatLib/FatVolume.cpp

@@ -24,7 +24,7 @@
  */
  */
 #include "FatVolume.h"
 #include "FatVolume.h"
 FatVolume* FatVolume::m_cwv = nullptr;
 FatVolume* FatVolume::m_cwv = nullptr;
-//----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatVolume::chdir(const char *path) {
 bool FatVolume::chdir(const char *path) {
   FatFile dir;
   FatFile dir;
   if (!dir.open(vwd(), path, O_RDONLY)) {
   if (!dir.open(vwd(), path, O_RDONLY)) {
@@ -36,6 +36,6 @@ bool FatVolume::chdir(const char *path) {
   m_vwd = dir;
   m_vwd = dir;
   return true;
   return true;
 
 
-fail:
+ fail:
   return false;
   return false;
 }
 }

+ 63 - 2
src/FsLib/FsFile.h

@@ -63,7 +63,7 @@ class FsBaseFile {
            m_xFile ? m_xFile->available() : 0;
            m_xFile ? m_xFile->available() : 0;
   }
   }
 
 
-  /** Set writeError to zero */
+  /** Clear writeError. */
   void clearWriteError() {
   void clearWriteError() {
     if (m_fFile) m_fFile->clearWriteError();
     if (m_fFile) m_fFile->clearWriteError();
     if (m_xFile) m_xFile->clearWriteError();
     if (m_xFile) m_xFile->clearWriteError();
@@ -74,6 +74,20 @@ class FsBaseFile {
    * \return true for success or false for failure.
    * \return true for success or false for failure.
    */
    */
   bool close();
   bool close();
+  /** Check for contiguous file and return its raw sector range.
+   *
+   * \param[out] bgnSector the first sector address for the file.
+   * \param[out] endSector the last  sector address for the file.
+   *
+   * Set contiguous flag for FAT16/FAT32 files.
+   * Parameters may be nullptr.
+   *
+   * \return true for success or false for failure.
+   */
+  bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
+    return m_fFile ? m_fFile->contiguousRange(bgnSector, endSector) :
+           m_xFile ? m_xFile->contiguousRange(bgnSector, endSector) : false;
+  }
   /** \return The current position for a file or directory. */
   /** \return The current position for a file or directory. */
   uint64_t curPosition() {
   uint64_t curPosition() {
     return m_fFile ? m_fFile->curPosition() :
     return m_fFile ? m_fFile->curPosition() :
@@ -135,6 +149,11 @@ class FsBaseFile {
     return m_fFile ? m_fFile->fileSize() :
     return m_fFile ? m_fFile->fileSize() :
            m_xFile ? m_xFile->fileSize() : 0;
            m_xFile ? m_xFile->fileSize() : 0;
   }
   }
+  /** \return Address of first sector or zero for empty file. */
+  uint32_t firstSector() {
+    return m_fFile ? m_fFile->firstSector() :
+           m_xFile ? m_xFile->firstSector() : 0;
+  }
   /** Ensure that any bytes written to the file are saved to the SD card. */
   /** Ensure that any bytes written to the file are saved to the SD card. */
   void flush() {sync();}
   void flush() {sync();}
   /** set position for streams
   /** set position for streams
@@ -144,11 +163,44 @@ class FsBaseFile {
     if (m_fFile) m_fFile->fsetpos(pos);
     if (m_fFile) m_fFile->fsetpos(pos);
     if (m_xFile) m_xFile->fsetpos(pos);
     if (m_xFile) m_xFile->fsetpos(pos);
   }
   }
+  /** Get a file's access date and time.
+   *
+   * \param[out] pdate Packed date for directory entry.
+   * \param[out] ptime Packed time for directory entry.
+   *
+   * \return true for success or false for failure.
+   */
+  bool getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
+    return m_fFile ? m_fFile->getAccessDateTime(pdate, ptime) :
+           m_xFile ? m_xFile->getAccessDateTime(pdate, ptime) : false;
+  }
+  /** Get a file's create date and time.
+   *
+   * \param[out] pdate Packed date for directory entry.
+   * \param[out] ptime Packed time for directory entry.
+   *
+   * \return true for success or false for failure.
+   */
+  bool getCreateDateTime(uint16_t* pdate, uint16_t* ptime) {
+    return m_fFile ? m_fFile->getCreateDateTime(pdate, ptime) :
+           m_xFile ? m_xFile->getCreateDateTime(pdate, ptime) : false;
+  }
   /** \return All error bits. */
   /** \return All error bits. */
   uint8_t getError() {
   uint8_t getError() {
     return m_fFile ? m_fFile->getError() :
     return m_fFile ? m_fFile->getError() :
            m_xFile ? m_xFile->getError() : 0XFF;
            m_xFile ? m_xFile->getError() : 0XFF;
   }
   }
+  /** Get a file's Modify date and time.
+   *
+   * \param[out] pdate Packed date for directory entry.
+   * \param[out] ptime Packed time for directory entry.
+   *
+   * \return true for success or false for failure.
+   */
+  bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
+    return m_fFile ? m_fFile->getModifyDateTime(pdate, ptime) :
+           m_xFile ? m_xFile->getModifyDateTime(pdate, ptime) : false;
+  }
   /**
   /**
    * Get a file's name followed by a zero byte.
    * Get a file's name followed by a zero byte.
    *
    *
@@ -169,6 +221,15 @@ class FsBaseFile {
     return m_fFile ? m_fFile->getWriteError() :
     return m_fFile ? m_fFile->getWriteError() :
            m_xFile ? m_xFile->getWriteError() : true;
            m_xFile ? m_xFile->getWriteError() : true;
   }
   }
+  /** \return True if the file is contiguous. */
+  bool isContiguous() {
+#if USE_FAT_FILE_FLAG_CONTIGUOUS
+    return m_fFile ? m_fFile->isContiguous() :
+           m_xFile ? m_xFile->isContiguous() : false;
+#else  // USE_FAT_FILE_FLAG_CONTIGUOUS
+    return m_xFile ? m_xFile->isContiguous() : false;
+#endif  // USE_FAT_FILE_FLAG_CONTIGUOUS
+  }
   /** \return True if this is a directory else false. */
   /** \return True if this is a directory else false. */
   bool isDir() {
   bool isDir() {
     return m_fFile ? m_fFile->isDir() :
     return m_fFile ? m_fFile->isDir() :
@@ -593,7 +654,7 @@ class FsBaseFile {
    * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
    * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
    * OR of flags from the following list
    * OR of flags from the following list
    *
    *
-   * T_ACCESS - Set the file's last access date.
+   * T_ACCESS - Set the file's last access date and time.
    *
    *
    * T_CREATE - Set the file's creation date and time.
    * T_CREATE - Set the file's creation date and time.
    *
    *

+ 1 - 1
src/FsLib/FsVolume.h

@@ -230,7 +230,7 @@ class FsVolume {
            m_xVol ? m_xVol->rmdir(path) : false;
            m_xVol ? m_xVol->rmdir(path) : false;
   }
   }
 #if ENABLE_ARDUINO_SERIAL
 #if ENABLE_ARDUINO_SERIAL
-  /** List directory contents. 
+  /** List directory contents.
    * \return true for success or false for failure.
    * \return true for success or false for failure.
    */
    */
   bool ls() {
   bool ls() {

+ 110 - 111
src/SdCard/SdSpiCard.cpp

@@ -151,7 +151,7 @@ static uint8_t CRC7(const uint8_t* data, uint8_t n) {
 #if USE_SD_CRC == 1
 #if USE_SD_CRC == 1
 // Shift based CRC-CCITT
 // Shift based CRC-CCITT
 // uses the x^16,x^12,x^5,x^1 polynomial.
 // uses the x^16,x^12,x^5,x^1 polynomial.
-static uint16_t CRC_CCITT(const uint8_t *data, size_t n) {
+static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
   uint16_t crc = 0;
   uint16_t crc = 0;
   for (size_t i = 0; i < n; i++) {
   for (size_t i = 0; i < n; i++) {
     crc = (uint8_t)(crc >> 8) | (crc << 8);
     crc = (uint8_t)(crc >> 8) | (crc << 8);
@@ -326,7 +326,7 @@ bool SdSpiCard::begin(SdSpiConfig spiConfig) {
   spiSetSckSpeed(spiConfig.maxSck);
   spiSetSckSpeed(spiConfig.maxSck);
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
@@ -363,7 +363,7 @@ uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
   spiSend(cmd | 0x40);
   spiSend(cmd | 0x40);
 
 
   // send argument
   // send argument
-  uint8_t *pa = reinterpret_cast<uint8_t *>(&arg);
+  uint8_t* pa = reinterpret_cast<uint8_t*>(&arg);
   for (int8_t i = 3; i >= 0; i--) {
   for (int8_t i = 3; i >= 0; i--) {
     spiSend(pa[i]);
     spiSend(pa[i]);
   }
   }
@@ -419,7 +419,7 @@ bool SdSpiCard::erase(uint32_t firstSector, uint32_t lastSector) {
   spiStop();
   spiStop();
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
@@ -458,7 +458,7 @@ bool SdSpiCard::isTimedOut(SdMillis_t startMS, SdMillis_t timeoutMS) {
   return (SysCall::curTimeMS() - startMS) > timeoutMS;
   return (SysCall::curTimeMS() - startMS) > timeoutMS;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-bool SdSpiCard::readData(uint8_t *dst) {
+bool SdSpiCard::readData(uint8_t* dst) {
   return readData(dst, 512);
   return readData(dst, 512);
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -501,13 +501,13 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) {
 #endif  // USE_SD_CRC
 #endif  // USE_SD_CRC
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 bool SdSpiCard::readOCR(uint32_t* ocr) {
 bool SdSpiCard::readOCR(uint32_t* ocr) {
-  uint8_t *p = reinterpret_cast<uint8_t*>(ocr);
+  uint8_t* p = reinterpret_cast<uint8_t*>(ocr);
   syncDevice();
   syncDevice();
   if (cardCommand(CMD58, 0)) {
   if (cardCommand(CMD58, 0)) {
     error(SD_CARD_ERROR_CMD58);
     error(SD_CARD_ERROR_CMD58);
@@ -519,7 +519,7 @@ bool SdSpiCard::readOCR(uint32_t* ocr) {
   spiStop();
   spiStop();
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
@@ -538,7 +538,7 @@ bool SdSpiCard::readRegister(uint8_t cmd, void* buf) {
   spiStop();
   spiStop();
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
@@ -558,7 +558,7 @@ bool SdSpiCard::readSingle(uint32_t sector, uint8_t* dst) {
   spiStop();
   spiStop();
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
@@ -574,7 +574,7 @@ bool SdSpiCard::readStart(uint32_t sector) {
 //  spiStop();
 //  spiStop();
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
@@ -591,16 +591,42 @@ bool SdSpiCard::readStatus(uint8_t* status) {
   spiStop();
   spiStop();
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-uint32_t SdSpiCard::sectorCount() {
-  csd_t csd;
-  return readCSD(&csd) ? sdCardCapacity(&csd) : 0;
+bool SdSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
+#if ENABLE_DEDICATED_SPI
+  if (m_curState != READ_STATE || sector != m_curSector) {
+    if (!syncDevice()) {
+      return false;
+    }
+    if (!SdSpiCard::readStart(sector)) {
+      return false;
+    }
+    m_curSector = sector;
+    m_curState = READ_STATE;
+  }
+  for (size_t i = 0; i < ns; i++, dst += 512) {
+    if (!readData(dst, 512)) {
+      return false;
+    }
+  }
+  m_curSector += ns;
+  return m_sharedSpi ? syncDevice() : true;
+#else  // ENABLE_DEDICATED_SPI
+  if (!readStart(sector)) {
+    return false;
+  }
+  for (size_t i = 0; i < ns; i++, dst += 512) {
+    if (!readData(dst, 512)) {
+      return false;
+    }
+  }
+  return readStop();
+#endif  // ENABLE_DEDICATED_SPI
 }
 }
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 bool SdSpiCard::readStop() {
 bool SdSpiCard::readStop() {
   if (cardCommand(CMD12, 0)) {
   if (cardCommand(CMD12, 0)) {
@@ -610,11 +636,16 @@ bool SdSpiCard::readStop() {
   spiStop();
   spiStop();
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+uint32_t SdSpiCard::sectorCount() {
+  csd_t csd;
+  return readCSD(&csd) ? sdCardCapacity(&csd) : 0;
+}
+//------------------------------------------------------------------------------
 void SdSpiCard::spiStart() {
 void SdSpiCard::spiStart() {
   if (!m_spiActive) {
   if (!m_spiActive) {
     spiActivate();
     spiActivate();
@@ -632,6 +663,22 @@ void SdSpiCard::spiStop() {
   }
   }
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+bool SdSpiCard::syncDevice() {
+#if ENABLE_DEDICATED_SPI
+  if (m_curState == READ_STATE) {
+    if (!SdSpiCard::readStop()) {
+      return false;
+    }
+  } else if (m_curState == WRITE_STATE) {
+    if (!SdSpiCard::writeStop()) {
+      return false;
+    }
+  }
+  m_curState = IDLE_STATE;
+#endif  // ENABLE_DEDICATED_SPI
+  return true;
+}
+//------------------------------------------------------------------------------
 // wait for card to go not busy
 // wait for card to go not busy
 bool SdSpiCard::waitNotBusy(SdMillis_t timeoutMS) {
 bool SdSpiCard::waitNotBusy(SdMillis_t timeoutMS) {
   SdMillis_t t0 = SysCall::curTimeMS();
   SdMillis_t t0 = SysCall::curTimeMS();
@@ -654,6 +701,48 @@ bool SdSpiCard::waitNotBusy(SdMillis_t timeoutMS) {
 #endif  // WDT_YIELD_TIME_MILLIS
 #endif  // WDT_YIELD_TIME_MILLIS
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+bool SdSpiCard::writeData(const uint8_t* src) {
+  // wait for previous write to finish
+  DBG_BEGIN_TIME(DBG_WRITE_BUSY);
+  if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
+    error(SD_CARD_ERROR_WRITE_TIMEOUT);
+    goto fail;
+  }
+  DBG_END_TIME(DBG_WRITE_BUSY);
+  if (!writeData(WRITE_MULTIPLE_TOKEN, src)) {
+    goto fail;
+  }
+  return true;
+
+ fail:
+  spiStop();
+  return false;
+}
+//------------------------------------------------------------------------------
+// send one sector of data for write sector or write multiple sectors
+bool SdSpiCard::writeData(uint8_t token, const uint8_t* src) {
+#if USE_SD_CRC
+  uint16_t crc = CRC_CCITT(src, 512);
+#else  // USE_SD_CRC
+  uint16_t crc = 0XFFFF;
+#endif  // USE_SD_CRC
+  spiSend(token);
+  spiSend(src, 512);
+  spiSend(crc >> 8);
+  spiSend(crc & 0XFF);
+
+  m_status = spiReceive();
+  if ((m_status & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
+    error(SD_CARD_ERROR_WRITE_DATA);
+    goto fail;
+  }
+  return true;
+
+ fail:
+  spiStop();
+  return false;
+}
+//------------------------------------------------------------------------------
 bool SdSpiCard::writeSingle(uint32_t sector, const uint8_t* src) {
 bool SdSpiCard::writeSingle(uint32_t sector, const uint8_t* src) {
   // use address if not SDHC card
   // use address if not SDHC card
   if (type() != SD_CARD_TYPE_SDHC) {
   if (type() != SD_CARD_TYPE_SDHC) {
@@ -685,59 +774,11 @@ bool SdSpiCard::writeSingle(uint32_t sector, const uint8_t* src) {
   spiStop();
   spiStop();
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-bool SdSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
-#if ENABLE_DEDICATED_SPI
-  if (m_curState != READ_STATE || sector != m_curSector) {
-    if (!syncDevice()) {
-      return false;
-    }
-    if (!SdSpiCard::readStart(sector)) {
-      return false;
-    }
-    m_curSector = sector;
-    m_curState = READ_STATE;
-  }
-  for (size_t i = 0; i < ns; i++, dst += 512) {
-    if (!readData(dst, 512)) {
-      return false;
-    }
-  }
-  m_curSector += ns;
-  return m_sharedSpi ? syncDevice() : true;
-#else  // ENABLE_DEDICATED_SPI
-  if (!readStart(sector)) {
-    return false;
-  }
-  for (size_t i = 0; i < ns; i++, dst += 512) {
-    if (!readData(dst, 512)) {
-      return false;
-    }
-  }
-  return readStop();
-#endif  // ENABLE_DEDICATED_SPI
-}
-//------------------------------------------------------------------------------
-bool SdSpiCard::syncDevice() {
-#if ENABLE_DEDICATED_SPI
-  if (m_curState == READ_STATE) {
-    if (!SdSpiCard::readStop()) {
-      return false;
-    }
-  } else if (m_curState == WRITE_STATE) {
-    if (!SdSpiCard::writeStop()) {
-      return false;
-    }
-  }
-  m_curState = IDLE_STATE;
-#endif  // ENABLE_DEDICATED_SPI
-  return true;
-}
-//------------------------------------------------------------------------------
 bool SdSpiCard::writeSectors(uint32_t sector, const uint8_t* src, size_t ns) {
 bool SdSpiCard::writeSectors(uint32_t sector, const uint8_t* src, size_t ns) {
   #if ENABLE_DEDICATED_SPI
   #if ENABLE_DEDICATED_SPI
   if (m_curState != WRITE_STATE || m_curSector != sector) {
   if (m_curState != WRITE_STATE || m_curSector != sector) {
@@ -774,48 +815,6 @@ bool SdSpiCard::writeSectors(uint32_t sector, const uint8_t* src, size_t ns) {
 #endif  // ENABLE_DEDICATED_SPI
 #endif  // ENABLE_DEDICATED_SPI
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-bool SdSpiCard::writeData(const uint8_t* src) {
-  // wait for previous write to finish
-  DBG_BEGIN_TIME(DBG_WRITE_BUSY);
-  if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
-    error(SD_CARD_ERROR_WRITE_TIMEOUT);
-    goto fail;
-  }
-  DBG_END_TIME(DBG_WRITE_BUSY);
-  if (!writeData(WRITE_MULTIPLE_TOKEN, src)) {
-    goto fail;
-  }
-  return true;
-
-fail:
-  spiStop();
-  return false;
-}
-//------------------------------------------------------------------------------
-// send one sector of data for write sector or write multiple sectors
-bool SdSpiCard::writeData(uint8_t token, const uint8_t* src) {
-#if USE_SD_CRC
-  uint16_t crc = CRC_CCITT(src, 512);
-#else  // USE_SD_CRC
-  uint16_t crc = 0XFFFF;
-#endif  // USE_SD_CRC
-  spiSend(token);
-  spiSend(src, 512);
-  spiSend(crc >> 8);
-  spiSend(crc & 0XFF);
-
-  m_status = spiReceive();
-  if ((m_status & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
-    error(SD_CARD_ERROR_WRITE_DATA);
-    goto fail;
-  }
-  return true;
-
-fail:
-  spiStop();
-  return false;
-}
-//------------------------------------------------------------------------------
 bool SdSpiCard::writeStart(uint32_t sector) {
 bool SdSpiCard::writeStart(uint32_t sector) {
   // use address if not SDHC card
   // use address if not SDHC card
   if (type() != SD_CARD_TYPE_SDHC) {
   if (type() != SD_CARD_TYPE_SDHC) {
@@ -827,7 +826,7 @@ bool SdSpiCard::writeStart(uint32_t sector) {
   }
   }
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
@@ -848,7 +847,7 @@ bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
   }
   }
   return true;
   return true;
 
 
-fail:
+ fail:
   spiStop();
   spiStop();
   return false;
   return false;
 }
 }
@@ -863,7 +862,7 @@ bool SdSpiCard::writeStop() {
   spiStop();
   spiStop();
   return true;
   return true;
 
 
-fail:
+ fail:
   error(SD_CARD_ERROR_STOP_TRAN);
   error(SD_CARD_ERROR_STOP_TRAN);
   spiStop();
   spiStop();
   return false;
   return false;

+ 1 - 1
src/SdCard/SdSpiCard.h

@@ -171,7 +171,7 @@ class SdSpiCard {
    *
    *
    * \return true for success or false for failure.
    * \return true for success or false for failure.
    */
    */
-  bool readData(uint8_t *dst);
+  bool readData(uint8_t* dst);
   /** Read OCR register.
   /** Read OCR register.
    *
    *
    * \param[out] ocr Value of OCR register.
    * \param[out] ocr Value of OCR register.

+ 1 - 1
src/SdCard/SdioCard.h

@@ -146,7 +146,7 @@ class SdioCard : public SdCardInterface {
    *
    *
    * \return true for success or false for failure.
    * \return true for success or false for failure.
    */
    */
-  bool readData(uint8_t *dst);
+  bool readData(uint8_t* dst);
   /** Read OCR register.
   /** Read OCR register.
    *
    *
    * \param[out] ocr Value of OCR register.
    * \param[out] ocr Value of OCR register.

+ 3 - 3
src/SdCard/SdioTeensy.cpp

@@ -733,9 +733,9 @@ bool SdioCard::readCSD(csd_t* csd) {
   return true;
   return true;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-bool SdioCard::readData(uint8_t *dst) {
+bool SdioCard::readData(uint8_t* dst) {
   DBG_IRQSTAT();
   DBG_IRQSTAT();
-  uint32_t *p32 = reinterpret_cast<uint32_t*>(dst);
+  uint32_t* p32 = reinterpret_cast<uint32_t*>(dst);
 
 
   if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_RTA)) {
   if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_RTA)) {
     SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
     SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
@@ -911,7 +911,7 @@ bool SdioCard::writeData(const uint8_t* src) {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
 bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
   if (m_sdioConfig.useDma()) {
   if (m_sdioConfig.useDma()) {
-    uint8_t *ptr;
+    uint8_t* ptr;
     uint8_t aligned[512];
     uint8_t aligned[512];
     if (3 & (uint32_t)src) {
     if (3 & (uint32_t)src) {
       ptr = aligned;
       ptr = aligned;

+ 1 - 1
src/SdCard/SdioTeensy.h

@@ -217,7 +217,7 @@
 #define SDHC_MMCBOOT_BOOTMODE   MAKE_REG_MASK(0x1,5)  //((uint32_t)0x00000020)    // Boot Mode Select
 #define SDHC_MMCBOOT_BOOTMODE   MAKE_REG_MASK(0x1,5)  //((uint32_t)0x00000020)    // Boot Mode Select
 #define SDHC_MMCBOOT_BOOTACK    MAKE_REG_MASK(0x1,4)  //((uint32_t)0x00000010)    // Boot Ack Mode Select
 #define SDHC_MMCBOOT_BOOTACK    MAKE_REG_MASK(0x1,4)  //((uint32_t)0x00000010)    // Boot Ack Mode Select
 #define SDHC_MMCBOOT_DTOCVACK(n)  MAKE_REG_MASK(0xF,0)  //(uint32_t)(((n) & 0xF)<<0)  // Boot ACK Time Out Counter Value
 #define SDHC_MMCBOOT_DTOCVACK(n)  MAKE_REG_MASK(0xF,0)  //(uint32_t)(((n) & 0xF)<<0)  // Boot ACK Time Out Counter Value
-//#define SDHC_HOSTVER    (*(volatile uint32_t *)0x400B10FC) // Host Controller Version
+//#define SDHC_HOSTVER    (*(volatile uint32_t*)0x400B10FC) // Host Controller Version
 
 
 #define CCM_ANALOG_PFD_528_PFD0_FRAC_MASK 0x3f
 #define CCM_ANALOG_PFD_528_PFD0_FRAC_MASK 0x3f
 #define CCM_ANALOG_PFD_528_PFD0_FRAC(n) ((n) & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
 #define CCM_ANALOG_PFD_528_PFD0_FRAC(n) ((n) & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)

+ 11 - 5
src/SdFat.h

@@ -39,7 +39,7 @@
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 /** SdFat version */
 /** SdFat version */
-#define SD_FAT_VERSION "2.0.0"
+#define SD_FAT_VERSION "2.0.2"
 //==============================================================================
 //==============================================================================
 /**
 /**
  * \class SdBase
  * \class SdBase
@@ -397,16 +397,22 @@ class SdFs : public SdBase<FsVolume> {
 /** Select type for SdFat. */
 /** Select type for SdFat. */
 typedef SdFat32 SdFat;
 typedef SdFat32 SdFat;
 /** Select type for File. */
 /** Select type for File. */
+#if !defined(__has_include) || !__has_include(<FS.h>)
 typedef File32 File;
 typedef File32 File;
+#endif
 /** Select type for SdBaseFile. */
 /** Select type for SdBaseFile. */
 typedef FatFile SdBaseFile;
 typedef FatFile SdBaseFile;
 #elif SDFAT_FILE_TYPE == 2
 #elif SDFAT_FILE_TYPE == 2
 typedef SdExFat SdFat;
 typedef SdExFat SdFat;
+#if !defined(__has_include) || !__has_include(<FS.h>)
 typedef ExFile File;
 typedef ExFile File;
+#endif
 typedef ExFatFile SdBaseFile;
 typedef ExFatFile SdBaseFile;
 #elif SDFAT_FILE_TYPE == 3
 #elif SDFAT_FILE_TYPE == 3
 typedef SdFs SdFat;
 typedef SdFs SdFat;
+#if !defined(__has_include) || !__has_include(<FS.h>)
 typedef FsFile File;
 typedef FsFile File;
+#endif
 typedef FsBaseFile SdBaseFile;
 typedef FsBaseFile SdBaseFile;
 #else  // SDFAT_FILE_TYPE
 #else  // SDFAT_FILE_TYPE
 #error Invalid SDFAT_FILE_TYPE
 #error Invalid SDFAT_FILE_TYPE
@@ -437,11 +443,11 @@ class SdFile : public PrintFile<SdBaseFile> {
    *
    *
    *   // User gets date and time from GPS or real-time clock here
    *   // User gets date and time from GPS or real-time clock here
    *
    *
-   *   // return date using FAT_DATE macro to format fields
-   *   *date = FAT_DATE(year, month, day);
+   *   // return date using FS_DATE macro to format fields
+   *   *date = FS_DATE(year, month, day);
    *
    *
-   *   // return time using FAT_TIME macro to format fields
-   *   *time = FAT_TIME(hour, minute, second);
+   *   // return time using FS_TIME macro to format fields
+   *   *time = FS_TIME(hour, minute, second);
    * }
    * }
    * \endcode
    * \endcode
    *
    *

+ 22 - 1
src/SdFatConfig.h

@@ -57,7 +57,7 @@
 #define INCLUDE_SDIOS 0
 #define INCLUDE_SDIOS 0
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 /**
 /**
- * Set USE_FAT_FILE_FLAG_CONTIGUOUS nonzero to optimize access to 
+ * Set USE_FAT_FILE_FLAG_CONTIGUOUS nonzero to optimize access to
  * contiguous files.
  * contiguous files.
  */
  */
 #define USE_FAT_FILE_FLAG_CONTIGUOUS 1
 #define USE_FAT_FILE_FLAG_CONTIGUOUS 1
@@ -73,6 +73,9 @@
 #if defined(__AVR__) && FLASHEND < 0X8000
 #if defined(__AVR__) && FLASHEND < 0X8000
 // 32K AVR boards.
 // 32K AVR boards.
 #define SDFAT_FILE_TYPE 1
 #define SDFAT_FILE_TYPE 1
+#elif defined(__arm__)
+// ARM boards usually have plenty of memory
+#define SDFAT_FILE_TYPE 3
 #else  // defined(__AVR__) && FLASHEND < 0X8000
 #else  // defined(__AVR__) && FLASHEND < 0X8000
 // All other boards.
 // All other boards.
 #define SDFAT_FILE_TYPE 1
 #define SDFAT_FILE_TYPE 1
@@ -152,6 +155,24 @@ typedef uint8_t SdCsPin_t;
  */
  */
 #define USE_LONG_FILE_NAMES 1
 #define USE_LONG_FILE_NAMES 1
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
+/**
+ * Set the default file time stamp when a RTC callback is not used.
+ * A valid date and time is required by the FAT/exFAT standard.
+ *
+ * The default below is YYYY-01-01 00:00:00 midnight where YYYY is
+ * the compile year from the __DATE__ macro.  This is easy to recognize
+ * as a placeholder for a correct date/time.
+ *
+ * The full compile date is:
+ * FS_DATE(compileYear(), compileMonth(), compileDay())
+ *
+ * The full compile time is:
+ * FS_TIME(compileHour(), compileMinute(), compileSecond())
+ */
+#define FS_DEFAULT_DATE FS_DATE(compileYear(), 1, 1)
+/** 00:00:00 midnight */
+#define FS_DEFAULT_TIME FS_TIME(0, 0, 0)
+//------------------------------------------------------------------------------
 /**
 /**
  * If CHECK_FLASH_PROGRAMMING is zero, overlap of single sector flash
  * If CHECK_FLASH_PROGRAMMING is zero, overlap of single sector flash
  * programming and other operations will be allowed for faster write
  * programming and other operations will be allowed for faster write

+ 2 - 2
src/SpiDriver/SdSpiArtemis.cpp

@@ -46,7 +46,7 @@ uint8_t SdSpiArduinoDriver::receive() {
   return m_spi->transfer(0XFF);
   return m_spi->transfer(0XFF);
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-uint8_t SdSpiArduinoDriver::receive(uint8_t *buf, size_t count) {
+uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
   m_spi->transferIn(buf, count);
   m_spi->transferIn(buf, count);
   return 0;
   return 0;
 }
 }
@@ -55,7 +55,7 @@ void SdSpiArduinoDriver::send(uint8_t data) {
   m_spi->transfer(data);
   m_spi->transfer(data);
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-void SdSpiArduinoDriver::send(const uint8_t *buf, size_t count) {
+void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) {
   // If not a multiple of four.  Command with CRC used six byte send.
   // If not a multiple of four.  Command with CRC used six byte send.
   while (count%4) {
   while (count%4) {
     send(*buf++);
     send(*buf++);

+ 1 - 1
src/SpiDriver/SdSpiBaseClass.h

@@ -36,7 +36,7 @@ class SdSpiBaseClass {
  public:
  public:
   /** Activate SPI hardware. */
   /** Activate SPI hardware. */
   virtual void activate() {}
   virtual void activate() {}
-  /** Initialize the SPI bus. 
+  /** Initialize the SPI bus.
    *
    *
    * \param[in] config SPI configuration.
    * \param[in] config SPI configuration.
    */
    */

+ 4 - 4
src/common/BlockDeviceInterface.h

@@ -39,7 +39,7 @@ class BlockDeviceInterface {
  public:
  public:
   virtual ~BlockDeviceInterface() {}
   virtual ~BlockDeviceInterface() {}
   /**
   /**
-   * Read a 512 byte sector.
+   * Read a sector.
    *
    *
    * \param[in] sector Logical sector to be read.
    * \param[in] sector Logical sector to be read.
    * \param[out] dst Pointer to the location that will receive the data.
    * \param[out] dst Pointer to the location that will receive the data.
@@ -48,7 +48,7 @@ class BlockDeviceInterface {
   virtual bool readSector(uint32_t sector, uint8_t* dst) = 0;
   virtual bool readSector(uint32_t sector, uint8_t* dst) = 0;
 #if USE_MULTI_SECTOR_IO
 #if USE_MULTI_SECTOR_IO
   /**
   /**
-   * Read multiple 512 byte sectors.
+   * Read multiple sectors.
    *
    *
    * \param[in] sector Logical sector to be read.
    * \param[in] sector Logical sector to be read.
    * \param[in] ns Number of sectors to be read.
    * \param[in] ns Number of sectors to be read.
@@ -66,7 +66,7 @@ class BlockDeviceInterface {
   virtual bool syncDevice() = 0;
   virtual bool syncDevice() = 0;
 
 
   /**
   /**
-   * Writes a 512 byte sector.
+   * Writes a sector.
    *
    *
    * \param[in] sector Logical sector to be written.
    * \param[in] sector Logical sector to be written.
    * \param[in] src Pointer to the location of the data to be written.
    * \param[in] src Pointer to the location of the data to be written.
@@ -75,7 +75,7 @@ class BlockDeviceInterface {
   virtual bool writeSector(uint32_t sector, const uint8_t* src) = 0;
   virtual bool writeSector(uint32_t sector, const uint8_t* src) = 0;
 #if USE_MULTI_SECTOR_IO
 #if USE_MULTI_SECTOR_IO
   /**
   /**
-   * Write multiple 512 byte sectors.
+   * Write multiple sectors.
    *
    *
    * \param[in] sector Logical sector to be written.
    * \param[in] sector Logical sector to be written.
    * \param[in] ns Number of sectors to be written.
    * \param[in] ns Number of sectors to be written.

+ 74 - 0
src/common/CompileDateTime.h

@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2011-2020 Bill Greiman
+ * This file is part of the SdFat library for SD memory cards.
+ *
+ * MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef CompileDateTime_h
+#define CompileDateTime_h
+// Note - these functions will compile to a few bytes
+//        since they are evaluated at compile time.
+
+/** \return year field of the __DATE__ macro. */
+constexpr uint16_t compileYear() {
+  return  1000*(__DATE__[7] - '0')
+         + 100*(__DATE__[8] - '0')
+          + 10*(__DATE__[9] - '0')
+             + (__DATE__[10] - '0');
+}
+/** \return true if str equals the month field of the __DATE__ macro. */
+constexpr bool compileMonthIs(const char* str) {
+  return __DATE__[0] == str[0]
+      && __DATE__[1] == str[1]
+      && __DATE__[2] == str[2];
+}
+/** \return month field of the __DATE__ macro. */
+constexpr uint8_t compileMonth() {
+  return compileMonthIs("Jan") ? 1 :
+         compileMonthIs("Feb") ? 2 :
+         compileMonthIs("Mar") ? 3 :
+         compileMonthIs("Apr") ? 4 :
+         compileMonthIs("May") ? 5 :
+         compileMonthIs("Jun") ? 6 :
+         compileMonthIs("Jul") ? 7 :
+         compileMonthIs("Aug") ? 8 :
+         compileMonthIs("Sep") ? 9 :
+         compileMonthIs("Oct") ? 10 :
+         compileMonthIs("Nov") ? 11 :
+         compileMonthIs("Dec") ? 12 : 0;
+}
+/** \return day field of the __DATE__ macro. */
+constexpr uint8_t compileDay() {
+  return 10*(__DATE__[4] == ' ' ? 0 : __DATE__[4] - '0') + (__DATE__[5] - '0');
+}
+/** \return hour field of the __TIME__ macro. */
+constexpr uint8_t compileHour() {
+  return 10*(__TIME__[0] - '0') + __TIME__[1] - '0';
+}
+/** \return minute field of the __TIME__ macro. */
+constexpr uint8_t compileMinute() {
+  return 10*(__TIME__[3] - '0') + __TIME__[4] - '0';
+}
+/** \return second field of the __TIME__ macro. */
+constexpr uint8_t compileSecond() {
+  return 10*(__TIME__[6] - '0') + __TIME__[7] - '0';
+}
+#endif  // CompileDateTime_h

+ 1 - 1
src/common/FmtNumber.cpp

@@ -511,6 +511,6 @@ float scanFloat(const char* str, const char** ptr) {
   v = scale10(static_cast<float>(fract), fracExp);
   v = scale10(static_cast<float>(fract), fracExp);
   return neg ? -v : v;
   return neg ? -v : v;
 
 
-fail:
+ fail:
   return 0;
   return 0;
 }
 }

+ 1 - 1
src/common/FsDateTime.cpp

@@ -43,7 +43,7 @@ namespace FsDateTime {
     callback2 = dateTime;
     callback2 = dateTime;
   }
   }
   void setCallback(
   void setCallback(
-    void (*dateTime)(uint16_t* date, uint16_t* time, uint8_t *ms10)) {
+    void (*dateTime)(uint16_t* date, uint16_t* time, uint8_t* ms10)) {
     callback = dateTime;
     callback = dateTime;
   }
   }
 }  // namespace FsDateTime
 }  // namespace FsDateTime

+ 30 - 16
src/common/FsDateTime.h

@@ -25,23 +25,26 @@
 #ifndef FsDateTime_h
 #ifndef FsDateTime_h
 #define FsDateTime_h
 #define FsDateTime_h
 #include <stdint.h>
 #include <stdint.h>
+#include "CompileDateTime.h"
 #include "SysCall.h"
 #include "SysCall.h"
+
 /** Backward compatible definition. */
 /** Backward compatible definition. */
 #define FAT_DATE(y, m, d) FS_DATE(y, m, d)
 #define FAT_DATE(y, m, d) FS_DATE(y, m, d)
 
 
 /** Backward compatible definition. */
 /** Backward compatible definition. */
 #define FAT_TIME(h, m, s) FS_TIME(h, m, s)
 #define FAT_TIME(h, m, s) FS_TIME(h, m, s)
+
 /** Date time callback */
 /** Date time callback */
 namespace FsDateTime {
 namespace FsDateTime {
   /** Date time callback. */
   /** Date time callback. */
   extern void (*callback)(uint16_t* date, uint16_t* time, uint8_t* ms10);
   extern void (*callback)(uint16_t* date, uint16_t* time, uint8_t* ms10);
   /** Date time callback. */
   /** Date time callback. */
   extern void (*callback2)(uint16_t* date, uint16_t* time);
   extern void (*callback2)(uint16_t* date, uint16_t* time);
-  /** Cancel callback */
+  /** Cancel callback. */
   void clearCallback();
   void clearCallback();
-   /** Set the date/time callback function
+   /** Set the date/time callback function.
    *
    *
-   * \param[in] dateTime The user's call back function.  The callback
+   * \param[in] dateTime The user's call back function.  The callback.
    * function is of the form:
    * function is of the form:
    *
    *
    * \code
    * \code
@@ -49,13 +52,13 @@ namespace FsDateTime {
    *   uint16_t year;
    *   uint16_t year;
    *   uint8_t month, day, hour, minute, second;
    *   uint8_t month, day, hour, minute, second;
    *
    *
-   *   // User gets date and time from GPS or real-time clock here
+   *   // User gets date and time from GPS or real-time clock here.
    *
    *
-   *   // return date using FAT_DATE macro to format fields
-   *   *date = FAT_DATE(year, month, day);
+   *   // Return date using FS_DATE macro to format fields.
+   *   *date = FS_DATE(year, month, day);
    *
    *
-   *   // return time using FAT_TIME macro to format fields
-   *   *time = FAT_TIME(hour, minute, second);
+   *   // Return time using FS_TIME macro to format fields.
+   *   *time = FS_TIME(hour, minute, second);
    * }
    * }
    * \endcode
    * \endcode
    *
    *
@@ -66,7 +69,7 @@ namespace FsDateTime {
    *
    *
    */
    */
   void setCallback(void (*dateTime)(uint16_t* date, uint16_t* time));
   void setCallback(void (*dateTime)(uint16_t* date, uint16_t* time));
-   /** Set the date/time callback function
+   /** Set the date/time callback function.
    *
    *
    * \param[in] dateTime The user's call back function.  The callback
    * \param[in] dateTime The user's call back function.  The callback
    * function is of the form:
    * function is of the form:
@@ -76,15 +79,20 @@ namespace FsDateTime {
    *   uint16_t year;
    *   uint16_t year;
    *   uint8_t month, day, hour, minute, second;
    *   uint8_t month, day, hour, minute, second;
    *
    *
-   *   // User gets date and time from GPS or real-time clock here
+   *   // User gets date and time from GPS or real-time clock here.
    *
    *
-   *   // return date using FAT_DATE macro to format fields
-   *   *date = FAT_DATE(year, month, day);
+   *   // Return date using FS_DATE macro to format fields
+   *   *date = FS_DATE(year, month, day);
    *
    *
-   *   // return time using FAT_TIME macro to format fields
-   *   *time = FAT_TIME(hour, minute, second);
+   *   // Return time using FS_TIME macro to format fields
+   *   *time = FS_TIME(hour, minute, second);
    *
    *
-   *   *ms10 = <tens of ms since second/1>
+   *   // Return tenths of milliseconds since last even second.
+   *   // The granularity of the seconds part of FS_TIME is 2 seconds so
+   *   // this field is a count of tenths of a second and its valid value
+   *   // range is 0-199 inclusive.
+   *   // For a simple RTC return 100*(seconds & 1).
+   *   *ms10 = <tens of ms since even second>
    * }
    * }
    * \endcode
    * \endcode
    *
    *
@@ -95,8 +103,9 @@ namespace FsDateTime {
    *
    *
    */
    */
   void setCallback(
   void setCallback(
-    void (*dateTime)(uint16_t* date, uint16_t* time, uint8_t *ms10));
+    void (*dateTime)(uint16_t* date, uint16_t* time, uint8_t* ms10));
 }  // namespace FsDateTime
 }  // namespace FsDateTime
+
 /** date field for directory entry
 /** date field for directory entry
  * \param[in] year [1980,2107]
  * \param[in] year [1980,2107]
  * \param[in] month [1,12]
  * \param[in] month [1,12]
@@ -109,6 +118,11 @@ static inline uint16_t FS_DATE(uint16_t year, uint8_t month, uint8_t day) {
   return year > 127 || month > 12 || day > 31 ? 0 :
   return year > 127 || month > 12 || day > 31 ? 0 :
          year << 9 | month << 5 | day;
          year << 9 | month << 5 | day;
 }
 }
+/** year part of FAT directory date field
+ * \param[in] fatDate Date in packed dir format.
+ *
+ * \return Extracted year [1980,2107]
+ */
 static inline uint16_t FS_YEAR(uint16_t fatDate) {
 static inline uint16_t FS_YEAR(uint16_t fatDate) {
   return 1980 + (fatDate >> 9);
   return 1980 + (fatDate >> 9);
 }
 }

+ 2 - 2
src/common/PrintBasic.h

@@ -138,7 +138,7 @@ class PrintBasic {
   }
   }
   virtual size_t write(uint8_t b) = 0;
   virtual size_t write(uint8_t b) = 0;
 
 
-  virtual size_t write(const uint8_t *buffer, size_t size) {
+  virtual size_t write(const uint8_t* buffer, size_t size) {
     size_t i;
     size_t i;
     for (i = 0; i < size; i++) {
     for (i = 0; i < size; i++) {
       if (!write(buffer[i])) break;
       if (!write(buffer[i])) break;
@@ -146,7 +146,7 @@ class PrintBasic {
     return i;
     return i;
   }
   }
   size_t write(const char *buffer, size_t size) {
   size_t write(const char *buffer, size_t size) {
-    return write((const uint8_t *)buffer, size);
+    return write((const uint8_t*)buffer, size);
   }
   }
 
 
  protected:
  protected:

+ 4 - 1
src/common/SysCall.h

@@ -79,7 +79,10 @@ inline SdMillis_t SysCall::curTimeMS() {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 #if defined(PLATFORM_ID)  // Only defined if a Particle device
 #if defined(PLATFORM_ID)  // Only defined if a Particle device
 inline void SysCall::yield() {
 inline void SysCall::yield() {
-  Particle.process();
+  // Recommended to only call Particle.process() if system threading is disabled
+  if (system_thread_get_state(NULL) == spark::feature::DISABLED) {
+    Particle.process();
+  }
 }
 }
 #elif defined(ARDUINO)
 #elif defined(ARDUINO)
 inline void SysCall::yield() {
 inline void SysCall::yield() {

+ 2 - 2
src/iostream/StdioStream.cpp

@@ -146,7 +146,7 @@ bool StdioStream::fopen(const char* path, const char* mode) {
   m_p = m_buf;
   m_p = m_buf;
   return true;
   return true;
 
 
-fail:
+ fail:
   m_status = 0;
   m_status = 0;
   return false;
   return false;
 }
 }
@@ -216,7 +216,7 @@ int StdioStream::fseek(int32_t offset, int origin) {
   m_p = m_buf;
   m_p = m_buf;
   return 0;
   return 0;
 
 
-fail:
+ fail:
   return EOF;
   return EOF;
 }
 }
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------

+ 1 - 1
src/iostream/StreamBaseClass.cpp

@@ -92,7 +92,7 @@ void StreamBaseClass::open(const char* path, ios::openmode mode) {
   clear();
   clear();
   return;
   return;
 
 
-fail:
+ fail:
   StreamBaseFile::close();
   StreamBaseFile::close();
   setstate(failbit);
   setstate(failbit);
   return;
   return;

+ 2 - 2
src/iostream/bufstream.h

@@ -66,7 +66,7 @@ class ibufstream : public istream {
     setstate(eofbit);
     setstate(eofbit);
     return -1;
     return -1;
   }
   }
-  void getpos(pos_t *pos) {
+  void getpos(pos_t* pos) {
     pos->position = m_pos;
     pos->position = m_pos;
   }
   }
   bool seekoff(off_type off, seekdir way) {
   bool seekoff(off_type off, seekdir way) {
@@ -81,7 +81,7 @@ class ibufstream : public istream {
     }
     }
     return false;
     return false;
   }
   }
-  void setpos(pos_t *pos) {
+  void setpos(pos_t* pos) {
     m_pos = pos->position;
     m_pos = pos->position;
   }
   }
   pos_type tellpos() {
   pos_type tellpos() {

+ 2 - 2
src/iostream/fstream.h

@@ -25,7 +25,7 @@
 /**
 /**
  * \file
  * \file
  * \brief iostreams for files.
  * \brief iostreams for files.
- */ 
+ */
 #ifndef fstream_h
 #ifndef fstream_h
 #define fstream_h
 #define fstream_h
 #include "iostream.h"
 #include "iostream.h"
@@ -41,7 +41,7 @@ class StreamBaseClass : protected StreamBaseFile, virtual public ios {
   }
   }
   /* Internal do not use
   /* Internal do not use
    * \return mode
    * \return mode
-   */  
+   */
   int16_t getch();
   int16_t getch();
   bool getWriteError() {
   bool getWriteError() {
     return StreamBaseFile::getWriteError();
     return StreamBaseFile::getWriteError();

Some files were not shown because too many files changed in this diff