Ver código fonte

Timestamp fix, edit src for cplint errors

Add time st
Bill Greiman 4 anos atrás
pai
commit
1535ac2b03
100 arquivos alterados com 1737 adições e 1096 exclusões
  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.
 // 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
 #if USE_RTC
 #include "RTClib.h"
-#endif
+#endif  // USE_RTC
 //------------------------------------------------------------------------------
 // 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.
 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 uint32_t MAX_FILE_SIZE = MAX_FILE_SIZE_MiB << 20;
@@ -303,8 +309,15 @@ void printUnusedStack() {
 }
 //------------------------------------------------------------------------------
 #if USE_RTC
+#if USE_RTC == 1
 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().
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
   DateTime now = rtc.now();
@@ -553,6 +566,15 @@ void binaryToCsv() {
   Serial.println(F(" Seconds"));
 }
 //------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+//------------------------------------------------------------------------------
 void createBinFile() {
   binFile.close();
   while (sd.exists(binName)) {
@@ -719,7 +741,7 @@ void logData() {
 //------------------------------------------------------------------------------
 void openBinFile() {
   char name[NAME_DIM];
-  serialClearInput();
+  clearSerialInput();
   Serial.println(F("Enter file name"));
   if (!serialReadLine(name, sizeof(name))) {
     return;
@@ -772,12 +794,6 @@ void printData() {
   Serial.println(F("Done"));
 }
 //------------------------------------------------------------------------------
-void serialClearInput() {
-  do {
-    delay(10);
-  } while (Serial.read() >= 0);
-}
-//------------------------------------------------------------------------------
 bool serialReadLine(char* str, size_t size) {
   size_t n = 0;
   while(!Serial.available()) {
@@ -840,9 +856,7 @@ void setup(void) {
 void loop(void) {
   printUnusedStack();
   // Read any Serial data.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
   Serial.println();
   Serial.println(F("type:"));
   Serial.println(F("b - open existing bin file"));
@@ -860,9 +874,7 @@ void loop(void) {
     digitalWrite(ERROR_LED_PIN, LOW);
   }
   // Read any Serial data.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
 
   if (c == 'b') {
     openBinFile();

+ 4 - 4
examples/BackwardCompatibility/BackwardCompatibility.ino

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

+ 14 - 8
examples/ExFatFormatter/ExFatFormatter.ino

@@ -3,7 +3,7 @@
 
 /*
   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:
   Arduino Ethernet shield: pin 4
   Sparkfun SD shield: pin 8
@@ -31,6 +31,15 @@ const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
 
 SdExFat sd;
 //------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+//------------------------------------------------------------------------------
 void errorHalt() {
   sd.printSdError(&Serial);
   SysCall::halt();
@@ -41,20 +50,17 @@ void setup() {
   Serial.begin(9600);
   while (!Serial) {}
   Serial.println(F("Type any character to begin"));
-  
+
   while (!Serial.available()) {
     yield();
   }
-  do {
-    delay(10);
-  } while(Serial.read() >= 0);
-  
+  clearSerialInput();
   Serial.println();
   Serial.println(F(
     "Your SD will be formated exFAT.\r\n"
     "All data on the SD will be lost.\r\n"
     "Type 'Y' to continue.\r\n"));
-    
+
   while (!Serial.available()) {
     yield();
   }
@@ -64,7 +70,7 @@ void setup() {
   }
   if (!sd.cardBegin(SD_CONFIG)) {
     error("cardBegin failed");
-  }    
+  }
   if(!sd.format(&Serial)) {
     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.
 // RAM use will be marginal on Uno with RTClib.
+// 0 - RTC not used
+// 1 - DS1307
+// 2 - DS3231
+// 3 - PCF8523
 #define USE_RTC 0
 #if USE_RTC
 #include "RTClib.h"
@@ -151,8 +155,15 @@ file_t csvFile;
 char binName[] = "ExFatLogger00.bin";
 //------------------------------------------------------------------------------
 #if USE_RTC
+#if USE_RTC == 1
 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().
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
   DateTime now = rtc.now();
@@ -211,6 +222,15 @@ void binaryToCsv() {
   Serial.print(0.001*(millis() - t0));
   Serial.println(F(" Seconds"));
 }
+//------------------------------------------------------------------------------
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
 //-------------------------------------------------------------------------------
 void createBinFile() {
   binFile.close();
@@ -261,7 +281,7 @@ bool createCsvFile() {
   if (!csvFile.open(csvName, O_WRONLY | O_CREAT | O_TRUNC)) {
     error("open csvFile failed");
   }
-  serialClearInput();
+  clearSerialInput();
   Serial.print(F("Writing: "));
   Serial.print(csvName);
   Serial.println(F(" - type any character to stop"));
@@ -289,7 +309,7 @@ void logData() {
   if (binFile.write(fifoBuf, 512) != 512) {
     error("write first sector failed");
   }
-  serialClearInput();
+  clearSerialInput();
   Serial.println(F("Type any character to stop"));
 
   // Wait until SD is not busy.
@@ -397,7 +417,7 @@ void logData() {
 //------------------------------------------------------------------------------
 void openBinFile() {
   char name[FILE_NAME_DIM];
-  serialClearInput();
+  clearSerialInput();
   Serial.println(F("Enter file name"));
   if (!serialReadLine(name, sizeof(name))) {
     return;
@@ -425,7 +445,7 @@ void printData() {
   if (!binFile.seekSet(512)) {
     error("seek failed");
   }
-  serialClearInput();
+  clearSerialInput();
   Serial.println(F("type any character to stop\n"));
   delay(1000);
   printRecord(&Serial, nullptr);
@@ -439,16 +459,10 @@ void printData() {
 }
 //------------------------------------------------------------------------------
 void printUnusedStack() {
-#if HAS_UNUSED_STACK  
+#if HAS_UNUSED_STACK
   Serial.print(F("\nUnused stack: "));
   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) {
@@ -476,7 +490,7 @@ void testSensor() {
   const uint32_t interval = 200000;
   int32_t diff;
   data_t data;
-  serialClearInput();
+  clearSerialInput();
   Serial.println(F("\nTesting - type any character to stop\n"));
   delay(1000);
   printRecord(&Serial, nullptr);
@@ -538,7 +552,7 @@ void setup() {
 void loop() {
   printUnusedStack();
   // Read any Serial data.
-  serialClearInput();
+  clearSerialInput();
 
   if (ERROR_LED_PIN >= 0) {
     digitalWrite(ERROR_LED_PIN, LOW);

+ 5 - 5
examples/OpenNext/OpenNext.ino

@@ -8,7 +8,7 @@
 #define SD_FAT_TYPE 0
 /*
   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:
   Arduino Ethernet shield: pin 4
   Sparkfun SD shield: pin 8
@@ -57,12 +57,12 @@ FsFile file;
 //------------------------------------------------------------------------------
 void setup() {
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
     SysCall::yield();
   }
-  
+
   Serial.println("Type any character to start");
   while (!Serial.available()) {
     SysCall::yield();
@@ -72,7 +72,7 @@ void setup() {
   if (!sd.begin(SD_CONFIG)) {
     sd.initErrorHalt(&Serial);
   }
-  // Open root directory 
+  // Open root directory
   if (!dir.open("/")){
     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");
 }
 
+void clearSerialInput() {
+  uint32_t m = micros();
+  do {
+    if (Serial.read() >= 0) {
+      m = micros();
+    }
+  } while (micros() - m < 10000);
+}
+
 void reformatMsg() {
   cout << F("Try reformatting the card.  For best results use\n");
   cout << F("the SdFormatter program in SdFat/examples or download\n");
@@ -88,9 +97,7 @@ void setup() {
 bool firstTry = true;
 void loop() {
   // Read any existing Serial data.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
 
   if (!firstTry) {
     cout << F("\nRestarting\n");
@@ -171,9 +178,8 @@ void loop() {
     return;
   }
   // Read any extra Serial data.
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read() >= 0);
+  clearSerialInput();
+
   cout << F("\nSuccess!  Type any character to restart.\n");
   while (!Serial.available()) {
     SysCall::yield();

+ 15 - 15
examples/ReadCsvFile/ReadCsvFile.ino

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

+ 106 - 14
examples/RtcTimestampTest/RtcTimestampTest.ino

@@ -4,13 +4,19 @@
 #include "SdFat.h"
 // https://github.com/adafruit/RTClib
 #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,
 // 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
 #define SD_FAT_TYPE 0
 /*
   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:
   Arduino Ethernet shield: pin 4
   Sparkfun SD shield: pin 8
@@ -50,7 +56,19 @@ FsFile file;
 #error Invalid SD_FAT_TYPE
 #endif  // SD_FAT_TYPE
 
+
+#if RTC_TYPE == 0
+RTC_Millis rtc;
+#elif RTC_TYPE == 1
 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().
 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.
   *time = FS_TIME(now.hour(), now.minute(), now.second());
-  
+
   // Return low time bits in units of 10 ms, 0 <= ms10 <= 199.
   *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) {
   if (sep) {
     pr->write(sep);
-  }  
+  }
   if (v < 10) {
     pr->write('0');
   }
   pr->print(v);
 }
-//------------------------------------------------------------------------------  
+//------------------------------------------------------------------------------
 void printNow(Print* pr) {
   DateTime now = rtc.now();
   pr->print(now.year());
   printField(pr, '-',now.month());
-  printField(pr, '-',now.day());  
+  printField(pr, '-',now.day());
   printField(pr, ' ',now.hour());
   printField(pr, ':',now.minute());
   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() {
   Serial.begin(9600);
   while (!Serial) {
     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()) {
     Serial.println(F("rtc.begin failed"));
     return;
   }
   if (!rtc.isrunning()) {
-    Serial.println("RTC is NOT running!");
+    Serial.println(F("RTC is NOT running!"));
     return;
     // following line sets the RTC to the date & time this sketch was compiled
     // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
@@ -108,13 +191,22 @@ void setup() {
     // January 21, 2014 at 3am you would call:
     // 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();
 
   // Set callback
   FsDateTime::setCallback(dateTime);
-  
+
   if (!sd.begin(SD_CONFIG)) {
     sd.initErrorHalt(&Serial);
   }
@@ -130,7 +222,7 @@ void setup() {
   file.print(F("Test file at: "));
   printNow(&file);
   file.println();
-  
+
   file.close();
   // List files in SD root.
   sd.ls(LS_DATE | LS_SIZE);

+ 6 - 6
examples/STM32Test/STM32Test.ino

@@ -7,7 +7,7 @@
 #include "FreeStack.h"
 
 // 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;
 FsFile file1;
 
@@ -36,7 +36,7 @@ void errorHalt() {
 //------------------------------------------------------------------------------
 void setup() {
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
     SysCall::yield();
   }
@@ -65,7 +65,7 @@ void setup() {
   }
   // Make Dir1 the working directory on sd1.
   if (!sd1.chdir("Dir1")) {
-     error("dsd1.chdir");   
+     error("dsd1.chdir");
   }
   // initialize the second card
   if (!sd2.begin(SD2_CONFIG)) {
@@ -79,8 +79,8 @@ void setup() {
   }
   // Make Dir2 the working directory on sd2.
   if (!sd2.chdir("Dir2")) {
-     error("sd2.chdir");   
-  }  
+     error("sd2.chdir");
+  }
   // remove test.bin from /Dir1 directory of sd1
   if (sd1.exists("test.bin")) {
     if (!sd1.remove("test.bin")) {
@@ -144,7 +144,7 @@ void setup() {
   // close test.bin
   file1.close();
   // sync copy.bin so ls works.
-  file2.close(); 
+  file2.close();
   // list directories.
   Serial.println(F("------sd1 -------"));
   sd1.ls("/", LS_R | LS_SIZE);

+ 12 - 6
examples/SdFormatter/SdFormatter.ino

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

+ 10 - 3
examples/SdInfo/SdInfo.ino

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

+ 2 - 2
examples/SoftwareSpi/SoftwareSpi.ino

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

+ 9 - 9
examples/TeensyRtcTimestamp/TeensyRtcTimestamp.ino

@@ -9,7 +9,7 @@
 #define SD_FAT_TYPE 3
 /*
   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:
   Arduino Ethernet shield: pin 4
   Sparkfun SD shield: pin 8
@@ -52,13 +52,13 @@ FsFile file;
 //------------------------------------------------------------------------------
 // Call back for file timestamps.  Only called for file create and sync().
 void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) {
-  
+
   // Return date using FS_DATE macro to format fields.
   *date = FS_DATE(year(), month(), day());
 
   // Return time using FS_TIME macro to format fields.
   *time = FS_TIME(hour(), minute(), second());
-  
+
   // Return low time bits in units of 10 ms.
   *ms10 = second() & 1 ? 100 : 0;
 }
@@ -71,17 +71,17 @@ time_t getTeensy3Time()
 void printField(Print* pr, char sep, uint8_t v) {
   if (sep) {
     pr->write(sep);
-  }  
+  }
   if (v < 10) {
     pr->write('0');
   }
   pr->print(v);
 }
-//------------------------------------------------------------------------------  
+//------------------------------------------------------------------------------
 void printNow(Print* pr) {
   pr->print(year());
   printField(pr, '-', month());
-  printField(pr, '-', day());  
+  printField(pr, '-', day());
   printField(pr, ' ', hour());
   printField(pr, ':', minute());
   printField(pr, ':', second());
@@ -90,7 +90,7 @@ void printNow(Print* pr) {
 void setup() {
   // set the Time library to use Teensy 3.0's RTC to keep time
   setSyncProvider(getTeensy3Time);
-  
+
   Serial.begin(9600);
   while (!Serial) {
     yield();
@@ -109,7 +109,7 @@ void setup() {
 
   // Set callback
   FsDateTime::setCallback(dateTime);
-  
+
   if (!sd.begin(SD_CONFIG)) {
     sd.initErrorHalt(&Serial);
   }
@@ -125,7 +125,7 @@ void setup() {
   file.print(F("Test file at: "));
   printNow(&file);
   file.println();
-  
+
   file.close();
   // List files in SD root.
   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.
 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) {
   Serial.print("Error: ");
   Serial.println(msg);
@@ -63,7 +72,7 @@ void errorHalt(const char* msg) {
     Serial.print(", ErrorData: 0X");
     Serial.println(sd.sdErrorData(), HEX);
   }
-  while (true) {} 
+  while (true) {}
 }
 bool ready = false;
 //------------------------------------------------------------------------------
@@ -94,14 +103,14 @@ void runTest() {
   totalMicros = 0;
   yieldMicros = 0;
   yieldCalls = 0;
-  yieldMaxUsec = 0; 
+  yieldMaxUsec = 0;
   if (!file.open("TeensyDemo.bin", O_RDWR | O_CREAT)) {
     errorHalt("open failed");
   }
   Serial.println("\nsize,write,read");
   Serial.println("bytes,KB/sec,KB/sec");
   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)) {
       errorHalt("truncate failed");
     }
@@ -123,19 +132,19 @@ void runTest() {
     Serial.print(',');
     file.rewind();
     t = micros();
-    
+
     for (uint32_t n = 0; n < nRdWr; n++) {
       if ((int)nb != file.read(buf, nb)) {
         errorHalt("read failed");
       }
-      // crude check of data.     
+      // crude check of data.
       if (buf32[0] != n || buf32[nb/4 - 1] != n) {
         errorHalt("data check");
       }
     }
     t = micros() - t;
-    totalMicros += t;   
-    Serial.println(1000.0*FILE_SIZE/t);    
+    totalMicros += t;
+    Serial.println(1000.0*FILE_SIZE/t);
   }
   file.close();
   Serial.print("\ntotalMicros  ");
@@ -145,7 +154,7 @@ void runTest() {
   Serial.print("yieldCalls   ");
   Serial.println(yieldCalls);
   Serial.print("yieldMaxUsec ");
-  Serial.println(yieldMaxUsec); 
+  Serial.println(yieldMaxUsec);
 //  Serial.print("kHzSdClk     ");
 //  Serial.println(kHzSdClk());
   Serial.println("Done");
@@ -166,9 +175,7 @@ void loop() {
       "SPI mode so do SDIO tests first.\n"
       "\nCycle power on the card if an error occurs.");
   }
-  do {
-    delay(10);
-  } while (Serial.available() && Serial.read());
+  clearSerialInput();
 
   Serial.println(
     "\nType '1' for FIFO SDIO"
@@ -198,7 +205,7 @@ void loop() {
     if (!sd.begin(SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(50)))) {
       errorHalt("begin failed");
     }
-    Serial.println("\nShared SPI mode - slow for small transfers.");    
+    Serial.println("\nShared SPI mode - slow for small transfers.");
   } else {
     Serial.println("Invalid input");
     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.
 // 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.
 #define SD_CS_PIN SS
@@ -34,11 +34,11 @@ void setup() {
     sd.initErrorHalt(&Serial);
   }
   sd.ls(&Serial, LS_SIZE);
-  
+
   Serial.print(F("sdCsInit calls: "));
   Serial.println(initCalls);
   Serial.print(F("sdCsWrite calls: "));
-  Serial.println(writeCalls); 
+  Serial.println(writeCalls);
 }
 //------------------------------------------------------------------------------
 void loop() {}

+ 2 - 2
examples/UserSPIDriver/UserSPIDriver.ino

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

+ 10 - 4
examples/bench/bench.ino

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -18,8 +18,8 @@ ArduinoOutStream cout(Serial);
 void setup() {
   int c;
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
     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) {
   // 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);
   SPI.transfer(registerAddress);
   SPI.transfer(value);
   digitalWrite(ADXL345_CS, HIGH);
-  SPI.endTransaction();  
+  SPI.endTransaction();
 }
 
 void userSetup() {
@@ -32,7 +32,7 @@ void userSetup() {
   //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
   writeADXL345Register(DATA_FORMAT, 0x01);
   //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.
@@ -45,7 +45,7 @@ void acquireData(data_t* data) {
   SPI.transfer(DATAX0 | 0XC0);
   data->accel[0] = 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);
   SPI.endTransaction();
 }

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

@@ -9,7 +9,7 @@ static uint32_t startMicros;
 // Acquire a data record.
 void acquireData(data_t* data) {
   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);
 }
 
@@ -21,7 +21,7 @@ void userSetup() {
 #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
   Fastwire::setup(400, true);
 #endif
-  mpu.initialize();  
+  mpu.initialize();
 }
 
 // Print a data record.

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

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

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

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

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

@@ -45,8 +45,8 @@ ArduinoOutStream cout(Serial);
 //------------------------------------------------------------------------------
 void setup(void) {
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
     SysCall::yield();
   }
@@ -101,7 +101,7 @@ void loop(void) {
   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 time: ") << TEST_TIME_SEC << F(" seconds\n");
-  
+
   // tell card to setup for multiple block write with pre-erase
   if (!sd.card()->writeStart(bgnBlock, BLOCK_COUNT)) {
     error("writeStart failed");
@@ -173,7 +173,7 @@ void loop(void) {
   cout << F(" seconds\n");
   cout << F("Min block write time: ") << minWriteTime << 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
   file.close();
   Serial.println();

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

@@ -30,7 +30,7 @@ File file;
  * delim - csv delimiter.
  *
  * 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) {
   char ch;
@@ -129,8 +129,8 @@ int csvReadFloat(File* file, float* num, char delim) {
 //------------------------------------------------------------------------------
 void setup() {
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
     yield();
   }
@@ -144,8 +144,8 @@ void setup() {
     return;
   }
   // Remove existing file.
-   SD.remove("READTEST.TXT"); 
-   
+   SD.remove("READTEST.TXT");
+
   // Create the file.
   file = SD.open("READTEST.TXT", FILE_WRITE);
   if (!file) {
@@ -169,7 +169,7 @@ void setup() {
   file.seek(0);
 
   // Read the file and print fields.
-  int16_t tcalc; 
+  int16_t tcalc;
   float t1, t2, h1, h2;
   // Must be dim 9 to allow for zero byte.
   char timeS[9], dateS[9];
@@ -188,7 +188,7 @@ void setup() {
       while ((ch = file.read()) > 0 && nr++ < 100) {
         Serial.write(ch);
       }
-      break;            
+      break;
     }
     Serial.print(tcalc);
     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() {
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
     SysCall::yield();
   }
@@ -63,7 +63,7 @@ void setup() {
   // Initialize the SD.
   if (!SD.begin(CS_PIN)) {
     errorHalt("begin failed");
-  } 
+  }
   // Create or open the file.
   file = SD.open("READNUM.TXT", FILE_WRITE);
   if (!file) {
@@ -93,7 +93,7 @@ void setup() {
   char *ptr;     // Test for valid field.
 
   // Read the file and store the data.
-  
+
   for (i = 0; i < ROW_DIM; i++) {
     for (j = 0; j < COL_DIM; j++) {
       n = readField(&file, str, sizeof(str), ",\n");
@@ -117,7 +117,7 @@ void setup() {
     // Allow missing endl at eof.
     if (str[n-1] != '\n' && file.available()) {
       errorHalt("missing endl");
-    }    
+    }
   }
 
   // Print the array.

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

@@ -92,14 +92,14 @@ void writeFile() {
 //------------------------------------------------------------------------------
 void setup() {
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
     SysCall::yield();
   }
   cout << F("Type any character to start\n");
   while (!Serial.available()) {
-    SysCall::yield();  
+    SysCall::yield();
   }
 
   // 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() {
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
   }
 
@@ -151,7 +151,7 @@ void setup() {
   Serial.println(F(" millis"));
   // close test.bin
   file1.close();
-  file2.close(); 
+  file2.close();
   // list current directory on both cards
   Serial.println(F("------sd1 -------"));
   sd1.ls("/", LS_R | LS_DATE | LS_SIZE);

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

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

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

@@ -5,7 +5,7 @@
 #include "SdFat.h"
 #include "sdios.h"
 #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
 /*
  * SD chip select pin.  Common values are:
@@ -143,8 +143,8 @@ void volDmp() {
 //------------------------------------------------------------------------------
 void setup() {
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
     SysCall::yield();
   }
@@ -154,7 +154,7 @@ void setup() {
 
   // F stores strings in flash to save RAM
   cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
-#if !USE_SDIO  
+#if !USE_SDIO
   if (DISABLE_CHIP_SELECT < 0) {
     cout << F(
            "\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("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
-#endif  // !USE_SDIO  
+#endif  // !USE_SDIO
 }
 //------------------------------------------------------------------------------
 void loop() {
@@ -195,7 +195,7 @@ void loop() {
     sdErrorMsg("cardBegin failed");
     return;
   }
- #endif  // USE_SDIO 
+ #endif  // USE_SDIO
   t = millis() - t;
 
   cardSize = sd.card()->cardSize();

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

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

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

@@ -42,7 +42,7 @@ void setup() {
   Serial.println(F("Starting test"));
 
   // 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))) {
     sd.errorHalt();
   }
@@ -146,7 +146,7 @@ void setup() {
             stdioFile.printField(n, '\n');
 #else  // PRINT_FIELD
             stdioFile.println(n);
-#endif  // PRINT_FIELD      
+#endif  // PRINT_FIELD
           }
           break;
 
@@ -157,7 +157,7 @@ void setup() {
               stdioFile.printField(f[i], '\n', 4);
 #else  // PRINT_FIELD
               stdioFile.println(f[i], 4);
-#endif  // PRINT_FIELD                            
+#endif  // PRINT_FIELD
             }
           }
           break;

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

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

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

@@ -53,7 +53,7 @@ void dateTime(uint16_t* date, uint16_t* time) {
 void printTimestamps(SdFile& f) {
   cout << F("Creation: ");
   f.printCreateDateTime(&Serial);
-  cout << endl << F("Modify: ");  
+  cout << endl << F("Modify: ");
   f.printModifyDateTime(&Serial);
   cout << endl << F("Access: ");
   f.printAccessDateTime(&Serial);
@@ -68,7 +68,7 @@ void setup(void) {
   }
   cout << F("Type any character to start\n");
   while (!Serial.available()) {
-    SysCall::yield();  
+    SysCall::yield();
   }
   // Initialize at the highest speed supported by the board that is
   // 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() {
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
     SysCall::yield();
   }
@@ -146,7 +146,7 @@ void setup() {
   Serial.println(F(" millis"));
   // close test.bin
   file1.close();
-  file2.close(); 
+  file2.close();
   // list current directory on both cards
   Serial.println(F("------sd1 -------"));
   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";
 
   Serial.begin(9600);
-  
-  // Wait for USB Serial 
+
+  // Wait for USB Serial
   while (!Serial) {
     SysCall::yield();
   }
@@ -78,7 +78,7 @@ void setup() {
   while (!Serial.available()) {
     SysCall::yield();
   }
-  
+
   // Initialize at the highest speed supported by the board that is
   // not over 50 MHz. Try a lower speed if SPI errors occur.
   if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {

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

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

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

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

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

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

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

@@ -9,7 +9,7 @@ SdFat sd;
 void setup() {
   int c;
   Serial.begin(9600);
-  // Wait for USB Serial 
+  // Wait for USB Serial
   while (!Serial) {
     SysCall::yield();
   }
@@ -22,7 +22,7 @@ void setup() {
     sd.errorHalt("Quitting, you did not type 'Y'.");
   }
   // 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))) {
     sd.initErrorHalt();
   }
@@ -32,7 +32,7 @@ void setup() {
   }
   // Must reinitialize after wipe.
   // 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))) {
     sd.errorHalt("Second init failed.");
   }

+ 153 - 32
extras/cpplint.py

@@ -51,12 +51,19 @@ import sre_compile
 import string
 import sys
 import unicodedata
+import sysconfig
+
+try:
+  xrange          # Python 2
+except NameError:
+  xrange = range  # Python 3
 
 
 _USAGE = """
 Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
                    [--counting=total|toplevel|detailed] [--root=subdir]
                    [--linelength=digits] [--headers=x,y,...]
+                   [--quiet]
         <file> [file] ...
 
   The style guidelines this tries to follow are those in
@@ -83,6 +90,9 @@ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
     verbose=#
       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,...
       Specify a comma-separated list of category-filters to apply: only
       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.
 
       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_
         --root=chrome => BROWSER_UI_BROWSER_H_
         --root=chrome/browser => UI_BROWSER_H_
+        --root=.. => SRC_CHROME_BROWSER_UI_BROWSER_H_
 
     linelength=digits
       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.
 
     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).
 
     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.
 # This is set by --root flag.
 _root = None
+_root_debug = False
 
 # The allowed line length of files.
 # 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
     _valid_extensions.update(_hpp_headers)
   except ValueError:
-    PrintUsage('Header extensions must be comma seperated list.')
+    PrintUsage('Header extensions must be comma separated list.')
 
 def IsHeaderExtension(file_extension):
   return file_extension in _hpp_headers
@@ -859,6 +871,7 @@ class _CppLintState(object):
     self._filters_backup = self.filters[:]
     self.counting = 'total'  # In what way are we counting errors?
     self.errors_by_category = {}  # string to int dict storing error counts
+    self.quiet = False  # Suppress non-error messagess?
 
     # output format:
     # "emacs" - format that emacs can parse (default)
@@ -869,6 +882,12 @@ class _CppLintState(object):
     """Sets the output format for errors."""
     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):
     """Sets the module's verbosity, and returns the previous setting."""
     last_verbose_level = self.verbose_level
@@ -950,6 +969,14 @@ def _SetOutputFormat(output_format):
   """Sets the module's 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():
   """Returns the module's verbosity setting."""
@@ -1356,7 +1383,7 @@ def FindNextMultiLineCommentEnd(lines, lineix):
 
 def RemoveMultiLineCommentsFromRange(lines, begin, end):
   """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.
   for i in range(begin, end):
     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."""
 
   # 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)):
     if re.search(r'Copyright', lines[line], re.I): break
   else:                       # means no copyright line was found
@@ -1754,6 +1781,30 @@ def GetIndentLevel(line):
   else:
     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):
   """Returns the CPP variable that should be used as a header guard.
@@ -1776,13 +1827,58 @@ def GetHeaderGuardCPPVariable(filename):
 
   fileinfo = FileInfo(filename)
   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() + '_'
 
 
@@ -3187,8 +3283,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
   line = clean_lines.elided[linenum]
 
   # 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,
           '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
   # 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:
   #    for (;;) {};
   #    while (...) {};
@@ -3828,11 +3924,11 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
     #  - INTERFACE_DEF
     #  - 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
     # 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.
     #
     # 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'):
         width += 2
       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
     return width
   else:
@@ -5018,19 +5124,19 @@ def CheckForNonConstReference(filename, clean_lines, linenum,
   #
   # We also accept & in static_assert, which looks like a function but
   # it's actually a declaration expression.
-  whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|'
+  allowed_functions = (r'(?:[sS]wap(?:<\w:+>)?|'
                            r'operator\s*[<>][<>]|'
                            r'static_assert|COMPILE_ASSERT'
                            r')\s*\(')
-  if Search(whitelisted_functions, line):
+  if Search(allowed_functions, line):
     return
   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
     # multi-line parameter list.  Try a bit harder to catch this case.
     for i in xrange(2):
       if (linenum > i and
-          Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])):
+          Search(allowed_functions, clean_lines.elided[linenum - i - 1])):
         return
 
   decls = ReplaceAll(r'{[^}]*}', ' ', line)  # exclude function body
@@ -5884,6 +5990,9 @@ def ProcessConfigOverrides(filename):
             if base_name:
               pattern = re.compile(val)
               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". '
                                  'File path component "%s" matches '
                                  'pattern "%s"\n' %
@@ -5897,7 +6006,8 @@ def ProcessConfigOverrides(filename):
                 sys.stderr.write('Line length must be numeric.')
           elif name == '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':
             ProcessHppHeadersOption(val)
           else:
@@ -5934,6 +6044,7 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
 
   _SetVerboseLevel(vlevel)
   _BackupFilters()
+  old_errors = _cpplint_state.error_count
 
   if not ProcessConfigOverrides(filename):
     _RestoreFilters()
@@ -6002,7 +6113,10 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
         Error(filename, linenum, 'whitespace/newline', 1,
               '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()
 
 
@@ -6046,13 +6160,15 @@ def ParseArguments(args):
                                                  'root=',
                                                  'linelength=',
                                                  'extensions=',
-                                                 'headers='])
+                                                 'headers=',
+                                                 'quiet'])
   except getopt.GetoptError:
     PrintUsage('Invalid arguments.')
 
   verbosity = _VerboseLevel()
   output_format = _OutputFormat()
   filters = ''
+  quiet = _Quiet()
   counting_style = ''
 
   for (opt, val) in opts:
@@ -6062,6 +6178,8 @@ def ParseArguments(args):
       if val not in ('emacs', 'vs7', 'eclipse'):
         PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
       output_format = val
+    elif opt == '--quiet':
+      quiet = True
     elif opt == '--verbose':
       verbosity = int(val)
     elif opt == '--filter':
@@ -6086,7 +6204,7 @@ def ParseArguments(args):
       try:
           _valid_extensions = set(val.split(','))
       except ValueError:
-          PrintUsage('Extensions must be comma seperated list.')
+          PrintUsage('Extensions must be comma separated list.')
     elif opt == '--headers':
       ProcessHppHeadersOption(val)
 
@@ -6094,6 +6212,7 @@ def ParseArguments(args):
     PrintUsage('No files were specified.')
 
   _SetOutputFormat(output_format)
+  _SetQuiet(quiet)
   _SetVerboseLevel(verbosity)
   _SetFilters(filters)
   _SetCountingStyle(counting_style)
@@ -6114,7 +6233,9 @@ def main():
   _cpplint_state.ResetErrorCounts()
   for filename in filenames:
     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)
 

+ 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
-version=2.0.1
+version=2.0.2
 license=MIT
 author=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/>.
  */
 /**
- * @file 
+ * @file
  * @brief  Software SPI.
  *
  * @defgroup softSPI Software SPI

+ 242 - 238
src/ExFatLib/ExFatDbg.cpp

@@ -25,31 +25,118 @@
 #include "ExFatVolume.h"
 #include "upcase.h"
 #include "ExFatFile.h"
-#include "../common/FsDateTime.h"
 #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) {
@@ -104,28 +191,6 @@ static void printHex(print_t* pr, uint8_t h) {
   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) {
   bool space = true;
   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(' ');
-      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(' ');
-    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) {
   bool skip = false;
   uint16_t u = 0;
@@ -430,6 +337,66 @@ void ExFatPartition::checkUpcase(print_t* pr) {
   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) {
   DirGeneric_t* dir = nullptr;
   DirFile_t* dirFile;
@@ -547,6 +514,21 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
   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) {
   uint8_t* upcase = nullptr;
   uint32_t sector;
@@ -593,5 +575,27 @@ void ExFatPartition::printUpcase(print_t* pr) {
   printHex(pr, checksum);
   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
-

+ 90 - 54
src/ExFatLib/ExFatFile.cpp

@@ -27,7 +27,7 @@
 #include "ExFatFile.h"
 #include "ExFatVolume.h"
 #include "upcase.h"
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::close() {
   bool rtn = sync();
   m_attributes = FILE_ATTR_CLOSED;
@@ -35,6 +35,20 @@ bool ExFatFile::close() {
   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) {
   pos->position = m_curPosition;
   pos->cluster = m_curCluster;
@@ -68,12 +82,61 @@ int ExFatFile::fgets(char* str, int num, char* delim) {
   return n;
 }
 //------------------------------------------------------------------------------
+uint32_t ExFatFile::firstSector() {
+  return m_firstCluster ? m_vol->clusterStartSector(m_firstCluster) : 0;
+}
+//------------------------------------------------------------------------------
 void ExFatFile::fsetpos(const fspos_t* pos) {
   m_curPosition = pos->position;
   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;
   DirPos_t pos = m_dirPos;
   size_t n = 0;
@@ -108,11 +171,11 @@ size_t ExFatFile::getName(ExChar_t *name, size_t length) {
   *name = 0;
   return 0;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::open(const ExChar_t* path, int oflag) {
   return open(ExFatVolume::cwv(), path, oflag);
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::open(ExFatVolume* vol, const ExChar_t* path, int 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);
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -170,7 +233,7 @@ bool ExFatFile::open(ExFatFile* dirFile, uint32_t index, oflag_t oflag) {
   }
   return false;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::openNext(ExFatFile* dir, oflag_t oflag) {
   if (isOpen() || !dir->isDir() || (dir->curPosition() & 0X1F)) {
     DBG_FAIL_MACRO;
@@ -400,13 +463,23 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name,
       dirFile->type = EXFAT_TYPE_FILE;
       m_setCount = freeNeed - 1;
       dirFile->setCount = m_setCount;
+
       if (FsDateTime::callback) {
         uint16_t date, time;
         uint8_t ms10;
         FsDateTime::callback(&date, &time, &ms10);
-        dirFile->createTimeMs = ms10;
-        setLe16(dirFile->createTime, time);
         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) {
       dirStream = reinterpret_cast<DirStream_t*>(cache);
@@ -438,7 +511,7 @@ bool ExFatFile::openRootFile(ExFatFile* dir, const ExChar_t* name,
   m_flags = 0;
   return false;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatFile::openRoot(ExFatVolume* vol) {
   if (isOpen()) {
     DBG_FAIL_MACRO;
@@ -494,7 +567,7 @@ bool ExFatFile::parsePathName(const ExChar_t* path,
   fname->len = len;
   return true;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 int ExFatFile::peek() {
   uint64_t curPosition = m_curPosition;
   uint32_t curCluster = m_curCluster;
@@ -503,44 +576,7 @@ int ExFatFile::peek() {
   m_curCluster = curCluster;
   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) {
   uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
   int8_t fg;
@@ -604,7 +640,7 @@ int ExFatFile::read(void* buf, size_t count) {
 #if USE_MULTI_SECTOR_IO
     } else if (toRead >= 2*m_vol->bytesPerSector()) {
       uint32_t ns = toRead >> m_vol->bytesPerSectorShift();
-      // Limit writes to current cluster.
+      // Limit reads to current cluster.
       uint32_t maxNs = m_vol->sectorsPerCluster()
                        - (clusterOffset >> m_vol->bytesPerSectorShift());
       if (ns > maxNs) {
@@ -639,7 +675,7 @@ int ExFatFile::read(void* buf, size_t count) {
   }
   return count - toRead;
 
-fail:
+ fail:
   m_error |= READ_ERROR;
   return -1;
 }
@@ -652,7 +688,7 @@ bool ExFatFile::remove(const ExChar_t* path) {
   }
   return file.remove();
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -702,11 +738,11 @@ bool ExFatFile::seekSet(uint64_t pos) {
     }
   }
 
-done:
+ done:
   m_curPosition = pos;
   return true;
 
-fail:
+ fail:
   m_curCluster = tmp;
   return false;
 }

+ 51 - 12
src/ExFatLib/ExFatFile.h

@@ -118,7 +118,7 @@ class ExFatFile {
   /** \return The number of bytes available from the current position
    * 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.
    *
@@ -133,6 +133,16 @@ class ExFatFile {
    * \return true for success or false for failure.
    */
   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. */
   uint64_t curPosition() const {return m_curPosition;}
 
@@ -163,8 +173,8 @@ class ExFatFile {
    * Get a string from a file.
    *
    * 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.
    *
    * 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".
    *
    * \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);
   /** \return The total number of bytes in a file. */
   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
    */
   void fsetpos(const fspos_t* pos);
@@ -195,19 +208,43 @@ class ExFatFile {
    * \param[in] size The size of the array in characters.
    * \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. */
   void clearError() {
     m_error = 0;
   }
-  /** Set writeError to zero */
+  /** Clear writeError. */
   void clearWriteError() {
     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. */
   uint8_t getError() {
     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 */
   bool getWriteError() {
     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
    * 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
-   * 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
    * or file corruption may occur.
@@ -586,10 +625,10 @@ class ExFatFile {
    */
   /** 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.
    *

+ 80 - 55
src/ExFatLib/ExFatFilePrint.cpp

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

+ 7 - 7
src/ExFatLib/ExFatFormatter.cpp

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

+ 76 - 76
src/ExFatLib/ExFatPartition.cpp

@@ -26,12 +26,7 @@
 #include "../common/DebugMacros.h"
 #include "ExFatVolume.h"
 #include "../common/FsStructs.h"
-//-----------------------------------------------------------------------------
-void FsCache::invalidate() {
-  m_status = 0;
-  m_sector = 0XFFFFFFFF;
-}
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint8_t* FsCache::get(uint32_t sector, uint8_t option) {
   if (!m_blockDev) {
     DBG_FAIL_MACRO;
@@ -54,10 +49,15 @@ uint8_t* FsCache::get(uint32_t sector, uint8_t option) {
   m_status |= option & CACHE_STATUS_MASK;
   return m_cacheBuffer;
 
-fail:
+ fail:
   return nullptr;
 }
 //------------------------------------------------------------------------------
+void FsCache::invalidate() {
+  m_status = 0;
+  m_sector = 0XFFFFFFFF;
+}
+//------------------------------------------------------------------------------
 bool FsCache::sync() {
   if (m_status & CACHE_STATUS_DIRTY) {
     if (!m_blockDev->writeSector(m_sector, m_cacheBuffer)) {
@@ -68,68 +68,10 @@ bool FsCache::sync() {
   }
   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:
   return false;
 }
-//-----------------------------------------------------------------------------
+//==============================================================================
 // return 0 if error, 1 if no space, else start cluster.
 uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
   uint32_t start = cluster ? cluster - 2 : m_bitmapStart;
@@ -178,7 +120,7 @@ uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) {
   }
   return 0;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatPartition::bitmapModify(uint32_t cluster,
                                   uint32_t count, bool value) {
   uint32_t sector;
@@ -229,7 +171,7 @@ bool ExFatPartition::bitmapModify(uint32_t cluster,
  fail:
   return false;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint32_t ExFatPartition::chainSize(uint32_t cluster) {
   uint32_t n = 0;
   int8_t status;
@@ -240,14 +182,14 @@ uint32_t ExFatPartition::chainSize(uint32_t cluster) {
   } while (status);
   return n;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint8_t* ExFatPartition::dirCache(DirPos_t* pos, uint8_t options) {
   uint32_t sector = clusterStartSector(pos->cluster);
   sector += (m_clusterMask & pos->position) >> m_bytesPerSectorShift;
   uint8_t* cache = dataCacheGet(sector, options);
   return cache ? cache + (pos->position & m_sectorMask) : nullptr;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 // return -1 error, 0 EOC, 1 OK
 int8_t ExFatPartition::dirSeek(DirPos_t* pos, uint32_t offset) {
   int8_t status;
@@ -266,10 +208,10 @@ int8_t ExFatPartition::dirSeek(DirPos_t* pos, uint32_t offset) {
   }
   return 1;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint8_t ExFatPartition::fatGet(uint32_t cluster, uint32_t* value) {
   uint8_t* cache;
-uint32_t next;
+  uint32_t next;
   uint32_t sector;
 
   if (cluster > (m_clusterCount + 1)) {
@@ -290,7 +232,7 @@ uint32_t next;
   *value = next;
   return 1;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatPartition::fatPut(uint32_t cluster, uint32_t value) {
   uint32_t sector;
   uint8_t* cache;
@@ -310,7 +252,7 @@ bool ExFatPartition::fatPut(uint32_t cluster, uint32_t value) {
  fail:
   return false;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool ExFatPartition::freeChain(uint32_t cluster) {
   uint32_t next;
   uint32_t start = cluster;
@@ -340,7 +282,7 @@ bool ExFatPartition::freeChain(uint32_t cluster) {
  fail:
   return false;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 uint32_t ExFatPartition::freeClusterCount() {
   uint32_t nc = 0;
   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 nc = chainSize(m_rootDirectoryCluster);
   return nc << bytesPerClusterShift();

+ 12 - 12
src/ExFatLib/ExFatPartition.h

@@ -110,7 +110,7 @@ class FsCache {
   uint32_t m_sector;
   uint8_t m_cacheBuffer[512];
 };
-//=============================================================================
+//==============================================================================
 /**
  * \class ExFatPartition
  * \brief Access exFat partitions on raw file devices.
@@ -119,15 +119,15 @@ class ExFatPartition {
  public:
   ExFatPartition() : m_fatType(0) {}
   /** \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. */
-  uint8_t bytesPerClusterShift() {
+  uint8_t bytesPerClusterShift() const {
     return m_bytesPerSectorShift + m_sectorsPerClusterShift;
   }
   /** \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. */
-  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.
    * \return A pointer to the cache buffer or zero if an error occurs.
@@ -136,13 +136,13 @@ class ExFatPartition {
     return m_dataCache.clear();
   }
   /** \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. */
-  uint32_t clusterHeapStartSector() {return m_clusterHeapStartSector;}
+  uint32_t clusterHeapStartSector() const {return m_clusterHeapStartSector;}
   /** \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. */
-  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. */
   uint8_t fatType() const {return m_fatType;}
   /** \return the free cluster count. */
@@ -158,17 +158,17 @@ class ExFatPartition {
    */
   bool init(BlockDevice* dev, uint8_t part);
   /** \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. */
   uint32_t rootLength();
   /** \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
   // Use sectorsPerCluster(). blocksPerCluster() will be removed in the future.
   uint32_t blocksPerCluster() __attribute__ ((deprecated)) {return sectorsPerCluster();} //NOLINT
 #endif  // DOXYGEN_SHOULD_SKIP_THIS
   /** \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
   void checkUpcase(print_t* pr);

+ 2 - 2
src/ExFatLib/ExFatVolume.cpp

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

+ 1 - 1
src/ExFatLib/ExFatVolume.h

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

+ 48 - 49
src/ExFatLib/upcase.cpp

@@ -47,7 +47,7 @@ struct pair16 {
   uint16_t val;
 };
 typedef struct pair16 pair16_t;
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 static const map16_t mapTable[] TABLE_MEM = {
   {0X0061, -32,  26},
   {0X00E0, -32,  23},
@@ -104,7 +104,7 @@ static const map16_t mapTable[] TABLE_MEM = {
   {0XFF41, -32,  26},
 };
 const size_t MAP_DIM = sizeof(mapTable)/sizeof(map16_t);
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 static const pair16_t lookupTable[] TABLE_MEM = {
   {0X00FF, 0X0178},
   {0X0180, 0X0243},
@@ -183,17 +183,7 @@ static const pair16_t lookupTable[] TABLE_MEM = {
   {0X2C76, 0X2C75},
 };
 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) {
   size_t left = 0;
   size_t right = size;
@@ -208,29 +198,11 @@ static size_t searchPair16(const pair16_t* table, size_t size, uint16_t key) {
   }
   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,
                   const ExChar16_t* name, size_t offset, size_t n) {
   uint16_t u;
@@ -242,11 +214,28 @@ bool exFatCmpName(const DirName_t* unicode,
   }
   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) {
   for (size_t i = 0; i < n; i++) {
     uint8_t c = name[i];
@@ -258,19 +247,29 @@ uint16_t exFatHashName(const char* name, size_t n, uint16_t 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) {
   sum = (sum << 31) + (sum >> 1) + (uc & 0XFF);
   sum = (sum << 31) + (sum >> 1) + (uc >> 8);

+ 0 - 1
src/FatLib/FatDbg.cpp

@@ -24,7 +24,6 @@
  */
 #include "FatVolume.h"
 #include "FatFile.h"
-#include "../common/FsDateTime.h"
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 //------------------------------------------------------------------------------
 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();
   return true;
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -103,7 +103,7 @@ DirFat_t* FatFile::cacheDirEntry(uint8_t action) {
   }
   return pc->dir + (m_dirIndex & 0XF);
 
-fail:
+ fail:
   return nullptr;
 }
 //------------------------------------------------------------------------------
@@ -116,7 +116,7 @@ bool FatFile::close() {
 //------------------------------------------------------------------------------
 bool FatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
   // error if no clusters
-  if (m_firstCluster == 0) {
+  if (!isFile() || m_firstCluster == 0) {
     DBG_FAIL_MACRO;
     goto fail;
   }
@@ -148,7 +148,7 @@ bool FatFile::contiguousRange(uint32_t* bgnSector, uint32_t* endSector) {
     }
   }
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -161,7 +161,7 @@ bool FatFile::createContiguous(const char* path, uint32_t size) {
     return true;
   }
   close();
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -175,33 +175,6 @@ bool FatFile::createContiguous(FatFile* dirFile,
     return true;
   }
   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:
   return false;
 }
@@ -223,7 +196,7 @@ bool FatFile::dirEntry(DirFat_t* dst) {
   memcpy(dst, dir, sizeof(DirFat_t));
   return true;
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -289,6 +262,47 @@ void FatFile::fsetpos(const fspos_t* pos) {
   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) {
   fname_t fname;
   FatFile tmpDir;
@@ -327,7 +341,7 @@ bool FatFile::mkdir(FatFile* parent, const char* path, bool pFlag) {
   }
   return mkdir(parent, &fname);
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -397,10 +411,10 @@ bool FatFile::mkdir(FatFile* parent, fname_t* fname) {
   // write first sector
   return m_vol->cacheSync();
 
-fail:
+ fail:
   return false;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatFile::open(const char* path, oflag_t 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);
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -574,7 +588,7 @@ bool FatFile::openCachedEntry(FatFile* dirFile, uint16_t dirIndex,
   }
   return true;
 
-fail:
+ fail:
   m_attributes = FILE_ATTR_CLOSED;
   m_flags = 0;
   return false;
@@ -629,7 +643,7 @@ bool FatFile::openNext(FatFile* dirFile, oflag_t oflag) {
     }
   }
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -662,7 +676,34 @@ bool FatFile::openRoot(FatVolume* vol) {
   m_flags = FILE_FLAG_READ;
   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;
 }
 //------------------------------------------------------------------------------
@@ -790,7 +831,7 @@ int FatFile::read(void* buf, size_t nbyte) {
   }
   return nbyte - toRead;
 
-fail:
+ fail:
   m_error |= READ_ERROR;
   return -1;
 }
@@ -842,7 +883,7 @@ DirFat_t* FatFile::readDirCache(bool skipReadOk) {
   // return pointer to entry
   return reinterpret_cast<DirFat_t*>(m_vol->cacheAddress()) + i;
 
-fail:
+ fail:
   return nullptr;
 }
 //------------------------------------------------------------------------------
@@ -854,7 +895,7 @@ bool FatFile::remove(const char* path) {
   }
   return file.remove();
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -966,7 +1007,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) {
   }
   return m_vol->cacheSync();
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -1008,7 +1049,7 @@ bool FatFile::rmdir() {
   m_flags |= FILE_FLAG_WRITE;
   return remove();
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -1083,7 +1124,7 @@ bool FatFile::rmRfStar() {
   }
   return true;
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -1117,9 +1158,16 @@ bool FatFile::seekSet(uint32_t pos) {
     DBG_FAIL_MACRO;
     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());
+#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) {
     // must follow chain from first cluster
@@ -1135,12 +1183,12 @@ bool FatFile::seekSet(uint32_t pos) {
     }
   }
 
-done:
+ done:
   m_curPosition = pos;
   m_flags &= ~FILE_FLAG_PREALLOCATE;
   return true;
 
-fail:
+ fail:
   m_curCluster = tmp;
   return false;
 }
@@ -1182,7 +1230,7 @@ bool FatFile::sync() {
   }
   DBG_FAIL_MACRO;
 
-fail:
+ fail:
   m_error |= WRITE_ERROR;
   return false;
 }
@@ -1233,7 +1281,7 @@ bool FatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
   }
   return m_vol->cacheSync();
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -1436,7 +1484,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) {
   }
   return nbyte;
 
-fail:
+ fail:
   // return for write error
   m_error |= WRITE_ERROR;
   return -1;

+ 54 - 9
src/FatLib/FatFile.h

@@ -151,10 +151,49 @@ class FatFile {
   }
   /** \return Directory entry index. */
   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. */
   uint8_t getError() {
     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 */
   bool getWriteError() {
     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] 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.
    */
   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.
    *
    * \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.
    *
    * \return true for success or false for failure.
@@ -212,7 +253,7 @@ class FatFile {
                         const char* path, uint32_t 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.
    *
    * \return true for success or false for failure.
@@ -263,8 +304,8 @@ class FatFile {
    * Get a string from a file.
    *
    * 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.
    *
    * 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".
    *
    * \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);
 
@@ -287,7 +329,7 @@ class FatFile {
   }
   /** \return first sector of file or zero for empty file. */
   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;
   /**
    * 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
    * 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
-   * 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
    * or file corruption may occur.
@@ -873,7 +917,8 @@ class FatFile {
    * \return For success write() returns the number of bytes written, always
    * \a count.  If an error occurs, write() returns -1.  Possible errors
    * 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);

+ 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.
  * \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) {
     return getLe16(ldir->unicode1 + 2*i);
   } else if (i < 11) {
@@ -70,7 +70,7 @@ static uint16_t lfnGetChar(DirLfn_t *ldir, uint8_t i) {
   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;
   size_t k = 13*((ldir->order & 0X1F) - 1);
   for (i = 0; i < 13; i++) {
@@ -104,7 +104,7 @@ inline bool lfnLegalChar(uint8_t c) {
  * \param[in] i Index of 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) {
     setLe16(ldir->unicode1 + 2*i, c);
   } 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);
   for (uint8_t i = 0; i < 13; i++, k++) {
     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.
   DBG_FAIL_MACRO;
 
-fail:
+ fail:
   name[0] = 0;
   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.
   if (oflag & O_EXCL) {
     DBG_FAIL_MACRO;
@@ -412,7 +412,7 @@ found:
   }
   goto open;
 
-create:
+ create:
   // don't create unless O_CREAT and write mode
   if (!(oflag & O_CREAT) || !isWriteMode(oflag)) {
     DBG_FAIL_MACRO;
@@ -484,21 +484,26 @@ create:
   // Set base-name and extension lower case bits.
   dir->caseFlags =  (FAT_CASE_LC_BASE | FAT_CASE_LC_EXT) & fname->flags;
 
-  // set timestamps
+  // Set timestamps.
   if (FsDateTime::callback) {
     // call user date/time function
     FsDateTime::callback(&date, &time, &ms10);
-    dir->createTimeMs = ms10;
     setLe16(dir->createDate, date);
     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.
   dirFile->m_vol->cacheDirty();
 
-open:
+ open:
   // open entry in cache.
   if (!openCachedEntry(dirFile, curIndex, oflag, lfnOrd)) {
     DBG_FAIL_MACRO;
@@ -506,7 +511,7 @@ open:
   }
   return true;
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -553,7 +558,7 @@ size_t FatFile::printName(print_t* pr) {
   }
   return n;
 
-fail:
+ fail:
   return 0;
 }
 //------------------------------------------------------------------------------
@@ -632,14 +637,14 @@ bool FatFile::remove() {
   // Fall into fail.
   DBG_FAIL_MACRO;
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
 bool FatFile::lfnUniqueSfn(fname_t* fname) {
   const uint8_t FIRST_HASH_SEQ = 2;  // min value is 2
   uint8_t pos = fname->seqPos;;
-  DirFat_t *dir;
+  DirFat_t* dir;
   uint16_t hex;
 
   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.
   DBG_FAIL_MACRO;
 
-fail:
+ fail:
   return false;
 
-done:
+ done:
   return true;
 }
 #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) {
-  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;
 }
 //------------------------------------------------------------------------------
 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;
 }
 //------------------------------------------------------------------------------
 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;
 }
 //------------------------------------------------------------------------------

+ 17 - 12
src/FatLib/FatFileSFN.cpp

@@ -31,7 +31,7 @@
 bool FatFile::getSFN(char* name) {
   uint8_t j = 0;
   uint8_t lcBit = FAT_CASE_LC_BASE;
-  DirFat_t *dir;
+  DirFat_t* dir;
 
   if (!isOpen()) {
     DBG_FAIL_MACRO;
@@ -67,7 +67,7 @@ bool FatFile::getSFN(char* name) {
   name[j] = 0;
   return true;
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -79,7 +79,7 @@ size_t FatFile::printSFN(print_t* pr) {
   }
   return pr->write(name);
 
-fail:
+ fail:
   return 0;
 }
 #if !USE_LONG_FILE_NAMES
@@ -138,7 +138,7 @@ bool FatFile::parsePathName(const char* path, fname_t* fname,
   *ptr = path;
   return true;
 
-fail:
+ fail:
   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.
   dir->caseFlags = (FAT_CASE_LC_BASE | FAT_CASE_LC_EXT) & fname->flags;
 
-  // set timestamps
+  // Set timestamps.
   if (FsDateTime::callback) {
     // call user date/time function
     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->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.
   dirFile->m_vol->cacheDirty();
@@ -259,7 +264,7 @@ bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) {
   // open entry in cache.
   return openCachedEntry(dirFile, index, oflag, 0);
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -295,7 +300,7 @@ bool FatFile::remove() {
   // Write entry to device.
   return m_vol->cacheSync();
 
-fail:
+ fail:
   return false;
 }
 #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_SECTOR_COUNT =
                32*FAT16_ROOT_ENTRY_COUNT/BYTES_PER_SECTOR;
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 #define PRINT_FORMAT_PROGRESS 1
 #if !PRINT_FORMAT_PROGRESS
 #define writeMsg(str)
@@ -44,7 +44,7 @@ const uint16_t FAT16_ROOT_SECTOR_COUNT =
 #else  // PRINT_FORMAT_PROGRESS
 #define writeMsg(str) if (m_pr) m_pr->write(str)
 #endif  // PRINT_FORMAT_PROGRESS
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) {
   bool rtn;
   m_dev = dev;
@@ -80,7 +80,7 @@ bool FatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) {
   }
   return rtn;
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatFormatter::initFatDir(uint8_t fatType, uint32_t sectorCount) {
   size_t n;
   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) &&
          m_dev->writeSector(m_fatStart + m_fatSize, m_secBuf);
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 void FatFormatter::initPbs() {
   PbsFat_t* pbs = reinterpret_cast<PbsFat_t*>(m_secBuf);
   memset(m_secBuf, 0, BYTES_PER_SECTOR);
@@ -128,7 +128,7 @@ void FatFormatter::initPbs() {
   // skip rest of bpb
   setLe16(pbs->signature, PBR_SIGNATURE);
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatFormatter::makeFat16() {
   uint32_t nc;
   uint32_t r;
@@ -180,7 +180,7 @@ bool FatFormatter::makeFat16() {
   }
   return initFatDir(16, m_dataStart - m_fatStart);
 }
-//-----------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 bool FatFormatter::makeFat32() {
   uint32_t nc;
   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;
   return &m_buffer;
 
-fail:
+ fail:
 
   return nullptr;
 }
@@ -69,7 +69,7 @@ bool FatCache::sync() {
   }
   return true;
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -130,7 +130,7 @@ bool FatPartition::allocateCluster(uint32_t current, uint32_t* next) {
   *next = find;
   return true;
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -195,7 +195,7 @@ bool FatPartition::allocContiguous(uint32_t count, uint32_t* firstCluster) {
   *firstCluster = bgnCluster;
   return true;
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -266,7 +266,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) {
   *value = next;
   return 1;
 
-fail:
+ fail:
   return -1;
 }
 //------------------------------------------------------------------------------
@@ -343,7 +343,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) {
     goto fail;
   }
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -372,7 +372,7 @@ bool FatPartition::freeChain(uint32_t cluster) {
 
   return true;
 
-fail:
+ fail:
   return false;
 }
 //------------------------------------------------------------------------------
@@ -434,7 +434,7 @@ int32_t FatPartition::freeClusterCount() {
   setFreeClusterCount(free);
   return free;
 
-fail:
+ fail:
   return -1;
 }
 //------------------------------------------------------------------------------
@@ -462,7 +462,7 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) {
     }
     mbr = reinterpret_cast<MbrSector_t*>
           (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)) {
       DBG_FAIL_MACRO;
@@ -533,6 +533,6 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) {
   }
   return true;
 
-fail:
+ fail:
   return false;
 }

+ 1 - 1
src/FatLib/FatPartition.h

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

+ 2 - 2
src/FatLib/FatVolume.cpp

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

+ 63 - 2
src/FsLib/FsFile.h

@@ -63,7 +63,7 @@ class FsBaseFile {
            m_xFile ? m_xFile->available() : 0;
   }
 
-  /** Set writeError to zero */
+  /** Clear writeError. */
   void clearWriteError() {
     if (m_fFile) m_fFile->clearWriteError();
     if (m_xFile) m_xFile->clearWriteError();
@@ -74,6 +74,20 @@ class FsBaseFile {
    * \return true for success or false for failure.
    */
   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. */
   uint64_t curPosition() {
     return m_fFile ? m_fFile->curPosition() :
@@ -135,6 +149,11 @@ class FsBaseFile {
     return m_fFile ? m_fFile->fileSize() :
            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. */
   void flush() {sync();}
   /** set position for streams
@@ -144,11 +163,44 @@ class FsBaseFile {
     if (m_fFile) m_fFile->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. */
   uint8_t getError() {
     return m_fFile ? m_fFile->getError() :
            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.
    *
@@ -169,6 +221,15 @@ class FsBaseFile {
     return m_fFile ? m_fFile->getWriteError() :
            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. */
   bool 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
    * 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.
    *

+ 1 - 1
src/FsLib/FsVolume.h

@@ -230,7 +230,7 @@ class FsVolume {
            m_xVol ? m_xVol->rmdir(path) : false;
   }
 #if ENABLE_ARDUINO_SERIAL
-  /** List directory contents. 
+  /** List directory contents.
    * \return true for success or false for failure.
    */
   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
 // Shift based CRC-CCITT
 // 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;
   for (size_t i = 0; i < n; i++) {
     crc = (uint8_t)(crc >> 8) | (crc << 8);
@@ -326,7 +326,7 @@ bool SdSpiCard::begin(SdSpiConfig spiConfig) {
   spiSetSckSpeed(spiConfig.maxSck);
   return true;
 
-fail:
+ fail:
   spiStop();
   return false;
 }
@@ -363,7 +363,7 @@ uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
   spiSend(cmd | 0x40);
 
   // 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--) {
     spiSend(pa[i]);
   }
@@ -419,7 +419,7 @@ bool SdSpiCard::erase(uint32_t firstSector, uint32_t lastSector) {
   spiStop();
   return true;
 
-fail:
+ fail:
   spiStop();
   return false;
 }
@@ -458,7 +458,7 @@ bool SdSpiCard::isTimedOut(SdMillis_t startMS, SdMillis_t timeoutMS) {
   return (SysCall::curTimeMS() - startMS) > timeoutMS;
 }
 //------------------------------------------------------------------------------
-bool SdSpiCard::readData(uint8_t *dst) {
+bool SdSpiCard::readData(uint8_t* dst) {
   return readData(dst, 512);
 }
 //------------------------------------------------------------------------------
@@ -501,13 +501,13 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) {
 #endif  // USE_SD_CRC
   return true;
 
-fail:
+ fail:
   spiStop();
   return false;
 }
 //------------------------------------------------------------------------------
 bool SdSpiCard::readOCR(uint32_t* ocr) {
-  uint8_t *p = reinterpret_cast<uint8_t*>(ocr);
+  uint8_t* p = reinterpret_cast<uint8_t*>(ocr);
   syncDevice();
   if (cardCommand(CMD58, 0)) {
     error(SD_CARD_ERROR_CMD58);
@@ -519,7 +519,7 @@ bool SdSpiCard::readOCR(uint32_t* ocr) {
   spiStop();
   return true;
 
-fail:
+ fail:
   spiStop();
   return false;
 }
@@ -538,7 +538,7 @@ bool SdSpiCard::readRegister(uint8_t cmd, void* buf) {
   spiStop();
   return true;
 
-fail:
+ fail:
   spiStop();
   return false;
 }
@@ -558,7 +558,7 @@ bool SdSpiCard::readSingle(uint32_t sector, uint8_t* dst) {
   spiStop();
   return true;
 
-fail:
+ fail:
   spiStop();
   return false;
 }
@@ -574,7 +574,7 @@ bool SdSpiCard::readStart(uint32_t sector) {
 //  spiStop();
   return true;
 
-fail:
+ fail:
   spiStop();
   return false;
 }
@@ -591,16 +591,42 @@ bool SdSpiCard::readStatus(uint8_t* status) {
   spiStop();
   return true;
 
-fail:
+ fail:
   spiStop();
   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() {
   if (cardCommand(CMD12, 0)) {
@@ -610,11 +636,16 @@ bool SdSpiCard::readStop() {
   spiStop();
   return true;
 
-fail:
+ fail:
   spiStop();
   return false;
 }
 //------------------------------------------------------------------------------
+uint32_t SdSpiCard::sectorCount() {
+  csd_t csd;
+  return readCSD(&csd) ? sdCardCapacity(&csd) : 0;
+}
+//------------------------------------------------------------------------------
 void SdSpiCard::spiStart() {
   if (!m_spiActive) {
     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
 bool SdSpiCard::waitNotBusy(SdMillis_t timeoutMS) {
   SdMillis_t t0 = SysCall::curTimeMS();
@@ -654,6 +701,48 @@ bool SdSpiCard::waitNotBusy(SdMillis_t timeoutMS) {
 #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) {
   // use address if not SDHC card
   if (type() != SD_CARD_TYPE_SDHC) {
@@ -685,59 +774,11 @@ bool SdSpiCard::writeSingle(uint32_t sector, const uint8_t* src) {
   spiStop();
   return true;
 
-fail:
+ fail:
   spiStop();
   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) {
   #if ENABLE_DEDICATED_SPI
   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
 }
 //------------------------------------------------------------------------------
-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) {
   // use address if not SDHC card
   if (type() != SD_CARD_TYPE_SDHC) {
@@ -827,7 +826,7 @@ bool SdSpiCard::writeStart(uint32_t sector) {
   }
   return true;
 
-fail:
+ fail:
   spiStop();
   return false;
 }
@@ -848,7 +847,7 @@ bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
   }
   return true;
 
-fail:
+ fail:
   spiStop();
   return false;
 }
@@ -863,7 +862,7 @@ bool SdSpiCard::writeStop() {
   spiStop();
   return true;
 
-fail:
+ fail:
   error(SD_CARD_ERROR_STOP_TRAN);
   spiStop();
   return false;

+ 1 - 1
src/SdCard/SdSpiCard.h

@@ -171,7 +171,7 @@ class SdSpiCard {
    *
    * \return true for success or false for failure.
    */
-  bool readData(uint8_t *dst);
+  bool readData(uint8_t* dst);
   /** Read 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.
    */
-  bool readData(uint8_t *dst);
+  bool readData(uint8_t* dst);
   /** Read 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;
 }
 //------------------------------------------------------------------------------
-bool SdioCard::readData(uint8_t *dst) {
+bool SdioCard::readData(uint8_t* dst) {
   DBG_IRQSTAT();
-  uint32_t *p32 = reinterpret_cast<uint32_t*>(dst);
+  uint32_t* p32 = reinterpret_cast<uint32_t*>(dst);
 
   if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_RTA)) {
     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) {
   if (m_sdioConfig.useDma()) {
-    uint8_t *ptr;
+    uint8_t* ptr;
     uint8_t aligned[512];
     if (3 & (uint32_t)src) {
       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_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_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(n) ((n) & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)

+ 11 - 5
src/SdFat.h

@@ -39,7 +39,7 @@
 
 //------------------------------------------------------------------------------
 /** SdFat version */
-#define SD_FAT_VERSION "2.0.0"
+#define SD_FAT_VERSION "2.0.2"
 //==============================================================================
 /**
  * \class SdBase
@@ -397,16 +397,22 @@ class SdFs : public SdBase<FsVolume> {
 /** Select type for SdFat. */
 typedef SdFat32 SdFat;
 /** Select type for File. */
+#if !defined(__has_include) || !__has_include(<FS.h>)
 typedef File32 File;
+#endif
 /** Select type for SdBaseFile. */
 typedef FatFile SdBaseFile;
 #elif SDFAT_FILE_TYPE == 2
 typedef SdExFat SdFat;
+#if !defined(__has_include) || !__has_include(<FS.h>)
 typedef ExFile File;
+#endif
 typedef ExFatFile SdBaseFile;
 #elif SDFAT_FILE_TYPE == 3
 typedef SdFs SdFat;
+#if !defined(__has_include) || !__has_include(<FS.h>)
 typedef FsFile File;
+#endif
 typedef FsBaseFile SdBaseFile;
 #else  // 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
    *
-   *   // 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
    *

+ 22 - 1
src/SdFatConfig.h

@@ -57,7 +57,7 @@
 #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.
  */
 #define USE_FAT_FILE_FLAG_CONTIGUOUS 1
@@ -73,6 +73,9 @@
 #if defined(__AVR__) && FLASHEND < 0X8000
 // 32K AVR boards.
 #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
 // All other boards.
 #define SDFAT_FILE_TYPE 1
@@ -152,6 +155,24 @@ typedef uint8_t SdCsPin_t;
  */
 #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
  * 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);
 }
 //------------------------------------------------------------------------------
-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);
   return 0;
 }
@@ -55,7 +55,7 @@ void SdSpiArduinoDriver::send(uint8_t 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.
   while (count%4) {
     send(*buf++);

+ 1 - 1
src/SpiDriver/SdSpiBaseClass.h

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

+ 4 - 4
src/common/BlockDeviceInterface.h

@@ -39,7 +39,7 @@ class BlockDeviceInterface {
  public:
   virtual ~BlockDeviceInterface() {}
   /**
-   * Read a 512 byte sector.
+   * Read a sector.
    *
    * \param[in] sector Logical sector to be read.
    * \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;
 #if USE_MULTI_SECTOR_IO
   /**
-   * Read multiple 512 byte sectors.
+   * Read multiple sectors.
    *
    * \param[in] sector Logical sector to be read.
    * \param[in] ns Number of sectors to be read.
@@ -66,7 +66,7 @@ class BlockDeviceInterface {
   virtual bool syncDevice() = 0;
 
   /**
-   * Writes a 512 byte sector.
+   * Writes a sector.
    *
    * \param[in] sector Logical sector 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;
 #if USE_MULTI_SECTOR_IO
   /**
-   * Write multiple 512 byte sectors.
+   * Write multiple sectors.
    *
    * \param[in] sector Logical sector 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);
   return neg ? -v : v;
 
-fail:
+ fail:
   return 0;
 }

+ 1 - 1
src/common/FsDateTime.cpp

@@ -43,7 +43,7 @@ namespace FsDateTime {
     callback2 = dateTime;
   }
   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;
   }
 }  // namespace FsDateTime

+ 30 - 16
src/common/FsDateTime.h

@@ -25,23 +25,26 @@
 #ifndef FsDateTime_h
 #define FsDateTime_h
 #include <stdint.h>
+#include "CompileDateTime.h"
 #include "SysCall.h"
+
 /** Backward compatible definition. */
 #define FAT_DATE(y, m, d) FS_DATE(y, m, d)
 
 /** Backward compatible definition. */
 #define FAT_TIME(h, m, s) FS_TIME(h, m, s)
+
 /** Date time callback */
 namespace FsDateTime {
   /** Date time callback. */
   extern void (*callback)(uint16_t* date, uint16_t* time, uint8_t* ms10);
   /** Date time callback. */
   extern void (*callback2)(uint16_t* date, uint16_t* time);
-  /** Cancel callback */
+  /** Cancel callback. */
   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:
    *
    * \code
@@ -49,13 +52,13 @@ namespace FsDateTime {
    *   uint16_t year;
    *   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
    *
@@ -66,7 +69,7 @@ namespace FsDateTime {
    *
    */
   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
    * function is of the form:
@@ -76,15 +79,20 @@ namespace FsDateTime {
    *   uint16_t year;
    *   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
    *
@@ -95,8 +103,9 @@ namespace FsDateTime {
    *
    */
   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
+
 /** date field for directory entry
  * \param[in] year [1980,2107]
  * \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 :
          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) {
   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(const uint8_t *buffer, size_t size) {
+  virtual size_t write(const uint8_t* buffer, size_t size) {
     size_t i;
     for (i = 0; i < size; i++) {
       if (!write(buffer[i])) break;
@@ -146,7 +146,7 @@ class PrintBasic {
     return i;
   }
   size_t write(const char *buffer, size_t size) {
-    return write((const uint8_t *)buffer, size);
+    return write((const uint8_t*)buffer, size);
   }
 
  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
 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)
 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;
   return true;
 
-fail:
+ fail:
   m_status = 0;
   return false;
 }
@@ -216,7 +216,7 @@ int StdioStream::fseek(int32_t offset, int origin) {
   m_p = m_buf;
   return 0;
 
-fail:
+ fail:
   return EOF;
 }
 //------------------------------------------------------------------------------

+ 1 - 1
src/iostream/StreamBaseClass.cpp

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

+ 2 - 2
src/iostream/bufstream.h

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

+ 2 - 2
src/iostream/fstream.h

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

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff