Переглянути джерело

Added Long File Names

main
Bill Greiman 10 роки тому
джерело
коміт
d60a3ab342
100 змінених файлів з 5793 додано та 3448 видалено
  1. +0
    -62
      ArduinoDue.txt
  2. +0
    -13
      MultipleCards.txt
  3. +0
    -21
      QuickStart.txt
  4. +0
    -23
      SPI_Transactions.txt
  5. +3
    -1
      SdFat/MinimumSerial.cpp
  6. +7
    -7
      SdFat/MinimumSerial.h
  7. +68
    -33
      SdFat/SdFat.h
  8. +3
    -5
      SdFat/SdFatBase.cpp
  9. +59
    -67
      SdFat/SdFatConfig.h
  10. +3
    -14
      SdFat/SdFatUtil.cpp
  11. +14
    -3
      SdFat/SdFatUtil.h
  12. +151
    -47
      SdFat/SdFatmainpage.h
  13. +59
    -42
      SdFat/SdFile.h
  14. +3
    -3
      SdFat/SdInfo.h
  15. +86
    -83
      SdFat/SdSpi.h
  16. +104
    -48
      SdFat/SdSpiCard.cpp
  17. +72
    -45
      SdFat/SdSpiCard.h
  18. +22
    -20
      SdFat/SdSpiSAM3X.cpp
  19. +17
    -15
      SdFat/SdVolume.h
  20. +39
    -24
      SdFat/examples/#attic/AnalogLogger/AnalogLogger.ino
  21. +38
    -0
      SdFat/examples/#attic/BaseExtCaseTest/BaseExtCaseTest.ino
  22. +1
    -1
      SdFat/examples/#attic/HelloWorld/HelloWorld.ino
  23. +20
    -12
      SdFat/examples/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino
  24. +2
    -2
      SdFat/examples/#attic/SD_Size/SD_Size.ino
  25. +4
    -4
      SdFat/examples/#attic/SdFatSize/SdFatSize.ino
  26. +21
    -13
      SdFat/examples/#attic/append/append.ino
  27. +15
    -9
      SdFat/examples/#attic/average/average.ino
  28. +20
    -11
      SdFat/examples/#attic/benchSD/benchSD.ino
  29. +2
    -2
      SdFat/examples/#attic/bufstream/bufstream.ino
  30. +13
    -9
      SdFat/examples/#attic/eventlog/eventlog.ino
  31. +50
    -36
      SdFat/examples/#attic/fgetsRewrite/fgetsRewrite.ino
  32. +14
    -8
      SdFat/examples/#attic/readlog/readlog.ino
  33. +114
    -76
      SdFat/examples/AnalogBinLogger/AnalogBinLogger.ino
  34. +31
    -24
      SdFat/examples/LongFileName/LongFileName.ino
  35. +0
    -0
      SdFat/examples/LongFileName/testFiles/With.Two dots.txt
  36. +72
    -48
      SdFat/examples/LowLatencyLogger/LowLatencyLogger.ino
  37. +7
    -4
      SdFat/examples/OpenNext/OpenNext.ino
  38. +41
    -35
      SdFat/examples/PrintBenchmark/PrintBenchmark.ino
  39. +62
    -60
      SdFat/examples/QuickStart/QuickStart.ino
  40. +30
    -25
      SdFat/examples/RawWrite/RawWrite.ino
  41. +88
    -0
      SdFat/examples/ReadWrite/ReadWrite.ino
  42. +12
    -8
      SdFat/examples/ReadWriteSdFat/ReadWriteSdFat.ino
  43. +101
    -77
      SdFat/examples/SdFormatter/SdFormatter.ino
  44. +74
    -68
      SdFat/examples/SdInfo/SdInfo.ino
  45. +14
    -12
      SdFat/examples/SoftwareSpi/SoftwareSpi.ino
  46. +52
    -48
      SdFat/examples/StdioBench/StdioBench.ino
  47. +7
    -7
      SdFat/examples/StreamParseInt/StreamParseInt.ino
  48. +114
    -74
      SdFat/examples/ThreeCards/ThreeCards.ino
  49. +27
    -23
      SdFat/examples/Timestamp/Timestamp.ino
  50. +70
    -43
      SdFat/examples/TwoCards/TwoCards.ino
  51. +50
    -39
      SdFat/examples/bench/bench.ino
  52. +1
    -1
      SdFat/examples/cin_cout/cin_cout.ino
  53. +31
    -23
      SdFat/examples/dataLogger/dataLogger.ino
  54. +54
    -40
      SdFat/examples/directoryFunctions/directoryFunctions.ino
  55. +33
    -27
      SdFat/examples/fgets/fgets.ino
  56. +6
    -4
      SdFat/examples/formatting/formatting.ino
  57. +13
    -11
      SdFat/examples/getline/getline.ino
  58. +46
    -32
      SdFat/examples/readCSV/readCSV.ino
  59. +50
    -26
      SdFat/examples/rename/rename.ino
  60. +32
    -14
      SdFat/utility/ArduinoStream.h
  61. +19
    -13
      SdFat/utility/DigitalPin.h
  62. +7
    -5
      SdFat/utility/FatApiConstants.h
  63. +497
    -530
      SdFat/utility/FatFile.cpp
  64. +258
    -175
      SdFat/utility/FatFile.h
  65. +593
    -212
      SdFat/utility/FatFileLFN.cpp
  66. +30
    -73
      SdFat/utility/FatFilePrint.cpp
  67. +273
    -0
      SdFat/utility/FatFileSFN.cpp
  68. +54
    -29
      SdFat/utility/FatFileSystem.h
  69. +27
    -0
      SdFat/utility/FatLibConfig.h
  70. +354
    -361
      SdFat/utility/FatStructs.h
  71. +154
    -52
      SdFat/utility/FatVolume.cpp
  72. +123
    -46
      SdFat/utility/FatVolume.h
  73. +64
    -24
      SdFat/utility/FmtNumber.cpp
  74. +7
    -1
      SdFat/utility/FmtNumber.h
  75. +16
    -8
      SdFat/utility/SoftSPI.h
  76. +132
    -54
      SdFat/utility/StdioStream.cpp
  77. +44
    -28
      SdFat/utility/StdioStream.h
  78. +25
    -9
      SdFat/utility/bufstream.h
  79. +64
    -46
      SdFat/utility/fstream.cpp
  80. +81
    -29
      SdFat/utility/fstream.h
  81. +37
    -13
      SdFat/utility/ios.h
  82. +53
    -19
      SdFat/utility/istream.cpp
  83. +93
    -85
      SdFat/utility/istream.h
  84. +21
    -7
      SdFat/utility/ostream.cpp
  85. +12
    -4
      SdFat/utility/ostream.h
  86. +9
    -9
      SdFatTestSuite/SdFatTestSuite.cpp
  87. +9
    -7
      SdFatTestSuite/examples/TestMkdir/TestMkdir.ino
  88. +1
    -1
      SdFatTestSuite/examples/TestRmdir/TestRmdir.ino
  89. +35
    -0
      SdFatTestSuite/examples/lfnSize/lfnSize.ino
  90. +235
    -0
      SdFatTestSuite/examples/lfnTest/lfnTest.ino
  91. +219
    -0
      SdFatTestSuite/examples/lfnTestCout/lfnTestCout.ino
  92. BIN
      SdLevel.png
  93. +0
    -15
      SoftwareSPI.txt
  94. +0
    -44
      WorkingDirectory.txt
  95. +4
    -0
      changes.txt
  96. +2
    -2
      html/_arduino_stream_8h.html
  97. BIN
      html/_arduino_stream_8h__incl.png
  98. +1
    -1
      html/_digital_pin_8h.html
  99. +98
    -14
      html/_fat_file_8h.html
  100. +0
    -0
      html/_fat_file_8h__incl.png

+ 0
- 62
ArduinoDue.txt Переглянути файл

@@ -1,62 +0,0 @@
Support has been added for the Arduino Due.

You must connect your SD socket to the 6-pin "ISP connector". You must have short
wires or a custom shield to run at full speed, 42 MHz.

If you have problems use a lower SPI speed. You can also check for SPI
errors by editing SdFatCobfig.h to enable CRC checking.

You should be be able to use any digital pin for SD chip select. The default
pin is SS which is pin 10 for Due.

The default SPI rate is 42 MHz. You can set SD chip select and the SPI rate
by calling:

bool SdFat::begin(uint8_t chipSelectPin, uint8_t spiRateID);

The second argument, spiRateID, sets the SCK rate and can be these symbols:

SPI_FULL_SPEED - 42 MHz

SPI_DIV3_SPEED - 28 MHz

SPI_HALF_SPEED - 21 MHz

SPI_DIV6_SPEED - 14 MHz

SPI_QUARTER_SPEED 10.5 MHz

SPI_EIGHTH_SPEED 5.25 MHz

Large reads and writes use fast multi-block SD read/write commands. For optimal
speed, use records that are a multiple of 512 bytes.

Run the bench.ino example to explore large read/write speed.

Replace this line:

#define BUF_SIZE 100

With a large size like this:

#define BUF_SIZE 8192

For best results the record size should be a power of two (512, 1024, 2048,
4096, 8192). In this case records will be aligned with FAT cluster boundaries.

Since Due is fast, increase the test file size by editing this line:

#define FILE_SIZE_MB 5

Run the PrintBenchmark.ino example to compare text formatting speed of Due
with AVR boards.

A number of options are available to configure SPI for the Due board.

You can use the standard SPI.h library by editing SdFatConfig.h and set
USE_ARDUINO_SPI_LIBRARY nonzero. You must include SPI.h in your sketch.

Several options can be set in Sd2Card.cpp in the USE_NATIVE_SAM3X_SPI
section. These include USE_SAM3X_DMAC to control use of DMA and
USE_SAM3X_BUS_MATRIX_FIX to change Bus Matrix operation. Most people
will not need to change these.

+ 0
- 13
MultipleCards.txt Переглянути файл

@@ -1,13 +0,0 @@
SdFat has support for multiple SD cards. This requires multiple instances
of SdFat objects.

You must edit SdFatConfig.h to enable multiple instances of SdFat. Set
USE_MULTIPLE_CARDS nonzero like this:

#define USE_MULTIPLE_CARDS 1

Look at TwoCards.pde in the SdFat/examples folder. This example demonstrates
use of two SD cards.

Read WorkingDirectory.txt for more information on volume working
directories and the current working directory.

+ 0
- 21
QuickStart.txt Переглянути файл

@@ -1,21 +0,0 @@
For those who don't like too much documentation.

To use this library place the SdFat folder into the libraries
subfolder in your main sketches folder. You may need to
create the libraries folder. Restart the Arduino IDE if
it was open.

Run the QuickStart.ino sketch from the
libraries/SdFat/examples/QuickStart folder. Click the
IDE up-arrow icon then -> libraries -> SdFat -> QuickStart.

You can also click File -> Examples -> SdFat -> QuickStart.

If problems occur try reading more documentation and use these
forums for help:

http://forums.adafruit.com/

http://arduino.cc/forum/

If QuickStart.ino runs successfully try more examples.

+ 0
- 23
SPI_Transactions.txt Переглянути файл

@@ -1,23 +0,0 @@
To enable support for SPI transactions, edit SfFatCinfig.h and modify these
defines.

//------------------------------------------------------------------------------
/**
* Set ENABLE_SPI_TRANSACTION nonzero to enable the SPI transaction feature
* of the standard Arduino SPI library. You must include SPI.h in your
* sketches when ENABLE_SPI_TRANSACTION is nonzero.
*/
#define ENABLE_SPI_TRANSACTION 0
//------------------------------------------------------------------------------
/**
* Set ENABLE_SPI_YIELD nonzero to enable release of the SPI bus during
* SD card busy waits.
*
* This will allow interrupt routines to access the SPI bus if
* ENABLE_SPI_TRANSACTION is nonzero.
*
* Setting ENABLE_SPI_YIELD will introduce some extra overhead and will
* slightly slow transfer rates. A few older SD cards may fail when
* ENABLE_SPI_YIELD is nonzero.
*/
#define ENABLE_SPI_YIELD 0

+ 3
- 1
SdFat/MinimumSerial.cpp Переглянути файл

@@ -44,7 +44,9 @@ void MinimumSerial::begin(uint32_t baud) {
}
//------------------------------------------------------------------------------
int MinimumSerial::read() {
if (UCSR0A & (1 << RXC0)) return UDR0;
if (UCSR0A & (1 << RXC0)) {
return UDR0;
}
return -1;
}
//------------------------------------------------------------------------------

+ 7
- 7
SdFat/MinimumSerial.h Переглянути файл

@@ -36,14 +36,14 @@ class MinimumSerial : public Print {
/**
* Unbuffered read
* \return -1 if no character is available or an available character.
*/
*/
int read();
/**
* Unbuffered write
*
* \param[in] b byte to write.
* \return 1
*/
/**
* Unbuffered write
*
* \param[in] b byte to write.
* \return 1
*/
size_t write(uint8_t b);
using Print::write;
};

+ 68
- 33
SdFat/SdFat.h Переглянути файл

@@ -28,7 +28,7 @@
#include "utility/FatLib.h"
//------------------------------------------------------------------------------
/** SdFat version YYYYMMDD */
#define SD_FAT_VERSION 20141115
#define SD_FAT_VERSION 20141204
//==============================================================================
/**
* \class SdFatBase
@@ -44,12 +44,16 @@ class SdFatBase : public FatFileSystem {
*/
bool begin(SdSpiCard::m_spi_t* spi, uint8_t csPin = SS, uint8_t divisor = 2) {
return m_sdCard.begin(spi, csPin, divisor) &&
FatFileSystem::begin(&m_vwd);
FatFileSystem::begin(&m_vwd);
}
/** \return Pointer to SD card object */
SdSpiCard *card() {return &m_sdCard;}
SdSpiCard *card() {
return &m_sdCard;
}
/** %Print any SD error code to Serial and halt. */
void errorHalt() {errorHalt(&Serial);}
void errorHalt() {
errorHalt(&Serial);
}
/** %Print any SD error code and halt.
*
* \param[in] pr Print destination.
@@ -59,7 +63,9 @@ class SdFatBase : public FatFileSystem {
*
* \param[in] msg Message to print.
*/
void errorHalt(char const* msg) {errorHalt(&Serial, msg);}
void errorHalt(char const* msg) {
errorHalt(&Serial, msg);
}
/** %Print msg, any SD error code, and halt.
*
* \param[in] pr Print destination.
@@ -70,7 +76,9 @@ class SdFatBase : public FatFileSystem {
*
* \param[in] msg Message to print.
*/
void errorHalt(const __FlashStringHelper* msg) {errorHalt(&Serial, msg);}
void errorHalt(const __FlashStringHelper* msg) {
errorHalt(&Serial, msg);
}
/** %Print msg, any SD error code, and halt.
*
* \param[in] pr Print destination.
@@ -78,7 +86,9 @@ class SdFatBase : public FatFileSystem {
*/
void errorHalt(Print* pr, const __FlashStringHelper* msg);
/** %Print any SD error code to Serial */
void errorPrint() {errorPrint(&Serial);}
void errorPrint() {
errorPrint(&Serial);
}
/** %Print any SD error code.
* \param[in] pr Print device.
*/
@@ -87,7 +97,9 @@ class SdFatBase : public FatFileSystem {
*
* \param[in] msg Message to print.
*/
void errorPrint(const char* msg) {errorPrint(&Serial, msg);}
void errorPrint(const char* msg) {
errorPrint(&Serial, msg);
}
/** %Print msg, any SD error code.
*
* \param[in] pr Print destination.
@@ -98,19 +110,26 @@ class SdFatBase : public FatFileSystem {
*
* \param[in] msg Message to print.
*/
void errorPrint(const __FlashStringHelper* msg) {errorPrint(&Serial, msg);}
void errorPrint(const __FlashStringHelper* msg) {
errorPrint(&Serial, msg);
}
/** %Print msg, any SD error code.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorPrint(Print* pr, const __FlashStringHelper* msg);
/** Diagnostic call to initialize FatFileSystem.
/** Diagnostic call to initialize FatFileSystem - use for
* diagnostic purposes only.
* \return true for success else false.
*/
bool fsBegin() {return FatFileSystem::begin(&m_vwd);}
bool fsBegin() {
return FatFileSystem::begin(&m_vwd);
}
/** %Print any SD error code and halt. */
void initErrorHalt() {initErrorHalt(&Serial);}
void initErrorHalt() {
initErrorHalt(&Serial);
}
/** %Print error details and halt after begin fails.
*
* \param[in] pr Print destination.
@@ -120,22 +139,30 @@ class SdFatBase : public FatFileSystem {
*
* \param[in] msg Message to print.
*/
void initErrorHalt(char const *msg) {initErrorHalt(&Serial, msg);}
void initErrorHalt(char const *msg) {
initErrorHalt(&Serial, msg);
}
/**Print message, error details, and halt after SdFatBase::init() fails.
* \param[in] pr Print device.
* \param[in] msg Message to print.
*/
void initErrorHalt(Print* pr, char const *msg);
/**Print message, error details, and halt after SdFat::init() fails.
*
* \param[in] msg Message to print.
*/
/**Print message, error details, and halt after SdFat::init() fails.
*
* \param[in] msg Message to print.
*/
void initErrorHalt(const __FlashStringHelper* msg) {
initErrorHalt(&Serial, msg);
}
/**Print message, error details, and halt after SdFatBase::init() fails.
* \param[in] pr Print device for message.
* \param[in] msg Message to print.
*/
void initErrorHalt(Print* pr, const __FlashStringHelper* msg);
/** Print error details after SdFat::init() fails. */
void initErrorPrint() {initErrorPrint(&Serial);}
void initErrorPrint() {
initErrorPrint(&Serial);
}
/** Print error details after SdFatBase::init() fails.
*
* \param[in] pr Print destination.
@@ -145,7 +172,9 @@ class SdFatBase : public FatFileSystem {
*
* \param[in] msg Message to print.
*/
void initErrorPrint(char const *msg) {initErrorPrint(&Serial, msg);}
void initErrorPrint(char const *msg) {
initErrorPrint(&Serial, msg);
}
/**Print message and error details and halt after SdFatBase::init() fails.
*
* \param[in] pr Print destination.
@@ -201,13 +230,19 @@ class SdFatBase : public FatFileSystem {
*/
File open(const char *path, uint8_t mode = FILE_READ);
/** \return a pointer to the volume working directory. */
SdBaseFile* vwd() {return &m_vwd;}
SdBaseFile* vwd() {
return &m_vwd;
}

using FatFileSystem::ls;

private:
uint8_t cardErrorCode() {return m_sdCard.errorCode();}
uint8_t cardErrorData() {return m_sdCard.errorData();}
uint8_t cardErrorCode() {
return m_sdCard.errorCode();
}
uint8_t cardErrorData() {
return m_sdCard.errorData();
}
bool readBlock(uint32_t block, uint8_t* dst) {
return m_sdCard.readBlock(block, dst);
}
@@ -239,7 +274,7 @@ class SdFat : public SdFatBase {
bool begin(uint8_t csPin = SS, uint8_t divisor = 2) {
return SdFatBase::begin(&m_spi, csPin, divisor);
}
/** Initialize SD card - use for diagnostic purposes.
/** Diagnostic call to initialize SD card - use for diagnostic purposes only.
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \return true for success else false.
@@ -251,23 +286,23 @@ class SdFat : public SdFatBase {
SpiDefault_t m_spi;
};
//==============================================================================
#if USE_MULTIPLE_SPI_TYPES || defined(DOXYGEN)
#if SD_SPI_CONFIGURATION >= 3 || defined(DOXYGEN)
/**
* \class SdFatLibSpi
* \brief SdFat class using the standard Arduino SPI library.
*/
class SdFatLibSpi: public SdFatBase {
public:
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \return true for success else false.
*/
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \return true for success else false.
*/
bool begin(uint8_t csPin = SS, uint8_t divisor = 2) {
return SdFatBase::begin(&m_spi, csPin, divisor);
}
/** Initialize SD card - use for diagnostic purposes.
/** Diagnostic call to initialize SD card - use for diagnostic purposes only.
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \return true for success else false.
@@ -296,7 +331,7 @@ class SdFatSoftSpi : public SdFatBase {
bool begin(uint8_t csPin = SS, uint8_t divisor = 2) {
return SdFatBase::begin(&m_spi, csPin, divisor);
}
/** Initialize SD card - use for diagnostic purposes.
/** Diagnostic call to initialize SD card - use for diagnostic purposes only.
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \return true for success else false.
@@ -308,5 +343,5 @@ class SdFatSoftSpi : public SdFatBase {
private:
SdSpiSoft<MisoPin, MosiPin, SckPin> m_spi;
};
#endif // USE_MULTIPLE_SPI_TYPES
#endif /// SD_SPI_CONFIGURATION >= 3 || defined(DOXYGEN)
#endif // SdFat_h

+ 3
- 5
SdFat/SdFatBase.cpp Переглянути файл

@@ -35,7 +35,9 @@ void SdFatBase::errorHalt(Print* pr, const __FlashStringHelper* msg) {
}
//------------------------------------------------------------------------------
void SdFatBase::errorPrint(Print* pr) {
if (!cardErrorCode()) return;
if (!cardErrorCode()) {
return;
}
pr->print(F("SD errorCode: 0X"));
pr->print(cardErrorCode(), HEX);
pr->print(F(",0X"));
@@ -64,10 +66,6 @@ void SdFatBase::initErrorHalt(Print* pr, char const *msg) {
initErrorHalt(pr);
}
//------------------------------------------------------------------------------
/**Print message, error details, and halt after SdFatBase::init() fails.
* \param[in] pr Print device for message.
* \param[in] msg Message to print.
*/
void SdFatBase::initErrorHalt(Print* pr, const __FlashStringHelper* msg) {
pr->println(msg);
initErrorHalt(pr);

+ 59
- 67
SdFat/SdFatConfig.h Переглянути файл

@@ -29,11 +29,58 @@
#endif // __AVR__
//------------------------------------------------------------------------------
/**
* Set USE_MULTIPLE_SPI_TYPES nonzero to enable the SdFatSoftSpi and
* SdFatLibSpi classes. SdFatSoftSpi uses software SPI and SdFatLibSpi
* uses the standard Arduino SPI library.
* Set USE_LONG_FILE_NAMES nonzero to use long file names (LFN).
* Long File Name are limited to a maximum length of 255 characters.
*
* This implementation allows 7-bit characters in the range
* 0X20 to 0X7E except the following characters are not allowed:
*
* < (less than)
* > (greater than)
* : (colon)
* " (double quote)
* / (forward slash)
* \ (backslash)
* | (vertical bar or pipe)
* ? (question mark)
* * (asterisk)
*
*/
#define USE_MULTIPLE_SPI_TYPES 0
#define USE_LONG_FILE_NAMES 1
//------------------------------------------------------------------------------
/**
* The symbol SD_SPI_CONFIGURATION defines SPI access to the SD card.
*
* IF SD_SPI_CONFIGUTATION is define to be zero, only the SdFat class
* is define and SdFat uses a fast custom SPI implementation.
*
* If SD_SPI_CONFIGURATION is define to be one, only the SdFat class is
* define and SdFat uses the standard Arduino SD.h library.
*
* If SD_SPI_CONFIGURATION is define to be two, only the SdFat class is
* define and SdFat uses software SPI on the pins defined below.
*
* If SD_SPI_CONFIGURATION is define to be three, the three classes, SdFat,
* SdFatLibSpi, and SdFatSoftSpi are defined. SdFat uses the fast
* custom SPI implementation. SdFatLibSpi uses the standard Arduino SPI
* library. SdFatSoftSpi is a template class that uses Software SPI. The
* template parameters define the software SPI pins. See the ThreeCard
* example for simultaneous use of all three classes.
*/
#define SD_SPI_CONFIGURATION 0
//------------------------------------------------------------------------------
/**
* If SD_SPI_CONFIGURATION is defined to be two, these definitions
* will define the pins used for software SPI.
*
* The default definition allows Uno shields to be used on other boards.
*/
/** Software SPI Master Out Slave In pin */
uint8_t const SOFT_SPI_MOSI_PIN = 11;
/** Software SPI Master In Slave Out pin */
uint8_t const SOFT_SPI_MISO_PIN = 12;
/** Software SPI Clock pin */
uint8_t const SOFT_SPI_SCK_PIN = 13;
//------------------------------------------------------------------------------
/**
* To enable SD card CRC checking set USE_SD_CRC nonzero.
@@ -47,78 +94,23 @@
/**
* Set ENABLE_SPI_TRANSACTION nonzero to enable the SPI transaction feature
* of the standard Arduino SPI library. You must include SPI.h in your
* sketches when ENABLE_SPI_TRANSACTION is nonzero.
* programs when ENABLE_SPI_TRANSACTION is nonzero.
*/
#define ENABLE_SPI_TRANSACTION 0
//------------------------------------------------------------------------------
/**
* Set ENABLE_SPI_YIELD nonzero to enable release of the SPI bus during
* SD card busy waits.
* SD card busy waits.
*
* This will allow interrupt routines to access the SPI bus if
* This will allow interrupt routines to access the SPI bus if
* ENABLE_SPI_TRANSACTION is nonzero.
*
*
* Setting ENABLE_SPI_YIELD will introduce some extra overhead and will
* slightly slow transfer rates. A few older SD cards may fail when
* slightly slow transfer rates. A few older SD cards may fail when
* ENABLE_SPI_YIELD is nonzero.
*/
#define ENABLE_SPI_YIELD 0
//------------------------------------------------------------------------------
/**
* Set USE_ARDUINO_SPI_LIBRARY nonzero to force use of the Arduino Standard
* SPI library in the SdFat class. This will override native and software
* SPI for all boards.
*/
#define USE_ARDUINO_SPI_LIBRARY 0
//------------------------------------------------------------------------------
/**
* Set AVR_SOFT_SPI nonzero to use software SPI in the SdFat class
* on all AVR Arduinos. Set the soft SPI pins below.
*/
#define AVR_SOFT_SPI 0
//------------------------------------------------------------------------------
/**
* Set DUE_SOFT_SPI nonzero to use software SPI in the SdFat class
* on Due Arduinos. Set the soft SPI pins below.
*/
#define DUE_SOFT_SPI 0
//------------------------------------------------------------------------------
/**
* Set LEONARDO_SOFT_SPI nonzero to use software SPI in the SdFat class
* on Leonardo Arduinos. Set the soft SPI pins below.
*
* LEONARDO_SOFT_SPI allows an unmodified 328 Shield to be used
* on Leonardo Arduinos.
*/
#define LEONARDO_SOFT_SPI 0
//------------------------------------------------------------------------------
/**
* Set MEGA_SOFT_SPI nonzero to use software SPI in the SdFat class
* on Mega Arduinos. Set the soft SPI pins below.
*
* MEGA_SOFT_SPI allows an unmodified 328 Shield to be used
* on Mega Arduinos. Set the soft SPI pins below.
*/
#define MEGA_SOFT_SPI 0
//------------------------------------------------------------------------------
/**
* Set TEENSY3_SOFT_SPI nonzero to use software SPI in the SdFat class
* on Teensy 3.x boards. Set the soft SPI pins below.
*/
#define TEENSY3_SOFT_SPI 0
//------------------------------------------------------------------------------
/**
* Define software SPI pins. Default allows Uno shields to be used on other
* boards.
*/
// define software SPI pins
/** Software SPI Master Out Slave In pin */
uint8_t const SOFT_SPI_MOSI_PIN = 11;
/** Software SPI Master In Slave Out pin */
uint8_t const SOFT_SPI_MISO_PIN = 12;
/** Software SPI Clock pin */
uint8_t const SOFT_SPI_SCK_PIN = 13;
//------------------------------------------------------------------------------
/**
* Set FAT12_SUPPORT nonzero to enable use if FAT12 volumes.
* FAT12 has not been well tested and requires additional flash.
@@ -154,7 +146,7 @@ uint8_t const SOFT_SPI_SCK_PIN = 13;
/**
* Set SD_FILE_USES_STREAM nonzero to use Stream instead of Print for SdFile.
* Using Stream will use more flash and may cause compatibility problems
* with code written for older versions of SdFat.
* with code written for older versions of SdFat.
*/
#define SD_FILE_USES_STREAM 0
//------------------------------------------------------------------------------
@@ -170,8 +162,8 @@ const uint8_t SPI_SCK_INIT_DIVISOR = 128;
//------------------------------------------------------------------------------
/**
* Set USE_SEPARATE_FAT_CACHE nonzero to use a second 512 byte cache
* for FAT table entries. Improves performance for large writes that
* are not a multiple of 512 bytes.
* for FAT table entries. This improves performance for large writes
* that are not a multiple of 512 bytes.
*/
#ifdef __arm__
#define USE_SEPARATE_FAT_CACHE 1

+ 3
- 14
SdFat/SdFatUtil.cpp Переглянути файл

@@ -23,9 +23,6 @@
//------------------------------------------------------------------------------
#ifdef __arm__
extern "C" char* sbrk(int incr);
/** Amount of free RAM
* \return The number of free bytes.
*/
int SdFatUtil::FreeRam() {
char top;
return &top - reinterpret_cast<char*>(sbrk(0));
@@ -42,20 +39,12 @@ int SdFatUtil::FreeRam() {
}
#endif // __arm
//------------------------------------------------------------------------------
/** %Print a string in flash memory.
*
* \param[in] pr Print object for output.
* \param[in] str Pointer to string stored in flash memory.
*/
void SdFatUtil::print_P(Print* pr, PGM_P str) {
for (uint8_t c; (c = pgm_read_byte(str)); str++) pr->write(c);
for (uint8_t c; (c = pgm_read_byte(str)); str++) {
pr->write(c);
}
}
//------------------------------------------------------------------------------
/** %Print a string in flash memory followed by a CR/LF.
*
* \param[in] pr Print object for output.
* \param[in] str Pointer to string stored in flash memory.
*/
void SdFatUtil::println_P(Print* pr, PGM_P str) {
print_P(pr, str);
pr->println();

+ 14
- 3
SdFat/SdFatUtil.h Переглянути файл

@@ -12,7 +12,7 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
@@ -30,8 +30,21 @@
#define PgmPrintln(x) SerialPrintln_P(PSTR(x))

namespace SdFatUtil {
/** Amount of free RAM
* \return The number of free bytes.
*/
int FreeRam();
/** %Print a string in flash memory.
*
* \param[in] pr Print object for output.
* \param[in] str Pointer to string stored in flash memory.
*/
void print_P(Print* pr, PGM_P str);
/** %Print a string in flash memory followed by a CR/LF.
*
* \param[in] pr Print object for output.
* \param[in] str Pointer to string stored in flash memory.
*/
void println_P(Print* pr, PGM_P str);
//----------------------------------------------------------------------------
/** %Print a string in flash memory to Serial.
@@ -49,8 +62,6 @@ namespace SdFatUtil {
inline void SerialPrintln_P(PGM_P str) {
println_P(&Serial, str);
}
void SerialPrint_P(PGM_P str);
void SerialPrintln_P(PGM_P str);
} // namespace SdFatUtil
using namespace SdFatUtil; // NOLINT
#endif // #define SdFatUtil_h

+ 151
- 47
SdFat/SdFatmainpage.h Переглянути файл

@@ -1,13 +1,13 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
*
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@@ -31,8 +31,8 @@ cards are supported.
Experimental support for FAT12 can be enabled by setting FAT12_SUPPORT
nonzero in SdFatConfig.h.

The %SdFat library only supports short 8.3 names. Limited Long %File Name
access is provided by \ref SdFile::openNextLFN. See the LongFileName example.
The %SdFat library supports Long %File Names or short 8.3 names.
Edit the SdFatConfig.h file to select short or long file names.

The main classes in %SdFat are SdFat, SdFatSoftSpi, SdFatLibSpi,
SdBaseFile, SdFile, File, StdioStream, \ref fstream, \ref ifstream,
@@ -42,7 +42,7 @@ The SdFat, SdFatLibSpi, and SdFatSoftSpi classes maintain a FAT volume,
a current working directory, and simplifies initialization of other classes.
The SdFat class uses a fast custom hardware SPI implementation. The
SdFatLibSpi class uses the standard Arduino SPI library. The SdFatSoftSpi
class uses software SPI.
class uses software SPI.

The SdBaseFile class provides basic file access functions such as open(),
binary read(), binary write(), close(), remove(), and sync(). SdBaseFile
@@ -52,11 +52,11 @@ The SdFile class has all the SdBaseFile class functions plus the Arduino
Print class functions.

The File class has all the SdBaseFile functions plus the functions in
the Arduino SD.h File class. This provides compatibility with the
the Arduino SD.h File class. This provides compatibility with the
Arduino SD.h library.

The StdioStream class implements functions similar to Linux/Unix standard
buffered input/output.
buffered input/output.

The \ref fstream class implements C++ iostreams for both reading and writing
text files.
@@ -65,7 +65,7 @@ The \ref ifstream class implements C++ iostreams for reading text files.

The \ref ofstream class implements C++ iostreams for writing text files.

The classes \ref ifstream, \ref ofstream, \ref istream, and \ref ostream
The classes \ref ifstream, \ref ofstream, \ref istream, and \ref ostream
follow the C++ \ref iostream standard when possible.

There are many tutorials and much documentation about using C++ iostreams
@@ -85,7 +85,7 @@ developed to test %SdFat and illustrate its use.
\section Install Installation

You must manually install SdFat by copying the SdFat folder from the download
package to the Arduino libraries folder in you sketch book.
package to the Arduino libraries folder in you sketch folder.

See the Manual installation section of this guide.

@@ -94,31 +94,77 @@ http://arduino.cc/en/Guide/Libraries
\section SDconfig SdFat Configuration

Several configuration options may be changed by editing the SdFatConfig.h
file in the SdFat folder.
file in the %SdFat folder.

Set USE_MULTIPLE_SPI_TYPES nonzero to enable the SdFatSoftSpi and
SdFatLibSpi classes. SdFatSoftSpi uses software SPI and SdFatLibSpi
uses the standard Arduino SPI library.
Set USE_LONG_FILE_NAMES nonzero to enable Long %File Names. By default,
Long %File Names are enabled. For the leanest fastest library disable
Long %File Names. Long %File names require extra flash but no extra RAM.
Opening Long %File Names can be slower than opening Short %File Names.
Data read and write performance is not changed by the type of %File Name.

Set SD_SPI_CONFIGURATION to enable various SPI options. The SdFatSoftSpi
and SdFatLibSpi classes can be enabled. SdFatLibSpi uses the standard
Arduino SPI library and SdFatSoftSpi uses software SPI.

To enable SD card CRC checking set USE_SD_CRC nonzero.

Set FAT12_SUPPORT nonzero to enable use of FAT12 volumes.
FAT12 has not been well tested and requires additional flash.

Set USE_ARDUINO_SPI_LIBRARY nonzero to force use of the Arduino Standard
SPI library in the SdFat class. This will override native and software
SPI for all boards.

Use of software SPI can be enabled in the SdFat class for selected boards
by setting the symbols AVR_SOFT_SPI, DUE_SOFT_SPI, LEONARDO_SOFT_SPI,
MEGA_SOFT_SPI, and TEENSY3_SOFT_SPI.

Set ENABLE_SPI_TRANSACTION nonzero to enable the SPI transaction feature
of the standard Arduino SPI library. You must include SPI.h in your
sketches when ENABLE_SPI_TRANSACTION is nonzero.
programs when ENABLE_SPI_TRANSACTION is nonzero.

Set ENABLE_SPI_YIELD nonzero to enable release of the SPI bus during
SD card busy waits.
SD card busy waits.

\section SDPath Paths and Working Directories

Relative paths in SdFat are resolved in a manner similar to Windows.

Each instance of SdFat has a current directory. In SdFat this directory
is called the volume working directory, vwd. Initially this directory is
the root directory for the volume.

The volume working directory is changed by calling SdFat::chdir(path).

The call sd.chdir("/2014") will change the volume working directory
for sd to "/2014", assuming "/2014" exists.

Relative paths for SdFat member functions are resolved by starting at
the volume working directory.

For example, the call sd.mkdir("April") will create the directory
"/2014/April" assuming the volume working directory is "/2014".

SdFat has a current working directory, cwd, that is used to resolve paths
for file.open() calls.

For a single SD card the current working directory is always the volume
working directory for that card.

For multiple SD cards the current working directory is set to the volume
working directory of a card by calling the SdFat::chvol() member function.
The chvol() call is like the Windows \<drive letter>: command.

The call sd2.chvol() will set the current working directory to the volume
working directory for sd2.

If the volume working directory for sd2 is "/music" the call

file.open("BigBand.wav", O_READ);

will then open "/music/BigBand.wav" on sd2.

The following functions are used to change or get current directories.
See the html documentation for more information.
@code
bool SdFat::chdir(bool set_cwd = false);
bool SdFat::chdir(const char* path, bool set_cwd = false);
void SdFat::chvol();
SdBaseFile* SdFat::vwd();
static SdBaseFile* SdBaseFile::cwd();
@endcode

\section SDcard SD\SDHC Cards

@@ -139,7 +185,7 @@ limited RAM.
\section Hardware Hardware Configuration

%SdFat was developed using an
<A HREF = "http://www.adafruit.com/"> Adafruit Industries</A>
<A HREF = "http://www.adafruit.com/"> Adafruit Industries</A>
Data Logging Shield.

The hardware interface to the SD card should not use a resistor based level
@@ -153,22 +199,78 @@ uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the
74LCX245.

If you are using a resistor based level shifter and are having problems try
setting the SPI bus frequency to 4 MHz. This can be done by using
setting the SPI bus frequency to 4 MHz. This can be done by using
card.init(SPI_HALF_SPEED) to initialize the SD card.

A feature to use software SPI is available. Software SPI is slower
than hardware SPI but allows any digital pins to be used. See
SdFatConfig.h for software SPI definitions.

An many shields designed for an Uno can be use on an Arduino Mega
by defining MEGA_SOFT_SPI in SdFatConfig.h.

\section comment Bugs and Comments

If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net.
If you wish to report bugs or have comments, send email to
fat16lib@sbcglobal.net. If possible, include a simple program that illustrates
the bug or problem.

\section Trouble Troubleshooting

The two example programs QuickStart, and SdInfo are useful for troubleshooting.

A message like this from SdInfo with erorCode 0X1 indicates the SD card
is not seen by SdFat. This is often caused by a wiring error and reformatting
the card will not solve the problem.
<PRE>
cardBegin failed
SD errorCode: 0X1
SD errorData: 0XFF
</PRE>
Here is a similar message from QuickStart:
<PRE>
SD initialization failed.
Do not reformat the card!
Is the card correctly inserted?
Is chipSelect set to the correct value?
Does another SPI device need to be disabled?
Is there a wiring/soldering problem?

errorCode: 0x1, errorData: 0xff
</PRE>
Here is a message from QuickStart that indicates a formatting problem:
<PRE>
Card successfully initialized.
Can't find a valid FAT16/FAT32 partition.
Try reformatting the card. For best results use
the SdFormatter program in SdFat/examples or download
and use SDFormatter from www.sdcard.org/downloads.
</PRE>

The best source of recent information and help is the Arduino forum.

http://arduino.cc/forum/

Also search the Adafruit forum.

http://forums.adafruit.com/

If you are using a Teensy try.

http://forum.pjrc.com/forum.php

\section SdFatClass SdFat Usage

SdFat supports Long File Names. Long names in SdFat are limited to 7-bit
ASCII characters in the range 0X20 - 0XFE The following are reserved characters:
<ul>
<li>< (less than)
<li>> (greater than)
<li>: (colon)
<li>" (double quote)
<li>/ (forward slash)
<li>\ (backslash)
<li>| (vertical bar or pipe)
<li>? (question mark)
<li>* (asterisk)
</ul>
%SdFat uses a slightly restricted form of short names.
Short names are limited to 8 characters followed by an optional period (.)
and extension of up to 3 characters. The characters may be any combination
@@ -177,13 +279,15 @@ of letters and digits. The following special characters are also allowed:
$ % ' - _ @ ~ ` ! ( ) { } ^ # &

Short names are always converted to upper case and their original case
value is lost.
value is lost. Files that have a base-name where all characters have the
same case and an extension where all characters have the same case will
display properly. Examples this type name are UPPER.low, lower.TXT,
UPPER.TXT, and lower.txt.

An application which writes to a file using print(), println() or
\link SdFile::write write() \endlink must call \link SdFile::sync() sync() \endlink
at the appropriate time to force data and directory information to be written
to the SD Card. Data and directory information are also written to the SD card
when \link SdFile::close() close() \endlink is called.
\link SdFile::write write() \endlink must close the file or call
\link SdFile::sync() sync() \endlink at the appropriate time to
force data and directory information to be written to the SD Card.

Applications must use care calling \link SdFile::sync() sync() \endlink
since 2048 bytes of I/O is required to update file and
@@ -202,8 +306,8 @@ SDFormatter which can be downloaded from:

http://www.sdcard.org/downloads

A formatter sketch, SdFormatter.ino, is included in the
%SdFat/examples/SdFormatter directory. This sketch attempts to
A formatter program, SdFormatter.ino, is included in the
%SdFat/examples/SdFormatter directory. This program attempts to
emulate SD Association's SDFormatter.

SDFormatter aligns flash erase boundaries with file
@@ -214,7 +318,7 @@ very small cards as FAT12. Use the SdFat formatter to force FAT16
formatting of small cards.

Do not format the SD card with an OS utility, OS utilities do not format SD
cards in conformance with the SD standard.
cards in conformance with the SD standard.

You should use a freshly formatted SD card for best performance. FAT
file systems become slower if many files have been created and deleted.
@@ -229,7 +333,7 @@ A number of examples are provided in the SdFat/examples folder.
See the html documentation for a list.

To access these examples from the Arduino development environment
go to: %File -> Examples -> %SdFat -> \<Sketch Name\>
go to: %File -> Examples -> %SdFat -> \<program Name\>

Compile, upload to your Arduino and click on Serial Monitor to run
the example.
@@ -252,7 +356,7 @@ formating - Print a table with various formatting options.

getline - Example of getline from section 27.7.1.3 of the C++ standard.

LongFileName - Example use of openNextLFN and open by index.
LongFileName - Example use of openNext, printName, and open by index.

LowLatencyLogger - A modifiable data logger for higher data rates.

@@ -260,7 +364,7 @@ OpenNext - Open all files in the root dir and print their filename.

PrintBenchmark - A simple benchmark for printing to a text file.

QuickStart - A sketch to quickly test your SD card and SD shield/module.
QuickStart - A program to quickly test your SD card and SD shield/module.

RawWrite - A test of raw write functions for contiguous files.

@@ -270,10 +374,10 @@ ReadWriteSdFat - SdFat version of Arduino SD ReadWrite example.

rename - A demo of SdFat::rename(old, new) and SdFile::rename(dirFile, newPath).

SdFormatter - This sketch will format an SD or SDHC card.
SdFormatter - This program will format an SD or SDHC card.

SoftwareSpi - Simple demonstration of the SdFatSoftSpi template class.
SdInfo - Initialize an SD card and analyze its structure for trouble shooting.

StdioBench - Demo and test of stdio style stream.
@@ -281,8 +385,8 @@ StdioBench - Demo and test of stdio style stream.
StreamParseInt - Demo of the SD.h API and the File class parseInt() function.

ThreeCards - Demonstrate simultaneous use of SdFat, SdFatLibSpi, SdFatSoftSpi.
Timestamp - Sets file create, modify, and access timestamps.

TwoCards - Example using two SD cards.
*/
*/

+ 59
- 42
SdFat/SdFile.h Переглянути файл

@@ -43,7 +43,9 @@ class SdBaseFile : public FatFile {
* \param[in] path File location and name.
* \param[in] oflag File open mode.
*/
SdBaseFile(const char* path, uint8_t oflag) {open(path, oflag);}
SdBaseFile(const char* path, uint8_t oflag) {
open(path, oflag);
}
using FatFile::ls;
using FatFile::printFatDate;
using FatFile::printFatTime;
@@ -81,8 +83,8 @@ class SdBaseFile : public FatFile {
}
/** Print a file's name.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
size_t printName() {
return FatFile::printName(&Serial);
@@ -124,24 +126,32 @@ class SdFile : public SdBaseFile, public Print {
return n > INT_MAX ? INT_MAX : n;
}
/** Ensure that any bytes written to the file are saved to the SD card. */
void flush() {SdBaseFile::sync();}
void flush() {
SdBaseFile::sync();
}
/** Return the next available byte without consuming it.
*
* \return The byte if no error and not at eof else -1;
*/
int peek() {return SdBaseFile::peek();}
int peek() {
return SdBaseFile::peek();
}
/** Read the next byte from a file.
*
* \return For success return the next byte in the file as an int.
* If an error occurs or end of file is reached return -1.
*/
int read() {return SdBaseFile::read();}
int read() {
return SdBaseFile::read();
}
/** Write a byte to a file. Required by the Arduino Print class.
* \param[in] b the byte to be written.
* Use getWriteError to check for errors.
* \return 1 for success and 0 for failure.
*/
size_t write(uint8_t b) {return SdBaseFile::write(b);}
size_t write(uint8_t b) {
return SdBaseFile::write(b);
}
/** Write a string to a file. Used by the Arduino Print class.
* \param[in] str Pointer to the string.
* Use getWriteError to check for errors.
@@ -168,21 +178,6 @@ class SdFile : public SdBaseFile, public Print {
size_t write(const uint8_t *buf, size_t size) {
return SdBaseFile::write(buf, size);
}
/** Write a PROGMEM string to a file.
* \param[in] str Pointer to the PROGMEM string.
* Use getWriteError to check for errors.
*/
void write_P(PGM_P str) {
for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c);
}
/** Write a PROGMEM string followed by CR/LF to a file.
* \param[in] str Pointer to the PROGMEM string.
* Use getWriteError to check for errors.
*/
void writeln_P(PGM_P str) {
write_P(str);
write_P(PSTR("\r\n"));
}
};
//==============================================================================
/**
@@ -200,14 +195,18 @@ class File : public SdBaseFile, public Stream {
* bitwise-inclusive OR of open flags. see
* SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
*/
File(const char* path, uint8_t oflag) {open(path, oflag);}
File(const char* path, uint8_t oflag) {
open(path, oflag);
}
using SdBaseFile::clearWriteError;
using SdBaseFile::getWriteError;
/** The parenthesis operator.
*
* \return true if a file is open.
*/
operator bool() {return isOpen();}
/** The parenthesis operator.
*
* \return true if a file is open.
*/
operator bool() {
return isOpen();
}
/** \return number of bytes available from the current position to EOF
* or INT_MAX if more than INT_MAX bytes are available.
*/
@@ -216,24 +215,32 @@ class File : public SdBaseFile, public Stream {
return n > INT_MAX ? INT_MAX : n;
}
/** Ensure that any bytes written to the file are saved to the SD card. */
void flush() {SdBaseFile::sync();}
/** This function reports if the current file is a directory or not.
* \return true if the file is a directory.
*/
bool isDirectory() {return isDir();}
/** \return a pointer to the file's name. */
void flush() {
SdBaseFile::sync();
}
/** This function reports if the current file is a directory or not.
* \return true if the file is a directory.
*/
bool isDirectory() {
return isDir();
}
/** \return a pointer to the file's short name. */
char* name() {
m_name[0] = 0;
getFilename(m_name);
getSFN(m_name);
return m_name;
}
/** Return the next available byte without consuming it.
*
* \return The byte if no error and not at eof else -1;
*/
int peek() {return SdBaseFile::peek();}
int peek() {
return SdBaseFile::peek();
}
/** \return the current file position. */
uint32_t position() {return curPosition();}
uint32_t position() {
return curPosition();
}
/** Opens the next file or folder in a directory.
*
* \param[in] mode open mode flags.
@@ -249,10 +256,14 @@ class File : public SdBaseFile, public Stream {
* \return For success return the next byte in the file as an int.
* If an error occurs or end of file is reached return -1.
*/
int read() {return SdBaseFile::read();}
int read() {
return SdBaseFile::read();
}
/** Rewind a file if it is a directory */
void rewindDirectory() {
if (isDir()) rewind();
if (isDir()) {
rewind();
}
}
/**
* Seek to a new position in the file, which must be between
@@ -261,15 +272,21 @@ class File : public SdBaseFile, public Stream {
* \param[in] pos the new file position.
* \return true for success else false.
*/
bool seek(uint32_t pos) {return seekSet(pos);}
bool seek(uint32_t pos) {
return seekSet(pos);
}
/** \return the file's size. */
uint32_t size() {return fileSize();}
uint32_t size() {
return fileSize();
}
/** Write a byte to a file. Required by the Arduino Print class.
* \param[in] b the byte to be written.
* Use getWriteError to check for errors.
* \return 1 for success and 0 for failure.
*/
size_t write(uint8_t b) {return SdBaseFile::write(b);}
size_t write(uint8_t b) {
return SdBaseFile::write(b);
}
/** Write data to an open file. Form required by Print.
*
* \note Data is moved to the cache but may not be written to the

+ 3
- 3
SdFat/SdInfo.h Переглянути файл

@@ -218,7 +218,7 @@ typedef struct CID {
unsigned char always1 : 1;
/** CRC7 checksum */
unsigned char crc : 7;
}__attribute__((packed)) cid_t;
} __attribute__((packed)) cid_t;
//==============================================================================
/**
* \class CSDV1
@@ -283,7 +283,7 @@ typedef struct CSDV1 {
// byte 15
unsigned char always1 : 1;
unsigned char crc : 7;
}__attribute__((packed)) csd1_t;
} __attribute__((packed)) csd1_t;
//==============================================================================
/**
* \class CSDV2
@@ -368,7 +368,7 @@ typedef struct CSDV2 {
unsigned char always1 : 1;
/** checksum */
unsigned char crc : 7;
}__attribute__((packed)) csd2_t;
} __attribute__((packed)) csd2_t;
//==============================================================================
/**
* \class csd_t

+ 86
- 83
SdFat/SdSpi.h Переглянути файл

@@ -17,40 +17,15 @@
* along with the Arduino SdSpi Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* \file
* \brief SdSpi class for V2 SD/SDHC cards
*/
/**
* \file
* \brief SdSpi class for V2 SD/SDHC cards
*/
#ifndef SdSpi_h
#define SdSpi_h
#include <Arduino.h>
#include "SdFatConfig.h"
#include "utility/SoftSPI.h"
#if !USE_ARDUINO_SPI_LIBRARY
// AVR Arduinos
#ifdef __AVR__
#if AVR_SOFT_SPI
#define USE_SOFTWARE_SPI 1
#elif LEONARDO_SOFT_SPI && defined(__AVR_ATmega32U4__) && !defined(CORE_TEENSY)
#define USE_SOFTWARE_SPI 1
#elif MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)\
|| defined(__AVR_ATmega2560__))
#define USE_SOFTWARE_SPI 1
#endif // USE_SOFTWARE_SPI
#endif // __AVR__
// Due
#if DUE_SOFT_SPI && defined(__arm__) && !defined(CORE_TEENSY)
#define USE_SOFTWARE_SPI 1
#endif // DUE_SOFT_SPI && defined(__arm__) && !defined(CORE_TEENSY)
// Teensy 3.x
#if TEENSY3_SOFT_SPI && defined(__arm__) && defined(CORE_TEENSY)
#define USE_SOFTWARE_SPI 1
#endif // TEENSY3_SOFT_SPI && defined(__arm__) && defined(CORE_TEENSY)
#endif // !USE_ARDUINO_SPI_LIBRARY
#ifndef USE_SOFTWARE_SPI
/** Default is no software SPI */
#define USE_SOFTWARE_SPI 0
#endif // USE_SOFTWARE_SPI
//------------------------------------------------------------------------------
/**
* \class SdSpiBase
@@ -83,11 +58,11 @@ class SdSpiBase {
* \param[in] data Byte to send
*/
virtual void send(uint8_t data) = 0;
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
virtual void send(const uint8_t* buf, size_t n) = 0;
/** \return true if hardware SPI else false */
virtual bool useSpiTransactions() = 0;
@@ -97,11 +72,11 @@ class SdSpiBase {
* \class SdSpi
* \brief SPI class for access to SD and SDHC flash memory cards.
*/
#if USE_MULTIPLE_SPI_TYPES
#if SD_SPI_CONFIGURATION >= 3
class SdSpi : public SdSpiBase {
#else
#else // SD_SPI_CONFIGURATION >= 3
class SdSpi {
#endif
#endif // SD_SPI_CONFIGURATION >= 3
public:
/** Initialize the SPI bus */
void begin();
@@ -135,27 +110,30 @@ class SdSpi {
*/
void send(const uint8_t* buf, size_t n);
/** \return true - uses SPI transactions */
bool useSpiTransactions() {return true;}
bool useSpiTransactions() {
return true;
}
};

//------------------------------------------------------------------------------
#if USE_MULTIPLE_SPI_TYPES || USE_ARDUINO_SPI_LIBRARY || defined(DOXYGEN)
#include <SPI.h>
/**
* \class SdSpiLib
* \brief Arduino SPI library class for access to SD and SDHC flash
* memory cards.
*/
#if USE_MULTIPLE_SPI_TYPES
#if SD_SPI_CONFIGURATION >= 3 || SD_SPI_CONFIGURATION == 1 || defined(DOXYGEN)
#include <SPI.h>
#if SD_SPI_CONFIGURATION >= 3
class SdSpiLib : public SdSpiBase {
#else
#else // SD_SPI_CONFIGURATION >= 3
class SdSpiLib {
#endif
#endif // SD_SPI_CONFIGURATION >= 3
public:
/**
* Initialize SPI pins.
*/
void begin() {SPI.begin();}
void begin() {
SPI.begin();
}
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] divisor SCK clock divider relative to the system clock.
@@ -163,25 +141,35 @@ class SdSpiLib {
void init(uint8_t divisor) {
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
#ifndef SPI_CLOCK_DIV128
#ifndef SPI_CLOCK_DIV128
SPI.setClockDivider(divisor);
#else // SPI_CLOCK_DIV128
#else // SPI_CLOCK_DIV128
int v;
if (divisor <= 2) v = SPI_CLOCK_DIV2;
else if (divisor <= 4) v = SPI_CLOCK_DIV4;
else if (divisor <= 8) v = SPI_CLOCK_DIV8;
else if (divisor <= 16) v = SPI_CLOCK_DIV16;
else if (divisor <= 32) v = SPI_CLOCK_DIV32;
else if (divisor <= 64) v = SPI_CLOCK_DIV64;
else v = SPI_CLOCK_DIV128;
if (divisor <= 2) {
v = SPI_CLOCK_DIV2;
} else if (divisor <= 4) {
v = SPI_CLOCK_DIV4;
} else if (divisor <= 8) {
v = SPI_CLOCK_DIV8;
} else if (divisor <= 16) {
v = SPI_CLOCK_DIV16;
} else if (divisor <= 32) {
v = SPI_CLOCK_DIV32;
} else if (divisor <= 64) {
v = SPI_CLOCK_DIV64;
} else {
v = SPI_CLOCK_DIV128;
}
SPI.setClockDivider(v);
#endif // SPI_CLOCK_DIV128
#endif // SPI_CLOCK_DIV128
}
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive() {return SPI.transfer(0XFF);}
uint8_t receive() {
return SPI.transfer(0XFF);
}
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
@@ -213,25 +201,25 @@ class SdSpiLib {
}
}
/** \return true - uses SPI transactions */
bool useSpiTransactions() {return true;}
bool useSpiTransactions() {
return true;
}
};
#endif // USE_MULTIPLE_SPI_TYPES || USE_ARDUINO_SPI_LIBRARY
#endif // SD_SPI_CONFIGURATION >= 3 || SD_SPI_CONFIGURATION == 1
//------------------------------------------------------------------------------
/**
* \class SdSpiSoft
* \brief Software SPI class for access to SD and SDHC flash memory cards.
*/
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
#if USE_MULTIPLE_SPI_TYPES
class SdSpiSoft : public SdSpiBase {
#else
class SdSpiSoft {
#endif
public:
/**
* initialize SPI pins
*/
void begin() {m_spi.begin();}
void begin() {
m_spi.begin();
}
/**
* Initialize hardware SPI - dummy for soft SPI
* \param[in] divisor SCK divisor - ignored.
@@ -241,14 +229,16 @@ class SdSpiSoft {
*
* \return The byte.
*/
uint8_t receive() {return m_spi.receive();}
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
uint8_t receive() {
return m_spi.receive();
}
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
uint8_t receive(uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
buf[i] = receive();
@@ -259,7 +249,9 @@ class SdSpiSoft {
*
* \param[in] data Byte to send
*/
void send(uint8_t data) {m_spi.send(data);}
void send(uint8_t data) {
m_spi.send(data);
}
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
@@ -271,22 +263,27 @@ class SdSpiSoft {
}
}
/** \return false - no SPI transactions */
bool useSpiTransactions() {return false;}
bool useSpiTransactions() {
return false;
}

private:
SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi;
};
//------------------------------------------------------------------------------
#if USE_ARDUINO_SPI_LIBRARY
#if SD_SPI_CONFIGURATION == 0 || SD_SPI_CONFIGURATION >= 3
/** Default is custom fast SPI. */
typedef SdSpi SpiDefault_t;
#elif SD_SPI_CONFIGURATION == 1
/** Default is Arduino library SPI. */
typedef SdSpiLib SpiDefault_t;
#elif USE_SOFTWARE_SPI
#elif SD_SPI_CONFIGURATION == 2
/** Default is software SPI. */
typedef SdSpiSoft<SOFT_SPI_MISO_PIN, SOFT_SPI_MOSI_PIN, SOFT_SPI_SCK_PIN>
SpiDefault_t;
#else // USE_ARDUINO_SPI_LIBRARY
/** Default is custom fast SPI. */
typedef SdSpi SpiDefault_t;
#endif
SpiDefault_t;
#else // SD_SPI_CONFIGURATION == 0 || SD_SPI_CONFIGURATION >= 3
#error bad SD_SPI_CONFIGURATION
#endif // SD_SPI_CONFIGURATION == 0 || SD_SPI_CONFIGURATION >= 3
//------------------------------------------------------------------------------
// Use of in-line for AVR to save flash.
#ifdef __AVR__
@@ -327,7 +324,9 @@ inline uint8_t SdSpi::receive() {
}
//------------------------------------------------------------------------------
inline uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
if (n-- == 0) return 0;
if (n-- == 0) {
return 0;
}
SPDR = 0XFF;
for (size_t i = 0; i < n; i++) {
while (!(SPSR & (1 << SPIF))) {}
@@ -346,7 +345,9 @@ inline void SdSpi::send(uint8_t data) {
}
//------------------------------------------------------------------------------
inline void SdSpi::send(const uint8_t* buf , size_t n) {
if (n == 0) return;
if (n == 0) {
return;
}
SPDR = buf[0];
if (n > 1) {
uint8_t b = buf[1];
@@ -354,7 +355,9 @@ inline void SdSpi::send(const uint8_t* buf , size_t n) {
while (1) {
while (!(SPSR & (1 << SPIF))) {}
SPDR = b;
if (i == n) break;
if (i == n) {
break;
}
b = buf[i++];
}
}

+ 104
- 48
SdFat/SdSpiCard.cpp Переглянути файл

@@ -19,9 +19,9 @@
*/
#include "SdSpiCard.h"
#include "SdSpi.h"
#if ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
#if ENABLE_SPI_TRANSACTION
#include <SPI.h>
#endif // ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
#endif // ENABLE_SPI_TRANSACTION
// debug trace macro
#define SD_TRACE(m, b)
// #define SD_TRACE(m, b) Serial.print(m);Serial.println(b);
@@ -35,7 +35,9 @@ static uint8_t CRC7(const uint8_t* data, uint8_t n) {
uint8_t d = data[i];
for (uint8_t j = 0; j < 8; j++) {
crc <<= 1;
if ((d & 0x80) ^ (crc & 0x80)) crc ^= 0x09;
if ((d & 0x80) ^ (crc & 0x80)) {
crc ^= 0x09;
}
d <<= 1;
}
}
@@ -131,7 +133,9 @@ bool SdSpiCard::begin(m_spi_t* spi, uint8_t chipSelectPin, uint8_t sckDivisor) {
spiInit(m_sckDivisor);

// must supply min of 74 clock cycles with CS high.
for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
for (uint8_t i = 0; i < 10; i++) {
spiSend(0XFF);
}

// command to go idle in SPI mode
while (cardCommand(CMD0, 0) != R1_IDLE_STATE) {
@@ -152,7 +156,9 @@ bool SdSpiCard::begin(m_spi_t* spi, uint8_t chipSelectPin, uint8_t sckDivisor) {
type(SD_CARD_TYPE_SD1);
break;
}
for (uint8_t i = 0; i < 4; i++) m_status = spiReceive();
for (uint8_t i = 0; i < 4; i++) {
m_status = spiReceive();
}
if (m_status == 0XAA) {
type(SD_CARD_TYPE_SD2);
break;
@@ -178,15 +184,19 @@ bool SdSpiCard::begin(m_spi_t* spi, uint8_t chipSelectPin, uint8_t sckDivisor) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
if ((spiReceive() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
if ((spiReceive() & 0XC0) == 0XC0) {
type(SD_CARD_TYPE_SDHC);
}
// Discard rest of ocr - contains allowed voltage range.
for (uint8_t i = 0; i < 3; i++) spiReceive();
for (uint8_t i = 0; i < 3; i++) {
spiReceive();
}
}
chipSelectHigh();
m_sckDivisor = sckDivisor;
return true;

fail:
fail:
chipSelectHigh();
return false;
}
@@ -209,20 +219,26 @@ uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
d[5] = CRC7(d, 5);

// send message
for (uint8_t k = 0; k < 6; k++) spiSend(d[k]);
for (uint8_t k = 0; k < 6; k++) {
spiSend(d[k]);
}
#else // USE_SD_CRC
// send command
spiSend(cmd | 0x40);

// send argument
for (int8_t i = 3; i >= 0; i--) spiSend(pa[i]);
for (int8_t i = 3; i >= 0; i--) {
spiSend(pa[i]);
}

// send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
spiSend(cmd == CMD0 ? 0X95 : 0X87);
#endif // USE_SD_CRC

// skip stuff byte for stop read
if (cmd == CMD12) spiReceive();
if (cmd == CMD12) {
spiReceive();
}

// wait for response
for (uint8_t i = 0; ((m_status = spiReceive()) & 0X80) && i != 0XFF; i++) {
@@ -232,7 +248,9 @@ uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
//------------------------------------------------------------------------------
uint32_t SdSpiCard::cardSize() {
csd_t csd;
if (!readCSD(&csd)) return 0;
if (!readCSD(&csd)) {
return 0;
}
if (csd.v1.csd_ver == 0) {
uint8_t read_bl_len = csd.v1.read_bl_len;
uint16_t c_size = (csd.v1.c_size_high << 10)
@@ -262,13 +280,17 @@ void SdSpiCard::chipSelectHigh() {
// insure MISO goes high impedance
spiSend(0XFF);
#if ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
if (useSpiTransactions()) SPI.endTransaction();
if (useSpiTransactions()) {
SPI.endTransaction();
}
#endif // ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
}
//------------------------------------------------------------------------------
void SdSpiCard::chipSelectLow() {
#if ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
if (useSpiTransactions()) SPI.beginTransaction(SPISettings());
if (useSpiTransactions()) {
SPI.beginTransaction(SPISettings());
}
#endif // ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
spiInit(m_sckDivisor);
digitalWrite(m_chipSelectPin, LOW);
@@ -276,7 +298,9 @@ void SdSpiCard::chipSelectLow() {
//------------------------------------------------------------------------------
bool SdSpiCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
csd_t csd;
if (!readCSD(&csd)) goto fail;
if (!readCSD(&csd)) {
goto fail;
}
// check for single block erase
if (!csd.v1.erase_blk_en) {
// erase size mask
@@ -292,10 +316,10 @@ bool SdSpiCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
lastBlock <<= 9;
}
if (cardCommand(CMD32, firstBlock)
|| cardCommand(CMD33, lastBlock)
|| cardCommand(CMD38, 0)) {
error(SD_CARD_ERROR_ERASE);
goto fail;
|| cardCommand(CMD33, lastBlock)
|| cardCommand(CMD38, 0)) {
error(SD_CARD_ERROR_ERASE);
goto fail;
}
if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
error(SD_CARD_ERROR_ERASE_TIMEOUT);
@@ -304,7 +328,7 @@ bool SdSpiCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
chipSelectHigh();
return true;

fail:
fail:
chipSelectHigh();
return false;
}
@@ -319,7 +343,9 @@ bool SdSpiCard::isBusy() {
chipSelectLow();
for (uint8_t i = 0; i < 8; i++) {
rtn = spiReceive() != 0XFF;
if (!rtn) break;
if (!rtn) {
break;
}
}
chipSelectHigh();
return rtn;
@@ -328,22 +354,28 @@ bool SdSpiCard::isBusy() {
bool SdSpiCard::readBlock(uint32_t blockNumber, uint8_t* dst) {
SD_TRACE("RB", blockNumber);
// use address if not SDHC card
if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (type()!= SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD17, blockNumber)) {
error(SD_CARD_ERROR_CMD17);
goto fail;
}
return readData(dst, 512);

fail:
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::readBlocks(uint32_t block, uint8_t* dst, size_t count) {
if (!readStart(block)) return false;
if (!readStart(block)) {
return false;
}
for (uint16_t b = 0; b < count; b++, dst += 512) {
if (!readData(dst)) return false;
if (!readData(dst)) {
return false;
}
}
return readStop();
}
@@ -390,7 +422,7 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) {
chipSelectHigh();
return true;

fail:
fail:
chipSelectHigh();
return false;
}
@@ -401,12 +433,14 @@ bool SdSpiCard::readOCR(uint32_t* ocr) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
for (uint8_t i = 0; i < 4; i++) p[3-i] = spiReceive();
for (uint8_t i = 0; i < 4; i++) {
p[3-i] = spiReceive();
}

chipSelectHigh();
return true;

fail:
fail:
chipSelectHigh();
return false;
}
@@ -420,14 +454,16 @@ bool SdSpiCard::readRegister(uint8_t cmd, void* buf) {
}
return readData(dst, 16);

fail:
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::readStart(uint32_t blockNumber) {
SD_TRACE("RS", blockNumber);
if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (type()!= SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD18, blockNumber)) {
error(SD_CARD_ERROR_CMD18);
goto fail;
@@ -435,7 +471,7 @@ bool SdSpiCard::readStart(uint32_t blockNumber) {
chipSelectHigh();
return true;

fail:
fail:
chipSelectHigh();
return false;
}
@@ -448,7 +484,7 @@ bool SdSpiCard::readStop() {
chipSelectHigh();
return true;

fail:
fail:
chipSelectHigh();
return false;
}
@@ -457,24 +493,30 @@ bool SdSpiCard::readStop() {
bool SdSpiCard::waitNotBusy(uint16_t timeoutMillis) {
uint16_t t0 = millis();
while (spiReceive() != 0XFF) {
if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail;
if (((uint16_t)millis() - t0) >= timeoutMillis) {
goto fail;
}
spiYield();
}
return true;

fail:
fail:
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeBlock(uint32_t blockNumber, const uint8_t* src) {
SD_TRACE("WB", blockNumber);
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (type() != SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD24, blockNumber)) {
error(SD_CARD_ERROR_CMD24);
goto fail;
}
if (!writeData(DATA_START_BLOCK, src)) goto fail;
if (!writeData(DATA_START_BLOCK, src)) {
goto fail;
}

#define CHECK_PROGRAMMING 0
#if CHECK_PROGRAMMING
@@ -493,15 +535,19 @@ bool SdSpiCard::writeBlock(uint32_t blockNumber, const uint8_t* src) {
chipSelectHigh();
return true;

fail:
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeBlocks(uint32_t block, const uint8_t* src, size_t count) {
if (!writeStart(block, count)) return false;
if (!writeStart(block, count)) {
return false;
}
for (size_t b = 0; b < count; b++, src += 512) {
if (!writeData(src)) return false;
if (!writeData(src)) {
return false;
}
}
return writeStop();
}
@@ -509,12 +555,16 @@ bool SdSpiCard::writeBlocks(uint32_t block, const uint8_t* src, size_t count) {
bool SdSpiCard::writeData(const uint8_t* src) {
chipSelectLow();
// wait for previous write to finish
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail;
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
goto fail;
}
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) {
goto fail;
}
chipSelectHigh();
return true;

fail:
fail:
error(SD_CARD_ERROR_WRITE_MULTIPLE);
chipSelectHigh();
return false;
@@ -539,7 +589,7 @@ bool SdSpiCard::writeData(uint8_t token, const uint8_t* src) {
}
return true;

fail:
fail:
chipSelectHigh();
return false;
}
@@ -552,7 +602,9 @@ bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
goto fail;
}
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (type() != SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD25, blockNumber)) {
error(SD_CARD_ERROR_CMD25);
goto fail;
@@ -560,20 +612,24 @@ bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
chipSelectHigh();
return true;

fail:
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeStop() {
chipSelectLow();
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
goto fail;
}
spiSend(STOP_TRAN_TOKEN);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
goto fail;
}
chipSelectHigh();
return true;

fail:
fail:
error(SD_CARD_ERROR_STOP_TRAN);
chipSelectHigh();
return false;

+ 72
- 45
SdFat/SdSpiCard.h Переглянути файл

@@ -35,11 +35,11 @@
class SdSpiCard {
public:
/** typedef for SPI class. */
#if USE_MULTIPLE_SPI_TYPES
typedef SdSpiBase m_spi_t;
#else // USE_MULTIPLE_SPI_TYPES
#if SD_SPI_CONFIGURATION < 3
typedef SpiDefault_t m_spi_t;
#endif // USE_MULTIPLE_SPI_TYPES
#else // SD_SPI_CONFIGURATION < 3
typedef SdSpiBase m_spi_t;
#endif // SD_SPI_CONFIGURATION < 3
/** Construct an instance of SdSpiCard. */
SdSpiCard() : m_errorCode(SD_CARD_ERROR_INIT_NOT_CALLED), m_type(0) {}
/** Initialize the SD card.
@@ -49,7 +49,7 @@ class SdSpiCard {
* \return true for success else false.
*/
bool begin(m_spi_t* spi, uint8_t chipSelectPin = SS,
uint8_t sckDivisor = SPI_FULL_SPEED);
uint8_t sckDivisor = SPI_FULL_SPEED);
/**
* Determine the size of an SD flash memory card.
*
@@ -67,8 +67,8 @@ class SdSpiCard {
* either 0 or 1, depends on the card vendor. The card must support
* single block erase.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool erase(uint32_t firstBlock, uint32_t lastBlock);
/** Determine if card supports single block erase.
@@ -81,13 +81,19 @@ class SdSpiCard {
* Set SD error code.
* \param[in] code value for error code.
*/
void error(uint8_t code) {m_errorCode = code;}
void error(uint8_t code) {
m_errorCode = code;
}
/**
* \return code for the last error. See SdSpiCard.h for a list of error codes.
*/
int errorCode() const {return m_errorCode;}
int errorCode() const {
return m_errorCode;
}
/** \return error data for last error. */
int errorData() const {return m_status;}
int errorData() const {
return m_status;
}
/**
* Check for busy. MISO low indicates the card is busy.
*
@@ -99,8 +105,8 @@ class SdSpiCard {
*
* \param[in] block Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlock(uint32_t block, uint8_t* dst);
/**
@@ -109,8 +115,8 @@ class SdSpiCard {
* \param[in] block Logical block to be read.
* \param[in] count Number of blocks to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlocks(uint32_t block, uint8_t* dst, size_t count);
/**
@@ -140,8 +146,8 @@ class SdSpiCard {
*
* \param[out] dst Pointer to the location for the data to be read.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readData(uint8_t *dst);
/** Read OCR register.
@@ -157,32 +163,36 @@ class SdSpiCard {
* \note This function is used with readData() and readStop() for optimized
* multiple block reads. SPI chipSelect must be low for the entire sequence.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStart(uint32_t blockNumber);
/** End a read multiple blocks sequence.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStop();
/** Return SCK divisor.
*
* \return Requested SCK divisor.
*/
uint8_t sckDivisor() {return m_sckDivisor;}
uint8_t sckDivisor() {
return m_sckDivisor;
}
/** Return the card type: SD V1, SD V2 or SDHC
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
*/
int type() const {return m_type;}
int type() const {
return m_type;
}
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] blockNumber Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlock(uint32_t blockNumber, const uint8_t* src);
/**
@@ -191,14 +201,14 @@ class SdSpiCard {
* \param[in] block Logical block to be written.
* \param[in] count Number of blocks to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlocks(uint32_t block, const uint8_t* src, size_t count);
/** Write one data block in a multiple block write sequence
* \param[in] src Pointer to the location of the data to be written.
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeData(const uint8_t* src);
/** Start a write multiple blocks sequence.
@@ -209,14 +219,14 @@ class SdSpiCard {
* \note This function is used with writeData() and writeStop()
* for optimized multiple block writes.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
/** End a write multiple blocks sequence.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStop();

@@ -232,17 +242,32 @@ class SdSpiCard {
void chipSelectHigh();
void chipSelectLow();
void spiYield();
void type(uint8_t value) {m_type = value;}
void type(uint8_t value) {
m_type = value;
}
bool waitNotBusy(uint16_t timeoutMillis);
bool writeData(uint8_t token, const uint8_t* src);
void spiBegin() {m_spi->begin();}
void spiInit(uint8_t spiDivisor) {m_spi->init(spiDivisor);}
uint8_t spiReceive() {return m_spi->receive();}
uint8_t spiReceive(uint8_t* buf, size_t n) {return m_spi->receive(buf, n);}
void spiSend(uint8_t data) {m_spi->send(data);}
void spiSend(const uint8_t* buf, size_t n) {m_spi->send(buf, n);}
bool useSpiTransactions() {return m_spi->useSpiTransactions();}

void spiBegin() {
m_spi->begin();
}
void spiInit(uint8_t spiDivisor) {
m_spi->init(spiDivisor);
}
uint8_t spiReceive() {
return m_spi->receive();
}
uint8_t spiReceive(uint8_t* buf, size_t n) {
return m_spi->receive(buf, n);
}
void spiSend(uint8_t data) {
m_spi->send(data);
}
void spiSend(const uint8_t* buf, size_t n) {
m_spi->send(buf, n);
}
bool useSpiTransactions() {
return m_spi->useSpiTransactions();
}
m_spi_t* m_spi;
uint8_t m_chipSelectPin;
uint8_t m_errorCode;
@@ -261,7 +286,7 @@ class Sd2Card : public SdSpiCard {
* \param[in] chipSelectPin SD chip select pin.
* \param[in] sckDivisor SPI clock divisor.
* \return true for success else false.
*/
*/
bool begin(uint8_t chipSelectPin = SS, uint8_t sckDivisor = 2) {
return SdSpiCard::begin(&m_spi, chipSelectPin, sckDivisor);
}
@@ -269,13 +294,15 @@ class Sd2Card : public SdSpiCard {
* \param[in] chipSelectPin SD chip select pin.
* \param[in] sckDivisor SPI clock divisor.
* \return true for success else false.
*/
*/
bool init(uint8_t sckDivisor = 2, uint8_t chipSelectPin = SS) {
return begin(chipSelectPin, sckDivisor);
}
private:
bool begin(m_spi_t* spi, uint8_t chipSelectPin = SS,
uint8_t sckDivisor = SPI_FULL_SPEED) {return false;}
bool begin(m_spi_t* spi, uint8_t chipSelectPin = SS,
uint8_t sckDivisor = SPI_FULL_SPEED) {
return false;
}
SpiDefault_t m_spi;
};
#endif // SpiCard_h

+ 22
- 20
SdFat/SdSpiSAM3X.cpp Переглянути файл

@@ -59,20 +59,20 @@ static bool dmac_channel_transfer_done(uint32_t ul_num) {
//------------------------------------------------------------------------------
void SdSpi::begin() {
PIO_Configure(
g_APinDescription[PIN_SPI_MOSI].pPort,
g_APinDescription[PIN_SPI_MOSI].ulPinType,
g_APinDescription[PIN_SPI_MOSI].ulPin,
g_APinDescription[PIN_SPI_MOSI].ulPinConfiguration);
g_APinDescription[PIN_SPI_MOSI].pPort,
g_APinDescription[PIN_SPI_MOSI].ulPinType,
g_APinDescription[PIN_SPI_MOSI].ulPin,
g_APinDescription[PIN_SPI_MOSI].ulPinConfiguration);
PIO_Configure(
g_APinDescription[PIN_SPI_MISO].pPort,
g_APinDescription[PIN_SPI_MISO].ulPinType,
g_APinDescription[PIN_SPI_MISO].ulPin,
g_APinDescription[PIN_SPI_MISO].ulPinConfiguration);
g_APinDescription[PIN_SPI_MISO].pPort,
g_APinDescription[PIN_SPI_MISO].ulPinType,
g_APinDescription[PIN_SPI_MISO].ulPin,
g_APinDescription[PIN_SPI_MISO].ulPinConfiguration);
PIO_Configure(
g_APinDescription[PIN_SPI_SCK].pPort,
g_APinDescription[PIN_SPI_SCK].ulPinType,
g_APinDescription[PIN_SPI_SCK].ulPin,
g_APinDescription[PIN_SPI_SCK].ulPinConfiguration);
g_APinDescription[PIN_SPI_SCK].pPort,
g_APinDescription[PIN_SPI_SCK].ulPinType,
g_APinDescription[PIN_SPI_SCK].ulPin,
g_APinDescription[PIN_SPI_SCK].ulPinConfiguration);
pmc_enable_periph_clk(ID_SPI0);
#if USE_SAM3X_DMAC
pmc_enable_periph_clk(ID_DMAC);
@@ -97,12 +97,12 @@ static void spiDmaRX(uint8_t* dst, uint16_t count) {
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DADDR = (uint32_t)dst;
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DSCR = 0;
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLA = count |
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING;
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING;
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CFG = DMAC_CFG_SRC_PER(SPI_RX_IDX) |
DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG;
DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG;
dmac_channel_enable(SPI_DMAC_RX_CH);
}
//------------------------------------------------------------------------------
@@ -119,11 +119,11 @@ static void spiDmaTX(const uint8_t* src, uint16_t count) {
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DADDR = (uint32_t)&SPI0->SPI_TDR;
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DSCR = 0;
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLA = count |
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;

DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
src_incr | DMAC_CTRLB_DST_INCR_FIXED;
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
src_incr | DMAC_CTRLB_DST_INCR_FIXED;

DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CFG = DMAC_CFG_DST_PER(SPI_TX_IDX) |
DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
@@ -181,7 +181,9 @@ uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
break;
}
}
if (pSpi->SPI_SR & SPI_SR_OVRES) rtn |= 1;
if (pSpi->SPI_SR & SPI_SR_OVRES) {
rtn |= 1;
}
#else // USE_SAM3X_DMAC
for (size_t i = 0; i < n; i++) {
pSpi->SPI_TDR = 0XFF;

+ 17
- 15
SdFat/SdVolume.h Переглянути файл

@@ -27,24 +27,26 @@
//==============================================================================
/**
* \class SdVolume
* \brief SdVolume used in Quick start. Soon to be removed.
* \brief SdVolume Soon to be removed.
*/
class SdVolume : public FatVolume {
public:
/** Initialize a FAT volume. Try partition one first then try super
* floppy format.
*
* \param[in] dev The Sd2Card where the volume is located.
*
* \return true for success else false.
*/
bool init(Sd2Card* dev) {return init(dev, 1) ? true : init(dev, 0);}
/** Initialize a FAT volume.
*
* \param[in] dev The Sd2Card where the volume is located.
* \param[in] part the partition to use. Zero for super floppy or 1-4.
* \return true for success else false.
*/
/** Initialize a FAT volume. Try partition one first then try super
* floppy format.
*
* \param[in] dev The Sd2Card where the volume is located.
*
* \return true for success else false.
*/
bool init(Sd2Card* dev) {
return init(dev, 1) ? true : init(dev, 0);
}
/** Initialize a FAT volume.
*
* \param[in] dev The Sd2Card where the volume is located.
* \param[in] part the partition to use. Zero for super floppy or 1-4.
* \return true for success else false.
*/
bool init(Sd2Card* dev, uint8_t part) {
m_sdCard = dev;
return FatVolume::init(part);

+ 39
- 24
SdFat/examples/#attic/AnalogLogger/AnalogLogger.ino Переглянути файл

@@ -1,6 +1,6 @@
// A simple data logger for the Arduino analog pins with optional DS1307
// uses RTClib from https://github.com/adafruit/RTClib
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h> // define FreeRam()

@@ -45,7 +45,7 @@ RTC_DS1307 RTC; // define the Real Time Clock object
//------------------------------------------------------------------------------
// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
DateTime now = RTC.now();
DateTime now = RTC.now();

// return date using FAT_DATE macro to format fields
*date = FAT_DATE(now.year(), now.month(), now.day());
@@ -65,21 +65,24 @@ ostream& operator << (ostream& os, DateTime& dt) {
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial){} // wait for Leonardo
// pstr stores strings in flash to save RAM
cout << endl << pstr("FreeRam: ") << FreeRam() << endl;
while (!Serial) {} // wait for Leonardo
// F() stores strings in flash to save RAM
cout << endl << F("FreeRam: ") << FreeRam() << endl;

#if WAIT_TO_START
cout << pstr("Type any character to start\n");
cout << F("Type any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem
while (Serial.read() >= 0) {}
#endif // WAIT_TO_START

#if USE_DS1307
// connect to RTC
Wire.begin();
if (!RTC.begin()) error("RTC failed");
if (!RTC.begin()) {
error("RTC failed");
}

// set date time callback function
SdFile::dateTimeCallback(dateTime);
@@ -88,34 +91,40 @@ void setup() {
#endif // USE_DS1307

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
if (!sd.begin(SD_CHIP_SELECT, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// create a new file in root, the current working directory
char name[] = "LOGGER00.CSV";
char name[] = "logger00.csv";

for (uint8_t i = 0; i < 100; i++) {
name[6] = i/10 + '0';
name[7] = i%10 + '0';
if (sd.exists(name)) continue;
if (sd.exists(name)) {
continue;
}
logfile.open(name);
break;
}
if (!logfile.is_open()) error("file.open");
if (!logfile.is_open()) {
error("file.open");
}

cout << F("Logging to: ") << name << endl;
cout << F("Type any character to stop\n\n");

cout << pstr("Logging to: ") << name << endl;
cout << pstr("Type any character to stop\n\n");
// format header in buffer
obufstream bout(buf, sizeof(buf));

bout << pstr("millis");
bout << F("millis");

#if USE_DS1307
bout << pstr(",date,time");
bout << F(",date,time");
#endif // USE_DS1307

for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
bout << pstr(",sens") << int(i);
bout << F(",sens") << int(i);
}
logfile << buf << endl;

@@ -157,17 +166,23 @@ void loop() {
logfile << buf << flush;

// check for error
if (!logfile) error("write data failed");
if (!logfile) {
error("write data failed");
}

#if ECHO_TO_SERIAL
cout << buf;
#endif // ECHO_TO_SERIAL

// don't log two points in the same millis
if (m == millis()) delay(1);
if (!Serial.available()) return;
if (m == millis()) {
delay(1);
}

if (!Serial.available()) {
return;
}
logfile.close();
cout << pstr("Done!");
cout << F("Done!");
while (1);
}
}

+ 38
- 0
SdFat/examples/#attic/BaseExtCaseTest/BaseExtCaseTest.ino Переглянути файл

@@ -0,0 +1,38 @@
/*
* Program to test Short File Name character case flags.
*/
#include <SPI.h>
#include <SdFat.h>

SdFat sd;

SdFile file;
char* name[] = {
"low.low", "low.Mix", "low.UP",
"Mix.low", "Mix.Mix", "Mix.UP",
"UP.low", "UP.Mix", "UP.UP"
};
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
Serial.println("type any character to start");
while (Serial.read() < 0) {}
if (!sd.begin()) {
Serial.println("begin failed");
return;
}
for (uint8_t i = 0; i < 9; i++) {
sd.remove(name[i]);
if (!file.open(name[i], O_RDWR | O_CREAT | O_EXCL)) {
sd.errorHalt(name[i]);
}
file.println(name[i]);

file.close();
}
sd.ls(LS_DATE|LS_SIZE);
Serial.println("Done");
}
//------------------------------------------------------------------------------
void loop() {}

+ 1
- 1
SdFat/examples/#attic/HelloWorld/HelloWorld.ino Переглянути файл

@@ -6,7 +6,7 @@ ArduinoOutStream cout(Serial);

void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
delay(2000);


+ 20
- 12
SdFat/examples/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino Переглянути файл

@@ -1,7 +1,7 @@
/*
* This sketch is a simple Print benchmark.
* This program is a simple Print benchmark.
*/
#include <SPI.h>
#include <SPI.h>
#include <SD.h>

// SD chip select pin
@@ -34,7 +34,7 @@ void loop() {

while (Serial.read() >= 0) {
}
// pstr stores strings in flash to save RAM
// F() stores strings in flash to save RAM
Serial.println(F("Type any character to start"));
while (Serial.read() <= 0) {
}
@@ -42,17 +42,21 @@ void loop() {


// initialize the SD card
if (!SD.begin(chipSelect)) error("begin");

if (!SD.begin(chipSelect)) {
error("begin");
}


Serial.println(F("Starting print test. Please wait.\n"));

// do write test
for (int test = 0; test < 2; test++) {
file = SD.open("BENCH.TXT", FILE_WRITE);
if (!file) error("open failed");
file = SD.open("bench.txt", FILE_WRITE);

if (!file) {
error("open failed");
}
switch(test) {
case 0:
Serial.println(F("Test of println(uint16_t)"));
@@ -83,8 +87,12 @@ void loop() {
error("write failed");
}
m = micros() - m;
if (maxLatency < m) maxLatency = m;
if (minLatency > m) minLatency = m;
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
totalLatency += m;
}
file.flush();
@@ -106,7 +114,7 @@ void loop() {
Serial.print(F(" usec, Avg Latency: "));
Serial.print(totalLatency/N_PRINT);
Serial.println(F(" usec\n"));
SD.remove("BENCH.TXT");
SD.remove("bench.txt");
}
file.close();
Serial.println(F("Done!\n"));

+ 2
- 2
SdFat/examples/#attic/SD_Size/SD_Size.ino Переглянути файл

@@ -1,6 +1,6 @@
/*
* Sketch to compare size of Arduino SD library with SdFat V2.
* See SdFatSize.pde for SdFat sketch.
* Program to compare size of Arduino SD library with SdFat.
* See SdFatSize.ino for SdFat program.
*/
#include <SPI.h>
#include <SD.h>

+ 4
- 4
SdFat/examples/#attic/SdFatSize/SdFatSize.ino Переглянути файл

@@ -1,9 +1,9 @@
/*
* Sketch to compare size of SdFat V2 with Arduino SD library.
* See SD_Size.pde for Arduino SD sketch.
* Program to compare size of SdFat with Arduino SD library.
* See SD_Size.ino for Arduino SD program.
*
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

SdFat sd;
@@ -18,7 +18,7 @@ void setup() {
Serial.println("begin failed");
return;
}
file.open("SIZE_TST.TXT", O_RDWR | O_CREAT | O_AT_END);
file.open("SizeTest.txt", O_RDWR | O_CREAT | O_AT_END);

file.println("Hello");


+ 21
- 13
SdFat/examples/#attic/append/append.ino Переглянути файл

@@ -1,11 +1,11 @@
/*
* Append Example
*
* This sketch shows how to use open for append.
* The sketch will append 100 line each time it opens the file.
* The sketch will open and close the file 100 times.
* This program shows how to use open for append.
* The program will append 100 line each time it opens the file.
* The program will open and close the file 100 times.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin
@@ -22,26 +22,30 @@ ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
void setup() {
// filename for this example
char name[] = "APPEND.TXT";
char name[] = "append.txt";

Serial.begin(9600);
while (!Serial) {} // wait for Leonardo

// pstr() stores strings in flash to save RAM
cout << endl << pstr("Type any character to start\n");
// F() stores strings in flash to save RAM
cout << endl << F("Type any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // Catch Due reset problem

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

cout << F("Appending to: ") << name;

cout << pstr("Appending to: ") << name;
for (uint8_t i = 0; i < 100; i++) {
// open stream for append
ofstream sdout(name, ios::out | ios::app);
if (!sdout) error("open failed");
if (!sdout) {
error("open failed");
}

// append 100 lines to the file
for (uint8_t j = 0; j < 100; j++) {
@@ -52,10 +56,14 @@ void setup() {
// close the stream
sdout.close();

if (!sdout) error("append data failed");
if (!sdout) {
error("append data failed");
}

// output progress indicator
if (i % 25 == 0) cout << endl;
if (i % 25 == 0) {
cout << endl;
}
cout << '.';
}
cout << endl << "Done" << endl;

+ 15
- 9
SdFat/examples/#attic/average/average.ino Переглянути файл

@@ -1,7 +1,7 @@
/*
* Calculate the sum and average of a list of floating point numbers
* Calculate the sum and average of a list of floating point numbers
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin
@@ -15,13 +15,15 @@ ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
void writeTestFile() {
// open the output file
ofstream sdout("AVG_TEST.TXT");
ofstream sdout("AvgTest.txt");

// write a series of float numbers
for (int16_t i = -1001; i < 2000; i += 13) {
sdout << 0.1 * i << endl;
}
if (!sdout) sd.errorHalt("sdout failed");
if (!sdout) {
sd.errorHalt("sdout failed");
}

sdout.close();
}
@@ -32,10 +34,12 @@ void calcAverage() {
double sum = 0; // sum of input numbers

// open the input file
ifstream sdin("AVG_TEST.TXT");
ifstream sdin("AvgTest.txt");

// check for an open failure
if (!sdin) sd.errorHalt("sdin failed");
if (!sdin) {
sd.errorHalt("sdin failed");
}

// read and sum the numbers
while (sdin >> num) {
@@ -52,14 +56,16 @@ void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo

// pstr stores strings in flash to save RAM
cout << pstr("Type any character to start\n");
// F() stores strings in flash to save RAM
cout << F("Type any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // Catch Due reset problem

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// write the test file
writeTestFile();

+ 20
- 11
SdFat/examples/#attic/benchSD/benchSD.ino Переглянути файл

@@ -1,5 +1,5 @@
/*
* This sketch is a simple binary write/read benchmark
* This program is a simple binary write/read benchmark
* for the standard Arduino SD.h library.
*/
#include <SPI.h>
@@ -25,7 +25,7 @@ void error(char* s) {
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial){} // wait for Leonardo
while (!Serial) {} // wait for Leonardo
}
//------------------------------------------------------------------------------
void loop() {
@@ -36,16 +36,17 @@ void loop() {
// discard any input
while (Serial.read() >= 0) {}

// pstr stores strings in flash to save RAM
// F() stores strings in flash to save RAM
Serial.println(F("Type any character to start"));
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem
if (!SD.begin(chipSelect)) error("begin");

if (!SD.begin(chipSelect)) {
error("begin");
}

// open or create file - truncate existing file.
file = SD.open("BENCH.DAT", FILE_WRITE | O_TRUNC);
// file = SD.open("BENCH.DAT", O_CREAT | O_TRUNC | O_CREAT);
file = SD.open("Bench.dat", O_CREAT | O_TRUNC | O_CREAT);
if (!file) {
error("open failed");
}
@@ -77,8 +78,12 @@ void loop() {
error("write failed");
}
m = micros() - m;
if (maxLatency < m) maxLatency = m;
if (minLatency > m) minLatency = m;
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
totalLatency += m;
}
file.flush();
@@ -108,8 +113,12 @@ void loop() {
error("read failed");
}
m = micros() - m;
if (maxLatency < m) maxLatency = m;
if (minLatency > m) minLatency = m;
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
totalLatency += m;
if (buf[BUF_SIZE-1] != '\n') {
error("data check");

+ 2
- 2
SdFat/examples/#attic/bufstream/bufstream.ino Переглянути файл

@@ -1,7 +1,7 @@
/*
* Use of ibufsteam to parse a line and obufstream to format a line
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// create a serial output stream
@@ -14,7 +14,7 @@ void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
delay(2000);
// initialize input string
ibufstream bin("123 456 789");


+ 13
- 9
SdFat/examples/#attic/eventlog/eventlog.ino Переглянути файл

@@ -1,7 +1,7 @@
/*
* Append a line to a file - demo of pathnames and streams
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin
@@ -14,20 +14,22 @@ SdFat sd;
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
/*
* Append a line to LOGFILE.TXT
* Append a line to logfile.txt
*/
void logEvent(const char *msg) {
// create dir if needed
sd.mkdir("LOGS/2011/JAN");
sd.mkdir("logs/2014/Jan");

// create or open a file for append
ofstream sdlog("LOGS/2011/JAN/LOGFILE.TXT", ios::out | ios::app);
ofstream sdlog("logs/2014/Jan/logfile.txt", ios::out | ios::app);

// append a line to the file
sdlog << msg << endl;

// check for errors
if (!sdlog) sd.errorHalt("append failed");
if (!sdlog) {
sd.errorHalt("append failed");
}

sdlog.close();
}
@@ -36,19 +38,21 @@ void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo

// pstr stores strings in flash to save RAM
cout << pstr("Type any character to start\n");
// F() stores strings in flash to save RAM
cout << F("Type any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// append a line to the logfile
logEvent("Another line for the logfile");

cout << "Done - check /LOGS/2011/JAN/LOGFILE.TXT on the SD" << endl;
cout << F("Done - check /logs/2014/Jan/logfile.txt on the SD") << endl;
}
//------------------------------------------------------------------------------
void loop() {}

+ 50
- 36
SdFat/examples/#attic/fgetsRewrite/fgetsRewrite.ino Переглянути файл

@@ -1,5 +1,5 @@
// Demo of rewriting a line read by fgets
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD card chip select pin
@@ -18,18 +18,22 @@ void demoFgets() {
char line[25];
int c;
uint32_t pos;
// open test file
SdFile rdfile("FGETS.TXT", O_RDWR);
SdFile rdfile("fgets.txt", O_RDWR);
// check for open error
if (!rdfile.isOpen()) error("demoFgets");
if (!rdfile.isOpen()) {
error("demoFgets");
}

// list file
cout << pstr("-----Before Rewrite\r\n");
while ((c = rdfile.read()) >= 0) Serial.write(c);
rdfile.rewind();
cout << F("-----Before Rewrite\r\n");
while ((c = rdfile.read()) >= 0) {
Serial.write(c);
}

rdfile.rewind();
// read lines from the file to get position
while (1) {
pos = rdfile.curPosition();
@@ -37,56 +41,66 @@ void demoFgets() {
error("Line not found");
}
// find line that contains "Line C"
if (strstr(line, "Line C"))break;
if (strstr(line, "Line C")) {
break;
}
}

// rewrite line with 'C'
if (!rdfile.seekSet(pos)) {
error("seekSet");
}
// rewrite line with 'C'
if (!rdfile.seekSet(pos))error("seekSet");
rdfile.println("Line R");
rdfile.rewind();

// list file
cout << pstr("\r\n-----After Rewrite\r\n");
while ((c = rdfile.read()) >= 0) Serial.write(c);
cout << F("\r\n-----After Rewrite\r\n");
while ((c = rdfile.read()) >= 0) {
Serial.write(c);
}

// close so rewrite is not lost
rdfile.close();
}
//------------------------------------------------------------------------------
void makeTestFile() {
// create or open test file
SdFile wrfile("FGETS.TXT", O_WRITE | O_CREAT | O_TRUNC);
SdFile wrfile("fgets.txt", O_WRITE | O_CREAT | O_TRUNC);
// check for open error
if (!wrfile.isOpen()) error("MakeTestFile");
if (!wrfile.isOpen()) {
error("MakeTestFile");
}

// write test file
wrfile.print(F(
"Line A\r\n"
"Line B\r\n"
"Line C\r\n"
"Line D\r\n"
"Line E\r\n"
));
"Line A\r\n"
"Line B\r\n"
"Line C\r\n"
"Line D\r\n"
"Line E\r\n"
));
wrfile.close();
}
//------------------------------------------------------------------------------
void setup(void) {
Serial.begin(9600);
while (!Serial){} // wait for Leonardo
while (!Serial) {} // wait for Leonardo

cout << pstr("Type any character to start\n");
cout << F("Type any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

makeTestFile();
demoFgets();
cout << pstr("\nDone\n");
cout << F("\nDone\n");
}
void loop(void) {}

+ 14
- 8
SdFat/examples/#attic/readlog/readlog.ino Переглянути файл

@@ -1,8 +1,8 @@
/*
* Read the logfile created by the eventlog.pde example.
* Read the logfile created by the eventlog.ino example.
* Demo of pathnames and working directories
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin
@@ -21,19 +21,25 @@ void setup() {

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// set current working directory
if (!sd.chdir("LOGS/2011/JAN/")) {
sd.errorHalt("chdir failed. Did you run eventlog.pde?");
if (!sd.chdir("logs/2014/Jan/")) {
sd.errorHalt("chdir failed. Did you run eventlog.ino?");
}
// open file in current working directory
ifstream file("LOGFILE.TXT");
ifstream file("logfile.txt");

if (!file.is_open()) sd.errorHalt("open failed");
if (!file.is_open()) {
sd.errorHalt("open failed");
}

// copy the file to Serial
while ((c = file.get()) >= 0) cout << (char)c;
while ((c = file.get()) >= 0) {
cout << (char)c;
}

cout << "Done" << endl;
}

+ 114
- 76
SdFat/examples/AnalogBinLogger/AnalogBinLogger.ino Переглянути файл

@@ -4,7 +4,7 @@
* Samples are logged at regular intervals. Each Sample consists of the ADC
* values for the analog pins defined in the PIN_LIST array. The pins numbers
* may be in any order.
*
*
* Edit the configuration constants below to set the sample pins, sample rate,
* and other configuration values.
*
@@ -20,7 +20,7 @@
* Data is written to the file using a SD multiple block write command.
*/
#ifdef __AVR__
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include "AnalogBinLogger.h"
@@ -50,7 +50,7 @@ const float SAMPLE_INTERVAL = 1.0/SAMPLE_RATE;
//
// You can select an ADC clock rate by defining the symbol ADC_PRESCALER to
// one of these values. You must choose an appropriate ADC clock rate for
// your sample interval.
// your sample interval.
// #define ADC_PRESCALER 7 // F_CPU/128 125 kHz on an Uno
// #define ADC_PRESCALER 6 // F_CPU/64 250 kHz on an Uno
// #define ADC_PRESCALER 5 // F_CPU/32 500 kHz on an Uno
@@ -72,7 +72,7 @@ uint8_t const ADC_REF = (1 << REFS0); // Vcc Reference.
const uint32_t FILE_BLOCK_COUNT = 256000;

// log file base name. Must be six characters or less.
#define FILE_BASE_NAME "ANALOG"
#define FILE_BASE_NAME "analog"

// Set RECORD_EIGHT_BITS non-zero to record only the high 8-bits of the ADC.
#define RECORD_EIGHT_BITS 0
@@ -89,7 +89,7 @@ const uint8_t SD_CS_PIN = SS;
//------------------------------------------------------------------------------
// Buffer definitions.
//
// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT additional
// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT additional
// buffers. QUEUE_DIM must be a power of two larger than
//(BUFFER_BLOCK_COUNT + 1).
//
@@ -124,7 +124,7 @@ const uint8_t QUEUE_DIM = 32; // Must be a power of two!
// End of configuration constants.
//==============================================================================
// Temporary log file. Will be deleted if a reset or power failure occurs.
#define TMP_FILE_NAME "TMP_LOG.BIN"
#define TMP_FILE_NAME "tmp_log.bin"

// Size of file base name. Must not be larger than six.
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
@@ -145,7 +145,7 @@ SdFat sd;

SdBaseFile binFile;

char binName[13] = FILE_BASE_NAME "00.BIN";
char binName[13] = FILE_BASE_NAME "00.bin";

#if RECORD_EIGHT_BITS
const size_t SAMPLES_PER_BLOCK = DATA_DIM8/PIN_COUNT;
@@ -164,7 +164,9 @@ volatile uint8_t fullHead; // volatile insures non-interrupt code sees changes.
uint8_t fullTail;

// queueNext assumes QUEUE_DIM is a power of two
inline uint8_t queueNext(uint8_t ht) {return (ht + 1) & (QUEUE_DIM -1);}
inline uint8_t queueNext(uint8_t ht) {
return (ht + 1) & (QUEUE_DIM -1);
}
//==============================================================================
// Interrupt Service Routines

@@ -193,14 +195,16 @@ ISR(ADC_vect) {
#if RECORD_EIGHT_BITS
uint8_t d = ADCH;
#else // RECORD_EIGHT_BITS
// This will access ADCL first.
// This will access ADCL first.
uint16_t d = ADC;
#endif // RECORD_EIGHT_BITS

if (isrBufNeeded && emptyHead == emptyTail) {
// no buffers - count overrun
if (isrOver < 0XFFFF) isrOver++;
if (isrOver < 0XFFFF) {
isrOver++;
}

// Avoid missed timer error.
timerFlag = false;
return;
@@ -210,30 +214,32 @@ ISR(ADC_vect) {
ADMUX = adcmux[adcindex];
ADCSRB = adcsrb[adcindex];
ADCSRA = adcsra[adcindex];
if (adcindex == 0) timerFlag = false;
if (adcindex == 0) {
timerFlag = false;
}
adcindex = adcindex < (PIN_COUNT - 1) ? adcindex + 1 : 0;
} else {
timerFlag = false;
}
// Check for buffer needed.
if (isrBufNeeded) {
if (isrBufNeeded) {
// Remove buffer from empty queue.
isrBuf = emptyQueue[emptyTail];
emptyTail = queueNext(emptyTail);
isrBuf->count = 0;
isrBuf->overrun = isrOver;
isrBufNeeded = false;
isrBufNeeded = false;
}
// Store ADC data.
isrBuf->data[isrBuf->count++] = d;

// Check for buffer full.
if (isrBuf->count >= PIN_COUNT*SAMPLES_PER_BLOCK) {
// Put buffer isrIn full queue.
// Put buffer isrIn full queue.
uint8_t tmp = fullHead; // Avoid extra fetch of volatile fullHead.
fullQueue[tmp] = (block_t*)isrBuf;
fullHead = queueNext(tmp);
// Set buffer needed and clear overruns.
isrBufNeeded = true;
isrOver = 0;
@@ -243,7 +249,9 @@ ISR(ADC_vect) {
// timer1 interrupt to clear OCF1B
ISR(TIMER1_COMPB_vect) {
// Make sure ADC ISR responded to timer event.
if (timerFlag) timerError = true;
if (timerFlag) {
timerError = true;
}
timerFlag = true;
}
//==============================================================================
@@ -273,7 +281,7 @@ void fatalBlink() {
//------------------------------------------------------------------------------
// initialize ADC and timer1
void adcInit(metadata_t* meta) {
uint8_t adps; // prescaler bits for ADCSRA
uint8_t adps; // prescaler bits for ADCSRA
uint32_t ticks = F_CPU*SAMPLE_INTERVAL + 0.5; // Sample interval cpu cycles.

if (ADC_REF & ~((1 << REFS0) | (1 << REFS1))) {
@@ -287,10 +295,12 @@ void adcInit(metadata_t* meta) {
#else // ADC_PRESCALER
// Allow extra cpu cycles to change ADC settings if more than one pin.
int32_t adcCycles = (ticks - ISR_TIMER0)/PIN_COUNT;
- (PIN_COUNT > 1 ? ISR_SETUP_ADC : 0);
- (PIN_COUNT > 1 ? ISR_SETUP_ADC : 0);
for (adps = 7; adps > 0; adps--) {
if (adcCycles >= (MIN_ADC_CYCLES << adps)) break;
if (adcCycles >= (MIN_ADC_CYCLES << adps)) {
break;
}
}
#endif // ADC_PRESCALER
meta->adcFrequency = F_CPU >> adps;
@@ -309,20 +319,26 @@ void adcInit(metadata_t* meta) {
}
meta->pinCount = PIN_COUNT;
meta->recordEightBits = RECORD_EIGHT_BITS;
for (int i = 0; i < PIN_COUNT; i++) {
uint8_t pin = PIN_LIST[i];
if (pin >= NUM_ANALOG_INPUTS) error("Invalid Analog pin number");
if (pin >= NUM_ANALOG_INPUTS) {
error("Invalid Analog pin number");
}
meta->pinNumber[i] = pin;
// Set ADC reference and low three bits of analog pin number.
// Set ADC reference and low three bits of analog pin number.
adcmux[i] = (pin & 7) | ADC_REF;
if (RECORD_EIGHT_BITS) adcmux[i] |= 1 << ADLAR;
if (RECORD_EIGHT_BITS) {
adcmux[i] |= 1 << ADLAR;
}

// If this is the first pin, trigger on timer/counter 1 compare match B.
adcsrb[i] = i == 0 ? (1 << ADTS2) | (1 << ADTS0) : 0;
#ifdef MUX5
if (pin > 7) adcsrb[i] |= (1 << MUX5);
if (pin > 7) {
adcsrb[i] |= (1 << MUX5);
}
#endif // MUX5
adcsra[i] = (1 << ADEN) | (1 << ADIE) | adps;
adcsra[i] |= i == 0 ? 1 << ADATE : 1 << ADSC;
@@ -360,10 +376,10 @@ void adcInit(metadata_t* meta) {
ICR1 = ticks - 1;
// compare for ADC start
OCR1B = 0;
// multiply by prescaler
ticks <<= tshift;
// Sample interval in CPU clock ticks.
meta->sampleInterval = ticks;
meta->cpuFrequency = F_CPU;
@@ -373,15 +389,15 @@ void adcInit(metadata_t* meta) {
Serial.print(' ');
Serial.print(meta->pinNumber[i], DEC);
}
Serial.println();
Serial.println();
Serial.print(F("ADC bits: "));
Serial.println(meta->recordEightBits ? 8 : 10);
Serial.print(F("ADC clock kHz: "));
Serial.println(meta->adcFrequency/1000);
Serial.print(F("Sample Rate: "));
Serial.println(sampleRate);
Serial.println(sampleRate);
Serial.print(F("Sample interval usec: "));
Serial.println(1000000.0/sampleRate, 4);
Serial.println(1000000.0/sampleRate, 4);
}
//------------------------------------------------------------------------------
// enable ADC and timer1 interrupts
@@ -393,7 +409,7 @@ void adcStart() {

// Clear any pending interrupt.
ADCSRA |= 1 << ADIF;
// Setup for first pin.
ADMUX = adcmux[0];
ADCSRB = adcsrb[0];
@@ -412,7 +428,7 @@ void adcStop() {
ADCSRA = 0;
}
//------------------------------------------------------------------------------
// Convert binary file to CSV file.
// Convert binary file to csv file.
void binaryToCsv() {
uint8_t lastPct = 0;
block_t buf;
@@ -420,19 +436,21 @@ void binaryToCsv() {
uint32_t t0 = millis();
char csvName[13];
StdioStream csvStream;
if (!binFile.isOpen()) {
Serial.println(F("No current binary file"));
return;
}
binFile.rewind();
if (!binFile.read(&buf , 512) == 512) error("Read metadata failed");
// Create a new CSV file.
if (!binFile.read(&buf , 512) == 512) {
error("Read metadata failed");
}
// Create a new csv file.
strcpy(csvName, binName);
strcpy_P(&csvName[BASE_NAME_SIZE + 3], PSTR("CSV"));
strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");

if (!csvStream.fopen(csvName, "w")) {
error("open csvStream failed");
error("open csvStream failed");
}
Serial.println();
Serial.print(F("Writing: "));
@@ -444,23 +462,29 @@ void binaryToCsv() {
csvStream.print(intervalMicros, 4);
csvStream.println(F(",usec"));
for (uint8_t i = 0; i < pm->pinCount; i++) {
if (i) csvStream.putc(',');
if (i) {
csvStream.putc(',');
}
csvStream.print(F("pin"));
csvStream.print(pm->pinNumber[i]);
}
csvStream.println();
csvStream.println();
uint32_t tPct = millis();
while (!Serial.available() && binFile.read(&buf, 512) == 512) {
uint16_t i;
if (buf.count == 0) break;
if (buf.count == 0) {
break;
}
if (buf.overrun) {
csvStream.print(F("OVERRUN,"));
csvStream.println(buf.overrun);
csvStream.println(buf.overrun);
}
for (uint16_t j = 0; j < buf.count; j += PIN_COUNT) {
for (uint16_t i = 0; i < PIN_COUNT; i++) {
if (i) csvStream.putc(',');
csvStream.print(buf.data[i + j]);
if (i) {
csvStream.putc(',');
}
csvStream.print(buf.data[i + j]);
}
csvStream.println();
}
@@ -473,9 +497,11 @@ void binaryToCsv() {
Serial.println('%');
}
}
if (Serial.available()) break;
if (Serial.available()) {
break;
}
}
csvStream.fclose();
csvStream.fclose();
Serial.print(F("Done: "));
Serial.print(0.001*(millis() - t0));
Serial.println(F(" Seconds"));
@@ -487,7 +513,7 @@ void checkOverrun() {
block_t buf;
uint32_t bgnBlock, endBlock;
uint32_t bn = 0;
if (!binFile.isOpen()) {
Serial.println(F("No current binary file"));
return;
@@ -503,7 +529,9 @@ void checkOverrun() {
}
bn++;
while (binFile.read(&buf, 512) == 512) {
if (buf.count == 0) break;
if (buf.count == 0) {
break;
}
if (buf.overrun) {
if (!headerPrinted) {
Serial.println();
@@ -541,7 +569,9 @@ void dumpData() {
Serial.println(F("Type any character to stop"));
delay(1000);
while (!Serial.available() && binFile.read(&buf , 512) == 512) {
if (buf.count == 0) break;
if (buf.count == 0) {
break;
}
if (buf.overrun) {
Serial.print(F("OVERRUN,"));
Serial.println(buf.overrun);
@@ -563,15 +593,15 @@ void dumpData() {
uint32_t const ERASE_SIZE = 262144L;
void logData() {
uint32_t bgnBlock, endBlock;
// Allocate extra buffer space.
block_t block[BUFFER_BLOCK_COUNT];
Serial.println();
// Initialize ADC and timer1.
adcInit((metadata_t*) &block[0]);
// Find unused file name.
if (BASE_NAME_SIZE > 6) {
error("FILE_BASE_NAME too long");
@@ -598,7 +628,7 @@ void logData() {
Serial.println(F("Creating new file"));
binFile.close();
if (!binFile.createContiguous(sd.vwd(),
TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
error("createContiguous failed");
}
// Get the address of the file on the SD.
@@ -607,15 +637,19 @@ void logData() {
}
// Use SdFat's internal buffer.
uint8_t* cache = (uint8_t*)sd.vol()->cacheClear();
if (cache == 0) error("cacheClear failed");
if (cache == 0) {
error("cacheClear failed");
}

// Flash erase all data in the file.
Serial.println(F("Erasing all data"));
uint32_t bgnErase = bgnBlock;
uint32_t endErase;
while (bgnErase < endBlock) {
endErase = bgnErase + ERASE_SIZE;
if (endErase > endBlock) endErase = endBlock;
if (endErase > endBlock) {
endErase = endBlock;
}
if (!sd.card()->erase(bgnErase, endErase)) {
error("erase failed");
}
@@ -628,15 +662,15 @@ void logData() {
// Write metadata.
if (!sd.card()->writeData((uint8_t*)&block[0])) {
error("Write metadata failed");
}
}
// Initialize queues.
emptyHead = emptyTail = 0;
fullHead = fullTail = 0;
// Use SdFat buffer for one block.
emptyQueue[emptyHead] = (block_t*)cache;
emptyHead = queueNext(emptyHead);
// Put rest of buffers in the empty queue.
for (uint8_t i = 0; i < BUFFER_BLOCK_COUNT; i++) {
emptyQueue[emptyHead] = &block[i];
@@ -661,7 +695,7 @@ void logData() {
if (fullHead != fullTail) {
// Get address of block to write.
block_t* pBlock = fullQueue[fullTail];
// Write block to SD.
uint32_t usec = micros();
if (!sd.card()->writeData((uint8_t*)pBlock)) {
@@ -669,10 +703,12 @@ void logData() {
}
usec = micros() - usec;
t1 = millis();
if (usec > maxLatency) maxLatency = usec;
if (usec > maxLatency) {
maxLatency = usec;
}
count += pBlock->count;
// Add overruns and possibly light LED.
// Add overruns and possibly light LED.
if (pBlock->overrun) {
overruns += pBlock->overrun;
if (ERROR_LED_PIN >= 0) {
@@ -704,22 +740,24 @@ void logData() {
fullHead = queueNext(fullHead);
isrBuf = 0;
}
if (fullHead == fullTail) break;
if (fullHead == fullTail) {
break;
}
}
}
if (!sd.card()->writeStop()) {
error("writeStop failed");
}
// Truncate file if recording stopped early.
if (bn != FILE_BLOCK_COUNT) {
if (bn != FILE_BLOCK_COUNT) {
Serial.println(F("Truncating file"));
if (!binFile.truncate(512L * bn)) {
error("Can't truncate file");
}
}
if (!binFile.rename(sd.vwd(), binName)) {
error("Can't rename file");
}
error("Can't rename file");
}
Serial.print(F("File renamed: "));
Serial.println(binName);
Serial.print(F("Max block write usec: "));
@@ -740,10 +778,10 @@ void setup(void) {
pinMode(ERROR_LED_PIN, OUTPUT);
}
Serial.begin(9600);
// Read the first sample pin to init the ADC.
analogRead(PIN_LIST[0]);
Serial.print(F("FreeRam: "));
Serial.println(FreeRam());

@@ -759,8 +797,8 @@ void loop(void) {
while (Serial.read() >= 0) {}
Serial.println();
Serial.println(F("type:"));
Serial.println(F("c - convert file to CSV"));
Serial.println(F("d - dump data to Serial"));
Serial.println(F("c - convert file to csv"));
Serial.println(F("d - dump data to Serial"));
Serial.println(F("e - overrun error details"));
Serial.println(F("r - record ADC data"));

@@ -773,12 +811,12 @@ void loop(void) {
do {
delay(10);
} while (Serial.read() >= 0);
if (c == 'c') {
binaryToCsv();
} else if (c == 'd') {
dumpData();
} else if (c == 'e') {
} else if (c == 'e') {
checkOverrun();
} else if (c == 'r') {
logData();

+ 31
- 24
SdFat/examples/LongFileName/LongFileName.ino Переглянути файл

@@ -1,5 +1,5 @@
// Example use of openNextLFN and open by index.
// You can use test files located in
// Example use of lfnOpenNext and open by index.
// You can use test files located in
// SdFat/examples/LongFileName/testFiles.
#include<SPI.h>
#include <SdFat.h>
@@ -10,6 +10,7 @@ const uint8_t SD_CS_PIN = SS;

SdFat sd;
SdFile file;
SdFile dirFile;

// Number of files found.
uint16_t n = 0;
@@ -21,37 +22,39 @@ const uint16_t nMax = 10;
uint16_t dirIndex[nMax];
//------------------------------------------------------------------------------
void setup() {
const size_t NAME_DIM = 50;
char name[NAME_DIM];
dir_t dir;
Serial.begin(9600);
while (!Serial) {}
delay(1000);

// Print the location of some test files.
Serial.println(F("\r\n"
"You can use test files located in\r\n"
"You can use test files located in\r\n"
"SdFat/examples/LongFileName/testFiles"));
if (!sd.begin(SD_CS_PIN)) sd.initErrorHalt();

if (!sd.begin(SD_CS_PIN)) {
sd.initErrorHalt();
}
Serial.print(F("Free RAM: "));
Serial.println(FreeRam());
Serial.println();
// List files in root directory. Volume working directory is initially root.
sd.vwd()->rewind();
while (n < nMax && file.openNextLFN(sd.vwd(), name, NAME_DIM, O_READ) > 0) {

// List files in root directory.
if (!dirFile.open("/", O_READ)) {
sd.errorHalt("open root failed");
}
while (n < nMax && file.openNext(&dirFile, O_READ)) {

// Skip directories and hidden files.
if (!file.isSubDir() && !file.isHidden()) {
// Save dirIndex of file in directory.
dirIndex[n] = file.dirIndex();
// Print the file number and name.
Serial.print(n++);
Serial.write(' ');
Serial.println(name);
file.printName(&Serial);
Serial.println();
}
file.close();
}
@@ -59,29 +62,33 @@ void setup() {
//------------------------------------------------------------------------------
void loop() {
int c;
// Discard any Serial input.
while (Serial.read() > 0) {}
Serial.print(F("\r\nEnter File Number: "));
while ((c = Serial.read()) < 0) {};
if (!isdigit(c) || (c -= '0') >= n) {
Serial.println(F("Invald number"));
return;
}
Serial.println(c);
if (!file.open(sd.vwd(), dirIndex[c], O_READ)) {
if (!file.open(&dirFile, dirIndex[c], O_READ)) {
sd.errorHalt(F("open"));
}
Serial.println();
char last;
// Copy up to 500 characters to Serial.
for (int i = 0; i < 500 && (c = file.read()) > 0; i++) {
Serial.write(last = (char)c);
}
// Add new line if missing from last line.
if (last != '\n') Serial.println();
if (last != '\n') {
Serial.println();
}
file.close();
Serial.flush();
delay(100);
}

SdFat/examples/LongFileName/testFiles/With Two.dots.txt → SdFat/examples/LongFileName/testFiles/With.Two dots.txt Переглянути файл


+ 72
- 48
SdFat/examples/LowLatencyLogger/LowLatencyLogger.ino Переглянути файл

@@ -1,6 +1,6 @@
/**
* This program logs data to a binary file. Functions are included
* to convert the binary file to a CSV text file.
* to convert the binary file to a csv text file.
*
* Samples are logged at regular intervals. The maximum logging rate
* depends on the quality of your SD card and the time required to
@@ -13,7 +13,7 @@
*
* Data is written to the file using a SD multiple block write command.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
//------------------------------------------------------------------------------
@@ -32,7 +32,7 @@ void acquireData(data_t* data) {
void printData(Print* pr, data_t* data) {
pr->print(data->time);
for (int i = 0; i < ADC_DIM; i++) {
pr->write(',');
pr->write(',');
pr->print(data->adc[i]);
}
pr->println();
@@ -61,7 +61,7 @@ const uint8_t SD_CS_PIN = SS;
// Digital pin to indicate an error, set to -1 if not used.
// The led blinks for fatal errors. The led goes on solid for SD write
// overrun errors and logging continues.
const int8_t ERROR_LED_PIN = 3;
const int8_t ERROR_LED_PIN = -1;
//------------------------------------------------------------------------------
// File definitions.
//
@@ -72,11 +72,11 @@ const int8_t ERROR_LED_PIN = 3;
const uint32_t FILE_BLOCK_COUNT = 256000;

// log file base name. Must be six characters or less.
#define FILE_BASE_NAME "DATA"
#define FILE_BASE_NAME "data"
//------------------------------------------------------------------------------
// Buffer definitions.
//
// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT additional
// The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT additional
// buffers.
//
#ifndef RAMEND
@@ -102,7 +102,7 @@ const uint8_t BUFFER_BLOCK_COUNT = 12;
// End of configuration constants.
//==============================================================================
// Temporary log file. Will be deleted if a reset or power failure occurs.
#define TMP_FILE_NAME "TMP_LOG.BIN"
#define TMP_FILE_NAME "tmp_log.bin"

// Size of file base name. Must not be larger than six.
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
@@ -111,7 +111,7 @@ SdFat sd;

SdBaseFile binFile;

char binName[13] = FILE_BASE_NAME "00.BIN";
char binName[13] = FILE_BASE_NAME "00.bin";

// Number of data records in a block.
const uint16_t DATA_DIM = (512 - 4)/sizeof(data_t);
@@ -137,7 +137,9 @@ uint8_t fullHead;
uint8_t fullTail;

// Advance queue index.
inline uint8_t queueNext(uint8_t ht) {return ht < (QUEUE_DIM - 1) ? ht + 1 : 0;}
inline uint8_t queueNext(uint8_t ht) {
return ht < (QUEUE_DIM - 1) ? ht + 1 : 0;
}
//==============================================================================
// Error messages stored in flash.
#define error(msg) errorFlash(F(msg))
@@ -159,7 +161,7 @@ void fatalBlink() {
}
}
//==============================================================================
// Convert binary file to CSV file.
// Convert binary file to csv file.
void binaryToCsv() {
uint8_t lastPct = 0;
block_t block;
@@ -167,7 +169,7 @@ void binaryToCsv() {
uint32_t syncCluster = 0;
SdFile csvFile;
char csvName[13];
if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
@@ -176,10 +178,10 @@ void binaryToCsv() {
binFile.rewind();
// Create a new csvFile.
strcpy(csvName, binName);
strcpy_P(&csvName[BASE_NAME_SIZE + 3], PSTR("CSV"));
strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");

if (!csvFile.open(csvName, O_WRITE | O_CREAT | O_TRUNC)) {
error("open csvFile failed");
error("open csvFile failed");
}
Serial.println();
Serial.print(F("Writing: "));
@@ -189,7 +191,9 @@ void binaryToCsv() {
uint32_t tPct = millis();
while (!Serial.available() && binFile.read(&block, 512) == 512) {
uint16_t i;
if (block.count == 0) break;
if (block.count == 0) {
break;
}
if (block.overrun) {
csvFile.print(F("OVERRUN,"));
csvFile.println(block.overrun);
@@ -210,7 +214,9 @@ void binaryToCsv() {
Serial.println('%');
}
}
if (Serial.available()) break;
if (Serial.available()) {
break;
}
}
csvFile.close();
Serial.print(F("Done: "));
@@ -224,7 +230,7 @@ void checkOverrun() {
block_t block;
uint32_t bgnBlock, endBlock;
uint32_t bn = 0;
if (!binFile.isOpen()) {
Serial.println();
Serial.println(F("No current binary file"));
@@ -237,7 +243,9 @@ void checkOverrun() {
Serial.println();
Serial.println(F("Checking overrun errors - type any character to stop"));
while (binFile.read(&block, 512) == 512) {
if (block.count == 0) break;
if (block.count == 0) {
break;
}
if (block.overrun) {
if (!headerPrinted) {
Serial.println();
@@ -274,7 +282,9 @@ void dumpData() {
delay(1000);
printHeader(&Serial);
while (!Serial.available() && binFile.read(&block , 512) == 512) {
if (block.count == 0) break;
if (block.count == 0) {
break;
}
if (block.overrun) {
Serial.print(F("OVERRUN,"));
Serial.println(block.overrun);
@@ -291,12 +301,12 @@ void dumpData() {
uint32_t const ERASE_SIZE = 262144L;
void logData() {
uint32_t bgnBlock, endBlock;
// Allocate extra buffer space.
block_t block[BUFFER_BLOCK_COUNT];
block_t* curBlock = 0;
Serial.println();
// Find unused file name.
if (BASE_NAME_SIZE > 6) {
error("FILE_BASE_NAME too long");
@@ -323,7 +333,7 @@ void logData() {
Serial.println(F("Creating new file"));
binFile.close();
if (!binFile.createContiguous(sd.vwd(),
TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
error("createContiguous failed");
}
// Get the address of the file on the SD.
@@ -332,15 +342,19 @@ void logData() {
}
// Use SdFat's internal buffer.
uint8_t* cache = (uint8_t*)sd.vol()->cacheClear();
if (cache == 0) error("cacheClear failed");
if (cache == 0) {
error("cacheClear failed");
}

// Flash erase all data in the file.
Serial.println(F("Erasing all data"));
uint32_t bgnErase = bgnBlock;
uint32_t endErase;
while (bgnErase < endBlock) {
endErase = bgnErase + ERASE_SIZE;
if (endErase > endBlock) endErase = endBlock;
if (endErase > endBlock) {
endErase = endBlock;
}
if (!sd.card()->erase(bgnErase, endErase)) {
error("erase failed");
}
@@ -353,11 +367,11 @@ void logData() {
// Initialize queues.
emptyHead = emptyTail = 0;
fullHead = fullTail = 0;
// Use SdFat buffer for one block.
emptyQueue[emptyHead] = (block_t*)cache;
emptyHead = queueNext(emptyHead);
// Put rest of buffers in the empty queue.
for (uint8_t i = 0; i < BUFFER_BLOCK_COUNT; i++) {
emptyQueue[emptyHead] = &block[i];
@@ -382,15 +396,17 @@ void logData() {
while (1) {
// Time for next data record.
logTime += LOG_INTERVAL_USEC;
if (Serial.available()) closeFile = true;
if (Serial.available()) {
closeFile = true;
}

if (closeFile) {
if (curBlock != 0 && curBlock->count >= 0) {
if (curBlock != 0 && curBlock->count >= 0) {
// Put buffer in full queue.
fullQueue[fullHead] = curBlock;
fullHead = queueNext(fullHead);
curBlock = 0;
}
}
} else {
if (curBlock == 0 && emptyTail != emptyHead) {
curBlock = emptyQueue[emptyTail];
@@ -402,26 +418,30 @@ void logData() {
do {
diff = logTime - micros();
} while(diff > 0);
if (diff < -10) error("LOG_INTERVAL_USEC too small");
if (diff < -10) {
error("LOG_INTERVAL_USEC too small");
}
if (curBlock == 0) {
overrun++;
} else {
acquireData(&curBlock->data[curBlock->count++]);
if (curBlock->count == DATA_DIM) {
fullQueue[fullHead] = curBlock;
fullHead = queueNext(fullHead);
fullHead = queueNext(fullHead);
curBlock = 0;
}
}
}
if (fullHead == fullTail) {
// Exit loop if done.
if (closeFile) break;
if (closeFile) {
break;
}
} else if (!sd.card()->isBusy()) {
// Get address of block to write.
block_t* pBlock = fullQueue[fullTail];
fullTail = queueNext(fullTail);
fullTail = queueNext(fullTail);
// Write block to SD.
uint32_t usec = micros();
if (!sd.card()->writeData((uint8_t*)pBlock)) {
@@ -429,10 +449,12 @@ void logData() {
}
usec = micros() - usec;
t1 = millis();
if (usec > maxLatency) maxLatency = usec;
if (usec > maxLatency) {
maxLatency = usec;
}
count += pBlock->count;
// Add overruns and possibly light LED.
// Add overruns and possibly light LED.
if (pBlock->overrun) {
overrunTotal += pBlock->overrun;
if (ERROR_LED_PIN >= 0) {
@@ -453,15 +475,15 @@ void logData() {
error("writeStop failed");
}
// Truncate file if recording stopped early.
if (bn != FILE_BLOCK_COUNT) {
if (bn != FILE_BLOCK_COUNT) {
Serial.println(F("Truncating file"));
if (!binFile.truncate(512L * bn)) {
error("Can't truncate file");
}
}
if (!binFile.rename(sd.vwd(), binName)) {
error("Can't rename file");
}
error("Can't rename file");
}
Serial.print(F("File renamed: "));
Serial.println(binName);
Serial.print(F("Max block write usec: "));
@@ -483,12 +505,14 @@ void setup(void) {
}
Serial.begin(9600);
while (!Serial) {}
Serial.print(F("FreeRam: "));
Serial.println(FreeRam());
Serial.print(F("Records/block: "));
Serial.println(DATA_DIM);
if (sizeof(block_t) != 512) error("Invalid block size");
if (sizeof(block_t) != 512) {
error("Invalid block size");
}
// initialize file system.
if (!sd.begin(SD_CS_PIN, SPI_FULL_SPEED)) {
sd.initErrorPrint();
@@ -501,19 +525,19 @@ void loop(void) {
while (Serial.read() >= 0) {}
Serial.println();
Serial.println(F("type:"));
Serial.println(F("c - convert file to CSV"));
Serial.println(F("d - dump data to Serial"));
Serial.println(F("c - convert file to csv"));
Serial.println(F("d - dump data to Serial"));
Serial.println(F("e - overrun error details"));
Serial.println(F("r - record data"));

while(!Serial.available()) {}
char c = tolower(Serial.read());
// Discard extra Serial data.
do {
delay(10);
} while (Serial.read() >= 0);
if (ERROR_LED_PIN >= 0) {
digitalWrite(ERROR_LED_PIN, LOW);
}
@@ -521,7 +545,7 @@ void loop(void) {
binaryToCsv();
} else if (c == 'd') {
dumpData();
} else if (c == 'e') {
} else if (c == 'e') {
checkOverrun();
} else if (c == 'r') {
logData();

+ 7
- 4
SdFat/examples/OpenNext/OpenNext.ino Переглянути файл

@@ -1,7 +1,7 @@
/*
* Print size, modify date/time, and name for all files in root.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin
@@ -16,17 +16,20 @@ void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
delay(1000);
Serial.println();

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// open next file in root. The volume working directory, vwd, is root
while (file.openNext(sd.vwd(), O_READ)) {
file.printFileSize(&Serial);
Serial.write(' ');
file.printModifyDateTime(&Serial);
Serial.write(' ');
Serial.write(' ');
file.printName(&Serial);
if (file.isDir()) {
// Indicate a directory.

+ 41
- 35
SdFat/examples/PrintBenchmark/PrintBenchmark.ino Переглянути файл

@@ -1,7 +1,7 @@
/*
* This sketch is a simple Print benchmark.
* This program is a simple Print benchmark.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>

@@ -38,24 +38,26 @@ void loop() {
while (Serial.read() >= 0) {
}
// pstr stores strings in flash to save RAM
cout << pstr("Type any character to start\n");
cout << F("Type any character to start\n");
while (Serial.read() <= 0) {
}
delay(400); // catch Due reset problem

cout << pstr("Free RAM: ") << FreeRam() << endl;
cout << F("Free RAM: ") << FreeRam() << endl;

// initialize the SD card at SPI_FULL_SPEED for best performance.
// try SPI_HALF_SPEED if bus errors occur.
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
sd.initErrorHalt();
}

cout << pstr("Type is FAT") << int(sd.vol()->fatType()) << endl;
cout << F("Type is FAT") << int(sd.vol()->fatType()) << endl;

cout << pstr("Starting print test. Please wait.\n\n");
cout << F("Starting print test. Please wait.\n\n");

// do write test
for (int test = 0; test < 6; test++) {
char fileName[13] = "BENCH0.TXT";
char fileName[13] = "bench0.txt";
fileName[5] = '0' + test;
// open or create file - truncate existing file.
if (!file.open(fileName, O_CREAT | O_TRUNC | O_RDWR)) {
@@ -66,29 +68,29 @@ void loop() {
totalLatency = 0;
switch(test) {
case 0:
cout << pstr("Test of println(uint16_t)\n");
cout << F("Test of println(uint16_t)\n");
break;

case 1:
cout << pstr("Test of printField(uint16_t, char)\n");
cout << F("Test of printField(uint16_t, char)\n");
break;

case 2:
cout << pstr("Test of println(uint32_t)\n");
cout << F("Test of println(uint32_t)\n");
break;
case 3:
cout << pstr("Test of printField(uint32_t, char)\n");
break;
cout << F("Test of printField(uint32_t, char)\n");
break;
case 4:
cout << pstr("Test of println(float)\n");
break;
cout << F("Test of println(float)\n");
break;
case 5:
cout << pstr("Test of printField(float, char)\n");
break;
cout << F("Test of printField(float, char)\n");
break;
}
uint32_t t = millis();
for (uint16_t i = 0; i < N_PRINT; i++) {
uint32_t m = micros();
@@ -104,16 +106,16 @@ void loop() {

case 2:
file.println(12345678UL + i);
break;
break;
case 3:
file.printField(12345678UL + i, '\n');
break;
break;
case 4:
file.println((float)0.01*i);
break;
case 5:
file.printField((float)0.01*i, '\n');
break;
@@ -122,20 +124,24 @@ void loop() {
error("write failed");
}
m = micros() - m;
if (maxLatency < m) maxLatency = m;
if (minLatency > m) minLatency = m;
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
totalLatency += m;
}
file.close();
t = millis() - t;
double s = file.fileSize();
cout << pstr("Time ") << 0.001*t << pstr(" sec\n");
cout << pstr("File size ") << 0.001*s << pstr(" KB\n");
cout << pstr("Write ") << s/t << pstr(" KB/sec\n");
cout << pstr("Maximum latency: ") << maxLatency;
cout << pstr(" usec, Minimum Latency: ") << minLatency;
cout << pstr(" usec, Avg Latency: ");
cout << totalLatency/N_PRINT << pstr(" usec\n\n");
cout << F("Time ") << 0.001*t << F(" sec\n");
cout << F("File size ") << 0.001*s << F(" KB\n");
cout << F("Write ") << s/t << F(" KB/sec\n");
cout << F("Maximum latency: ") << maxLatency;
cout << F(" usec, Minimum Latency: ") << minLatency;
cout << F(" usec, Avg Latency: ");
cout << totalLatency/N_PRINT << F(" usec\n\n");
}
cout << pstr("Done!\n\n");
cout << F("Done!\n\n");
}

+ 62
- 60
SdFat/examples/QuickStart/QuickStart.ino Переглянути файл

@@ -1,6 +1,6 @@
// Quick hardware test.
//
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>
//
// Set DISABLE_CHIP_SELECT to disable a second SPI device.
@@ -27,39 +27,39 @@ ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));
int chipSelect;

void cardOrSpeed() {
cout << pstr("Try another SD card or reduce the SPI bus speed.\n");
cout << pstr("Edit spiSpeed in this sketch to change it.\n");
cout << F("Try another SD card or reduce the SPI bus speed.\n");
cout << F("Edit spiSpeed in this program to change it.\n");
}

void reformatMsg() {
cout << pstr("Try reformatting the card. For best results use\n");
cout << pstr("the SdFormatter sketch in SdFat/examples or download\n");
cout << pstr("and use SDFormatter from www.sdcard.org/downloads.\n");
cout << F("Try reformatting the card. For best results use\n");
cout << F("the SdFormatter program in SdFat/examples or download\n");
cout << F("and use SDFormatter from www.sdcard.org/downloads.\n");
}

void setup() {
Serial.begin(9600);
while (!Serial) {} // Wait for Leonardo.
cout << pstr("\nSPI pins:\n");
cout << pstr("MISO: ") << int(MISO) << endl;
cout << pstr("MOSI: ") << int(MOSI) << endl;
cout << pstr("SCK: ") << int(SCK) << endl;
cout << pstr("SS: ") << int(SS) << endl;
cout << F("\nSPI pins:\n");
cout << F("MISO: ") << int(MISO) << endl;
cout << F("MOSI: ") << int(MOSI) << endl;
cout << F("SCK: ") << int(SCK) << endl;
cout << F("SS: ") << int(SS) << endl;
if (DISABLE_CHIP_SELECT < 0) {
cout << pstr(
"\nBe sure to edit DISABLE_CHIP_SELECT if you have\n"
"a second SPI device. For example, with the Ethernet\n"
"shield, DISABLE_CHIP_SELECT should be set to 10\n"
"to disable the Ethernet controller.\n");
cout << F(
"\nBe sure to edit DISABLE_CHIP_SELECT if you have\n"
"a second SPI device. For example, with the Ethernet\n"
"shield, DISABLE_CHIP_SELECT should be set to 10\n"
"to disable the Ethernet controller.\n");
}
cout << pstr(
"\nSD chip select is the key hardware option.\n"
"Common values are:\n"
"Arduino Ethernet shield, pin 4\n"
"Sparkfun SD shield, pin 8\n"
"Adafruit SD shields and modules, pin 10\n");
cout << F(
"\nSD chip select is the key hardware option.\n"
"Common values are:\n"
"Arduino Ethernet shield, pin 4\n"
"Sparkfun SD shield, pin 8\n"
"Adafruit SD shields and modules, pin 10\n");
}

bool firstTry = true;
@@ -67,89 +67,91 @@ void loop() {
// read any existing Serial data
while (Serial.read() >= 0) {}

if (!firstTry) cout << pstr("\nRestarting\n");
if (!firstTry) {
cout << F("\nRestarting\n");
}
firstTry = false;

cout << pstr("\nEnter the chip select pin number: ");
cout << F("\nEnter the chip select pin number: ");
while (!Serial.available()) {}
delay(400); // catch Due restart problem
delay(400); // catch Due restart problem
cin.readline();
if (cin >> chipSelect) {
cout << chipSelect << endl;
} else {
cout << pstr("\nInvalid pin number\n");
cout << F("\nInvalid pin number\n");
return;
}
if (DISABLE_CHIP_SELECT < 0) {
cout << pstr(
"\nAssuming the SD is the only SPI device.\n"
"Edit DISABLE_CHIP_SELECT to disable another device.\n");
cout << F(
"\nAssuming the SD is the only SPI device.\n"
"Edit DISABLE_CHIP_SELECT to disable another device.\n");
} else {
cout << pstr("\nDisabling SPI device on pin ");
cout << F("\nDisabling SPI device on pin ");
cout << int(DISABLE_CHIP_SELECT) << endl;
pinMode(DISABLE_CHIP_SELECT, OUTPUT);
digitalWrite(DISABLE_CHIP_SELECT, HIGH);
}
if (!sd.begin(chipSelect, spiSpeed)) {
if (sd.card()->errorCode()) {
cout << pstr(
"\nSD initialization failed.\n"
"Do not reformat the card!\n"
"Is the card correctly inserted?\n"
"Is chipSelect set to the correct value?\n"
"Does another SPI device need to be disabled?\n"
"Is there a wiring/soldering problem?\n");
cout << pstr("\nerrorCode: ") << hex << showbase;
cout << F(
"\nSD initialization failed.\n"
"Do not reformat the card!\n"
"Is the card correctly inserted?\n"
"Is chipSelect set to the correct value?\n"
"Does another SPI device need to be disabled?\n"
"Is there a wiring/soldering problem?\n");
cout << F("\nerrorCode: ") << hex << showbase;
cout << int(sd.card()->errorCode());
cout << pstr(", errorData: ") << int(sd.card()->errorData());
cout << F(", errorData: ") << int(sd.card()->errorData());
cout << dec << noshowbase << endl;
return;
}
cout << pstr("\nCard successfully initialized.\n");
cout << F("\nCard successfully initialized.\n");
if (sd.vol()->fatType() == 0) {
cout << pstr("Can't find a valid FAT16/FAT32 partition.\n");
cout << F("Can't find a valid FAT16/FAT32 partition.\n");
reformatMsg();
return;
}
}
if (!sd.vwd()->isOpen()) {
cout << pstr("Can't open root directory.\n");
cout << F("Can't open root directory.\n");
reformatMsg();
return;
}
cout << pstr("Can't determine error type\n");
}
cout << F("Can't determine error type\n");
return;
}
cout << pstr("\nCard successfully initialized.\n");
cout << F("\nCard successfully initialized.\n");
cout << endl;

uint32_t size = sd.card()->cardSize();
if (size == 0) {
cout << pstr("Can't determine the card size.\n");
cout << F("Can't determine the card size.\n");
cardOrSpeed();
return;
}
uint32_t sizeMB = 0.000512 * size + 0.5;
cout << pstr("Card size: ") << sizeMB;
cout << pstr(" MB (MB = 1,000,000 bytes)\n");
cout << F("Card size: ") << sizeMB;
cout << F(" MB (MB = 1,000,000 bytes)\n");
cout << endl;
cout << pstr("Volume is FAT") << int(sd.vol()->fatType());
cout << pstr(", Cluster size (bytes): ") << 512L * sd.vol()->blocksPerCluster();
cout << F("Volume is FAT") << int(sd.vol()->fatType());
cout << F(", Cluster size (bytes): ") << 512L * sd.vol()->blocksPerCluster();
cout << endl << endl;

cout << pstr("Files found (name date time size):\n");
cout << F("Files found (date time size name):\n");
sd.ls(LS_R | LS_DATE | LS_SIZE);

if ((sizeMB > 1100 && sd.vol()->blocksPerCluster() < 64)
|| (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
cout << pstr("\nThis card should be reformatted for best performance.\n");
cout << pstr("Use a cluster size of 32 KB for cards larger than 1 GB.\n");
cout << pstr("Only cards larger than 2 GB should be formatted FAT32.\n");
|| (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
cout << F("\nThis card should be reformatted for best performance.\n");
cout << F("Use a cluster size of 32 KB for cards larger than 1 GB.\n");
cout << F("Only cards larger than 2 GB should be formatted FAT32.\n");
reformatMsg();
return;
}
// read any existing Serial data
while (Serial.read() >= 0) {}
cout << pstr("\nSuccess! Type any character to restart.\n");
cout << F("\nSuccess! Type any character to restart.\n");
while (Serial.read() < 0) {}
}

+ 30
- 25
SdFat/examples/RawWrite/RawWrite.ino Переглянути файл

@@ -1,11 +1,11 @@
/*
* This sketch illustrates raw write functions in SdFat that
* can be used for high speed data logging.
* This program illustrates raw write functions in SdFat that
* can be used for high speed data logging.
*
* This sketch simulates logging from a source that produces
* This program simulates logging from a source that produces
* data at a constant rate of one block every MICROS_PER_BLOCK.
*
* If a high quality SanDisk card is used with this sketch
* If a high quality SanDisk card is used with this program
* no overruns occur and the maximum block write time is
* under 2000 micros.
*
@@ -14,7 +14,7 @@
* a few seconds to erase a 500 MB file since the card only
* marks the blocks as erased; no data transfer is required.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>

@@ -57,21 +57,23 @@ void setup(void) {
void loop(void) {
while (Serial.read() >= 0) {}
// pstr stores strings in flash to save RAM
cout << pstr("Type any character to start\n");
cout << F("Type any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem

cout << pstr("Free RAM: ") << FreeRam() << endl;
cout << F("Free RAM: ") << FreeRam() << endl;

// initialize the SD card at SPI_FULL_SPEED for best performance.
// try SPI_HALF_SPEED if bus errors occur.
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
sd.initErrorHalt();
}

// delete possible existing file
sd.remove("RAW.TXT");
sd.remove("RawWrite.txt");

// create a contiguous file
if (!file.createContiguous(sd.vwd(), "RAW.TXT", 512UL*BLOCK_COUNT)) {
if (!file.createContiguous(sd.vwd(), "RawWrite.txt", 512UL*BLOCK_COUNT)) {
error("createContiguous failed");
}
// get the location of the file's blocks
@@ -94,10 +96,10 @@ void loop(void) {
pCache[i + 63] = '\n';
}

cout << pstr("Start raw write of ") << file.fileSize() << pstr(" bytes at\n");
cout << 512000000UL/MICROS_PER_BLOCK << pstr(" bytes per second\n");
cout << pstr("Please wait ") << (BLOCK_COUNT*MICROS_PER_BLOCK)/1000000UL;
cout << pstr(" seconds\n");
cout << F("Start raw write of ") << file.fileSize() << F(" bytes at\n");
cout << 512000000UL/MICROS_PER_BLOCK << F(" bytes per second\n");
cout << F("Please wait ") << (BLOCK_COUNT*MICROS_PER_BLOCK)/1000000UL;
cout << F(" seconds\n");

// tell card to setup for multiple block write with pre-erase
if (!sd.card()->writeStart(bgnBlock, BLOCK_COUNT)) {
@@ -116,13 +118,15 @@ void loop(void) {

// put block number at start of first line in block
uint32_t n = b;
for (int8_t d = 5; d >= 0; d--){
for (int8_t d = 5; d >= 0; d--) {
pCache[d] = n || d == 5 ? n % 10 + '0' : ' ';
n /= 10;
}
// write a 512 byte block
uint32_t tw = micros();
if (!sd.card()->writeData(pCache)) error("writeData failed");
if (!sd.card()->writeData(pCache)) {
error("writeData failed");
}
tw = micros() - tw;

// check for max write time
@@ -138,8 +142,7 @@ void loop(void) {
overruns++;
// advance time to reflect overrun
tNext = micros();
}
else {
} else {
// wait for time to write next block
while(micros() < tNext);
}
@@ -148,16 +151,18 @@ void loop(void) {
t = micros() - t;

// end multiple block write mode
if (!sd.card()->writeStop()) error("writeStop failed");
if (!sd.card()->writeStop()) {
error("writeStop failed");
}

cout << pstr("Done\n");
cout << pstr("Elapsed time: ") << setprecision(3)<< 1.e-6*t;
cout << pstr(" seconds\n");
cout << pstr("Max write time: ") << maxWriteTime << pstr(" micros\n");
cout << pstr("Overruns: ") << overruns << endl;
cout << F("Done\n");
cout << F("Elapsed time: ") << setprecision(3)<< 1.e-6*t;
cout << F(" seconds\n");
cout << F("Max write time: ") << maxWriteTime << F(" micros\n");
cout << F("Overruns: ") << overruns << endl;
if (overruns) {
uint8_t n = overruns > OVER_DIM ? OVER_DIM : overruns;
cout << pstr("fileBlock,micros") << endl;
cout << F("fileBlock,micros") << endl;
for (uint8_t i = 0; i < n; i++) {
cout << over[i].block << ',' << over[i].micros << endl;
}

+ 88
- 0
SdFat/examples/ReadWrite/ReadWrite.ino Переглянути файл

@@ -0,0 +1,88 @@
/*
SD card read/write

This example shows how to read and write data to and from an SD card file
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4

created Nov 2010
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe

This example code is in the public domain.

*/
#define SD_CS_PIN SS
#include <SPI.h>
//#include <SD.h>
#include <SdFat.h>
SdFat SD;

File myFile;

void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}


Serial.print("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);

if (!SD.begin(SD_CS_PIN)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");

// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
myFile = SD.open("test.txt", FILE_WRITE);

// if the file opened okay, write to it:
if (myFile) {
Serial.print("Writing to test.txt...");
myFile.println("testing 1, 2, 3.");
// close the file:
myFile.close();
Serial.println("done.");
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}

// re-open the file for reading:
myFile = SD.open("test.txt");
if (myFile) {
Serial.println("test.txt:");

// read from the file until there's nothing else in it:
while (myFile.available()) {
Serial.write(myFile.read());
}
// close the file:
myFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}
}

void loop()
{
// nothing happens after setup
}



+ 12
- 8
SdFat/examples/ReadWriteSdFat/ReadWriteSdFat.ino Переглянути файл

@@ -3,24 +3,24 @@
const int chipSelect = 4;
/*
SD card read/write
This example shows how to read and write data to and from an SD card file
This example shows how to read and write data to and from an SD card file
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
created Nov 2010
by David A. Mellis
updated 2 Dec 2010
by Tom Igoe
modified by Bill Greiman 11 Apr 2011
This example code is in the public domain.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>
SdFat sd;
SdFile myFile;
@@ -31,11 +31,13 @@ void setup() {
Serial.println("Type any character to start");
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem
// Initialize SdFat or print a detailed error message and halt
// Use half speed like the native library.
// change to SPI_FULL_SPEED for more performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// open the file for write at end like the Native SD library
if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
@@ -57,7 +59,9 @@ void setup() {

// read from the file until there's nothing else in it:
int data;
while ((data = myFile.read()) >= 0) Serial.write(data);
while ((data = myFile.read()) >= 0) {
Serial.write(data);
}
// close the file:
myFile.close();
}

+ 101
- 77
SdFat/examples/SdFormatter/SdFormatter.ino Переглянути файл

@@ -1,19 +1,19 @@
/*
* This sketch will format an SD or SDHC card.
* This program will format an SD or SDHC card.
* Warning all data will be deleted!
*
* For SD/SDHC cards larger than 64 MB this
* sketch attempts to match the format
* program attempts to match the format
* generated by SDFormatter available here:
*
* http://www.sdcard.org/consumers/formatter/
*
* For smaller cards this sketch uses FAT16
* For smaller cards this program uses FAT16
* and SDFormatter uses FAT12.
*/
// Print extra info for debug if DEBUG_PRINT is nonzero
#define DEBUG_PRINT 0
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>
#if DEBUG_PRINT
#include <SdFatUtil.h>
@@ -65,13 +65,13 @@ char noName[] = "NO NAME ";
char fat16str[] = "FAT16 ";
char fat32str[] = "FAT32 ";
//------------------------------------------------------------------------------
#define sdError(msg) sdError_P(PSTR(msg))
#define sdError(msg) sdError_F(F(msg))

void sdError_P(const char* str) {
cout << pstr("error: ");
cout << pgm(str) << endl;
void sdError_F(const __FlashStringHelper* str) {
cout << F("error: ");
cout << str << endl;
if (card.errorCode()) {
cout << pstr("SD error: ") << hex << int(card.errorCode());
cout << F("SD error: ") << hex << int(card.errorCode());
cout << ',' << int(card.errorData()) << dec << endl;
}
while (1);
@@ -79,19 +79,19 @@ void sdError_P(const char* str) {
//------------------------------------------------------------------------------
#if DEBUG_PRINT
void debugPrint() {
cout << pstr("FreeRam: ") << FreeRam() << endl;
cout << pstr("partStart: ") << relSector << endl;
cout << pstr("partSize: ") << partSize << endl;
cout << pstr("reserved: ") << reservedSectors << endl;
cout << pstr("fatStart: ") << fatStart << endl;
cout << pstr("fatSize: ") << fatSize << endl;
cout << pstr("dataStart: ") << dataStart << endl;
cout << pstr("clusterCount: ");
cout << F("FreeRam: ") << FreeRam() << endl;
cout << F("partStart: ") << relSector << endl;
cout << F("partSize: ") << partSize << endl;
cout << F("reserved: ") << reservedSectors << endl;
cout << F("fatStart: ") << fatStart << endl;
cout << F("fatSize: ") << fatSize << endl;
cout << F("dataStart: ") << dataStart << endl;
cout << F("clusterCount: ");
cout << ((relSector + partSize - dataStart)/sectorsPerCluster) << endl;
cout << endl;
cout << pstr("Heads: ") << int(numberOfHeads) << endl;
cout << pstr("Sectors: ") << int(sectorsPerTrack) << endl;
cout << pstr("Cylinders: ");
cout << F("Heads: ") << int(numberOfHeads) << endl;
cout << F("Sectors: ") << int(sectorsPerTrack) << endl;
cout << F("Cylinders: ");
cout << cardSizeBlocks/(numberOfHeads*sectorsPerTrack) << endl;
}
#endif // DEBUG_PRINT
@@ -122,7 +122,7 @@ void initSizes() {
sectorsPerCluster = 128;
}

cout << pstr("Blocks/Cluster: ") << int(sectorsPerCluster) << endl;
cout << F("Blocks/Cluster: ") << int(sectorsPerCluster) << endl;
// set fake disk geometry
sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63;

@@ -161,7 +161,9 @@ void clearFatDir(uint32_t bgn, uint32_t count) {
sdError("Clear FAT/DIR writeStart failed");
}
for (uint32_t i = 0; i < count; i++) {
if ((i & 0XFF) == 0) cout << '.';
if ((i & 0XFF) == 0) {
cout << '.';
}
if (!card.writeData(cache.data)) {
sdError("Clear FAT/DIR writeData failed");
}
@@ -193,7 +195,9 @@ void writeMbr() {
part_t* p = cache.mbr.part;
p->boot = 0;
uint16_t c = lbnToCylinder(relSector);
if (c > 1023) sdError("MBR CHS");
if (c > 1023) {
sdError("MBR CHS");
}
p->beginCylinderHigh = c >> 8;
p->beginCylinderLow = c & 0XFF;
p->beginHead = lbnToHead(relSector);
@@ -215,7 +219,9 @@ void writeMbr() {
}
p->firstSector = relSector;
p->totalSectors = partSize;
if (!writeCache(0)) sdError("write MBR");
if (!writeCache(0)) {
sdError("write MBR");
}
}
//------------------------------------------------------------------------------
// generate serial number from card size and micros since boot
@@ -230,12 +236,16 @@ void makeFat16() {
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
fatSize = (nc + 2 + 255)/256;
uint32_t r = BU16 + 1 + 2 * fatSize + 32;
if (dataStart < r) continue;
if (dataStart < r) {
continue;
}
relSector = dataStart - r + BU16;
break;
}
// check valid cluster count for FAT16 volume
if (nc < 4085 || nc >= 65525) sdError("Bad cluster count");
if (nc < 4085 || nc >= 65525) {
sdError("Bad cluster count");
}
reservedSectors = 1;
fatStart = relSector + reservedSectors;
partSize = nc * sectorsPerCluster + 2 * fatSize + reservedSectors + 32;
@@ -283,7 +293,7 @@ void makeFat16() {
cache.fat16[1] = 0XFFFF;
// write first block of FAT and backup for reserved clusters
if (!writeCache(fatStart)
|| !writeCache(fatStart + fatSize)) {
|| !writeCache(fatStart + fatSize)) {
sdError("FAT16 reserve failed");
}
}
@@ -296,10 +306,14 @@ void makeFat32() {
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
fatSize = (nc + 2 + 127)/128;
uint32_t r = relSector + 9 + 2 * fatSize;
if (dataStart >= r) break;
if (dataStart >= r) {
break;
}
}
// error if too few clusters in FAT32 volume
if (nc < 65525) sdError("Bad cluster count");
if (nc < 65525) {
sdError("Bad cluster count");
}
reservedSectors = dataStart - relSector - 2 * fatSize;
fatStart = relSector + reservedSectors;
partSize = nc * sectorsPerCluster + dataStart - relSector;
@@ -342,13 +356,13 @@ void makeFat32() {
memcpy(pb->fileSystemType, fat32str, sizeof(pb->fileSystemType));
// write partition boot sector and backup
if (!writeCache(relSector)
|| !writeCache(relSector + 6)) {
|| !writeCache(relSector + 6)) {
sdError("FAT32 write PBS failed");
}
clearCache(true);
// write extra boot area and backup
if (!writeCache(relSector + 2)
|| !writeCache(relSector + 8)) {
|| !writeCache(relSector + 8)) {
sdError("FAT32 PBS ext failed");
}
fat32_fsinfo_t* pf = &cache.fsinfo;
@@ -358,7 +372,7 @@ void makeFat32() {
pf->nextFree = 0XFFFFFFFF;
// write FSINFO sector and backup
if (!writeCache(relSector + 1)
|| !writeCache(relSector + 7)) {
|| !writeCache(relSector + 7)) {
sdError("FAT32 FSINFO failed");
}
clearFatDir(fatStart, 2 * fatSize + sectorsPerCluster);
@@ -368,7 +382,7 @@ void makeFat32() {
cache.fat32[2] = 0x0FFFFFFF;
// write first block of FAT and backup for reserved clusters
if (!writeCache(fatStart)
|| !writeCache(fatStart + fatSize)) {
|| !writeCache(fatStart + fatSize)) {
sdError("FAT32 reserve failed");
}
}
@@ -376,43 +390,51 @@ void makeFat32() {
// flash erase all data
uint32_t const ERASE_SIZE = 262144L;
void eraseCard() {
cout << endl << pstr("Erasing\n");
cout << endl << F("Erasing\n");
uint32_t firstBlock = 0;
uint32_t lastBlock;
uint16_t n = 0;

do {
lastBlock = firstBlock + ERASE_SIZE - 1;
if (lastBlock >= cardSizeBlocks) lastBlock = cardSizeBlocks - 1;
if (!card.erase(firstBlock, lastBlock)) sdError("erase failed");
if (lastBlock >= cardSizeBlocks) {
lastBlock = cardSizeBlocks - 1;
}
if (!card.erase(firstBlock, lastBlock)) {
sdError("erase failed");
}
cout << '.';
if ((n++)%32 == 31) cout << endl;
if ((n++)%32 == 31) {
cout << endl;
}
firstBlock += ERASE_SIZE;
} while (firstBlock < cardSizeBlocks);
cout << endl;

if (!card.readBlock(0, cache.data)) sdError("readBlock");
if (!card.readBlock(0, cache.data)) {
sdError("readBlock");
}
cout << hex << showbase << setfill('0') << internal;
cout << pstr("All data set to ") << setw(4) << int(cache.data[0]) << endl;
cout << F("All data set to ") << setw(4) << int(cache.data[0]) << endl;
cout << dec << noshowbase << setfill(' ') << right;
cout << pstr("Erase done\n");
cout << F("Erase done\n");
}
//------------------------------------------------------------------------------
void formatCard() {
cout << endl;
cout << pstr("Formatting\n");
cout << F("Formatting\n");
initSizes();
if (card.type() != SD_CARD_TYPE_SDHC) {
cout << pstr("FAT16\n");
cout << F("FAT16\n");
makeFat16();
} else {
cout << pstr("FAT32\n");
cout << F("FAT32\n");
makeFat32();
}
#if DEBUG_PRINT
debugPrint();
#endif // DEBUG_PRINT
cout << pstr("Format done\n");
cout << F("Format done\n");
}
//------------------------------------------------------------------------------
void setup() {
@@ -420,61 +442,63 @@ void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo

cout << pstr(
"\n"
"This sketch can erase and/or format SD/SDHC cards.\n"
"\n"
"Erase uses the card's fast flash erase command.\n"
"Flash erase sets all data to 0X00 for most cards\n"
"and 0XFF for a few vendor's cards.\n"
"\n"
"Cards larger than 2 GB will be formatted FAT32 and\n"
"smaller cards will be formatted FAT16.\n"
"\n"
"Warning, all data on the card will be erased.\n"
"Enter 'Y' to continue: ");
cout << F(
"\n"
"This program can erase and/or format SD/SDHC cards.\n"
"\n"
"Erase uses the card's fast flash erase command.\n"
"Flash erase sets all data to 0X00 for most cards\n"
"and 0XFF for a few vendor's cards.\n"
"\n"
"Cards larger than 2 GB will be formatted FAT32 and\n"
"smaller cards will be formatted FAT16.\n"
"\n"
"Warning, all data on the card will be erased.\n"
"Enter 'Y' to continue: ");
while (!Serial.available()) {}
delay(400); // catch Due restart problem
c = Serial.read();
cout << c << endl;
if (c != 'Y') {
cout << pstr("Quiting, you did not enter 'Y'.\n");
cout << F("Quiting, you did not enter 'Y'.\n");
return;
}
// read any existing Serial data
while (Serial.read() >= 0) {}
cout << pstr(
"\n"
"Options are:\n"
"E - erase the card and skip formatting.\n"
"F - erase and then format the card. (recommended)\n"
"Q - quick format the card without erase.\n"
"\n"
"Enter option: ");
cout << F(
"\n"
"Options are:\n"
"E - erase the card and skip formatting.\n"
"F - erase and then format the card. (recommended)\n"
"Q - quick format the card without erase.\n"
"\n"
"Enter option: ");
while (!Serial.available()) {}
c = Serial.read();
cout << c << endl;
if (!strchr("EFQ", c)) {
cout << pstr("Quiting, invalid option entered.") << endl;
cout << F("Quiting, invalid option entered.") << endl;
return;
}

if (!card.begin(chipSelect, spiSpeed)) {
cout << pstr(
"\nSD initialization failure!\n"
"Is the SD card inserted correctly?\n"
"Is chip select correct at the top of this sketch?\n");
cout << F(
"\nSD initialization failure!\n"
"Is the SD card inserted correctly?\n"
"Is chip select correct at the top of this program?\n");
sdError("card.begin failed");
}
cardSizeBlocks = card.cardSize();
if (cardSizeBlocks == 0) sdError("cardSize");
if (cardSizeBlocks == 0) {
sdError("cardSize");
}
cardCapacityMB = (cardSizeBlocks + 2047)/2048;

cout << pstr("Card Size: ") << cardCapacityMB;
cout << pstr(" MB, (MB = 1,048,576 bytes)") << endl;
cout << F("Card Size: ") << cardCapacityMB;
cout << F(" MB, (MB = 1,048,576 bytes)") << endl;

if (c == 'E' || c == 'F') {
eraseCard();

+ 74
- 68
SdFat/examples/SdInfo/SdInfo.ino Переглянути файл

@@ -1,5 +1,5 @@
/*
* This sketch attempts to initialize an SD card and analyze its structure.
* This program attempts to initialize an SD card and analyze its structure.
*/
#include <SPI.h>
#include <SdFat.h>
@@ -30,13 +30,13 @@ uint32_t cardSize;
uint32_t eraseSize;
//------------------------------------------------------------------------------
// store error strings in flash
#define sdErrorMsg(msg) sdErrorMsg_P(PSTR(msg));
void sdErrorMsg_P(const char* str) {
cout << pgm(str) << endl;
#define sdErrorMsg(msg) sdErrorMsg_F(F(msg));
void sdErrorMsg_F(const __FlashStringHelper* str) {
cout << str << endl;
if (sd.card()->errorCode()) {
cout << pstr("SD errorCode: ");
cout << F("SD errorCode: ");
cout << hex << int(sd.card()->errorCode()) << endl;
cout << pstr("SD errorData: ");
cout << F("SD errorData: ");
cout << int(sd.card()->errorData()) << dec << endl;
}
}
@@ -47,17 +47,17 @@ uint8_t cidDmp() {
sdErrorMsg("readCID failed");
return false;
}
cout << pstr("\nManufacturer ID: ");
cout << F("\nManufacturer ID: ");
cout << hex << int(cid.mid) << dec << endl;
cout << pstr("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
cout << pstr("Product: ");
cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
cout << F("Product: ");
for (uint8_t i = 0; i < 5; i++) {
cout << cid.pnm[i];
}
cout << pstr("\nVersion: ");
cout << F("\nVersion: ");
cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
cout << pstr("Serial number: ") << hex << cid.psn << dec << endl;
cout << pstr("Manufacturing date: ");
cout << F("Serial number: ") << hex << cid.psn << dec << endl;
cout << F("Manufacturing date: ");
cout << int(cid.mdt_month) << '/';
cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
cout << endl;
@@ -78,19 +78,19 @@ uint8_t csdDmp() {
eraseSingleBlock = csd.v2.erase_blk_en;
eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
} else {
cout << pstr("csd version error\n");
cout << F("csd version error\n");
return false;
}
eraseSize++;
cout << pstr("cardSize: ") << 0.000512*cardSize;
cout << pstr(" MB (MB = 1,000,000 bytes)\n");
cout << F("cardSize: ") << 0.000512*cardSize;
cout << F(" MB (MB = 1,000,000 bytes)\n");

cout << pstr("flashEraseSize: ") << int(eraseSize) << pstr(" blocks\n");
cout << pstr("eraseSingleBlock: ");
cout << F("flashEraseSize: ") << int(eraseSize) << F(" blocks\n");
cout << F("eraseSingleBlock: ");
if (eraseSingleBlock) {
cout << pstr("true\n");
cout << F("true\n");
} else {
cout << pstr("false\n");
cout << F("false\n");
}
return true;
}
@@ -103,18 +103,18 @@ uint8_t partDmp() {
return false;
}
if (!sd.card()->readBlock(0, p->data)) {
sdErrorMsg("read MBR failed");
return false;
sdErrorMsg("read MBR failed");
return false;
}
for (uint8_t ip = 1; ip < 5; ip++) {
part_t *pt = &p->mbr.part[ip - 1];
if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize) {
cout << pstr("\nNo MBR. Assuming Super Floppy format.\n");
cout << F("\nNo MBR. Assuming Super Floppy format.\n");
return true;
}
}
cout << pstr("\nSD Partition Table\n");
cout << pstr("part,boot,type,start,length\n");
cout << F("\nSD Partition Table\n");
cout << F("part,boot,type,start,length\n");
for (uint8_t ip = 1; ip < 5; ip++) {
part_t *pt = &p->mbr.part[ip - 1];
cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
@@ -124,22 +124,22 @@ uint8_t partDmp() {
}
//------------------------------------------------------------------------------
void volDmp() {
cout << pstr("\nVolume is FAT") << int(sd.vol()->fatType()) << endl;
cout << pstr("blocksPerCluster: ") << int(sd.vol()->blocksPerCluster()) << endl;
cout << pstr("clusterCount: ") << sd.vol()->clusterCount() << endl;
cout << pstr("freeClusters: ");
cout << F("\nVolume is FAT") << int(sd.vol()->fatType()) << endl;
cout << F("blocksPerCluster: ") << int(sd.vol()->blocksPerCluster()) << endl;
cout << F("clusterCount: ") << sd.vol()->clusterCount() << endl;
cout << F("freeClusters: ");
uint32_t volFree = sd.vol()->freeClusterCount();
cout << volFree << endl;
float fs = 0.000512*volFree*sd.vol()->blocksPerCluster();
cout << pstr("freeSpace: ") << fs << pstr(" MB (MB = 1,000,000 bytes)\n");
cout << pstr("fatStartBlock: ") << sd.vol()->fatStartBlock() << endl;
cout << pstr("fatCount: ") << int(sd.vol()->fatCount()) << endl;
cout << pstr("blocksPerFat: ") << sd.vol()->blocksPerFat() << endl;
cout << pstr("rootDirStart: ") << sd.vol()->rootDirStart() << endl;
cout << pstr("dataStartBlock: ") << sd.vol()->dataStartBlock() << endl;
cout << F("freeSpace: ") << fs << F(" MB (MB = 1,000,000 bytes)\n");
cout << F("fatStartBlock: ") << sd.vol()->fatStartBlock() << endl;
cout << F("fatCount: ") << int(sd.vol()->fatCount()) << endl;
cout << F("blocksPerFat: ") << sd.vol()->blocksPerFat() << endl;
cout << F("rootDirStart: ") << sd.vol()->rootDirStart() << endl;
cout << F("dataStartBlock: ") << sd.vol()->dataStartBlock() << endl;
if (sd.vol()->dataStartBlock() % eraseSize) {
cout << pstr("Data area is not aligned on flash erase boundaries!\n");
cout << pstr("Download and use formatter from www.sdsd.card()->org/consumer!\n");
cout << F("Data area is not aligned on flash erase boundaries!\n");
cout << F("Download and use formatter from www.sdsd.card()->org/consumer!\n");
}
}
//------------------------------------------------------------------------------
@@ -151,19 +151,19 @@ void setup() {
cout << uppercase << showbase << endl;

// pstr stores strings in flash to save RAM
cout << pstr("SdFat version: ") << SD_FAT_VERSION << endl;
cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
if (DISABLE_CHIP_SELECT < 0) {
cout << pstr(
"\nAssuming the SD is the only SPI device.\n"
"Edit DISABLE_CHIP_SELECT to disable another device.\n");
cout << F(
"\nAssuming the SD is the only SPI device.\n"
"Edit DISABLE_CHIP_SELECT to disable another device.\n");
} else {
cout << pstr("\nDisabling SPI device on pin ");
cout << F("\nDisabling SPI device on pin ");
cout << int(DISABLE_CHIP_SELECT) << endl;
pinMode(DISABLE_CHIP_SELECT, OUTPUT);
digitalWrite(DISABLE_CHIP_SELECT, HIGH);
}
cout << pstr("\nAssuming the SD chip select pin is: ") <<int(SD_CHIP_SELECT);
cout << pstr("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
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");
}
//------------------------------------------------------------------------------
void loop() {
@@ -171,10 +171,10 @@ void loop() {
while (Serial.read() >= 0) {}

// pstr stores strings in flash to save RAM
cout << pstr("\ntype any character to start\n");
cout << F("\ntype any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem
uint32_t t = millis();
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
@@ -183,43 +183,49 @@ void loop() {
return;
}
t = millis() - t;
cardSize = sd.card()->cardSize();
if (cardSize == 0) {
sdErrorMsg("cardSize failed");
return;
}
cout << pstr("\ninit time: ") << t << " ms" << endl;
cout << pstr("\nCard type: ");
cout << F("\ninit time: ") << t << " ms" << endl;
cout << F("\nCard type: ");
switch (sd.card()->type()) {
case SD_CARD_TYPE_SD1:
cout << pstr("SD1\n");
break;
case SD_CARD_TYPE_SD1:
cout << F("SD1\n");
break;

case SD_CARD_TYPE_SD2:
cout << pstr("SD2\n");
break;
case SD_CARD_TYPE_SD2:
cout << F("SD2\n");
break;

case SD_CARD_TYPE_SDHC:
if (cardSize < 70000000) {
cout << pstr("SDHC\n");
} else {
cout << pstr("SDXC\n");
}
break;
case SD_CARD_TYPE_SDHC:
if (cardSize < 70000000) {
cout << F("SDHC\n");
} else {
cout << F("SDXC\n");
}
break;

default:
cout << pstr("Unknown\n");
default:
cout << F("Unknown\n");
}
if (!cidDmp()) {
return;
}
if (!csdDmp()) {
return;
}
if (!cidDmp()) return;
if (!csdDmp()) return;
uint32_t ocr;
if (!sd.card()->readOCR(&ocr)) {
sdErrorMsg("\nreadOCR failed");
return;
return;
}
cout << F("OCR: ") << hex << ocr << dec << endl;
if (!partDmp()) {
return;
}
cout << pstr("OCR: ") << hex << ocr << dec << endl;
if (!partDmp()) return;
if (!sd.fsBegin()) {
sdErrorMsg("\nFile System initialization failed.\n");
return;

+ 14
- 12
SdFat/examples/SoftwareSpi/SoftwareSpi.ino Переглянути файл

@@ -5,7 +5,7 @@
//
#include <SPI.h>
#include <SdFat.h>
#if USE_MULTIPLE_SPI_TYPES // Must be nonzero in SdFat/SdFatConfig.h
#if SD_SPI_CONFIGURATION >= 3 // Must be set in SdFat/SdFatConfig.h
//
// Pin numbers in templates must be constants.
const uint8_t SOFT_MISO_PIN = 12;
@@ -23,24 +23,26 @@ SdFile file;

void setup() {
Serial.begin(9600);
while (!Serial) {} // Wait for Leonardo
while (!Serial) {} // Wait for Leonardo
Serial.println("Type any character to start");
while (Serial.read() <= 0) {}
if (!sd.begin(SD_CHIP_SELECT_PIN)) sd.initErrorHalt();
if (!file.open("SOFT_SPI.TXT", O_CREAT | O_RDWR)) {

if (!sd.begin(SD_CHIP_SELECT_PIN)) {
sd.initErrorHalt();
}

if (!file.open("SoftSPI.txt", O_CREAT | O_RDWR)) {
sd.errorHalt(F("open failed"));
}
file.println(F("This line was printed using software SPI."));
file.close();
Serial.println(F("Done."));
}
//------------------------------------------------------------------------------
void loop() {}
#else // USE_MULTIPLE_SPI_TYPES
#error USE_MULTIPLE_SPI_TYPES must be set nonzero in SdFat/SdFatConfig.h
#endif //USE_MULTIPLE_SPI_TYPES
#else // SD_SPI_CONFIGURATION >= 3
#error SD_SPI_CONFIGURATION must be set to 3 in SdFat/SdFatConfig.h
#endif //SD_SPI_CONFIGURATION >= 3

+ 52
- 48
SdFat/examples/StdioBench/StdioBench.ino Переглянути файл

@@ -1,5 +1,5 @@
// Benchmark comparing SdFile and StdioStream.
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// Define PRINT_FIELD nonzero to use printField.
@@ -17,10 +17,11 @@ StdioStream stdioFile;

float f[100];
char buf[20];
char* label[] =
{"uint8_t 0 to 255, 100 times ", "uint16_t 0 to 20000",
char* label[] =
{ "uint8_t 0 to 255, 100 times ", "uint16_t 0 to 20000",
"uint32_t 0 to 20000", "uint32_t 1000000000 to 1000010000",
"float nnn.ffff, 10000 times"};
"float nnn.ffff, 10000 times"
};
//------------------------------------------------------------------------------
void setup() {
uint32_t m;
@@ -28,25 +29,27 @@ void setup() {
uint32_t stdioSize;
uint32_t printTime;
uint32_t stdioTime;
Serial.begin(9600);
while (!Serial) {}
Serial.println(F("Type any character to start"));
while (!Serial.available());
Serial.println(F("Starting test"));
if (!sd.begin(SD_CS_PIN)) sd.errorHalt();
if (!sd.begin(SD_CS_PIN)) {
sd.errorHalt();
}

for (uint8_t i = 0; i < 100; i++) {
f[i] = 123.0 + 0.1234*i;
}
}

for (uint8_t dataType = 0; dataType < 5; dataType++) {
for (uint8_t fileType = 0; fileType < 2; fileType++) {
if (!fileType) {
if (!printFile.open("PRRINT.TXT", O_CREAT | O_RDWR | O_TRUNC)) {
if (!printFile.open("print.txt", O_CREAT | O_RDWR | O_TRUNC)) {
Serial.println("open fail");
return;
return;
}
printTime = millis();
switch (dataType) {
@@ -55,121 +58,122 @@ void setup() {
for (uint8_t j = 0; j < 255; j++) {
printFile.println(j);
}
}
}
break;
case 1:
for (uint16_t i = 0; i < 20000; i++) {
printFile.println(i);
}
break;
case 2:
for (uint32_t i = 0; i < 20000; i++) {
printFile.println(i);
}
break;
case 3:
for (uint16_t i = 0; i < 10000; i++) {
printFile.println(i + 1000000000UL);
}
break;
case 4:
for (int j = 0; j < 100; j++) {
for (uint8_t i = 0; i < 100; i++) {
printFile.println(f[i], 4);
}
}
break;
break;
default:
break;
}
printFile.sync();
printFile.sync();
printTime = millis() - printTime;
printFile.rewind();
printSize = printFile.fileSize();
printSize = printFile.fileSize();

} else {
if (!stdioFile.fopen("STREAM.TXT", "w+")) {
if (!stdioFile.fopen("stream.txt", "w+")) {
Serial.println("fopen fail");
return;
}
stdioTime = millis();
switch (dataType) {
switch (dataType) {
case 0:
for (uint16_t i =0; i < 100; i++) {
for (uint8_t j = 0; j < 255; j++) {
#if PRINT_FIELD
#if PRINT_FIELD
stdioFile.printField(j, '\n');
#else // PRINT_FIELD
#else // PRINT_FIELD
stdioFile.println(j);
#endif // PRINT_FIELD
#endif // PRINT_FIELD
}
}
}
break;
case 1:
for (uint16_t i = 0; i < 20000; i++) {
#if PRINT_FIELD
#if PRINT_FIELD
stdioFile.printField(i, '\n');
#else // PRINT_FIELD
#else // PRINT_FIELD
stdioFile.println(i);
#endif // PRINT_FIELD
#endif // PRINT_FIELD
}
break;
case 2:
for (uint32_t i = 0; i < 20000; i++) {
#if PRINT_FIELD
#if PRINT_FIELD
stdioFile.printField(i, '\n');
#else // PRINT_FIELD
#else // PRINT_FIELD
stdioFile.println(i);
#endif // PRINT_FIELD
#endif // PRINT_FIELD
}
break;
case 3:
for (uint16_t i = 0; i < 10000; i++) {
#if PRINT_FIELD
#if PRINT_FIELD
stdioFile.printField(i + 1000000000UL, '\n');
#else // PRINT_FIELD
#else // PRINT_FIELD
stdioFile.println(i + 1000000000UL);
#endif // PRINT_FIELD
#endif // PRINT_FIELD
}
break;
case 4:
for (int j = 0; j < 100; j++) {
for (uint8_t i = 0; i < 100; i++) {
#if PRINT_FIELD
#if PRINT_FIELD
stdioFile.printField(f[i], '\n', 4);
#else // PRINT_FIELD
stdioFile.println(f[i], 4);
#endif // PRINT_FIELD
#else // PRINT_FIELD
stdioFile.println(f[i], 4);
#endif // PRINT_FIELD
}
}
break;
break;
default:
break;
}
stdioFile.fflush();
stdioTime = millis() - stdioTime;
stdioSize = stdioFile.ftell();
stdioSize = stdioFile.ftell();
if (STDIO_LIST_COUNT) {
size_t len;
stdioFile.rewind();
for (int i = 0; i < STDIO_LIST_COUNT; i++) {
stdioFile.fgets(buf, sizeof(buf), &len);
Serial.print(len);Serial.print(',');
Serial.print(len);
Serial.print(',');
Serial.print(buf);
}
}

}
}
Serial.println(label[dataType]);
Serial.println(label[dataType]);
if (VERIFY_CONTENT && printSize == stdioSize) {
printFile.rewind();
stdioFile.rewind();
@@ -187,7 +191,7 @@ void setup() {
Serial.print(printSize);
Serial.print(" != ");
}
Serial.println(stdioSize);
Serial.println(stdioSize);
Serial.print("print millis: ");
Serial.println(printTime);
Serial.print("stdio millis: ");
@@ -195,8 +199,8 @@ void setup() {
Serial.print("ratio: ");
Serial.println((float)printTime/(float)stdioTime);
Serial.println();
printFile.close();
stdioFile.fclose();
printFile.close();
stdioFile.fclose();
}
Serial.println("Done");
}

+ 7
- 7
SdFat/examples/StreamParseInt/StreamParseInt.ino Переглянути файл

@@ -15,26 +15,26 @@ void setup() {
while(!Serial) {}
Serial.println(F("Type any character to start"));
while (!Serial.available()) {}
// Initialize the SD.
if (!SD.begin(csPin)) {
Serial.println(F("begin error"));
return;
}
// Create and open the file. Use flag to truncate an existing file.
file = SD.open("stream.txt", O_RDWR|O_CREAT|O_TRUNC);
if (!file) {
Serial.println(F("open error"));
return;
file = SD.open("stream.txt", O_RDWR|O_CREAT|O_TRUNC);
if (!file) {
Serial.println(F("open error"));
return;
}
// Write a test number to the file.
file.println("12345");
// Rewind the file and read the number with parseInt().
file.seek(0);
int i = file.parseInt();
Serial.print(F("parseInt: "));
Serial.println(i);
Serial.println(i);
file.close();
}


+ 114
- 74
SdFat/examples/ThreeCards/ThreeCards.ino Переглянути файл

@@ -4,13 +4,13 @@
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#if USE_MULTIPLE_SPI_TYPES // Must be nonzero in SdFat/SdFatConfig.h
#if SD_SPI_CONFIGURATION >= 3 // Must be set in SdFat/SdFatConfig.h

// SD1 is a microSD on hardware SPI pins 50-52
// Using my fast custom SPI
SdFat sd1;
const uint8_t SD1_CS = 53;
// SD2 is a Catalex shield on hardware SPI pins 50-52
// Using the standard Arduino SPI library
SdFatLibSpi sd2;
@@ -33,14 +33,14 @@ const uint16_t NWRITE = FILE_SIZE/BUF_DIM;
#define initError(msg) initErrorHalt(F(msg))
//------------------------------------------------------------------------------
void list() {
// list current directory on both cards
// list current directory on all cards
Serial.println(F("------sd1-------"));
sd1.ls("/", LS_SIZE|LS_R);
Serial.println(F("------sd2-------"));
sd2.ls("/", LS_SIZE|LS_R);
Serial.println(F("------sd3-------"));
sd3.ls("/", LS_SIZE|LS_R);
Serial.println(F("---------------------"));
sd3.ls("/", LS_SIZE|LS_R);
Serial.println(F("---------------------"));
}
//------------------------------------------------------------------------------
void setup() {
@@ -49,71 +49,97 @@ void setup() {
Serial.print(F("FreeRam: "));

Serial.println(FreeRam());
// fill buffer with known data
for (int i = 0; i < sizeof(buf); i++) buf[i] = i;
for (int i = 0; i < sizeof(buf); i++) {
buf[i] = i;
}

Serial.println(F("type any character to start"));
while (Serial.read() <= 0) {}

// disable sd2 while initializing sd1
pinMode(SD2_CS, OUTPUT);
digitalWrite(SD2_CS, HIGH);
// initialize the first card
if (!sd1.begin(SD1_CS)) sd1.initError("sd1:");
if (!sd1.begin(SD1_CS)) {
sd1.initError("sd1:");
}

// initialize the second card
if (!sd2.begin(SD2_CS)) sd2.initError("sd2:");
if (!sd2.begin(SD2_CS)) {
sd2.initError("sd2:");
}

// initialize the third card
if (!sd3.begin(SD3_CS)) sd3.initError("sd3:");
if (!sd3.begin(SD3_CS)) {
sd3.initError("sd3:");
}

Serial.println(F("Cards OK - creating directories"));
// create DIR1 on sd1 if it does not exist
if (!sd1.exists("/DIR1")) {
if (!sd1.mkdir("/DIR1")) sd1.errorExit("sd1.mkdir");
}
// make /DIR1 the default directory for sd1
if (!sd1.chdir("/DIR1")) sd1.errorExit("sd1.chdir");
// create DIR2 on sd2 if it does not exist
if (!sd2.exists("/DIR2")) {
if (!sd2.mkdir("/DIR2")) sd2.errorExit("sd2.mkdir");
}
// make /DIR2 the default directory for sd2
if (!sd2.chdir("/DIR2")) sd2.errorExit("sd2.chdir");
// create DIR3 on sd3 if it does not exist
if (!sd3.exists("/DIR3")) {
if (!sd3.mkdir("/DIR3")) sd2.errorExit("sd3.mkdir");
}
// make /DIR3 the default directory for sd3
if (!sd3.chdir("/DIR3")) sd3.errorExit("sd3.chdir");

// create Dir1 on sd1 if it does not exist
if (!sd1.exists("/Dir1")) {
if (!sd1.mkdir("/Dir1")) {
sd1.errorExit("sd1.mkdir");
}
}
// make /Dir1 the default directory for sd1
if (!sd1.chdir("/Dir1")) {
sd1.errorExit("sd1.chdir");
}

// create Dir2 on sd2 if it does not exist
if (!sd2.exists("/Dir2")) {
if (!sd2.mkdir("/Dir2")) {
sd2.errorExit("sd2.mkdir");
}
}
// make /Dir2 the default directory for sd2
if (!sd2.chdir("/Dir2")) {
sd2.errorExit("sd2.chdir");
}

// create Dir3 on sd3 if it does not exist
if (!sd3.exists("/Dir3")) {
if (!sd3.mkdir("/Dir3")) {
sd2.errorExit("sd3.mkdir");
}
}
// make /Dir3 the default directory for sd3
if (!sd3.chdir("/Dir3")) {
sd3.errorExit("sd3.chdir");
}

Serial.println(F("Directories created - removing old files"));
if (sd1.exists("TEST1.BIN")) {
if (!sd1.remove("TEST1.BIN")) sd1.errorExit("sd1.remove");
}
if (sd2.exists("TEST2.BIN")) {
if (!sd2.remove("TEST2.BIN")) sd2.errorExit("sd2.remove");
}
if (sd3.exists("TEST3.BIN")) {
if (!sd3.remove("TEST3.BIN")) sd2.errorExit("sd3.remove");
}

if (sd1.exists("TEST1.bin")) {
if (!sd1.remove("TEST1.bin")) {
sd1.errorExit("sd1.remove");
}
}
if (sd2.exists("TEST2.bin")) {
if (!sd2.remove("TEST2.bin")) {
sd2.errorExit("sd2.remove");
}
}
if (sd3.exists("TEST3.bin")) {
if (!sd3.remove("TEST3.bin")) {
sd2.errorExit("sd3.remove");
}
}
Serial.println("Initial SD directories");
list();

// create or open /DIR1/TEST1.BIN and truncate it to zero length
// create or open /Dir1/TEST1.bin and truncate it to zero length
SdFile file1;
if (!file1.open(&sd1, "TEST1.BIN", O_RDWR | O_CREAT | O_TRUNC)) {
if (!file1.open(&sd1, "TEST1.bin", O_RDWR | O_CREAT | O_TRUNC)) {
sd1.errorExit("file1");
}
Serial.println(F("Writing SD1:/DIR1/TEST1.BIN"));
// write data to /DIR1/TEST.BIN on sd1
Serial.println(F("Writing SD1:/Dir1/TEST1.bin"));
// write data to /Dir1/TEST1.bin on sd1
for (int i = 0; i < NWRITE; i++) {
if (file1.write(buf, sizeof(buf)) != sizeof(buf)) {
sd1.errorExit("sd1.write");
@@ -121,24 +147,30 @@ void setup() {
}
file1.sync();
list();
// create or open /DIR2/TEST2.BIN and truncate it to zero length
// create or open /Dir2/TEST2.bin and truncate it to zero length
SdFile file2;
if (!file2.open(&sd2, "TEST2.BIN", O_RDWR | O_CREAT | O_TRUNC)) {
if (!file2.open(&sd2, "TEST2.bin", O_RDWR | O_CREAT | O_TRUNC)) {
sd2.errorExit("file2");
}
Serial.println(F("Copying SD1:/DIR1/TEST1.BIN to SD2::/DIR2/TEST2.BIN"));
Serial.println(F("Copying SD1:/Dir1/TEST1.bin to SD2::/Dir2/TEST2.bin"));
// copy file1 to file2
file1.rewind();
uint32_t t = millis();

while (1) {
int n = file1.read(buf, sizeof(buf));
if (n < 0) sd1.errorExit("read1");
if (n == 0) break;
if (file2.write(buf, n) != n) sd2.errorExit("write3");
if (n < 0) {
sd1.errorExit("read1");
}
if (n == 0) {
break;
}
if (file2.write(buf, n) != n) {
sd2.errorExit("write3");
}
}
t = millis() - t;
file2.sync();
@@ -148,32 +180,40 @@ void setup() {
Serial.print(t);
Serial.println(F(" millis"));
list();
// create or open /DIR3/TEST3.BIN and truncate it to zero length
// create or open /Dir3/TEST3.bin and truncate it to zero length
SdFile file3;
if (!file3.open(&sd3, "TEST3.BIN", O_RDWR | O_CREAT | O_TRUNC)) {
if (!file3.open(&sd3, "TEST3.bin", O_RDWR | O_CREAT | O_TRUNC)) {
sd3.errorExit("file3");
}
file2.rewind();
Serial.println(F("Copying SD2:/DIR2/TEST2.BIN to SD3:/DIR3/TEST3.BIN"));
Serial.println(F("Copying SD2:/Dir2/TEST2.bin to SD3:/Dir3/TEST3.bin"));
while (1) {
int n = file2.read(buf, sizeof(buf));
if (n == 0) break;
if (n != sizeof(buf)) sd2.errorExit("read2");
if (file3.write(buf, n) != n) sd3.errorExit("write2");
if (n == 0) {
break;
}
if (n != sizeof(buf)) {
sd2.errorExit("read2");
}
if (file3.write(buf, n) != n) {
sd3.errorExit("write2");
}
}
file3.sync();
list();
// Verify content of file3
file3.rewind();
Serial.println(F("Verifying content of TEST3.BIN"));
Serial.println(F("Verifying content of TEST3.bin"));
for (int i = 0; i < NWRITE; i++) {
if (file3.read(buf, sizeof(buf)) != sizeof(buf)) {
sd3.errorExit("sd3.read");
}
for (int j = 0; j < sizeof(buf); j++) {
if (j != buf[j]) sd3.errorExit("Verify error");
if (j != buf[j]) {
sd3.errorExit("Verify error");
}
}
}
Serial.println(F("Done - Verify OK"));
@@ -183,6 +223,6 @@ void setup() {
}
//------------------------------------------------------------------------------
void loop() {}
#else // USE_MULTIPLE_SPI_TYPES
#error USE_MULTIPLE_SPI_TYPES must be set nonzero in SdFat/SdFatConfig.h
#endif //USE_MULTIPLE_SPI_TYPES
#else // SD_SPI_CONFIGURATION >= 3
#error SD_SPI_CONFIGURATION must be set to 3 in SdFat/SdFatConfig.h
#endif //SD_SPI_CONFIGURATION >= 3

+ 27
- 23
SdFat/examples/Timestamp/Timestamp.ino Переглянути файл

@@ -1,8 +1,8 @@
/*
* This sketch tests the dateTimeCallback() function
* This program tests the dateTimeCallback() function
* and the timestamp() function.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

SdFat sd;
@@ -52,21 +52,23 @@ void dateTime(uint16_t* date, uint16_t* time) {
*/
void printTimestamps(SdFile& f) {
dir_t d;
if (!f.dirEntry(&d)) error("f.dirEntry failed");
if (!f.dirEntry(&d)) {
error("f.dirEntry failed");
}

cout << pstr("Creation: ");
cout << F("Creation: ");
f.printFatDate(d.creationDate);
cout << ' ';
f.printFatTime(d.creationTime);
cout << endl;

cout << pstr("Modify: ");
cout << F("Modify: ");
f.printFatDate(d.lastWriteDate);
cout <<' ';
f.printFatTime(d.lastWriteTime);
cout << endl;

cout << pstr("Access: ");
cout << F("Access: ");
f.printFatDate(d.lastAccessDate);
cout << endl;
}
@@ -75,24 +77,26 @@ void setup(void) {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo

cout << pstr("Type any character to start\n");
cout << F("Type any character to start\n");
while (!Serial.available());
delay(400); // catch Due reset problem
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// remove files if they exist
sd.remove("CALLBACK.TXT");
sd.remove("DEFAULT.TXT");
sd.remove("STAMP.TXT");
sd.remove("callback.txt");
sd.remove("default.txt");
sd.remove("stamp.txt");

// create a new file with default timestamps
if (!file.open("DEFAULT.TXT", O_CREAT | O_WRITE)) {
error("open DEFAULT.TXT failed");
if (!file.open("default.txt", O_CREAT | O_WRITE)) {
error("open default.txt failed");
}
cout << pstr("\nOpen with default times\n");
cout << F("\nOpen with default times\n");
printTimestamps(file);

// close file
@@ -112,8 +116,8 @@ void setup(void) {
SdFile::dateTimeCallback(dateTime);

// create a new file with callback timestamps
if (!file.open("CALLBACK.TXT", O_CREAT | O_WRITE)) {
error("open CALLBACK.TXT failed");
if (!file.open("callback.txt", O_CREAT | O_WRITE)) {
error("open callback.txt failed");
}
cout << ("\nOpen with callback times\n");
printTimestamps(file);
@@ -130,7 +134,7 @@ void setup(void) {
// force dir update
file.sync();

cout << pstr("\nTimes after write\n");
cout << F("\nTimes after write\n");
printTimestamps(file);

// close file
@@ -144,8 +148,8 @@ void setup(void) {
SdFile::dateTimeCallbackCancel();

// create a new file with default timestamps
if (!file.open("STAMP.TXT", O_CREAT | O_WRITE)) {
error("open STAMP.TXT failed");
if (!file.open("stamp.txt", O_CREAT | O_WRITE)) {
error("open stamp.txt failed");
}
// set creation date time
if (!file.timestamp(T_CREATE, 2014, 11, 10, 1, 2, 3)) {
@@ -159,11 +163,11 @@ void setup(void) {
if (!file.timestamp(T_ACCESS, 2014, 11, 12, 7, 8, 9)) {
error("set access time failed");
}
cout << pstr("\nTimes after timestamp() calls\n");
cout << F("\nTimes after timestamp() calls\n");
printTimestamps(file);

file.close();
cout << pstr("\nDone\n");
cout << F("\nDone\n");
}

void loop(void){}
void loop(void) {}

+ 70
- 43
SdFat/examples/TwoCards/TwoCards.ino Переглянути файл

@@ -9,7 +9,7 @@ SdFat sd1;
const uint8_t SD1_CS = 10; // chip select for sd1

SdFat sd2;
const uint8_t SD2_CS = 9; // chip select for sd2
const uint8_t SD2_CS = 4; // chip select for sd2

const uint8_t BUF_DIM = 100;
uint8_t buf[BUF_DIM];
@@ -28,10 +28,12 @@ void setup() {
Serial.print(F("FreeRam: "));

Serial.println(FreeRam());
// fill buffer with known data
for (int i = 0; i < sizeof(buf); i++) buf[i] = i;
for (int i = 0; i < sizeof(buf); i++) {
buf[i] = i;
}

Serial.println(F("type any character to start"));
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem
@@ -39,22 +41,26 @@ void setup() {
// disable sd2 while initializing sd1
pinMode(SD2_CS, OUTPUT);
digitalWrite(SD2_CS, HIGH);
// initialize the first card
if (!sd1.begin(SD1_CS)) {
sd1.initError("sd1:");
}
// create DIR1 on sd1 if it does not exist
if (!sd1.exists("/DIR1")) {
if (!sd1.mkdir("/DIR1")) sd1.errorExit("sd1.mkdir");
// create Dir1 on sd1 if it does not exist
if (!sd1.exists("/Dir1")) {
if (!sd1.mkdir("/Dir1")) {
sd1.errorExit("sd1.mkdir");
}
}
// initialize the second card
if (!sd2.begin(SD2_CS)) {
sd2.initError("sd2:");
}
// create DIR2 on sd2 if it does not exist
if (!sd2.exists("/DIR2")) {
if (!sd2.mkdir("/DIR2")) sd2.errorExit("sd2.mkdir");
// create Dir2 on sd2 if it does not exist
if (!sd2.exists("/Dir2")) {
if (!sd2.mkdir("/Dir2")) {
sd2.errorExit("sd2.mkdir");
}
}
// list root directory on both cards
Serial.println(F("------sd1 root-------"));
@@ -62,36 +68,40 @@ void setup() {
Serial.println(F("------sd2 root-------"));
sd2.ls();

// make /DIR1 the default directory for sd1
if (!sd1.chdir("/DIR1")) sd1.errorExit("sd1.chdir");
// make /DIR2 the default directory for sd2
if (!sd2.chdir("/DIR2")) sd2.errorExit("sd2.chdir");
// make /Dir1 the default directory for sd1
if (!sd1.chdir("/Dir1")) {
sd1.errorExit("sd1.chdir");
}

// make /Dir2 the default directory for sd2
if (!sd2.chdir("/Dir2")) {
sd2.errorExit("sd2.chdir");
}

// list current directory on both cards
Serial.println(F("------sd1 DIR1-------"));
Serial.println(F("------sd1 Dir1-------"));
sd1.ls();
Serial.println(F("------sd2 DIR2-------"));
Serial.println(F("------sd2 Dir2-------"));
sd2.ls();
Serial.println(F("---------------------"));
// remove RENAME.BIN from /DIR2 directory of sd2
if (sd2.exists("RENAME.BIN")) {
if (!sd2.remove("RENAME.BIN")) {
sd2.errorExit("remove RENAME.BIN");
// remove rename.bin from /Dir2 directory of sd2
if (sd2.exists("rename.bin")) {
if (!sd2.remove("rename.bin")) {
sd2.errorExit("remove rename.bin");
}
}
// set the current working directory for open() to sd1
sd1.chvol();
// create or open /DIR1/TEST.BIN and truncate it to zero length
// create or open /Dir1/test.bin and truncate it to zero length
SdFile file1;
if (!file1.open("TEST.BIN", O_RDWR | O_CREAT | O_TRUNC)) {
if (!file1.open("test.bin", O_RDWR | O_CREAT | O_TRUNC)) {
sd1.errorExit("file1");
}
Serial.println(F("Writing TEST.BIN to sd1"));
// write data to /DIR1/TEST.BIN on sd1
Serial.println(F("Writing test.bin to sd1"));
// write data to /Dir1/test.bin on sd1
for (int i = 0; i < NWRITE; i++) {
if (file1.write(buf, sizeof(buf)) != sizeof(buf)) {
sd1.errorExit("sd1.write");
@@ -99,23 +109,29 @@ void setup() {
}
// set the current working directory for open() to sd2
sd2.chvol();
// create or open /DIR2/COPY.BIN and truncate it to zero length
// create or open /Dir2/copy.bin and truncate it to zero length
SdFile file2;
if (!file2.open("COPY.BIN", O_WRITE | O_CREAT | O_TRUNC)) {
if (!file2.open("copy.bin", O_WRITE | O_CREAT | O_TRUNC)) {
sd2.errorExit("file2");
}
Serial.println(F("Copying TEST.BIN to COPY.BIN"));
Serial.println(F("Copying test.bin to copy.bin"));
// copy file1 to file2
file1.rewind();
uint32_t t = millis();

while (1) {
int n = file1.read(buf, sizeof(buf));
if (n < 0) sd1.errorExit("read1");
if (n == 0) break;
if (file2.write(buf, n) != n) sd2.errorExit("write2");
if (n < 0) {
sd1.errorExit("read1");
}
if (n == 0) {
break;
}
if (file2.write(buf, n) != n) {
sd2.errorExit("write2");
}
}
t = millis() - t;
Serial.print(F("File size: "));
@@ -123,15 +139,26 @@ void setup() {
Serial.print(F("Copy time: "));
Serial.print(t);
Serial.println(F(" millis"));
// close TEST.BIN
// close test.bin
file1.close();
file2.close();
// list current directory on both cards
Serial.println(F("------sd1 -------"));
sd1.ls("/", LS_R | LS_DATE | LS_SIZE);
Serial.println(F("------sd2 -------"));
sd2.ls("/", LS_R | LS_DATE | LS_SIZE);
Serial.println(F("---------------------"));
Serial.println(F("Renaming copy.bin"));
// rename the copy
file2.close();
if (!sd2.rename("COPY.BIN", "RENAME.BIN")) {
if (!sd2.rename("copy.bin", "rename.bin")) {
sd2.errorExit("sd2.rename");
}
// list current directory on both cards
Serial.println(F("------sd1 -------"));
sd1.ls("/", LS_R | LS_DATE | LS_SIZE);
Serial.println(F("------sd2 -------"));
sd2.ls("/", LS_R | LS_DATE | LS_SIZE);
Serial.println(F("---------------------"));
Serial.println(F("Done"));
}
//------------------------------------------------------------------------------

+ 50
- 39
SdFat/examples/bench/bench.ino Переглянути файл

@@ -1,7 +1,7 @@
/*
* This sketch is a simple binary write/read benchmark.
* This program is a simple binary write/read benchmark.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>

@@ -44,17 +44,17 @@ void cidDmp() {
if (!sd.card()->readCID(&cid)) {
error("readCID failed");
}
cout << pstr("\nManufacturer ID: ");
cout << F("\nManufacturer ID: ");
cout << hex << int(cid.mid) << dec << endl;
cout << pstr("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
cout << pstr("Product: ");
cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
cout << F("Product: ");
for (uint8_t i = 0; i < 5; i++) {
cout << cid.pnm[i];
}
cout << pstr("\nVersion: ");
cout << F("\nVersion: ");
cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
cout << pstr("Serial number: ") << hex << cid.psn << dec << endl;
cout << pstr("Manufacturing date: ");
cout << F("Serial number: ") << hex << cid.psn << dec << endl;
cout << F("Manufacturing date: ");
cout << int(cid.mdt_month) << '/';
cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
cout << endl;
@@ -62,9 +62,10 @@ void cidDmp() {
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial){} // wait for Leonardo
cout << pstr("\nUse a freshly formatted SD for best performance.\n");
while (!Serial) {} // wait for Leonardo
delay(1000);
cout << F("\nUse a freshly formatted SD for best performance.\n");

// use uppercase in hex and use 0X base prefix
cout << uppercase << showbase << endl;
}
@@ -79,25 +80,27 @@ void loop() {
// discard any input
while (Serial.read() >= 0) {}

// pstr stores strings in flash to save RAM
cout << pstr("Type any character to start\n");
// F( stores strings in flash to save RAM
cout << F("Type any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem
cout << pstr("Free RAM: ") << FreeRam() << endl;
cout << F("Free RAM: ") << FreeRam() << endl;

// initialize the SD card at SPI_FULL_SPEED for best performance.
// try SPI_HALF_SPEED if bus errors occur.
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
sd.initErrorHalt();
}

cout << F("Type is FAT") << int(sd.vol()->fatType()) << endl;
cout << F("Card size: ") << sd.card()->cardSize()*512E-9;
cout << F(" GB (GB = 1E9 bytes)") << endl;

cout << pstr("Type is FAT") << int(sd.vol()->fatType()) << endl;
cout << pstr("Card size: ") << sd.card()->cardSize()*512E-9;
cout << pstr(" GB (GB = 1E9 bytes)") << endl;
cidDmp();

// open or create file - truncate existing file.
if (!file.open("BENCH.DAT", O_CREAT | O_TRUNC | O_RDWR)) {
if (!file.open("bench.dat", O_CREAT | O_TRUNC | O_RDWR)) {
error("open failed");
}

@@ -108,15 +111,15 @@ void loop() {
buf[BUF_SIZE-2] = '\r';
buf[BUF_SIZE-1] = '\n';

cout << pstr("File size ") << FILE_SIZE_MB << pstr(" MB\n");
cout << pstr("Buffer size ") << BUF_SIZE << pstr(" bytes\n");
cout << pstr("Starting write test, please wait.") << endl << endl;
cout << F("File size ") << FILE_SIZE_MB << F(" MB\n");
cout << F("Buffer size ") << BUF_SIZE << F(" bytes\n");
cout << F("Starting write test, please wait.") << endl << endl;

// do write test
uint32_t n = FILE_SIZE/sizeof(buf);
cout <<pstr("write speed and latency") << endl;
cout << pstr("speed,max,min,avg") << endl;
cout << pstr("KB/Sec,usec,usec,usec") << endl;
cout <<F("write speed and latency") << endl;
cout << F("speed,max,min,avg") << endl;
cout << F("KB/Sec,usec,usec,usec") << endl;
for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
file.truncate(0);
maxLatency = 0;
@@ -129,21 +132,25 @@ void loop() {
error("write failed");
}
m = micros() - m;
if (maxLatency < m) maxLatency = m;
if (minLatency > m) minLatency = m;
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
totalLatency += m;
}
file.sync();
t = millis() - t;
s = file.fileSize();
cout << s/t <<',' << maxLatency << ',' << minLatency;
cout << s/t <<',' << maxLatency << ',' << minLatency;
cout << ',' << totalLatency/n << endl;
}

cout << endl << pstr("Starting read test, please wait.") << endl;
cout << endl <<pstr("read speed and latency") << endl;
cout << pstr("speed,max,min,avg") << endl;
cout << pstr("KB/Sec,usec,usec,usec") << endl;
cout << endl << F("Starting read test, please wait.") << endl;
cout << endl <<F("read speed and latency") << endl;
cout << F("speed,max,min,avg") << endl;
cout << F("KB/Sec,usec,usec,usec") << endl;
// do read test
for (uint8_t nTest = 0; nTest < READ_COUNT; nTest++) {
file.rewind();
@@ -158,17 +165,21 @@ void loop() {
error("read failed");
}
m = micros() - m;
if (maxLatency < m) maxLatency = m;
if (minLatency > m) minLatency = m;
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
totalLatency += m;
if (buf[BUF_SIZE-1] != '\n') {
error("data check");
}
}
t = millis() - t;
cout << s/t <<',' << maxLatency << ',' << minLatency;
cout << s/t <<',' << maxLatency << ',' << minLatency;
cout << ',' << totalLatency/n << endl;
}
cout << endl << pstr("Done") << endl;
cout << endl << F("Done") << endl;
file.close();
}

+ 1
- 1
SdFat/examples/cin_cout/cin_cout.ino Переглянути файл

@@ -1,7 +1,7 @@
/*
* Demo of ArduinoInStream and ArduinoOutStream
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// create serial output stream

+ 31
- 23
SdFat/examples/dataLogger/dataLogger.ino Переглянути файл

@@ -1,20 +1,20 @@
/*
* Simple data logger.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin. Be sure to disable any other SPI devices such as Enet.
const uint8_t chipSelect = SS;

// Interval between data records in milliseconds.
// Interval between data records in milliseconds.
// The interval must be greater than the maximum SD write latency plus the
// time to acquire and write data to the SD to avoid overrun errors.
// Run the bench example to check the quality of your SD card.
const uint32_t SAMPLE_INTERVAL_MS = 200;

// Log file base name. Must be six characters or less.
#define FILE_BASE_NAME "DATA"
#define FILE_BASE_NAME "Data"
//------------------------------------------------------------------------------
// File system object.
SdFat sd;
@@ -43,14 +43,14 @@ void writeHeader() {
// Log a data record.
void logData() {
uint16_t data[ANALOG_COUNT];
// Read all channels to avoid SD write latency between readings.
for (uint8_t i = 0; i < ANALOG_COUNT; i++) {
data[i] = analogRead(i);
}
// Write data to file. Start with log time in micros.
file.print(logTime);
// Write ADC data to CSV record.
for (uint8_t i = 0; i < ANALOG_COUNT; i++) {
file.write(',');
@@ -64,19 +64,21 @@ void logData() {
//------------------------------------------------------------------------------
void setup() {
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
char fileName[13] = FILE_BASE_NAME "00.CSV";
char fileName[13] = FILE_BASE_NAME "00.csv";
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
delay(1000);
Serial.println(F("Type any character to start"));
while (!Serial.available()) {}
// Initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// Find an unused file name.
if (BASE_NAME_SIZE > 6) {
error("FILE_BASE_NAME too long");
@@ -91,18 +93,20 @@ void setup() {
error("Can't create file name");
}
}
if (!file.open(fileName, O_CREAT | O_WRITE | O_EXCL)) error("file.open");
if (!file.open(fileName, O_CREAT | O_WRITE | O_EXCL)) {
error("file.open");
}
do {
delay(10);
} while (Serial.read() >= 0);
Serial.print(F("Logging to: "));
Serial.println(fileName);
Serial.println(F("Type any character to stop"));
// Write data header.
writeHeader();
// Start on a multiple of the sample interval.
logTime = micros()/(1000UL*SAMPLE_INTERVAL_MS) + 1;
logTime *= 1000UL*SAMPLE_INTERVAL_MS;
@@ -111,21 +115,25 @@ void setup() {
void loop() {
// Time for next record.
logTime += 1000UL*SAMPLE_INTERVAL_MS;
// Wait for log time.
int32_t diff;
do {
diff = micros() - logTime;
} while (diff < 0);
// Check for data rate too high.
if (diff > 10) error("Missed data record");

// Check for data rate too high.
if (diff > 10) {
error("Missed data record");
}

logData();
// Force data to SD and update the directory entry to avoid data loss.
if (!file.sync() || file.getWriteError()) error("write error");
if (!file.sync() || file.getWriteError()) {
error("write error");
}

if (Serial.available()) {
// Close file and stop.
file.close();

+ 54
- 40
SdFat/examples/directoryFunctions/directoryFunctions.ino Переглянути файл

@@ -1,7 +1,7 @@
/*
* Example use of chdir(), ls(), mkdir(), and rmdir().
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>
// SD card chip select pin.
const uint8_t SD_CHIP_SELECT = SS;
@@ -31,22 +31,24 @@ void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
delay(1000);
cout << pstr("Type any character to start\n");
cout << F("Type any character to start\n");
// Wait for input line and discard.
cin.readline();

// Initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(SD_CHIP_SELECT, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// Check for empty SD.
if (file.openNext(sd.vwd(), O_READ)) {
cout << pstr("Found files/folders in the root directory.\n");
cout << F("Found files/folders in the root directory.\n");
if (!ALLOW_WIPE) {
error("SD not empty, use a blank SD or set ALLOW_WIPE true.");
error("SD not empty, use a blank SD or set ALLOW_WIPE true.");
} else {
cout << pstr("Type: 'WIPE' to delete all SD files.\n");
cout << F("Type: 'WIPE' to delete all SD files.\n");
char buf[10];
cin.readline();
cin.get(buf, sizeof(buf));
@@ -54,51 +56,63 @@ void setup() {
error("Invalid WIPE input");
}
file.close();
sd.vwd()->rmRfStar();
cout << pstr("***SD wiped clean.***\n\n");
if (!sd.vwd()->rmRfStar()) {
error("wipe failed");
}
cout << F("***SD wiped clean.***\n\n");
}
}
// Create a new folder.
if (!sd.mkdir("FOLDER1")) error("Create FOLDER1 failed");
cout << pstr("Created FOLDER1\n");
// Create a file in FOLDER1 using a path.
if (!file.open("FOLDER1/FILE1.TXT", O_CREAT | O_WRITE)) {
error("create FOLDER1/FILE1.TXT failed");
if (!sd.mkdir("Folder1")) {
error("Create Folder1 failed");
}
cout << F("Created Folder1\n");

// Create a file in Folder1 using a path.
if (!file.open("Folder1/file1.txt", O_CREAT | O_WRITE)) {
error("create Folder1/file1.txt failed");
}
file.close();
cout << pstr("Created FOLDER1/FILE1.TXT\n");
// Change volume working directory to FOLDER1.
if (!sd.chdir("FOLDER1")) error("chdir failed for FOLDER1.\n");
cout << pstr("chdir to FOLDER1\n");
// Create FILE2.TXT in current directory.
if (!file.open("FILE2.TXT", O_CREAT | O_WRITE)) {
error("create FILE2.TXT failed");
cout << F("Created Folder1/file1.txt\n");

// Change volume working directory to Folder1.
if (!sd.chdir("Folder1")) {
error("chdir failed for Folder1.\n");
}
cout << F("chdir to Folder1\n");

// Create File2.txt in current directory.
if (!file.open("File2.txt", O_CREAT | O_WRITE)) {
error("create File2.txt failed");
}
file.close();
cout << pstr("Created FILE2.TXT in current directory\n");
cout << pstr("List of files on the SD.\n");
cout << F("Created File2.txt in current directory\n");
cout << F("List of files on the SD.\n");
sd.ls("/", LS_R);

// Remove files from current directory.
if (!sd.remove("FILE1.TXT") || !sd.remove("FILE2.TXT")) error("remove failed");
cout << pstr("\nFILE1.TXT and FILE2.TXT removed.\n");
if (!sd.remove("file1.txt") || !sd.remove("File2.txt")) {
error("remove failed");
}
cout << F("\nfile1.txt and File2.txt removed.\n");

// Change current directory to root.
if (!sd.chdir()) error("chdir to root failed.\n");
cout << pstr("List of files on the SD.\n");
if (!sd.chdir()) {
error("chdir to root failed.\n");
}

cout << F("List of files on the SD.\n");
sd.ls(LS_R);
// Remove FOLDER1.
if (!sd.rmdir("FOLDER1")) error("rmdir for FOLDER1 failed\n");
cout << pstr("\nFOLDER1 removed, SD empty.\n");
cout << pstr("Done!\n");

// Remove Folder1.
if (!sd.rmdir("Folder1")) {
error("rmdir for Folder1 failed\n");
}

cout << F("\nFolder1 removed, SD empty.\n");
cout << F("Done!\n");
}
//------------------------------------------------------------------------------
// Nothing happens in loop.

+ 33
- 27
SdFat/examples/fgets/fgets.ino Переглянути файл

@@ -1,5 +1,5 @@
// Demo of fgets function to read lines from a file.
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin
@@ -16,16 +16,18 @@ void demoFgets() {
char line[25];
int n;
// open test file
SdFile rdfile("FGETS.TXT", O_READ);
SdFile rdfile("fgets.txt", O_READ);
// check for open error
if (!rdfile.isOpen()) error("demoFgets");
cout << endl << pstr(
"Lines with '>' end with a '\\n' character\n"
"Lines with '#' do not end with a '\\n' character\n"
"\n");
if (!rdfile.isOpen()) {
error("demoFgets");
}

cout << endl << F(
"Lines with '>' end with a '\\n' character\n"
"Lines with '#' do not end with a '\\n' character\n"
"\n");

// read lines from the file
while ((n = rdfile.fgets(line, sizeof(line))) > 0) {
if (line[n - 1] == '\n') {
@@ -38,19 +40,21 @@ void demoFgets() {
//------------------------------------------------------------------------------
void makeTestFile() {
// create or open test file
SdFile wrfile("FGETS.TXT", O_WRITE | O_CREAT | O_TRUNC);
SdFile wrfile("fgets.txt", O_WRITE | O_CREAT | O_TRUNC);
// check for open error
if (!wrfile.isOpen()) error("MakeTestFile");
if (!wrfile.isOpen()) {
error("MakeTestFile");
}

// write test file
wrfile.print(F(
"Line with CRLF\r\n"
"Line with only LF\n"
"Long line that will require an extra read\n"
"\n" // empty line
"Line at EOF without NL"
));
"Line with CRLF\r\n"
"Line with only LF\n"
"Long line that will require an extra read\n"
"\n" // empty line
"Line at EOF without NL"
));
wrfile.close();
}
//------------------------------------------------------------------------------
@@ -58,18 +62,20 @@ void setup(void) {
Serial.begin(9600);
while (!Serial) {} // Wait for Leonardo

cout << pstr("Type any character to start\n");
cout << F("Type any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

makeTestFile();
demoFgets();
cout << pstr("\nDone\n");
cout << F("\nDone\n");
}
void loop(void) {}

+ 6
- 4
SdFat/examples/formatting/formatting.ino Переглянути файл

@@ -15,7 +15,7 @@ void example(void) {

for (int row = 1; row <= max; row++) {
for (int col = 1; col <= max; col++) {
cout << setw(width) << row * col << (col == max ? '\n' : ' ');
cout << setw(width) << row * col << (col == max ? '\n' : ' ');
}
}
cout << endl;
@@ -25,7 +25,9 @@ void example(void) {
// shows how to set and restore the fill character
void showDate(int m, int d, int y) {
// convert two digit year
if (y < 100) y += 2000;
if (y < 100) {
y += 2000;
}

// set new fill to '0' save old fill character
char old = cout.fill('0');
@@ -39,10 +41,10 @@ void showDate(int m, int d, int y) {
//------------------------------------------------------------------------------
void setup(void) {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
delay(2000);
cout << endl << "default formatting" << endl;
example();


+ 13
- 11
SdFat/examples/getline/getline.ino Переглянути файл

@@ -6,7 +6,7 @@
* Note: This example is meant to demonstrate subtleties the standard and
* may not the best way to read a file.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin
@@ -19,14 +19,14 @@ SdFat sd;
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
void makeTestFile() {
ofstream sdout("GETLINE.TXT");
ofstream sdout("getline.txt");
// use flash for text to save RAM
sdout << pstr(
"short line\n"
"\n"
"17 character line\n"
"too long for buffer\n"
"line with no nl");
sdout << F(
"short line\n"
"\n"
"17 character line\n"
"too long for buffer\n"
"line with no nl");

sdout.close();
}
@@ -34,7 +34,7 @@ void makeTestFile() {
void testGetline() {
const int line_buffer_size = 18;
char buffer[line_buffer_size];
ifstream sdin("GETLINE.TXT");
ifstream sdin("getline.txt");
int line_number = 0;

while (sdin.getline(buffer, line_buffer_size, '\n') || sdin.gcount()) {
@@ -57,13 +57,15 @@ void setup(void) {
while (!Serial) {} // wait for Leonardo

// pstr stores strings in flash to save RAM
cout << pstr("Type any character to start\n");
cout << F("Type any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// make the test file
makeTestFile();

+ 46
- 32
SdFat/examples/readCSV/readCSV.ino Переглянути файл

@@ -1,8 +1,8 @@
/*
* This example reads a simple CSV, comma-separated values, file.
* Each line of the file has three values, a long and two floats.
* Each line of the file has a label and three values, a long and two floats.
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin
@@ -14,7 +14,7 @@ SdFat sd;
// create Serial stream
ArduinoOutStream cout(Serial);

char fileName[] = "TESTFILE.CSV";
char fileName[] = "testfile.csv";
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt(F(s))
@@ -25,37 +25,47 @@ void readFile() {
float f1, f2;
char text[10];
char c1, c2, c3; // space for commas.
// open input file
ifstream sdin(fileName);
// check for open error
if (!sdin.is_open()) error("open");
if (!sdin.is_open()) {
error("open");
}

// read until input fails
while (1) {
// Get text field.
sdin.get(text, sizeof(text), ',');
// Assume EOF if fail.
if (sdin.fail()) break;
if (sdin.fail()) {
break;
}

// Get commas and numbers.
sdin >> c1 >> lg >> c2 >> f1 >> c3 >> f2;
// Skip CR/LF.
sdin.skipWhite();
if (sdin.fail()) error("bad input");

if (sdin.fail()) {
error("bad input");
}

// error in line if not commas
if (c1 != ',' || c2 != ',' || c3 != ',') error("comma");
if (c1 != ',' || c2 != ',' || c3 != ',') {
error("comma");
}

// print in six character wide columns
cout << text << setw(6) << lg << setw(6) << f1 << setw(6) << f2 << endl;
}
// Error in an input line if file is not at EOF.
if (!sdin.eof()) error("readFile");
if (!sdin.eof()) {
error("readFile");
}
}
//------------------------------------------------------------------------------
// write test file
@@ -63,39 +73,43 @@ void writeFile() {

// create or open and truncate output file
ofstream sdout(fileName);
// write file from string stored in flash
sdout << pstr(
"Line 1,1,2.3,4.5\n"
"Line 2,6,7.8,9.0\n"
"Line 3,9,8.7,6.5\n"
"Line 4,-4,-3.2,-1\n") << flush;
sdout << F(
"Line 1,1,2.3,4.5\n"
"Line 2,6,7.8,9.0\n"
"Line 3,9,8.7,6.5\n"
"Line 4,-4,-3.2,-1\n") << flush;

// check for any errors
if (!sdout) error("writeFile");
if (!sdout) {
error("writeFile");
}

sdout.close();
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
cout << pstr("Type any character to start\n");
cout << F("Type any character to start\n");
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// create test file
writeFile();
cout << endl;

// read and print test
readFile();
readFile();
cout << "\nDone!" << endl;
}
void loop() {}

+ 50
- 26
SdFat/examples/rename/rename.ino Переглянути файл

@@ -1,8 +1,8 @@
/*
* This sketch demonstrates use of SdFile::rename()
* This program demonstrates use of SdFile::rename()
* and SdFat::rename().
*/
#include <SPI.h>
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin
@@ -21,58 +21,82 @@ void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo

cout << pstr("Insert an empty SD. Type any character to start.") << endl;
cout << F("Insert an empty SD. Type any character to start.") << endl;
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}

// Remove file/dirs from previous run.
if (sd.exists("dir2/DIR3/NAME3.txt")) {
cout << F("Removing /dir2/DIR3/NAME3.txt") << endl;
if (!sd.remove("dir2/DIR3/NAME3.txt") ||
!sd.rmdir("dir2/DIR3/") ||
!sd.rmdir("dir2/")) {
error("remove/rmdir failed");
}
}
// create a file and write one line to the file
SdFile file("NAME1.TXT", O_WRITE | O_CREAT);
if (!file.isOpen()) error("NAME1");
file.println("A test line for NAME1.TXT");
SdFile file("Name1.txt", O_WRITE | O_CREAT);
if (!file.isOpen()) {
error("Name1.txt");
}
file.println("A test line for Name1.txt");

// rename the file NAME2.TXT and add a line.
// rename the file name2.txt and add a line.
// sd.vwd() is the volume working directory, root.
if (!file.rename(sd.vwd(), "NAME2.TXT")) error("NAME2");
file.println("A test line for NAME2.TXT");
if (!file.rename(sd.vwd(), "name2.txt")) {
error("name2.txt");
}
file.println("A test line for name2.txt");

// list files
cout << pstr("------") << endl;
cout << F("------") << endl;
sd.ls(LS_R);

// make a new directory - "DIR1"
if (!sd.mkdir("DIR1")) error("DIR1");
// make a new directory - "Dir1"
if (!sd.mkdir("Dir1")) {
error("Dir1");
}

// move file into DIR1, rename it NAME3.TXT and add a line
if (!file.rename(sd.vwd(), "DIR1/NAME3.TXT")) error("NAME3");
file.println("A line for DIR1/NAME3.TXT");
// move file into Dir1, rename it NAME3.txt and add a line
if (!file.rename(sd.vwd(), "Dir1/NAME3.txt")) {
error("NAME3.txt");
}
file.println("A line for Dir1/NAME3.txt");

// list files
cout << pstr("------") << endl;
cout << F("------") << endl;
sd.ls(LS_R);

// make directory "DIR2"
if (!sd.mkdir("DIR2")) error("DIR2");
// make directory "dir2"
if (!sd.mkdir("dir2")) {
error("dir2");
}

// close file before rename(oldPath, newPath)
file.close();

// move DIR1 into DIR2 and rename it DIR3
if (!sd.rename("DIR1", "DIR2/DIR3")) error("DIR2/DIR3");
// move Dir1 into dir2 and rename it DIR3
if (!sd.rename("Dir1", "dir2/DIR3")) {
error("dir2/DIR3");
}

// open file for append in new location and add a line
if (!file.open("DIR2/DIR3/NAME3.TXT", O_WRITE | O_APPEND)) {
error("DIR2/DIR3/NAME3.TXT");
if (!file.open("dir2/DIR3/NAME3.txt", O_WRITE | O_APPEND)) {
error("dir2/DIR3/NAME3.txt");
}
file.println("A line for DIR2/DIR3/NAME3.TXT");
file.println("A line for dir2/DIR3/NAME3.txt");
file.close();

// list files
cout << pstr("------") << endl;
cout << F("------") << endl;
sd.ls(LS_R);

cout << pstr("Done") << endl;
cout << F("Done") << endl;
}
void loop() {}

+ 32
- 14
SdFat/utility/ArduinoStream.h Переглянути файл

@@ -54,7 +54,9 @@ class ArduinoInStream : public ibufstream {
while (1) {
t = millis();
while (!m_hw->available()) {
if ((millis() - t) > 10) goto done;
if ((millis() - t) > 10) {
goto done;
}
}
if (i >= (m_size - 1)) {
setstate(failbit);
@@ -63,7 +65,7 @@ class ArduinoInStream : public ibufstream {
m_line[i++] = m_hw->read();
m_line[i] = '\0';
}
done:
done:
init(m_line);
}

@@ -73,12 +75,16 @@ class ArduinoInStream : public ibufstream {
* \param[in] way
* \return true/false.
*/
bool seekoff(off_type off, seekdir way) {return false;}
/** Internal - do not use.
* \param[in] pos
* \return true/false.
*/
bool seekpos(pos_type pos) {return false;}
bool seekoff(off_type off, seekdir way) {
return false;
}
/** Internal - do not use.
* \param[in] pos
* \return true/false.
*/
bool seekpos(pos_type pos) {
return false;
}

private:
char *m_line;
@@ -105,14 +111,26 @@ class ArduinoOutStream : public ostream {
* \param[in] c
*/
void putch(char c) {
if (c == '\n') m_pr->write('\r');
if (c == '\n') {
m_pr->write('\r');
}
m_pr->write(c);
}
void putstr(const char* str) {m_pr->write(str);}
bool seekoff(off_type off, seekdir way) {return false;}
bool seekpos(pos_type pos) {return false;}
bool sync() {return true;}
pos_type tellpos() {return 0;}
void putstr(const char* str) {
m_pr->write(str);
}
bool seekoff(off_type off, seekdir way) {
return false;
}
bool seekpos(pos_type pos) {
return false;
}
bool sync() {
return true;
}
pos_type tellpos() {
return 0;
}
/// @endcond
private:
ArduinoOutStream() {}

+ 19
- 13
SdFat/utility/DigitalPin.h Переглянути файл

@@ -81,7 +81,9 @@ inline void fastDigitalToggle(uint8_t pin) {
fastDigitalWrite(pin, !fastDigitalRead(pin));
}
//------------------------------------------------------------------------------
inline void fastPinMode(uint8_t pin, bool mode) {pinMode(pin, mode);}
inline void fastPinMode(uint8_t pin, bool mode) {
pinMode(pin, mode);
}
#else // __arm__
#include <avr/io.h>
#include <util/atomic.h>
@@ -449,7 +451,7 @@ static const uint8_t digitalPinCount = sizeof(pinMap)/sizeof(pin_map_t);
//==============================================================================
/** generate bad pin number error */
void badPinNumber(void)
__attribute__((error("Pin number is too large or not a constant")));
__attribute__((error("Pin number is too large or not a constant")));
//------------------------------------------------------------------------------
/** Check for valid pin number
* @param[in] pin Number of pin to be checked.
@@ -457,7 +459,7 @@ void badPinNumber(void)
static inline __attribute__((always_inline))
void badPinCheck(uint8_t pin) {
if (!__builtin_constant_p(pin) || pin >= digitalPinCount) {
badPinNumber();
badPinNumber();
}
}
//------------------------------------------------------------------------------
@@ -502,13 +504,13 @@ bool fastDigitalRead(uint8_t pin) {
static inline __attribute__((always_inline))
void fastDigitalToggle(uint8_t pin) {
badPinCheck(pin);
if (pinMap[pin].pin > reinterpret_cast<uint8_t*>(0X5F)) {
// must write bit to high address port
*pinMap[pin].pin = 1 << pinMap[pin].bit;
} else {
// will compile to sbi and PIN register will not be read.
*pinMap[pin].pin |= 1 << pinMap[pin].bit;
}
if (pinMap[pin].pin > reinterpret_cast<uint8_t*>(0X5F)) {
// must write bit to high address port
*pinMap[pin].pin = 1 << pinMap[pin].bit;
} else {
// will compile to sbi and PIN register will not be read.
*pinMap[pin].pin |= 1 << pinMap[pin].bit;
}
}
//------------------------------------------------------------------------------
/** Set pin value
@@ -594,7 +596,7 @@ class DigitalPin {
//----------------------------------------------------------------------------
/** set pin configuration
* @param[in] mode If true set output mode else input mode
* @param[in] level If mode is output, set level high/low. If mode
* @param[in] level If mode is output, set level high/low. If mode
* is input, enable or disable the pin's 20K pull-up.
*/
inline __attribute__((always_inline))
@@ -606,13 +608,17 @@ class DigitalPin {
* Set pin level high if output mode or enable 20K pull-up if input mode.
*/
inline __attribute__((always_inline))
void high() {write(true);}
void high() {
write(true);
}
//----------------------------------------------------------------------------
/**
* Set pin level low if output mode or disable 20K pull-up if input mode.
*/
inline __attribute__((always_inline))
void low() {write(false);}
void low() {
write(false);
}
//----------------------------------------------------------------------------
/**
* Set pin mode

+ 7
- 5
SdFat/utility/FatApiConstants.h Переглянути файл

@@ -48,12 +48,14 @@ uint8_t const O_EXCL = 0X80;

// FatFile class static and const definitions
// flags for ls()
/** ls() flag to print modify date */
uint8_t const LS_DATE = 1;
/** ls() flag to print file size */
uint8_t const LS_SIZE = 2;
/** ls() flag for list all files including hidden. */
uint8_t const LS_A = 1;
/** ls() flag to print modify. date */
uint8_t const LS_DATE = 2;
/** ls() flag to print file size. */
uint8_t const LS_SIZE = 4;
/** ls() flag for recursive list of subdirectories */
uint8_t const LS_R = 4;
uint8_t const LS_R = 8;

// flags for timestamp
/** set the file's last access date */

+ 497
- 530
SdFat/utility/FatFile.cpp
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 258
- 175
SdFat/utility/FatFile.h Переглянути файл

@@ -23,7 +23,7 @@
* \file
* \brief FatFile class
*/
#include <ctype.h>
// #include <ctype.h>
#include <string.h>
#include <stddef.h>
#include <limits.h>
@@ -33,25 +33,6 @@
#include "FatVolume.h"
class FatFileSystem;
//------------------------------------------------------------------------------
#if defined(ARDUINO) || defined(DOXYGEN)
#include <Arduino.h>
/** Use Print on Arduino */
typedef Print print_t;
#else // ARDUINO
// Arduino type for flash string.
class __FlashStringHelper;
/**
* \class CharWriter
* \brief Character output - often serial port.
*/
class CharWriter {
public:
virtual size_t write(char c) = 0;
virtual size_t write(const char* s) = 0;
};
typedef Print print_t;
#endif // ARDUINO
//------------------------------------------------------------------------------
// Stuff to store strings in AVR flash.
#ifdef __AVR__
#include <avr/pgmspace.h>
@@ -89,6 +70,37 @@ struct FatPos_t {
uint32_t cluster;
FatPos_t() : position(0), cluster(0) {}
};
//------------------------------------------------------------------------------
/** Expression for path name separator. */
#define isDirSeparator(c) ((c) == '/')
//------------------------------------------------------------------------------
/**
* \struct fname_t
* \brief Internal type for Short File Name - do not use in user apps.
*/
struct fname_t {
/** Flags for base and extension character case and LFN. */
uint8_t flags;
/** length of Long File Name */
size_t len;
/** Long File Name start. */
const char* lfn;
/** position for sequence number */
uint8_t seqPos;
/** Short File Name */
uint8_t sfn[11];
};
/** Derived from a LFN with loss or conversion of characters. */
const uint8_t FNAME_FLAG_LOST_CHARS = 0X01;
/** Base-name or extension has mixed case. */
const uint8_t FNAME_FLAG_MIXED_CASE = 0X02;
/** LFN entries are required for file name. */
const uint8_t FNAME_FLAG_NEED_LFN =
FNAME_FLAG_LOST_CHARS | FNAME_FLAG_MIXED_CASE;
/** Filename base-name is all lower case */
const uint8_t FNAME_FLAG_LC_BASE = DIR_NT_LC_BASE;
/** Filename extension is all lower case. */
const uint8_t FNAME_FLAG_LC_EXT = DIR_NT_LC_EXT;
//==============================================================================
/**
* \class FatFile
@@ -96,15 +108,8 @@ struct FatPos_t {
*/
class FatFile {
public:
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// development tests - DO NOT USE!
bool createLfn(FatFile* dirFile, ////////////////////////////////////////////////////
uint16_t bgnIndex, char* name, uint8_t oflag); ///////////////////////
bool findLfn(const char* name, uint16_t* bgnIndex, uint16_t *endIndex); /////////////
bool findSfn(uint8_t* sfn, uint16_t* index); ////////////////////////////////////////
#endif // DOXYGEN_SHOULD_SKIP_THIS
/** Create an instance. */
FatFile() : m_writeError(false), m_attr(FILE_ATTR_CLOSED) {}
FatFile() : m_attr(FILE_ATTR_CLOSED), m_error(0) {}
/** Create a file object and open it in the current working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
@@ -114,19 +119,33 @@ class FatFile {
*/
FatFile(const char* path, uint8_t oflag) {
m_attr = FILE_ATTR_CLOSED;
m_writeError = false;
m_error = 0;
open(path, oflag);
}
#if DESTRUCTOR_CLOSES_FILE
~FatFile() {if(isOpen()) close();}
~FatFile() {
if (isOpen()) {
close();
}
}
#endif // DESTRUCTOR_CLOSES_FILE

/** \return value of writeError */
bool getWriteError() {return m_writeError;}
bool getWriteError() {
return m_error & WRITE_ERROR;
}
/** Set writeError to zero */
void clearWriteError() {m_writeError = 0;}
//----------------------------------------------------------------------------
// helpers for stream classes
void clearWriteError() {
m_error &= ~WRITE_ERROR;
}
/** Clear all error bits. */
void clearError() {
m_error = 0;
}
/** \return All error bits. */
uint8_t getError() {
return m_error;
}
/** get position for streams
* \param[out] pos struct to receive position
*/
@@ -135,15 +154,17 @@ class FatFile {
* \param[out] pos struct with value for new position
*/
void setpos(FatPos_t* pos);
//----------------------------------------------------------------------------
/** \return number of bytes available from the current position to EOF */
uint32_t available() {return fileSize() - curPosition();}
/** \return The number of bytes available from the current position
* to EOF for normal files. Zero is returned for directory files.
*/
uint32_t available() {
return isFile() ? fileSize() - curPosition() : 0;
}
/** Close a file and force cached data and directory information
* to be written to the storage device.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include no file is open or an I/O error.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool close();
/** Check for contiguous file and return its raw block range.
@@ -151,10 +172,8 @@ class FatFile {
* \param[out] bgnBlock the first block address for the file.
* \param[out] endBlock the last block address for the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include file is not contiguous, file has zero length
* or an I/O error occurred.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
/** Create and open a new contiguous file of a specified size.
@@ -166,22 +185,23 @@ class FatFile {
* \param[in] path A path with a valid DOS 8.3 file name.
* \param[in] size The desired file size.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include \a path contains
* an invalid DOS 8.3 file name, the FAT volume has not been initialized,
* a file is already open, the file already exists, the root
* directory is full or an I/O error.
*
* \return The value true is returned for success and
* the value false, is returned for failure.
*/
bool createContiguous(FatFile* dirFile,
const char* path, uint32_t size);
const char* path, uint32_t size);
/** \return The current cluster number for a file or directory. */
uint32_t curCluster() const {return m_curCluster;}
uint32_t curCluster() const {
return m_curCluster;
}
/** \return The current position for a file or directory. */
uint32_t curPosition() const {return m_curPosition;}
uint32_t curPosition() const {
return m_curPosition;
}
/** \return Current working directory */
static FatFile* cwd() {return m_cwd;}
static FatFile* cwd() {
return m_cwd;
}
/** Set the date/time callback function
*
* \param[in] dateTime The user's call back function. The callback
@@ -214,20 +234,23 @@ class FatFile {
m_dateTime = dateTime;
}
/** Cancel the date/time callback function. */
static void dateTimeCallbackCancel() {m_dateTime = 0;}
static void dateTimeCallbackCancel() {
m_dateTime = 0;
}
/** Return a file's directory entry.
*
* \param[out] dir Location for return of the file's directory entry.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool dirEntry(dir_t* dir);

/**
* \return The index of this file in it's directory.
*/
uint16_t dirIndex() {return m_dirIndex;}
uint16_t dirIndex() {
return m_dirIndex;
}
/** Format the name field of \a dir into the 13 byte array
* \a name in standard 8.3 short name format.
*
@@ -236,6 +259,16 @@ class FatFile {
* \return length of the name.
*/
static uint8_t dirName(const dir_t* dir, char* name);
/** \return The number of bytes allocated to a directory or zero
* if an error occurs.
*/
uint32_t dirSize();
/** Dump file in Hex
* \param[in] pr Print stream for list.
* \param[in] pos Start position in file.
* \param[in] n number of locations to dump.
*/
void dmpFile(print_t* pr, uint32_t pos, size_t n);
/** Test for the existence of a file in a directory
*
* \param[in] path Path of the file to be tested for.
@@ -272,38 +305,100 @@ class FatFile {
* If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
*/
int16_t fgets(char* str, int16_t num, char* delim = 0);
/** \return The total number of bytes in a file or directory. */
uint32_t fileSize() const {return m_fileSize;}
/** \return The total number of bytes in a file. */
uint32_t fileSize() const {
return m_fileSize;
}
/** \return The first cluster number for a file or directory. */
uint32_t firstCluster() const {return m_firstCluster;}
/** Get a file's name
*
* \param[out] name An array of 13 characters for the file's name.
uint32_t firstCluster() const {
return m_firstCluster;
}
/**
* Get a file's name followed by a zero byte.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \param[out] name An array of characters for the file's name.
* \param[in] size The size of the array in bytes. The array
* must be at least 13 bytes long. The file name will be
* truncated if it is too long.
* \return The value true, is returned for success and
* the value false, is returned for failure.
*/
bool getFilename(char* name);

bool getFilename(char* name, size_t size);
/**
* Get a file's Short File Name followed by a zero byte.
*
* \param[out] name An array of characters for the file's name.
* The array must be at least 13 bytes long.
* \return The value true, is returned for success and
* the value false, is returned for failure.
*/
bool getSFN(char* name);
/** \return True if this is a directory else false. */
bool isDir() const {return m_attr & FILE_ATTR_DIR;}
bool isDir() const {
return m_attr & FILE_ATTR_DIR;
}
/** \return True if this is a normal file else false. */
bool isFile() const {return !isDir();}
bool isFile() const {
return m_attr & FILE_ATTR_FILE;
}
/** \return True if this is a hidden file else false. */
bool isHidden() const {return m_attr & FILE_ATTR_HIDDEN;}
bool isHidden() const {
return m_attr & FILE_ATTR_HIDDEN;
}
/** \return true if this file has a Long File Name. */
bool isLFN() const {
return m_lfnOrd;
}
/** \return True if this is an open file/directory else false. */
bool isOpen() const {return m_attr & FILE_ATTR_IS_OPEN;}
bool isOpen() const {
return m_attr;
}
/** \return True if this is the root directory. */
bool isRoot() const {return m_attr & FILE_ATTR_ROOT;}
/** \return True if file is read-only */
bool isReadOnly() const {return m_attr & FILE_ATTR_READ_ONLY;}
bool isRoot() const {
return m_attr & FILE_ATTR_ROOT;
}
/** \return True if this is the FAT32 root directory. */
bool isRoot32() const {
return m_attr & FILE_ATTR_ROOT32;
}
/** \return True if this is the FAT12 of FAT16 root directory. */
bool isRootFixed() const {return m_attr & FILE_ATTR_ROOT_FIXED;}
bool isRootFixed() const {
return m_attr & FILE_ATTR_ROOT_FIXED;
}
/** \return True if file is read-only */
bool isReadOnly() const {
return m_attr & FILE_ATTR_READ_ONLY;
}
/** \return True if this is a subdirectory else false. */
bool isSubDir() const {return m_attr & FILE_ATTR_SUBDIR;}
bool isSubDir() const {
return m_attr & FILE_ATTR_SUBDIR;
}
/** \return True if this is a system file else false. */
bool isSystem() const {return m_attr & FILE_ATTR_SYSTEM;}

bool isSystem() const {
return m_attr & FILE_ATTR_SYSTEM;
}
/** Check for a legal 8.3 character.
* \param[in] c Character to be checked.
* \return true for a legal 8.3 character else false.
*/
static bool legal83Char(uint8_t c) {
if (c == '"' || c == '|') {
return false;
}
// *+,./
if (0X2A <= c && c <= 0X2F && c != 0X2D) {
return false;
}
// :;<=>?
if (0X3A <= c && c <= 0X3F) {
return false;
}
// [\]
if (0X5B <= c && c <= 0X5D) {
return false;
}
return 0X20 < c && c < 0X7F;
}
/** List directory contents.
*
* \param[in] pr Print stream for list.
@@ -329,10 +424,8 @@ class FatFile {
*
* \param[in] pFlag Create missing parent directories if true.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include this file is already open, \a parent is not a
* directory, \a path is invalid or already exists in \a parent.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool mkdir(FatFile* dir, const char* path, bool pFlag = true);
/** Open a file in the volume working directory of a FatFileSystem.
@@ -344,8 +437,8 @@ class FatFile {
* \param[in] oflag bitwise-inclusive OR of open mode flags.
* See see FatFile::open(FatFile*, const char*, uint8_t).
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool open(FatFileSystem* fs, const char* path, uint8_t oflag);
/** Open a file by index.
@@ -405,11 +498,8 @@ class FatFile {
* \note Directory files must be opened read only. Write and truncation is
* not allowed for directory files.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include this file is already open, \a dirFile is not
* a directory, \a path is invalid, the file does not exist
* or can't be opened in the access mode specified by oflag.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool open(FatFile* dirFile, const char* path, uint8_t oflag);
/** Open a file in the current working directory.
@@ -419,8 +509,8 @@ class FatFile {
* \param[in] oflag bitwise-inclusive OR of open mode flags.
* See see FatFile::open(FatFile*, const char*, uint8_t).
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool open(const char* path, uint8_t oflag = O_READ) {
return open(m_cwd, path, oflag);
@@ -436,34 +526,12 @@ class FatFile {
* \return true for success or false for failure.
*/
bool openNext(FatFile* dirFile, uint8_t oflag = O_READ);
/** Open the next file or subdirectory in a directory and return the
* file name. The Long %File Name, LFN, is returned if present otherwise
* the 8.3 short name will be returned.
*
* \param[in] dirFile An open FatFile instance for the directory
* containing the file to be opened.
*
* \param[out] name Location that will receive the name.
*
* \param[in] size The size of the name array.
*
* \param[in] oflag bitwise-inclusive OR of open mode flags.
* See see FatFile::open(FatFile*, const char*, uint8_t).
*
* \return For success, the length of the returned name. The name
* will be truncated to size - 1 bytes followed by a zero byte.
* For EOF, zero will be returned. If an error occurs, -1 is
* returned.
*/
int openNextLFN(FatFile* dirFile, char* name, size_t size, uint8_t oflag);
/** Open a volume's root directory.
*
* \param[in] vol The FAT volume containing the root directory to be opened.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file is already open, the FAT volume has
* not been initialized or it a FAT12 volume.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool openRoot(FatVolume* vol);
/** Return the next available byte without consuming it.
@@ -475,8 +543,8 @@ class FatFile {
*
* \param[in] pr Print stream for output.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool printCreateDateTime(print_t* pr);
/** %Print a directory date field.
@@ -530,26 +598,34 @@ class FatFile {
*
* \param[in] pr Print stream for output.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool printModifyDateTime(print_t* pr);
/** Print a file's name
*
* \param[in] pr Print stream for output.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
size_t printName(print_t* pr);
/** Print a file's size.
*
* \param[in] pr Print stream for output.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The number of characters printed is returned
* for success and zero is returned for failure.
*/
size_t printFileSize(print_t* pr);
/** Print a file's Short File Name.
*
* \param[in] pr Print stream for output.
*
* \return The number of characters printed is returned
* for success and zero is returned for failure.
*/
size_t printSFN(print_t* pr);
/** Read the next byte from a file.
*
* \return For success read returns the next byte in the file as an int.
@@ -592,10 +668,8 @@ class FatFile {
* file that has a long name. For example if a file has the long name
* "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file read-only, is a directory,
* or an I/O error occurred.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool remove();
/** Remove a file.
@@ -609,24 +683,21 @@ class FatFile {
* file that has a long name. For example if a file has the long name
* "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file is a directory, is read only,
* \a dirFile is not a directory, \a path is not found
* or an I/O error occurred.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
static bool remove(FatFile* dirFile, const char* path);
/** Set the file's current position to zero. */
void rewind() {seekSet(0);}
void rewind() {
seekSet(0);
}
/** Rename a file or subdirectory.
*
* \param[in] dirFile Directory for the new path.
* \param[in] newPath New path name for the file/directory.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include \a dirFile is not open or is not a directory
* file, newPath is invalid or already exists, or an I/O error occurs.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool rename(FatFile* dirFile, const char* newPath);
/** Remove a directory file.
@@ -639,10 +710,8 @@ class FatFile {
* directory that has a long name. For example if a directory has the
* long name "New folder" you should not delete the 8.3 name "NEWFOL~1".
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file is not a directory, is the root
* directory, is not empty, or an I/O error occurred.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool rmdir();
/** Recursively delete a directory and all contained files.
@@ -657,8 +726,8 @@ class FatFile {
* \note This function should not be used to delete the 8.3 version of
* a directory that has a long name. See remove() and rmdir().
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool rmRfStar();
/** Set the files position to current position + \a pos. See seekSet().
@@ -669,16 +738,19 @@ class FatFile {
return seekSet(m_curPosition + offset);
}
/** Set the files position to end-of-file + \a offset. See seekSet().
* Can't be used for directory files since file size is not defined.
* \param[in] offset The new position in bytes from end-of-file.
* \return true for success or false for failure.
*/
bool seekEnd(int32_t offset = 0) {return seekSet(m_fileSize + offset);}
bool seekEnd(int32_t offset = 0) {
return isFile() ? seekSet(m_fileSize + offset) : false;
}
/** Sets a file's position.
*
* \param[in] pos The new position in bytes from the beginning of the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool seekSet(uint32_t pos);
/** Set the current working directory.
@@ -688,17 +760,17 @@ class FatFile {
* \return true for success else false.
*/
static bool setCwd(FatFile* dir) {
if (!dir->isDir()) return false;
if (!dir->isDir()) {
return false;
}
m_cwd = dir;
return true;
}
/** The sync() call causes all modified data and directory fields
* to be written to the storage device.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include a call to sync() before a file has been
* opened or an I/O error.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool sync();
/** Copy a file's timestamps
@@ -709,8 +781,8 @@ class FatFile {
* Modify and access timestamps may be overwritten if a date time callback
* function has been set by dateTimeCallback().
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool timestamp(FatFile* file);
/** Set a file's timestamps in its directory entry.
@@ -743,36 +815,40 @@ class FatFile {
* Modify and access timestamps may be overwritten if a date time callback
* function has been set by dateTimeCallback().
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool timestamp(uint8_t flags, uint16_t year, uint8_t month, uint8_t day,
uint8_t hour, uint8_t minute, uint8_t second);
uint8_t hour, uint8_t minute, uint8_t second);
/** Type of file. You should use isFile() or isDir() instead of fileType()
* if possible.
*
* \return The file or directory type.
*/
uint8_t fileAttr() const {return m_attr;}
uint8_t fileAttr() const {
return m_attr;
}
/** Truncate a file to a specified length. The current file position
* will be maintained if it is less than or equal to \a length otherwise
* it will be set to end of file.
*
* \param[in] length The desired length for the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include file is read only, file is a directory,
* \a length is greater than the current file size or an I/O error occurs.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool truncate(uint32_t length);
/** \return FatVolume that contains this file. */
FatVolume* volume() const {return m_vol;}
FatVolume* volume() const {
return m_vol;
}
/** Write a single byte.
* \param[in] b The byte to be written.
* \return +1 for success or -1 for failure.
*/
int write(uint8_t b) {return write(&b, 1);}
int write(uint8_t b) {
return write(&b, 1);
}
/** Write data to an open file.
*
* \note Data is moved to the cache but may not be written to the
@@ -800,7 +876,7 @@ class FatFile {
/** Entry is for a system file. */
static const uint8_t FILE_ATTR_SYSTEM = DIR_ATT_SYSTEM;
/** Entry for normal data file */
static const uint8_t FILE_ATTR_IS_OPEN = 0X08;
static const uint8_t FILE_ATTR_FILE = 0X08;
/** Entry is for a subdirectory */
static const uint8_t FILE_ATTR_SUBDIR = DIR_ATT_DIRECTORY;
/** A FAT12 or FAT16 root directory */
@@ -816,19 +892,23 @@ class FatFile {
DIR_ATT_SYSTEM | DIR_ATT_DIRECTORY;

/** experimental don't use */

bool openParent(FatFile* dir);

// private functions
bool addCluster();
bool addDirCluster();
dir_t* cacheDirEntry(uint8_t action);
int8_t lsPrintNext(print_t* pr, uint8_t flags, uint8_t indent);
static bool make83Name(const char* str, uint8_t* name, const char** ptr);
bool mkdir(FatFile* parent, const uint8_t dname[11]);
bool open(FatFile* dirFile, const uint8_t dname[11], uint8_t oflag);
bool openCachedEntry(FatFile* dirFile, uint16_t cacheIndex, uint8_t oflag);
static uint8_t lfnChecksum(uint8_t* name);
bool lfnUniqueSfn(fname_t* fname);
bool openCluster(FatFile* file);
static bool parsePathName(const char* str, fname_t* fname, const char** ptr);
bool mkdir(FatFile* parent, fname_t* fname);
bool open(FatFile* dirFile, fname_t* fname, uint8_t oflag);
bool openCachedEntry(FatFile* dirFile, uint16_t cacheIndex, uint8_t oflag,
uint8_t lfnOrd);
bool readLBN(uint32_t* lbn);
dir_t* readDirCache();
dir_t* readDirCache(bool skipReadOk = false);
bool setDirSize();

// bits defined in m_flags
@@ -842,15 +922,18 @@ class FatFile {
// data time callback function
static void (*m_dateTime)(uint16_t* date, uint16_t* time);
// private data
bool m_writeError; // Set when a write error occurs
static const uint8_t WRITE_ERROR = 0X1;
static const uint8_t READ_ERROR = 0X2;
uint8_t m_attr; // File attributes
uint8_t m_error; // Error bits.
uint8_t m_flags; // See above for definition of m_flags bits
uint8_t m_lfnOrd;
uint16_t m_dirIndex; // index of directory entry in dir file
FatVolume* m_vol; // volume where file is located
uint32_t m_dirCluster;
uint32_t m_curCluster; // cluster for current file position
uint32_t m_curPosition; // current file position
uint32_t m_dirBlock; // block for this files directory entry
uint32_t m_dirFirstCluster; // first cluster of this file's directory
uint32_t m_fileSize; // file size in bytes
uint32_t m_firstCluster; // first cluster of file
};

+ 593
- 212
SdFat/utility/FatFileLFN.cpp Переглянути файл

@@ -17,286 +17,667 @@
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include "FatFile.h"
bool FatFile::findSfn(uint8_t sfn[11], uint16_t* index) {
uint16_t free = 0XFFFF;
uint16_t idx;
dir_t* dir;

if (!isDir()) {
//------------------------------------------------------------------------------
//
uint8_t FatFile::lfnChecksum(uint8_t* name) {
uint8_t sum = 0;
for (uint8_t i = 0; i < 11; i++) {
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + name[i];
}
return sum;
}
#if USE_LONG_FILE_NAMES
//------------------------------------------------------------------------------
// Saves about 90 bytes of flash on 328 over tolower().
inline char lfnToLower(char c) {
return 'A' <= c && c <= 'Z' ? c + 'a' - 'A' : c;
}
//------------------------------------------------------------------------------
// Daniel Bernstein University of Illinois at Chicago.
// Original had + instead of ^
static uint16_t Bernstein(uint16_t hash, const char *str, size_t len) {
for (size_t i = 0; i < len; i++) {
// hash = hash * 33 ^ str[i];
hash = ((hash << 5) + hash) ^ str[i];
}
return hash;
}
//------------------------------------------------------------------------------
/**
* Fetch a 16-bit long file name character.
*
* \param[in] ldir Pointer to long file name directory entry.
* \param[in] i Index of character.
* \return The 16-bit character.
*/
static uint16_t lfnGetChar(ldir_t *ldir, uint8_t i) {
if (i < LDIR_NAME1_DIM) {
return ldir->name1[i];
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM)) {
return ldir->name2[i - LDIR_NAME1_DIM];
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM + LDIR_NAME2_DIM)) {
return ldir->name3[i - LDIR_NAME1_DIM - LDIR_NAME2_DIM];
}
return 0;
}
//------------------------------------------------------------------------------
static bool lfnGetName(ldir_t *ldir, char* name, size_t n) {
uint8_t i;
size_t k = 13*((ldir->ord & 0X1F) - 1);
for (i = 0; i < 13; i++) {
uint16_t c = lfnGetChar(ldir, i);
if (c == 0 || k >= n) {
break;
}
name[k++] = c >= 0X7F ? '?' : c;
}
// Terminate with zero byte if name fits.
if (k < n && (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY)) {
name[k] = 0;
}
// Truncate if name is too long.
name[n-1] = 0;
return true;
}
//------------------------------------------------------------------------------
inline bool lfnLegalChar(char c) {
if (c == '/' || c == '\\' || c == '"' || c == '*' ||
c == ':' || c == '<' || c == '>' || c == '?' || c == '|') {
return false;
}
return 0X1F < c && c < 0X7F;
}
//------------------------------------------------------------------------------
/**
* Store a 16-bit long file name character.
*
* \param[in] ldir Pointer to long file name directory entry.
* \param[in] i Index of character.
* \param[in] c The 16-bit character.
*/
static void lfnPutChar(ldir_t *ldir, uint8_t i, uint16_t c) {
if (i < LDIR_NAME1_DIM) {
ldir->name1[i] = c;
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM)) {
ldir->name2[i - LDIR_NAME1_DIM] = c;
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM + LDIR_NAME2_DIM)) {
ldir->name3[i - LDIR_NAME1_DIM - LDIR_NAME2_DIM] = c;
}
}
//------------------------------------------------------------------------------
static void lfnPutName(ldir_t *ldir, const char* name, size_t n) {
size_t k = 13*((ldir->ord & 0X1F) - 1);
for (uint8_t i = 0; i < 13; i++, k++) {
uint16_t c = k < n ? name[k] : k == n ? 0 : 0XFFFF;
lfnPutChar(ldir, i, c);
}
}
//==============================================================================
bool FatFile::getFilename(char* name, size_t size) {
FatFile dirFile;
ldir_t* ldir;
if (!isOpen() || size < 13) {
DBG_FAIL_MACRO;
goto fail;
}
rewind();
while (m_curPosition < m_fileSize) {
idx = m_curPosition/32;
if ((0XF & idx) == 0) {
dir = readDirCache();
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
} else {
m_curPosition += 32;
dir++;
if (!isLFN()) {
return getSFN(name);
}
if (!dirFile.openCluster(this)) {
DBG_FAIL_MACRO;
goto fail;
}
for (uint8_t ord = 1; ord <= m_lfnOrd; ord++) {
if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
DBG_FAIL_MACRO;
goto fail;
}
// done if last entry
if (dir->name[0] == DIR_NAME_FREE || dir->name[0] == DIR_NAME_DELETED) {
if (free == 0XFFFF) free = idx;
if (dir->name[0] == DIR_NAME_FREE) goto fail;
} else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
if (!memcmp(sfn, dir->name, 11)) {
*index = idx;
return true;
}
ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
if (!ldir) {
DBG_FAIL_MACRO;
goto fail;
}
if (ldir->attr != DIR_ATT_LONG_NAME) {
DBG_FAIL_MACRO;
goto fail;
}
if (ord != (ldir->ord & 0X1F)) {
DBG_FAIL_MACRO;
goto fail;
}
if (!lfnGetName(ldir, name, size)) {
DBG_FAIL_MACRO;
goto fail;
}
if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) {
return true;
}
}
// Fall into fail.
DBG_FAIL_MACRO;

fail:
*index = free;
fail:
name[0] = 0;
return false;
}
//------------------------------------------------------------------------------
bool FatFile::createLfn(FatFile* dirFile,
uint16_t bgnIndex, char* name, uint8_t oflag) {
return false;
bool FatFile::openCluster(FatFile* file) {
if (file->m_dirCluster == 0) {
return openRoot(file->m_vol);
}
memset(this, 0, sizeof(FatFile));
m_attr = FILE_ATTR_SUBDIR;
m_flags = O_READ;
m_vol = file->m_vol;
m_firstCluster = file->m_dirCluster;
return true;
}
//------------------------------------------------------------------------------
bool FatFile::findLfn(const char* name,
uint16_t *bgnIndex, uint16_t* endIndex) {
bool fill;
bool haveLong = false;
uint8_t ndir;
uint8_t test;
uint16_t lfnBgn;
uint16_t curIndex = 0XFFFF;
uint16_t freeIndex = 0XFFFF;
uint8_t freeCount = 0;
bool FatFile::parsePathName(const char* path,
fname_t* fname, const char** ptr) {
char c;
bool is83;
uint8_t bit = DIR_NT_LC_BASE;
uint8_t lc = 0;
uint8_t uc = 0;
uint8_t i = 0;
uint8_t in = 7;
size_t end;
size_t len = 0;
int si;
int dot;

// Skip leading spaces.
while (*path == ' ') {
path++;
}
fname->lfn = path;

for (len = 0; ; len++) {
c = path[len];
if (c == 0 || isDirSeparator(c)) {
break;
}
if (!lfnLegalChar(c)) {
return false;
}
}
// Advance to next path component.
for (end = len; path[end] == ' ' || isDirSeparator(path[end]); end++) {}
*ptr = &path[end];

// Back over spaces and dots.
while (len) {
c = path[len - 1];
if (c != '.' && c != ' ') {
break;
}
len--;
}
// Max length of LFN is 255.
if (len > 255) {
return false;
}
fname->len = len;
// Blank file short name.
for (uint8_t k = 0; k < 11; k++) {
fname->sfn[k] = ' ';
}
// skip leading spaces and dots.
for (si = 0; path[si] == '.' || path[si] == ' '; si++) {}
// Not 8.3 if leading dot or space.
is83 = !si;

// find last dot.
for (dot = len - 1; dot >= 0 && path[dot] != '.'; dot--) {}
for (; si < len; si++) {
c = path[si];
if (c == ' ' || (c == '.' && dot != si)) {
is83 = false;
continue;
}
if (!legal83Char(c) && si != dot) {
is83 = false;
c = '_';
}
if (si == dot || i > in) {
if (in == 10) {
// Done - extension longer than three characters.
is83 = false;
break;
}
if (si != dot) {
is83 = false;
}
// Break if no dot and base-name is longer than eight characters.
if (si > dot) {
break;
}
si = dot;
in = 10; // Max index for full 8.3 name.
i = 8; // Place for extension.
bit = DIR_NT_LC_EXT; // bit for extension.
} else {
if ('a' <= c && c <= 'z') {
c += 'A' - 'a';
lc |= bit;
} else if ('A' <= c && c <= 'Z') {
uc |= bit;
}
fname->sfn[i++] = c;
if (i < 7) {
fname->seqPos = i;
}
}
}
if (fname->sfn[0] == ' ') {
return false;
}

if (is83) {
fname->flags = lc & uc ? FNAME_FLAG_MIXED_CASE : lc;
} else {
fname->flags = FNAME_FLAG_LOST_CHARS;
fname->sfn[fname->seqPos] = '~';
fname->sfn[fname->seqPos + 1] = '1';
}
return true;
}
//------------------------------------------------------------------------------
bool FatFile::open(FatFile* dirFile, fname_t* fname, uint8_t oflag) {
bool fnameFound = false;
uint8_t lfnOrd = 0;
uint8_t freeNeed;
uint8_t freeFound = 0;
uint8_t ord;
uint8_t chksum;
uint16_t freeIndex;
uint16_t curIndex;
dir_t* dir;
size_t len;
bool is83;
bool foundFree = false;
const char* ptr;
uint8_t name83[11];
if (!isDir()) {
ldir_t* ldir;
size_t len = fname->len;

if (!dirFile->isDir() || isOpen()) {
DBG_FAIL_MACRO;
goto fail;
}
is83 = make83Name(name, name83, &ptr);
for (len = 0; name[len] !=0 && name[len] != '/'; len++) {}
// Assume LFN.
freeNeed = (len + 12)/13 + 1;
rewind();
// Number of directory entries needed.
freeNeed = fname->flags & FNAME_FLAG_NEED_LFN ? 1 + (len + 12)/13 : 1;

dirFile->rewind();
while (1) {
curIndex = m_curPosition/32;
if (m_curPosition == m_fileSize) {
DBG_FAIL_MACRO;
goto fail;
}
// read entry into cache
dir = readDirCache();
curIndex = dirFile->m_curPosition/32;
dir = dirFile->readDirCache(true);
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
if (dirFile->getError()) {
DBG_FAIL_MACRO;
goto fail;
}
// At EOF
goto create;
}
#if 1
if (dir->name[0] == DIR_NAME_DELETED) {
if (!foundFree) {
if (freeIndex == 0XFFFF) {
freeIndex = curIndex;
freeCount = 0;
}
if (++freeCount == freeNeed) {
foundFree = true;
}
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == DIR_NAME_FREE) {
if (freeFound == 0) {
freeIndex = curIndex;
}
if (freeFound < freeNeed) {
freeFound++;
}
if (dir->name[0] == DIR_NAME_FREE) {
goto create;
}
continue;
} else {
if (!foundFree) freeIndex = 0XFFFF;
}
#endif
if (dir->name[0] == DIR_NAME_FREE) {
DBG_FAIL_MACRO;
goto fail;
if (freeFound < freeNeed) {
freeFound = 0;
}
}
// skip empty slot or '.' or '..'
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') {
haveLong = false;
continue;
}
if (DIR_IS_LONG_NAME(dir)) {
lfnOrd = 0;
} else if (DIR_IS_LONG_NAME(dir)) {
ldir_t *ldir = reinterpret_cast<ldir_t*>(dir);
if (!haveLong) {
if ((ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) == 0) continue;
ndir = ldir->ord & ~LDIR_ORD_LAST_LONG_ENTRY;
if (ndir < 1 || ndir > 20) continue;
test = ldir->chksum;
haveLong = true;
lfnBgn = curIndex;
fill = true;
} else if (ldir->ord != --ndir || test != ldir->chksum) {
haveLong = false;
if (!lfnOrd) {
if ((ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) == 0) {
continue;
}
lfnOrd = ord = ldir->ord & 0X1F;
chksum = ldir->chksum;
} else if (ldir->ord != --ord || chksum != ldir->chksum) {
lfnOrd = 0;
continue;
}
size_t nOff = 13*(ndir -1);
for (int i = 12; i >= 0; i--) {
uint16_t u = lfnChar(ldir, i);

if (fill) {
if (u == 0 || u == 0XFFFF) {
continue;
}
if (len != (nOff + i +1)) {
haveLong = false;
break;
size_t k = 13*(ord - 1);
if (k >= len) {
// Not found.
lfnOrd = 0;
continue;
}
for (uint8_t i = 0; i < 13; i++) {
uint16_t u = lfnGetChar(ldir, i);
if (k == len) {
if (u != 0) {
// Not found.
lfnOrd = 0;
}
fill = false;
break;
}
if (u > 255 || toupper(u) != toupper(name[nOff + i])) {
haveLong = false;
if (u > 255 || lfnToLower(u) != lfnToLower(fname->lfn[k++])) {
// Not found.
lfnOrd = 0;
break;
}
}
} else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
if (haveLong) {
uint8_t sum = 0;
for (uint8_t i = 0; i < 11; i++) {
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir->name[i];
}
if (sum != test || ndir != 1) {
haveLong = false;
if (lfnOrd) {
if (1 == ord && lfnChecksum(dir->name) == chksum) {
goto found;
}
DBG_FAIL_MACRO;
goto fail;
}
if (haveLong) goto done;
if (is83 && !memcmp(dir->name, name83, sizeof(name83))) {
goto done;
if (!memcmp(dir->name, fname->sfn, sizeof(fname->sfn))) {
if (!(fname->flags & FNAME_FLAG_LOST_CHARS)) {
goto found;
}
fnameFound = true;
}
} else {
haveLong = false;
lfnOrd = 0;
}
}

done:
*bgnIndex = haveLong ? lfnBgn : curIndex;
*endIndex = curIndex;
found:
// Don't open if create only.
if (oflag & O_EXCL) {
DBG_FAIL_MACRO;
goto fail;
}
goto open;

create:
// don't create unless O_CREAT and O_WRITE
if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) {
DBG_FAIL_MACRO;
goto fail;
}
// If at EOF start in next cluster.
if (freeFound == 0) {
freeIndex = curIndex;
}

while (freeFound < freeNeed) {
dir = dirFile->readDirCache();
if (!dir) {
if (dirFile->getError()) {
DBG_FAIL_MACRO;
goto fail;
}
// EOF if no error.
break;
}
freeFound++;
}
while (freeFound < freeNeed) {
// Will fail if FAT16 root.
if (!dirFile->addDirCluster()) {
DBG_FAIL_MACRO;
goto fail;
}
// Done if more than one block per cluster. Max freeNeed is 21.
if (dirFile->m_vol->blocksPerCluster() > 1) {
break;
}
freeFound += 16;
}
if (fnameFound) {
if (!dirFile->lfnUniqueSfn(fname)) {
goto fail;
}
}
if (!dirFile->seekSet(32UL*freeIndex)) {
DBG_FAIL_MACRO;
goto fail;
}
lfnOrd = freeNeed - 1;
for (uint8_t ord = lfnOrd ; ord ; ord--) {
ldir = reinterpret_cast<ldir_t*>(dirFile->readDirCache());
if (!ldir) {
DBG_FAIL_MACRO;
goto fail;
}
dirFile->m_vol->cacheDirty();
ldir->ord = ord == lfnOrd ? LDIR_ORD_LAST_LONG_ENTRY | ord : ord;
ldir->attr = DIR_ATT_LONG_NAME;
ldir->type = 0;
ldir->chksum = lfnChecksum(fname->sfn);
ldir->mustBeZero = 0;
lfnPutName(ldir, fname->lfn, len);
}
curIndex = dirFile->m_curPosition/32;
dir = dirFile->readDirCache();
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
// initialize as empty file
memset(dir, 0, sizeof(dir_t));
memcpy(dir->name, fname->sfn, 11);

// Set base-name and extension lower case bits.
dir->reservedNT = (DIR_NT_LC_BASE | DIR_NT_LC_EXT) & fname->flags;

// set timestamps
if (m_dateTime) {
// call user date/time function
m_dateTime(&dir->creationDate, &dir->creationTime);
} else {
// use default date/time
dir->creationDate = FAT_DEFAULT_DATE;
dir->creationTime = FAT_DEFAULT_TIME;
}
dir->lastAccessDate = dir->creationDate;
dir->lastWriteDate = dir->creationDate;
dir->lastWriteTime = dir->creationTime;

// Force write of entry to device.
dirFile->m_vol->cacheDirty();

open:
// open entry in cache.
if (!openCachedEntry(dirFile, curIndex, oflag, lfnOrd)) {
DBG_FAIL_MACRO;
goto fail;
}
return true;

fail:
*bgnIndex = foundFree ? freeIndex : curIndex;
fail:
return false;
}
//------------------------------------------------------------------------------
int FatFile::openNextLFN(FatFile* dirFile,
char* name, size_t size, uint8_t oflag) {
bool fill;
bool haveLong = false;
size_t lfnIn;
uint8_t ndir;
uint8_t test;
size_t FatFile::printName(print_t* pr) {
FatFile dirFile;
uint16_t u;
size_t n = 0;
ldir_t* ldir;

if (!isLFN()) {
return printSFN(pr);
}
if (!dirFile.openCluster(this)) {
DBG_FAIL_MACRO;
goto fail;
}
for (uint8_t ord = 1; ord <= m_lfnOrd; ord++) {
if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
DBG_FAIL_MACRO;
goto fail;
}
ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
if (!ldir) {
DBG_FAIL_MACRO;
goto fail;
}
if (ldir->attr !=DIR_ATT_LONG_NAME ||
ord != (ldir->ord & 0X1F)) {
DBG_FAIL_MACRO;
goto fail;
}
for (uint8_t i = 0; i < 13; i++) {
u = lfnGetChar(ldir, i);
if (u == 0) {
// End of name.
break;
}
if (u > 0X7E) {
u = '?';
}
pr->write(static_cast<char>(u));
n++;
}
if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) {
return n;
}
}
// Fall into fail;
DBG_FAIL_MACRO;

fail:
return 0;
}
//------------------------------------------------------------------------------
bool FatFile::remove() {
bool last;
uint8_t chksum;
uint8_t ord;
FatFile dirFile;
dir_t* dir;
uint16_t index;
int rtn;
ldir_t* ldir;

// Check for valid directory and file is not open.
if (!dirFile->isDir() || isOpen() || size < 13) {
// Cant' remove not open for write.
if (!isFile() || !(m_flags & O_WRITE)) {
DBG_FAIL_MACRO;
goto fail;
}
// Free any clusters.
if (m_firstCluster && !m_vol->freeChain(m_firstCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
// Cache directory entry.
dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
chksum = lfnChecksum(dir->name);

while (1) {
// Check for EOF.
if (dirFile->curPosition() == dirFile->fileSize()) goto done;
index = dirFile->curPosition()/32;
// read entry into cache
dir = dirFile->readDirCache();
if (!dir) {
// Mark entry deleted.
dir->name[0] = DIR_NAME_DELETED;

// Set this file closed.
m_attr = FILE_ATTR_CLOSED;

// Write entry to device.
if (!m_vol->cacheSync()) {
DBG_FAIL_MACRO;
goto fail;
}
if (!isLFN()) {
// Done, no LFN entries.
return true;
}
if (!dirFile.openCluster(this)) {
DBG_FAIL_MACRO;
goto fail;
}
for (ord = 1; ord <= m_lfnOrd; ord++) {
if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
DBG_FAIL_MACRO;
goto fail;
}

// done if last entry
if (dir->name[0] == DIR_NAME_FREE) {
ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
if (!ldir) {
DBG_FAIL_MACRO;
return 0;
goto fail;
}
// skip empty slot or '.' or '..'
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') {
haveLong = false;
continue;
if (ldir->attr != DIR_ATT_LONG_NAME ||
ord != (ldir->ord & 0X1F) ||
chksum != ldir->chksum) {
DBG_FAIL_MACRO;
goto fail;
}
if (DIR_IS_LONG_NAME(dir)) {
ldir_t *ldir = reinterpret_cast<ldir_t*>(dir);
if (!haveLong) {
if ((ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) == 0) continue;
ndir = ldir->ord & ~LDIR_ORD_LAST_LONG_ENTRY;
if (ndir < 1 || ndir > 20) continue;
test = ldir->chksum;
haveLong = true;
rtn = 0;
fill = true;
lfnIn = 13*ndir;
} else if (ldir->ord != --ndir || test != ldir->chksum) {
haveLong = false;
continue;
last = ldir->ord & LDIR_ORD_LAST_LONG_ENTRY;
ldir->ord = DIR_NAME_DELETED;
m_vol->cacheDirty();
if (last) {
if (!m_vol->cacheSync()) {
DBG_FAIL_MACRO;
goto fail;
}
for (int i = 12; i >= 0; i--) {
uint16_t u = lfnChar(ldir, i);
if (fill) {
if (rtn == 0 && u != 0 && u != 0XFFFF) rtn = lfnIn;
if (u == 0 || u == 0XFFFF || lfnIn >= size) {
lfnIn--;
continue;
}
name[lfnIn] = 0;
fill = false;
}
if (lfnIn == 0 || u > 255) {
haveLong = false;
break;
}
name[--lfnIn] = u;
return true;
}
}
// Fall into fail.
DBG_FAIL_MACRO;

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;;
dir_t *dir;
uint16_t hex;

DBG_HALT_IF(!(fname->flags & FNAME_FLAG_LOST_CHARS));
DBG_HALT_IF(fname->sfn[pos] != '~' && fname->sfn[pos + 1] != '1');

for (uint8_t seq = 2; seq < 100; seq++) {
if (seq < FIRST_HASH_SEQ) {
fname->sfn[pos + 1] = '0' + seq;
} else {
DBG_PRINT_IF(seq > FIRST_HASH_SEQ);
hex = Bernstein(seq + fname->len, fname->lfn, fname->len);
if (pos > 3) {
// Make space in name for ~HHHH.
pos = 3;
}
} else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
if (haveLong) {
uint8_t sum = 0;
for (uint8_t i = 0; i < 11; i++) {
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir->name[i];
}
if (sum != test || ndir != 1) {
haveLong = false;
}
for (uint8_t i = pos + 4 ; i > pos; i--) {
uint8_t h = hex & 0XF;
fname->sfn[i] = h < 10 ? h + '0' : h + 'A' - 10;
hex >>= 4;
}
if (!haveLong) {
rtn = dirName(dir, name);
if (dir->reservedNT) {
uint8_t lowerTest = 0X08;
for (char *ptr = name; *ptr; ptr++) {
if (*ptr == '.') {
lowerTest = 0X10;
continue;
}
if (dir->reservedNT & lowerTest) {
*ptr = tolower(*ptr);
}
}
}
fname->sfn[pos] = '~';
rewind();
while (1) {
dir = readDirCache(true);
if (!dir) {
if (!getError()) {
// At EOF and name not found if no error.
goto done;
}
}
if (!openCachedEntry(dirFile, index, oflag)) {
DBG_FAIL_MACRO;
goto fail;
}
return rtn;
} else {
haveLong = false;
if (dir->name[0] == DIR_NAME_FREE) {
goto done;
}
if (DIR_IS_FILE_OR_SUBDIR(dir) && !memcmp(fname->sfn, dir->name, 11)) {
// Name found - try another.
break;
}
}
}
// fall inti fail - too many tries.
DBG_FAIL_MACRO;

done:
return 0;
fail:
return false;

fail:
return -1;
done:
return true;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
#endif // #if USE_LONG_FILE_NAMES

+ 30
- 73
SdFat/utility/FatFilePrint.cpp Переглянути файл

@@ -42,70 +42,36 @@ static void printU32(print_t* pr, uint32_t v) {
}
//------------------------------------------------------------------------------
void FatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) {
if (!isDir()) return;
FatFile file;
rewind();
int8_t status;
while ((status = lsPrintNext(pr, flags, indent))) {
if (status > 1 && (flags & LS_R)) {
uint16_t index = curPosition()/32 - 1;
FatFile s;
if (s.open(this, index, O_READ)) s.ls(pr, flags, indent + 2);
seekSet(32 * (index + 1));
while (file.openNext(this, O_READ)) {
// indent for dir level
if (!file.isHidden() && !(flags & LS_A)) {
for (uint8_t i = 0; i < indent; i++) {
pr->write(' ');
}
if (flags & LS_DATE) {
file.printModifyDateTime(pr);
pr->write(' ');
}
if (flags & LS_SIZE) {
file.printFileSize(pr);
pr->write(' ');
}
file.printName(pr);
if (file.isDir()) {
pr->write('/');
}
pr->write('\r');
pr->write('\n');
if ((flags & LS_R) && file.isDir()) {
file.ls(pr, flags, indent + 2);
}
}
file.close();
}
}
//------------------------------------------------------------------------------
// saves 32 bytes on stack for ls recursion
// return 0 - EOF, 1 - normal file, or 2 - directory
int8_t FatFile::lsPrintNext(print_t* pr, uint8_t flags, uint8_t indent) {
dir_t dir;
uint8_t w = 0;

while (1) {
if (read(&dir, sizeof(dir)) != sizeof(dir)) return 0;
if (dir.name[0] == DIR_NAME_FREE) return 0;

// skip deleted entry and entries for . and ..
if (dir.name[0] != DIR_NAME_DELETED && dir.name[0] != '.'
&& DIR_IS_FILE_OR_SUBDIR(&dir)) break;
}
// indent for dir level
for (uint8_t i = 0; i < indent; i++) pr->write(' ');

// print name
for (uint8_t i = 0; i < 11; i++) {
if (dir.name[i] == ' ')continue;
if (i == 8) {
pr->write('.');
w++;
}
pr->write(dir.name[i]);
w++;
}
if (DIR_IS_SUBDIR(&dir)) {
pr->write('/');
w++;
}
if (flags & (LS_DATE | LS_SIZE)) {
while (w++ < 14) pr->write(' ');
}
// print modify date/time if requested
if (flags & LS_DATE) {
pr->write(' ');
printFatDate(pr, dir.lastWriteDate);
pr->write(' ');
printFatTime(pr, dir.lastWriteTime);
}
// print size if requested
if (!DIR_IS_SUBDIR(&dir) && (flags & LS_SIZE)) {
pr->write(' ');
printU32(pr, dir.fileSize);
}
pr->write('\r');
pr->write('\n');
return DIR_IS_FILE(&dir) ? 1 : 2;
}
//------------------------------------------------------------------------------
bool FatFile::printCreateDateTime(print_t* pr) {
dir_t dir;
if (!dirEntry(&dir)) {
@@ -117,7 +83,7 @@ bool FatFile::printCreateDateTime(print_t* pr) {
printFatTime(pr, dir.creationTime);
return true;

fail:
fail:
return false;
}
//------------------------------------------------------------------------------
@@ -215,27 +181,18 @@ bool FatFile::printModifyDateTime(print_t* pr) {
printFatTime(pr, dir.lastWriteTime);
return true;

fail:
fail:
return false;
}
//------------------------------------------------------------------------------
size_t FatFile::printName(print_t* pr) {
char name[13];
if (!getFilename(name)) {
DBG_FAIL_MACRO;
goto fail;
}
return pr->write(name);

fail:
return 0;
}
//------------------------------------------------------------------------------
size_t FatFile::printFileSize(print_t* pr) {
char buf[11];
char *ptr = buf + sizeof(buf);
*--ptr = 0;
ptr = fmtDec(fileSize(), ptr);
while (ptr > buf) *--ptr = ' ';
while (ptr > buf) {
*--ptr = ' ';
}
return pr->write(buf);
}

+ 273
- 0
SdFat/utility/FatFileSFN.cpp Переглянути файл

@@ -0,0 +1,273 @@
/* FatLib Library
* Copyright (C) 2012 by William Greiman
*
* This file is part of the FatLib Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "FatFile.h"
#include "FatFileSystem.h"
//------------------------------------------------------------------------------
bool FatFile::getSFN(char* name) {
dir_t* dir;
if (!isOpen()) {
DBG_FAIL_MACRO;
goto fail;
}
if (isRoot()) {
name[0] = '/';
name[1] = '\0';
return true;
}
// cache entry
dir = cacheDirEntry(FatCache::CACHE_FOR_READ);
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
// format name
dirName(dir, name);
return true;

fail:
return false;
}
//------------------------------------------------------------------------------
size_t FatFile::printSFN(print_t* pr) {
char name[13];
if (!getSFN(name)) {
DBG_FAIL_MACRO;
goto fail;
}
return pr->write(name);

fail:
return 0;
}
#if !USE_LONG_FILE_NAMES
//------------------------------------------------------------------------------
bool FatFile::getFilename(char* name, size_t size) {
return size < 13 ? 0 : getSFN(name);
}
//------------------------------------------------------------------------------
// format directory name field from a 8.3 name string
bool FatFile::parsePathName(const char* path, fname_t* fname,
const char** ptr) {
uint8_t uc = 0;
uint8_t lc = 0;
uint8_t bit = FNAME_FLAG_LC_BASE;
// blank fill name and extension
for (uint8_t i = 0; i < 11; i++) {
fname->sfn[i] = ' ';
}

for (uint8_t i = 0, n = 7;; path++) {
uint8_t c = *path;
if (c == 0 || isDirSeparator(c)) {
// Done.
break;
}
if (c == '.' && n == 7) {
n = 10; // max index for full 8.3 name
i = 8; // place for extension

// bit for extension.
bit = FNAME_FLAG_LC_EXT;
} else {
if (!legal83Char(c) || i > n) {
DBG_FAIL_MACRO;
goto fail;
}
if ('a' <= c && c <= 'z') {
c += 'A' - 'a';
lc |= bit;
} else if ('A' <= c && c <= 'Z') {
uc |= bit;
}
fname->sfn[i++] = c;
}
}
// must have a file name, extension is optional
if (fname->sfn[0] == ' ') {
DBG_FAIL_MACRO;
goto fail;
}
// Set base-name and extension bits.
fname->flags = lc & uc ? 0 : lc;
while (isDirSeparator(*path)) {
path++;
}
*ptr = path;
return true;

fail:
return false;
}
//------------------------------------------------------------------------------
// open with filename in fname
#define SFN_OPEN_USES_CHKSUM 0
bool FatFile::open(FatFile* dirFile, fname_t* fname, uint8_t oflag) {
bool emptyFound = false;
#if SFN_OPEN_USES_CHKSUM
uint8_t chksum;
#endif
uint8_t lfnOrd = 0;
uint16_t emptyIndex;
uint16_t index = 0;
dir_t* dir;
ldir_t* ldir;

dirFile->rewind();
while (1) {
if (!emptyFound) {
emptyIndex = index;
}
dir = dirFile->readDirCache(true);
if (!dir) {
if (dirFile->getError()) {
DBG_FAIL_MACRO;
goto fail;
}
// At EOF if no error.
break;
}
if (dir->name[0] == DIR_NAME_FREE) {
emptyFound = true;
break;
}
if (dir->name[0] == DIR_NAME_DELETED) {
lfnOrd = 0;
emptyFound = true;
} else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
if (!memcmp(fname->sfn, dir->name, 11)) {
// don't open existing file if O_EXCL
if (oflag & O_EXCL) {
DBG_FAIL_MACRO;
goto fail;
}
#if SFN_OPEN_USES_CHKSUM
if (lfnOrd && chksum != lfnChecksum(dir->name)) {
DBG_FAIL_MACRO;
goto fail;
}
#endif // SFN_OPEN_USES_CHKSUM
if (!openCachedEntry(dirFile, index, oflag, lfnOrd)) {
DBG_FAIL_MACRO;
goto fail;
}
return true;
} else {
lfnOrd = 0;
}
} else if (DIR_IS_LONG_NAME(dir)) {
ldir = (ldir_t*)dir;
if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) {
lfnOrd = ldir->ord & 0X1F;
#if SFN_OPEN_USES_CHKSUM
chksum = ldir->chksum;
#endif // SFN_OPEN_USES_CHKSUM
}
} else {
lfnOrd = 0;
}
index++;
}
// don't create unless O_CREAT and O_WRITE
if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) {
DBG_FAIL_MACRO;
goto fail;
}
if (emptyFound) {
index = emptyIndex;
} else {
if (!dirFile->addDirCluster()) {
DBG_FAIL_MACRO;
goto fail;
}
}
if (!dirFile->seekSet(32UL*index)) {
DBG_FAIL_MACRO;
goto fail;
}
dir = dirFile->readDirCache();
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
// initialize as empty file
memset(dir, 0, sizeof(dir_t));
memcpy(dir->name, fname->sfn, 11);

// Set base-name and extension lower case bits.
dir->reservedNT = (DIR_NT_LC_BASE | DIR_NT_LC_EXT) & fname->flags;

// set timestamps
if (m_dateTime) {
// call user date/time function
m_dateTime(&dir->creationDate, &dir->creationTime);
} else {
// use default date/time
dir->creationDate = FAT_DEFAULT_DATE;
dir->creationTime = FAT_DEFAULT_TIME;
}
dir->lastAccessDate = dir->creationDate;
dir->lastWriteDate = dir->creationDate;
dir->lastWriteTime = dir->creationTime;

// Force write of entry to device.
dirFile->m_vol->cacheDirty();

// open entry in cache.
return openCachedEntry(dirFile, index, oflag, 0);

fail:
return false;
}
//------------------------------------------------------------------------------
size_t FatFile::printName(print_t* pr) {
return printSFN(pr);
}
//------------------------------------------------------------------------------
bool FatFile::remove() {
dir_t* dir;
// Can't remove if LFN or not open for write.
if (!isFile() || isLFN() || !(m_flags & O_WRITE)) {
DBG_FAIL_MACRO;
goto fail;
}
// Free any clusters.
if (m_firstCluster && !m_vol->freeChain(m_firstCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
// Cache directory entry.
dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
// Mark entry deleted.
dir->name[0] = DIR_NAME_DELETED;

// Set this file closed.
m_attr = FILE_ATTR_CLOSED;

// Write entry to device.
return m_vol->cacheSync();

fail:
return false;
}
#endif // !USE_LONG_FILE_NAMES

+ 54
- 29
SdFat/utility/FatFileSystem.h Переглянути файл

@@ -27,7 +27,7 @@
*/
//------------------------------------------------------------------------------
/** FatFileSystem version YYYYMMDD */
#define FAT_LIB_VERSION 20141115
#define FAT_LIB_VERSION 20141201
//------------------------------------------------------------------------------
/**
* \class FatFileSystem
@@ -38,8 +38,8 @@ class FatFileSystem : protected FatVolume {
/**
* Initialize an FatFileSystem object.
* \param[in] d Volume Working Directory.
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool begin(FatFile* d) {
m_vwd = d;
@@ -57,8 +57,8 @@ class FatFileSystem : protected FatVolume {
* \param[in] set_cwd Set the current working directory to this volume's
* working directory if true.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool chdir(bool set_cwd = false) {
vwd()->close();
@@ -81,20 +81,28 @@ class FatFileSystem : protected FatVolume {
* \param[in] set_cwd Set the current working directory to this volume's
* working directory if true.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
//----------------------------------------------------------------------------
bool chdir(const char *path, bool set_cwd = false) {
FatFile dir;
if (path[0] == '/' && path[1] == '\0') return chdir(set_cwd);
if (!dir.open(vwd(), path, O_READ)) goto fail;
if (!dir.isDir()) goto fail;
if (path[0] == '/' && path[1] == '\0') {
return chdir(set_cwd);
}
if (!dir.open(vwd(), path, O_READ)) {
goto fail;
}
if (!dir.isDir()) {
goto fail;
}
*m_vwd = dir;
if (set_cwd) FatFile::setCwd(vwd());
if (set_cwd) {
FatFile::setCwd(vwd());
}
return true;

fail:
fail:
return false;
}
//----------------------------------------------------------------------------
@@ -164,8 +172,8 @@ class FatFileSystem : protected FatVolume {
*
* \param[in] pFlag Create missing parent directories if true.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool mkdir(const char* path, bool pFlag = true) {
FatFile sub;
@@ -176,8 +184,8 @@ class FatFileSystem : protected FatVolume {
*
* \param[in] path A path with a valid 8.3 DOS name for the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool remove(const char* path) {
return FatFile::remove(vwd(), path);
@@ -195,12 +203,14 @@ class FatFileSystem : protected FatVolume {
* moved and file system corruption could occur if the file is accessed by
* a file object that was opened before the rename() call.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool rename(const char *oldPath, const char *newPath) {
FatFile file;
if (!file.open(vwd(), oldPath, O_READ)) return false;
if (!file.open(vwd(), oldPath, O_READ)) {
return false;
}
return file.rename(vwd(), newPath);
}
//----------------------------------------------------------------------------
@@ -210,12 +220,14 @@ class FatFileSystem : protected FatVolume {
*
* The subdirectory file will be removed only if it is empty.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool rmdir(const char* path) {
FatFile sub;
if (!sub.open(vwd(), path, O_READ)) return false;
if (!sub.open(vwd(), path, O_READ)) {
return false;
}
return sub.rmdir();
}
//----------------------------------------------------------------------------
@@ -226,20 +238,33 @@ class FatFileSystem : protected FatVolume {
* \param[in] path A path with a valid 8.3 DOS name for the file.
* \param[in] length The desired length for the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include file is read only, file is a directory,
* \a length is greater than the current file size or an I/O error occurs.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool truncate(const char* path, uint32_t length) {
FatFile file;
if (!file.open(vwd(), path, O_WRITE)) return false;
if (!file.open(vwd(), path, O_WRITE)) {
return false;
}
return file.truncate(length);
}
/** \return a pointer to the FatVolume object. */
FatVolume* vol() {return this;}
FatVolume* vol() {
return this;
}
/** \return a pointer to the volume working directory. */
FatFile* vwd() {return m_vwd;}
FatFile* vwd() {
return m_vwd;
}
/** Wipe all data from the volume. You must reinitialize the volume before
* accessing it again.
* \param[in] pr print stream for status dots.
* \return true for success else false.
*/
bool wipe(print_t* pr = 0) {
m_vwd->close();
return FatVolume::wipe(pr);
}

private:
FatFile* m_vwd;

+ 27
- 0
SdFat/utility/FatLibConfig.h Переглянути файл

@@ -23,21 +23,48 @@
*/
#ifndef FatLibConfig_h
#define FatLibConfig_h

/** Use SdFatConfig.h if nonzero */
#define USE_SDFAT_CONFIG 1
#if USE_SDFAT_CONFIG
#include "../SdFatConfig.h"
#if !defined(USE_LONG_FILE_NAMES) || !defined(USE_SEPARATE_FAT_CACHE) || \
!defined(USE_MULTI_BLOCK_IO) || !defined(DESTRUCTOR_CLOSES_FILE) || \
!defined(ENDL_CALLS_FLUSH) || !defined(FAT12_SUPPORT)
#error Undefined congiguration symbols.
#endif // Configuration symbols
#else // USE_SDFAT_CONFIG
#include <stdint.h>
#ifdef __AVR__
#include <avr/io.h>
#endif // __AVR__
//------------------------------------------------------------------------------
/**
* Set USE_LONG_FILE_NAMES nonzero to use long file names (LFN).
* Long File Name are limited to a maximum length of 255 characters.
*
* This implementation allows 7-bit characters in the range
* 0X20 to 0X7E. The following characters are not allowed:
*
* < (less than)
* > (greater than)
* : (colon)
* " (double quote)
* / (forward slash)
* \ (backslash)
* | (vertical bar or pipe)
* ? (question mark)
* * (asterisk)
*
*/
#define USE_LONG_FILE_NAMES 1
//------------------------------------------------------------------------------
/**
* Set USE_SEPARATE_FAT_CACHE non-zero to use a second 512 byte cache
* for FAT table entries. Improves performance for large writes that
* are not a multiple of 512 bytes.
*/

#ifdef __arm__
#define USE_SEPARATE_FAT_CACHE 1
#else // __arm__

+ 354
- 361
SdFat/utility/FatStructs.h Переглянути файл

@@ -43,56 +43,56 @@ uint8_t const EXTENDED_BOOT_SIG = 0X29;
* The MBR partition table has four entries.
*/
struct partitionTable {
/**
* Boot Indicator . Indicates whether the volume is the active
* partition. Legal values include: 0X00. Do not use for booting.
* 0X80 Active partition.
*/
/**
* Boot Indicator . Indicates whether the volume is the active
* partition. Legal values include: 0X00. Do not use for booting.
* 0X80 Active partition.
*/
uint8_t boot;
/**
* Head part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 0-255. Only used in old PC BIOS.
*/
/**
* Head part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t beginHead;
/**
* Sector part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
/**
* Sector part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned beginSector : 6;
/** High bits cylinder for first block in partition. */
/** High bits cylinder for first block in partition. */
unsigned beginCylinderHigh : 2;
/**
* Combine beginCylinderLow with beginCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
/**
* Combine beginCylinderLow with beginCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t beginCylinderLow;
/**
* Partition type. See defines that begin with PART_TYPE_ for
* some Microsoft partition types.
*/
/**
* Partition type. See defines that begin with PART_TYPE_ for
* some Microsoft partition types.
*/
uint8_t type;
/**
* head part of cylinder-head-sector address of the last sector in the
* partition. Legal values are 0-255. Only used in old PC BIOS.
*/
/**
* head part of cylinder-head-sector address of the last sector in the
* partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t endHead;
/**
* Sector part of cylinder-head-sector address of the last sector in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
/**
* Sector part of cylinder-head-sector address of the last sector in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned endSector : 6;
/** High bits of end cylinder */
/** High bits of end cylinder */
unsigned endCylinderHigh : 2;
/**
* Combine endCylinderLow with endCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
/**
* Combine endCylinderLow with endCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t endCylinderLow;
/** Logical block address of the first block in the partition. */
/** Logical block address of the first block in the partition. */
uint32_t firstSector;
/** Length of the partition, in blocks. */
/** Length of the partition, in blocks. */
uint32_t totalSectors;
}__attribute__((packed));
} __attribute__((packed));
/** Type name for partitionTable */
typedef struct partitionTable part_t;
//------------------------------------------------------------------------------
@@ -104,19 +104,19 @@ typedef struct partitionTable part_t;
* The first block of a storage device that is formatted with a MBR.
*/
struct masterBootRecord {
/** Code Area for master boot program. */
/** Code Area for master boot program. */
uint8_t codeArea[440];
/** Optional Windows NT disk signature. May contain boot code. */
/** Optional Windows NT disk signature. May contain boot code. */
uint32_t diskSignature;
/** Usually zero but may be more boot code. */
/** Usually zero but may be more boot code. */
uint16_t usuallyZero;
/** Partition tables. */
/** Partition tables. */
part_t part[4];
/** First MBR signature byte. Must be 0X55 */
/** First MBR signature byte. Must be 0X55 */
uint8_t mbrSig0;
/** Second MBR signature byte. Must be 0XAA */
/** Second MBR signature byte. Must be 0XAA */
uint8_t mbrSig1;
}__attribute__((packed));
} __attribute__((packed));
/** Type name for masterBootRecord */
typedef struct masterBootRecord mbr_t;
//------------------------------------------------------------------------------
@@ -127,124 +127,124 @@ typedef struct masterBootRecord mbr_t;
*
*/
struct fat_boot {
/**
* The first three bytes of the boot sector must be valid,
* executable x 86-based CPU instructions. This includes a
* jump instruction that skips the next non-executable bytes.
*/
/**
* The first three bytes of the boot sector must be valid,
* executable x 86-based CPU instructions. This includes a
* jump instruction that skips the next non-executable bytes.
*/
uint8_t jump[3];
/**
* This is typically a string of characters that identifies
* the operating system that formatted the volume.
*/
/**
* This is typically a string of characters that identifies
* the operating system that formatted the volume.
*/
char oemId[8];
/**
* The size of a hardware sector. Valid decimal values for this
* field are 512, 1024, 2048, and 4096. For most disks used in
* the United States, the value of this field is 512.
*/
/**
* The size of a hardware sector. Valid decimal values for this
* field are 512, 1024, 2048, and 4096. For most disks used in
* the United States, the value of this field is 512.
*/
uint16_t bytesPerSector;
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
*/
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
*/
uint8_t sectorsPerCluster;
/**
* The number of sectors preceding the start of the first FAT,
* including the boot sector. The value of this field is always 1.
*/
/**
* The number of sectors preceding the start of the first FAT,
* including the boot sector. The value of this field is always 1.
*/
uint16_t reservedSectorCount;
/**
* The number of copies of the FAT on the volume.
* The value of this field is always 2.
*/
/**
* The number of copies of the FAT on the volume.
* The value of this field is always 2.
*/
uint8_t fatCount;
/**
* For FAT12 and FAT16 volumes, this field contains the count of
* 32-byte directory entries in the root directory. For FAT32 volumes,
* this field must be set to 0. For FAT12 and FAT16 volumes, this
* value should always specify a count that when multiplied by 32
* results in a multiple of bytesPerSector. FAT16 volumes should
* use the value 512.
*/
/**
* For FAT12 and FAT16 volumes, this field contains the count of
* 32-byte directory entries in the root directory. For FAT32 volumes,
* this field must be set to 0. For FAT12 and FAT16 volumes, this
* value should always specify a count that when multiplied by 32
* results in a multiple of bytesPerSector. FAT16 volumes should
* use the value 512.
*/
uint16_t rootDirEntryCount;
/**
* This field is the old 16-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then totalSectors32
* must be non-zero. For FAT32 volumes, this field must be 0. For
* FAT12 and FAT16 volumes, this field contains the sector count, and
* totalSectors32 is 0 if the total sector count fits
* (is less than 0x10000).
*/
/**
* This field is the old 16-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then totalSectors32
* must be non-zero. For FAT32 volumes, this field must be 0. For
* FAT12 and FAT16 volumes, this field contains the sector count, and
* totalSectors32 is 0 if the total sector count fits
* (is less than 0x10000).
*/
uint16_t totalSectors16;
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xF8 is the standard value
* for fixed (non-removable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xF8 is the standard value
* for fixed (non-removable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
uint8_t mediaType;
/**
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
/**
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
uint16_t sectorsPerFat16;
/** Sectors per track for interrupt 0x13. Not used otherwise. */
/** Sectors per track for interrupt 0x13. Not used otherwise. */
uint16_t sectorsPerTrack;
/** Number of heads for interrupt 0x13. Not used otherwise. */
/** Number of heads for interrupt 0x13. Not used otherwise. */
uint16_t headCount;
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
uint32_t hidddenSectors;
/**
* This field is the new 32-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then
* totalSectors16 must be non-zero.
*/
/**
* This field is the new 32-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then
* totalSectors16 must be non-zero.
*/
uint32_t totalSectors32;
/**
* Related to the BIOS physical drive number. Floppy drives are
* identified as 0x00 and physical hard disks are identified as
* 0x80, regardless of the number of physical disk drives.
* Typically, this value is set prior to issuing an INT 13h BIOS
* call to specify the device to access. The value is only
* relevant if the device is a boot device.
*/
/**
* Related to the BIOS physical drive number. Floppy drives are
* identified as 0x00 and physical hard disks are identified as
* 0x80, regardless of the number of physical disk drives.
* Typically, this value is set prior to issuing an INT 13h BIOS
* call to specify the device to access. The value is only
* relevant if the device is a boot device.
*/
uint8_t driveNumber;
/** used by Windows NT - should be zero for FAT */
/** used by Windows NT - should be zero for FAT */
uint8_t reserved1;
/** 0X29 if next three fields are valid */
/** 0X29 if next three fields are valid */
uint8_t bootSignature;
/**
* A random serial number created when formatting a disk,
* which helps to distinguish between disks.
* Usually generated by combining date and time.
*/
/**
* A random serial number created when formatting a disk,
* which helps to distinguish between disks.
* Usually generated by combining date and time.
*/
uint32_t volumeSerialNumber;
/**
* A field once used to store the volume label. The volume label
* is now stored as a special file in the root directory.
*/
/**
* A field once used to store the volume label. The volume label
* is now stored as a special file in the root directory.
*/
char volumeLabel[11];
/**
* A field with a value of either FAT, FAT12 or FAT16,
* depending on the disk format.
*/
/**
* A field with a value of either FAT, FAT12 or FAT16,
* depending on the disk format.
*/
char fileSystemType[8];
/** X86 boot code */
/** X86 boot code */
uint8_t bootCode[448];
/** must be 0X55 */
/** must be 0X55 */
uint8_t bootSectorSig0;
/** must be 0XAA */
/** must be 0XAA */
uint8_t bootSectorSig1;
}__attribute__((packed));
} __attribute__((packed));
/** Type name for FAT Boot Sector */
typedef struct fat_boot fat_boot_t;
//------------------------------------------------------------------------------
@@ -255,150 +255,150 @@ typedef struct fat_boot fat_boot_t;
*
*/
struct fat32_boot {
/**
* The first three bytes of the boot sector must be valid,
* executable x 86-based CPU instructions. This includes a
* jump instruction that skips the next non-executable bytes.
*/
/**
* The first three bytes of the boot sector must be valid,
* executable x 86-based CPU instructions. This includes a
* jump instruction that skips the next non-executable bytes.
*/
uint8_t jump[3];
/**
* This is typically a string of characters that identifies
* the operating system that formatted the volume.
*/
/**
* This is typically a string of characters that identifies
* the operating system that formatted the volume.
*/
char oemId[8];
/**
* The size of a hardware sector. Valid decimal values for this
* field are 512, 1024, 2048, and 4096. For most disks used in
* the United States, the value of this field is 512.
*/
/**
* The size of a hardware sector. Valid decimal values for this
* field are 512, 1024, 2048, and 4096. For most disks used in
* the United States, the value of this field is 512.
*/
uint16_t bytesPerSector;
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
*/
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
*/
uint8_t sectorsPerCluster;
/**
* The number of sectors preceding the start of the first FAT,
* including the boot sector. Must not be zero
*/
/**
* The number of sectors preceding the start of the first FAT,
* including the boot sector. Must not be zero
*/
uint16_t reservedSectorCount;
/**
* The number of copies of the FAT on the volume.
* The value of this field is always 2.
*/
/**
* The number of copies of the FAT on the volume.
* The value of this field is always 2.
*/
uint8_t fatCount;
/**
* FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0.
*/
/**
* FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0.
*/
uint16_t rootDirEntryCount;
/**
* For FAT32 volumes, this field must be 0.
*/
/**
* For FAT32 volumes, this field must be 0.
*/
uint16_t totalSectors16;
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xF8 is the standard value
* for fixed (non-removable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xF8 is the standard value
* for fixed (non-removable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
uint8_t mediaType;
/**
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
/**
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
uint16_t sectorsPerFat16;
/** Sectors per track for interrupt 0x13. Not used otherwise. */
/** Sectors per track for interrupt 0x13. Not used otherwise. */
uint16_t sectorsPerTrack;
/** Number of heads for interrupt 0x13. Not used otherwise. */
/** Number of heads for interrupt 0x13. Not used otherwise. */
uint16_t headCount;
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
uint32_t hidddenSectors;
/**
* Contains the total number of sectors in the FAT32 volume.
*/
/**
* Contains the total number of sectors in the FAT32 volume.
*/
uint32_t totalSectors32;
/**
* Count of sectors occupied by one FAT on FAT32 volumes.
*/
/**
* Count of sectors occupied by one FAT on FAT32 volumes.
*/
uint32_t sectorsPerFat32;
/**
* This field is only defined for FAT32 media and does not exist on
* FAT12 and FAT16 media.
* Bits 0-3 -- Zero-based number of active FAT.
* Only valid if mirroring is disabled.
* Bits 4-6 -- Reserved.
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
* -- 1 means only one FAT is active; it is the one referenced
* in bits 0-3.
* Bits 8-15 -- Reserved.
*/
/**
* This field is only defined for FAT32 media and does not exist on
* FAT12 and FAT16 media.
* Bits 0-3 -- Zero-based number of active FAT.
* Only valid if mirroring is disabled.
* Bits 4-6 -- Reserved.
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
* -- 1 means only one FAT is active; it is the one referenced
* in bits 0-3.
* Bits 8-15 -- Reserved.
*/
uint16_t fat32Flags;
/**
* FAT32 version. High byte is major revision number.
* Low byte is minor revision number. Only 0.0 define.
*/
/**
* FAT32 version. High byte is major revision number.
* Low byte is minor revision number. Only 0.0 define.
*/
uint16_t fat32Version;
/**
* Cluster number of the first cluster of the root directory for FAT32.
* This usually 2 but not required to be 2.
*/
/**
* Cluster number of the first cluster of the root directory for FAT32.
* This usually 2 but not required to be 2.
*/
uint32_t fat32RootCluster;
/**
* Sector number of FSINFO structure in the reserved area of the
* FAT32 volume. Usually 1.
*/
/**
* Sector number of FSINFO structure in the reserved area of the
* FAT32 volume. Usually 1.
*/
uint16_t fat32FSInfo;
/**
* If non-zero, indicates the sector number in the reserved area
* of the volume of a copy of the boot record. Usually 6.
* No value other than 6 is recommended.
*/
/**
* If non-zero, indicates the sector number in the reserved area
* of the volume of a copy of the boot record. Usually 6.
* No value other than 6 is recommended.
*/
uint16_t fat32BackBootBlock;
/**
* Reserved for future expansion. Code that formats FAT32 volumes
* should always set all of the bytes of this field to 0.
*/
/**
* Reserved for future expansion. Code that formats FAT32 volumes
* should always set all of the bytes of this field to 0.
*/
uint8_t fat32Reserved[12];
/**
* Related to the BIOS physical drive number. Floppy drives are
* identified as 0x00 and physical hard disks are identified as
* 0x80, regardless of the number of physical disk drives.
* Typically, this value is set prior to issuing an INT 13h BIOS
* call to specify the device to access. The value is only
* relevant if the device is a boot device.
*/
/**
* Related to the BIOS physical drive number. Floppy drives are
* identified as 0x00 and physical hard disks are identified as
* 0x80, regardless of the number of physical disk drives.
* Typically, this value is set prior to issuing an INT 13h BIOS
* call to specify the device to access. The value is only
* relevant if the device is a boot device.
*/
uint8_t driveNumber;
/** used by Windows NT - should be zero for FAT */
/** used by Windows NT - should be zero for FAT */
uint8_t reserved1;
/** 0X29 if next three fields are valid */
/** 0X29 if next three fields are valid */
uint8_t bootSignature;
/**
* A random serial number created when formatting a disk,
* which helps to distinguish between disks.
* Usually generated by combining date and time.
*/
/**
* A random serial number created when formatting a disk,
* which helps to distinguish between disks.
* Usually generated by combining date and time.
*/
uint32_t volumeSerialNumber;
/**
* A field once used to store the volume label. The volume label
* is now stored as a special file in the root directory.
*/
/**
* A field once used to store the volume label. The volume label
* is now stored as a special file in the root directory.
*/
char volumeLabel[11];
/**
* A text field with a value of FAT32.
*/
/**
* A text field with a value of FAT32.
*/
char fileSystemType[8];
/** X86 boot code */
/** X86 boot code */
uint8_t bootCode[420];
/** must be 0X55 */
/** must be 0X55 */
uint8_t bootSectorSig0;
/** must be 0XAA */
/** must be 0XAA */
uint8_t bootSectorSig1;
}__attribute__((packed));
} __attribute__((packed));
/** Type name for FAT32 Boot Sector */
typedef struct fat32_boot fat32_boot_t;
//------------------------------------------------------------------------------
@@ -413,32 +413,32 @@ uint32_t const FSINFO_STRUCT_SIG = 0x61417272;
*
*/
struct fat32_fsinfo {
/** must be 0X52, 0X52, 0X61, 0X41 */
/** must be 0X52, 0X52, 0X61, 0X41 */
uint32_t leadSignature;
/** must be zero */
/** must be zero */
uint8_t reserved1[480];
/** must be 0X72, 0X72, 0X41, 0X61 */
/** must be 0X72, 0X72, 0X41, 0X61 */
uint32_t structSignature;
/**
* Contains the last known free cluster count on the volume.
* If the value is 0xFFFFFFFF, then the free count is unknown
* and must be computed. Any other value can be used, but is
* not necessarily correct. It should be range checked at least
* to make sure it is <= volume cluster count.
*/
/**
* Contains the last known free cluster count on the volume.
* If the value is 0xFFFFFFFF, then the free count is unknown
* and must be computed. Any other value can be used, but is
* not necessarily correct. It should be range checked at least
* to make sure it is <= volume cluster count.
*/
uint32_t freeCount;
/**
* This is a hint for the FAT driver. It indicates the cluster
* number at which the driver should start looking for free clusters.
* If the value is 0xFFFFFFFF, then there is no hint and the driver
* should start looking at cluster 2.
*/
/**
* This is a hint for the FAT driver. It indicates the cluster
* number at which the driver should start looking for free clusters.
* If the value is 0xFFFFFFFF, then there is no hint and the driver
* should start looking at cluster 2.
*/
uint32_t nextFree;
/** must be zero */
/** must be zero */
uint8_t reserved2[12];
/** must be 0X00, 0X00, 0X55, 0XAA */
/** must be 0X00, 0X00, 0X55, 0XAA */
uint8_t tailSignature[4];
}__attribute__((packed));
} __attribute__((packed));
/** Type name for FAT32 FSINFO Sector */
typedef struct fat32_fsinfo fat32_fsinfo_t;
//------------------------------------------------------------------------------
@@ -463,80 +463,80 @@ uint32_t const FAT32MASK = 0X0FFFFFFF;
* \brief FAT short directory entry
*
* Short means short 8.3 name, not the entry size.
*
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
*
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
* 16-bit word):
*
* Bits 9-15: Count of years from 1980, valid value range 0-127
*
* Bits 9-15: Count of years from 1980, valid value range 0-127
* inclusive (1980-2107).
*
*
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
*
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
*
* Time Format. A FAT directory entry time stamp is a 16-bit field that has
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
* 16-bit word, bit 15 is the MSB of the 16-bit word).
*
*
* Bits 11-15: Hours, valid value range 0-23 inclusive.
*
*
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
*
*
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
*
*
* The valid time range is from Midnight 00:00:00 to 23:59:58.
*/
struct directoryEntry {
/** Short 8.3 name.
*
* The first eight bytes contain the file name with blank fill.
* The last three bytes contain the file extension with blank fill.
*/
/** Short 8.3 name.
*
* The first eight bytes contain the file name with blank fill.
* The last three bytes contain the file extension with blank fill.
*/
uint8_t name[11];
/** Entry attributes.
*
* The upper two bits of the attribute byte are reserved and should
* always be set to 0 when a file is created and never modified or
* looked at after that. See defines that begin with DIR_ATT_.
*/
/** Entry attributes.
*
* The upper two bits of the attribute byte are reserved and should
* always be set to 0 when a file is created and never modified or
* looked at after that. See defines that begin with DIR_ATT_.
*/
uint8_t attributes;
/**
* Reserved for use by Windows NT. Set value to 0 when a file is
* created and never modify or look at it after that.
*/
/**
* Reserved for use by Windows NT. Set value to 0 when a file is
* created and never modify or look at it after that.
*/
uint8_t reservedNT;
/**
* The granularity of the seconds part of creationTime is 2 seconds
* so this field is a count of tenths of a second and its valid
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
*/
/**
* The granularity of the seconds part of creationTime is 2 seconds
* so this field is a count of tenths of a second and its valid
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
*/
uint8_t creationTimeTenths;
/** Time file was created. */
/** Time file was created. */
uint16_t creationTime;
/** Date file was created. */
/** Date file was created. */
uint16_t creationDate;
/**
* Last access date. Note that there is no last access time, only
* a date. This is the date of last read or write. In the case of
* a write, this should be set to the same date as lastWriteDate.
*/
/**
* Last access date. Note that there is no last access time, only
* a date. This is the date of last read or write. In the case of
* a write, this should be set to the same date as lastWriteDate.
*/
uint16_t lastAccessDate;
/**
* High word of this entry's first cluster number (always 0 for a
* FAT12 or FAT16 volume).
*/
/**
* High word of this entry's first cluster number (always 0 for a
* FAT12 or FAT16 volume).
*/
uint16_t firstClusterHigh;
/** Time of last write. File creation is considered a write. */
/** Time of last write. File creation is considered a write. */
uint16_t lastWriteTime;
/** Date of last write. File creation is considered a write. */
/** Date of last write. File creation is considered a write. */
uint16_t lastWriteDate;
/** Low word of this entry's first cluster number. */
/** Low word of this entry's first cluster number. */
uint16_t firstClusterLow;
/** 32-bit unsigned holding this file's size in bytes. */
/** 32-bit unsigned holding this file's size in bytes. */
uint32_t fileSize;
}__attribute__((packed));
} __attribute__((packed));
/** Type name for directoryEntry */
typedef struct directoryEntry dir_t;
//------------------------------------------------------------------------------
@@ -571,6 +571,12 @@ uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
/** Mask for file/subdirectory tests */
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);

/** Filename base-name is all lower case */
const uint8_t DIR_NT_LC_BASE = 0X08;
/** Filename extension is all lower case.*/
const uint8_t DIR_NT_LC_EXT = 0X10;


/** Directory entry is for a file
* \param[in] dir Pointer to a directory entry.
*
@@ -593,9 +599,9 @@ static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
* \return true if the entry is for part of a long name else false.
*/
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
return dir->attributes == DIR_ATT_LONG_NAME;
}
/** Directory entry is hidden
/** Directory entry is hidden
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is hidden else false.
@@ -611,7 +617,7 @@ static inline uint8_t DIR_IS_HIDDEN(const dir_t* dir) {
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
}
/** Directory entry is system type
/** Directory entry is system type
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is system else false.
@@ -705,39 +711,39 @@ const uint8_t LDIR_NAME3_DIM = 2;
* \brief FAT long directory entry
*/
struct longDirectoryEntry {
/**
* The order of this entry in the sequence of long dir entries
* associated with the short dir entry at the end of the long dir set.
*
* If masked with 0x40 (LAST_LONG_ENTRY), this indicates the
* entry is the last long dir entry in a set of long dir entries.
* All valid sets of long dir entries must begin with an entry having
* this mask.
*/
/**
* The order of this entry in the sequence of long dir entries
* associated with the short dir entry at the end of the long dir set.
*
* If masked with 0X40 (LAST_LONG_ENTRY), this indicates the
* entry is the last long dir entry in a set of long dir entries.
* All valid sets of long dir entries must begin with an entry having
* this mask.
*/
uint8_t ord;
/** Characters 1-5 of the long-name sub-component in this entry. */
/** Characters 1-5 of the long-name sub-component in this entry. */
uint16_t name1[LDIR_NAME1_DIM];
/** Attributes - must be ATTR_LONG_NAME */
/** Attributes - must be ATTR_LONG_NAME */
uint8_t attr;
/**
* If zero, indicates a directory entry that is a sub-component of a
* long name. NOTE: Other values reserved for future extensions.
*
* Non-zero implies other directory entry types.
*/
/**
* If zero, indicates a directory entry that is a sub-component of a
* long name. NOTE: Other values reserved for future extensions.
*
* Non-zero implies other directory entry types.
*/
uint8_t type;
/**
* Checksum of name in the short dir entry at the end of the
* long dir set.
*/
/**
* Checksum of name in the short dir entry at the end of the
* long dir set.
*/
uint8_t chksum;
/** Characters 6-11 of the long-name sub-component in this entry. */
/** Characters 6-11 of the long-name sub-component in this entry. */
uint16_t name2[LDIR_NAME2_DIM];
/** Must be ZERO. This is an artifact of the FAT "first cluster" */
/** Must be ZERO. This is an artifact of the FAT "first cluster" */
uint16_t mustBeZero;
/** Characters 6-11 of the long-name sub-component in this entry. */
/** Characters 12 and 13 of the long-name sub-component in this entry. */
uint16_t name3[LDIR_NAME3_DIM];
}__attribute__((packed));
} __attribute__((packed));
/** Type name for longDirectoryEntry */
typedef struct longDirectoryEntry ldir_t;
/**
@@ -746,17 +752,4 @@ typedef struct longDirectoryEntry ldir_t;
* begin with an entry having this mask.
*/
const uint8_t LDIR_ORD_LAST_LONG_ENTRY = 0X40;
/**
* Fetch a 16-bit long file name character.
*
* \param[in] ldir Pointer to long file name directory entry.
* \param[in] i Index of character to return;
* \return The 16-bit field.
*/
inline uint16_t lfnChar(ldir_t *ldir, uint8_t i) {
return i < LDIR_NAME1_DIM ? ldir->name1[i] :
i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM) ?
ldir->name2[i - LDIR_NAME1_DIM] :
ldir->name3[i - (LDIR_NAME1_DIM + LDIR_NAME2_DIM)];
}
#endif // FatStructs_h

+ 154
- 52
SdFat/utility/FatVolume.cpp Переглянути файл

@@ -17,6 +17,7 @@
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "FatVolume.h"
//------------------------------------------------------------------------------
cache_t* FatCache::read(uint32_t lbn, uint8_t option) {
@@ -37,7 +38,7 @@ cache_t* FatCache::read(uint32_t lbn, uint8_t option) {
m_status |= option & CACHE_STATUS_MASK;
return &m_block;

fail:
fail:
return 0;
}
//------------------------------------------------------------------------------
@@ -59,7 +60,7 @@ bool FatCache::sync() {
}
return true;

fail:
fail:
return false;
}
//------------------------------------------------------------------------------
@@ -69,14 +70,19 @@ bool FatVolume::allocateCluster(uint32_t current, uint32_t* next) {
while (1) {
find++;
// If at end of FAT go to beginning of FAT.
if (find > m_lastCluster) find = 2;
if (find > m_lastCluster) {
find = 2;
}

uint32_t f;
if (!fatGet(find, &f)) {
int8_t fg = fatGet(find, &f);
if (fg < 0) {
DBG_FAIL_MACRO;
goto fail;
}
if (f == 0) break;
if (fg && f == 0) {
break;
}
if (find == start) {
// Can't find space checked all clusters.
DBG_FAIL_MACRO;
@@ -101,7 +107,7 @@ bool FatVolume::allocateCluster(uint32_t current, uint32_t* next) {
*next = find;
return true;

fail:
fail:
return false;
}
//------------------------------------------------------------------------------
@@ -124,16 +130,19 @@ bool FatVolume::allocContiguous(uint32_t count, uint32_t* firstCluster) {
bgnCluster = endCluster = 2;
}
uint32_t f;
if (!fatGet(endCluster, &f)) {
int8_t fg = fatGet(endCluster, &f);
if (fg < 0) {
DBG_FAIL_MACRO;
goto fail;
}
if (f != 0) {
// don't update search start if unallocated clusters before endCluster.
if (bgnCluster != endCluster) setStart = false;

if (f || fg == 0) {
// cluster in use try next cluster as bgnCluster
bgnCluster = endCluster + 1;

// don't update search start if unallocated clusters before endCluster.
if (bgnCluster != endCluster) {
setStart = false;
}
} else if ((endCluster - bgnCluster + 1) == count) {
// done - found space
break;
@@ -146,7 +155,9 @@ bool FatVolume::allocContiguous(uint32_t count, uint32_t* firstCluster) {
endCluster++;
}
// remember possible next free cluster
if (setStart) m_allocSearchStart = endCluster + 1;
if (setStart) {
m_allocSearchStart = endCluster + 1;
}

// mark end of chain
if (!fatPutEOC(endCluster)) {
@@ -165,7 +176,7 @@ bool FatVolume::allocContiguous(uint32_t count, uint32_t* firstCluster) {
*firstCluster = bgnCluster;
return true;

fail:
fail:
return false;
}
//------------------------------------------------------------------------------
@@ -173,16 +184,14 @@ uint32_t FatVolume::clusterStartBlock(uint32_t cluster) const {
return m_dataStartBlock + ((cluster - 2) << m_clusterSizeShift);
}
//------------------------------------------------------------------------------
// Fetch a FAT entry
bool FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
// Fetch a FAT entry - return -1 error, 0 EOC, else 1.
int8_t FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
uint32_t lba;
uint32_t next;
cache_t* pc;

// error if reserved cluster of beyond FAT
if (cluster < 2 || cluster > m_lastCluster) {
DBG_FAIL_MACRO;
goto fail;
}
DBG_HALT_IF(cluster < 2 || cluster > m_lastCluster);

if (m_fatType == 32) {
lba = m_fatStartBlock + (cluster >> 7);
@@ -191,8 +200,8 @@ bool FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
DBG_FAIL_MACRO;
goto fail;
}
*value = pc->fat32[cluster & 0X7F] & FAT32MASK;
return true;
next = pc->fat32[cluster & 0X7F] & FAT32MASK;
goto done;
}

if (m_fatType == 16) {
@@ -202,8 +211,8 @@ bool FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
DBG_FAIL_MACRO;
goto fail;
}
*value = pc->fat16[cluster & 0XFF];
return true;
next = pc->fat16[cluster & 0XFF];
goto done;
}
if (FAT12_SUPPORT && m_fatType == 12) {
uint16_t index = cluster;
@@ -226,15 +235,21 @@ bool FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
index = 0;
}
tmp |= pc->data[index] << 8;
*value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
return true;
next = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
goto done;
} else {
DBG_FAIL_MACRO;
goto fail;
}
done:
if (isEOC(next)) {
return 0;
}
*value = next;
return 1;

fail:
return false;
fail:
return -1;
}
//------------------------------------------------------------------------------
// Store a FAT entry
@@ -243,13 +258,10 @@ bool FatVolume::fatPut(uint32_t cluster, uint32_t value) {
cache_t* pc;

// error if reserved cluster of beyond FAT
if (cluster < 2 || cluster > m_lastCluster) {
DBG_FAIL_MACRO;
goto fail;
}
DBG_HALT_IF(cluster < 2 || cluster > m_lastCluster);

if (m_fatType == 32) {
lba = m_fatStartBlock + (cluster >> 7);
lba = m_fatStartBlock + (cluster >> 7);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
@@ -307,16 +319,17 @@ bool FatVolume::fatPut(uint32_t cluster, uint32_t value) {
goto fail;
}

fail:
fail:
return false;
}
//------------------------------------------------------------------------------
// free a cluster chain
bool FatVolume::freeChain(uint32_t cluster) {
uint32_t next;
int8_t fg;
do {
if (!fatGet(cluster, &next)) {
fg = fatGet(cluster, &next);
if (fg < 0) {
DBG_FAIL_MACRO;
goto fail;
}
@@ -325,13 +338,15 @@ bool FatVolume::freeChain(uint32_t cluster) {
DBG_FAIL_MACRO;
goto fail;
}
if (cluster < m_allocSearchStart) m_allocSearchStart = cluster;
if (cluster < m_allocSearchStart) {
m_allocSearchStart = cluster;
}
cluster = next;
} while (!isEOC(cluster));
} while (fg);

return true;

fail:
fail:
return false;
}
//------------------------------------------------------------------------------
@@ -344,11 +359,14 @@ int32_t FatVolume::freeClusterCount() {
if (FAT12_SUPPORT && m_fatType == 12) {
for (unsigned i = 2; i < todo; i++) {
uint32_t c;
if (!fatGet(i, &c)) {
int8_t fg = fatGet(i, &c);
if (fg < 0) {
DBG_FAIL_MACRO;
goto fail;
}
if (c == 0) free++;
if (fg && c == 0) {
free++;
}
}
} else if (m_fatType == 16 || m_fatType == 32) {
lba = m_fatStartBlock;
@@ -359,14 +377,20 @@ int32_t FatVolume::freeClusterCount() {
goto fail;
}
n = m_fatType == 16 ? 256 : 128;
if (todo < n) n = todo;
if (todo < n) {
n = todo;
}
if (m_fatType == 16) {
for (uint16_t i = 0; i < n; i++) {
if (pc->fat16[i] == 0) free++;
if (pc->fat16[i] == 0) {
free++;
}
}
} else {
for (uint16_t i = 0; i < n; i++) {
if (pc->fat32[i] == 0) free++;
if (pc->fat32[i] == 0) {
free++;
}
}
}
todo -= n;
@@ -378,7 +402,7 @@ int32_t FatVolume::freeClusterCount() {
}
return free;

fail:
fail:
return -1;
}
//------------------------------------------------------------------------------
@@ -424,11 +448,11 @@ bool FatVolume::init(uint8_t part) {
}
fbs = &(pc->fbs32);
if (fbs->bytesPerSector != 512 ||
fbs->fatCount != 2 ||
fbs->reservedSectorCount == 0) {
// not valid FAT volume
DBG_FAIL_MACRO;
goto fail;
fbs->fatCount != 2 ||
fbs->reservedSectorCount == 0) {
// not valid FAT volume
DBG_FAIL_MACRO;
goto fail;
}
m_blocksPerCluster = fbs->sectorsPerCluster;
m_clusterBlockMask = m_blocksPerCluster - 1;
@@ -443,7 +467,7 @@ bool FatVolume::init(uint8_t part) {
}

m_blocksPerFat = fbs->sectorsPerFat16 ?
fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
fbs->sectorsPerFat16 : fbs->sectorsPerFat32;

m_fatStartBlock = volumeStartBlock + fbs->reservedSectorCount;

@@ -457,13 +481,14 @@ bool FatVolume::init(uint8_t part) {

// total blocks for FAT16 or FAT32
totalBlocks = fbs->totalSectors16 ?
fbs->totalSectors16 : fbs->totalSectors32;
fbs->totalSectors16 : fbs->totalSectors32;
// total data blocks
clusterCount = totalBlocks - (m_dataStartBlock - volumeStartBlock);

// divide by cluster size to get cluster count
clusterCount >>= m_clusterSizeShift;
m_lastCluster = clusterCount + 1;

// FAT type is determined by cluster count
if (clusterCount < 4085) {
m_fatType = 12;
@@ -479,6 +504,83 @@ bool FatVolume::init(uint8_t part) {
}
return true;

fail:
fail:
return false;
}
//------------------------------------------------------------------------------
bool FatVolume::wipe(print_t* pr) {
cache_t* cache;
uint16_t count;
uint32_t lbn;
if (!m_fatType) {
DBG_FAIL_MACRO;
goto fail;
}
cache = cacheClear();
if (!cache) {
DBG_FAIL_MACRO;
goto fail;
}
memset(cache->data, 0, 512);
// Zero root.
if (m_fatType == 32) {
lbn = clusterStartBlock(m_rootDirStart);
count = m_blocksPerCluster;
} else {
lbn = m_rootDirStart;
count = m_rootDirEntryCount/16;
}
for (uint32_t n = 0; n < count; n++) {
if (!writeBlock(lbn + n, cache->data)) {
DBG_FAIL_MACRO;
goto fail;
}
}
// Clear FATs.
count = 2*m_blocksPerFat;
lbn = m_fatStartBlock;
for (uint32_t nb = 0; nb < count; nb++) {
if (pr && (nb & 0XFF) == 0) {
pr->write('.');
}
if (!writeBlock(lbn + nb, cache->data)) {
DBG_FAIL_MACRO;
goto fail;
}
}
// Reserve first two clusters.
if (m_fatType == 32) {
cache->fat32[0] = 0x0FFFFFF8;
cache->fat32[1] = 0x0FFFFFFF;
} else if (m_fatType == 16) {
cache->fat16[0] = 0XFFF8;
cache->fat16[1] = 0XFFFF;
} else if (FAT12_SUPPORT && m_fatType == 12) {
cache->fat32[0] = 0XFFFFF8;
} else {
DBG_FAIL_MACRO;
goto fail;
}
if (!writeBlock(m_fatStartBlock, cache->data) ||
!writeBlock(m_fatStartBlock + m_blocksPerFat, cache->data)) {
DBG_FAIL_MACRO;
goto fail;
}
if (m_fatType == 32) {
// Reserve root cluster.
if (!fatPutEOC(m_rootDirStart) || !cacheSync()) {
DBG_FAIL_MACRO;
goto fail;
}
}
if (pr) {
pr->write('\r');
pr->write('\n');
}
m_fatType = 0;
return true;

fail:
m_fatType = 0;
return false;
}

+ 123
- 46
SdFat/utility/FatVolume.h Переглянути файл

@@ -27,9 +27,40 @@
#include "FatLibConfig.h"
#include "FatStructs.h"
//------------------------------------------------------------------------------
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/** Macro for debug. */
// #include <Arduino.h>
#define DBG_FAIL_MACRO // Serial.print(__FILE__);Serial.println(__LINE__)
#define DEBUG_MODE 0
#if DEBUG_MODE
#include <Arduino.h>
#define DBG_FAIL_MACRO Serial.print(F(__FILE__)); Serial.println(__LINE__)
#define DBG_PRINT_IF(b) if (b) {Serial.println(F(#b)); DBG_FAIL_MACRO;}
#define DBG_HALT_IF(b) if (b) {Serial.println(F(#b));\
DBG_FAIL_MACRO; while (1);}
#else // DEBUG_MODE
#define DBG_FAIL_MACRO
#define DBG_PRINT_IF(b)
#define DBG_HALT_IF(b)
#endif // DEBUG_MODE
#endif // DOXYGEN_SHOULD_SKIP_THIS
//------------------------------------------------------------------------------
#if defined(ARDUINO) || defined(DOXYGEN)
#include <Arduino.h>
/** Use Print on Arduino */
typedef Print print_t;
#else // ARDUINO
// Arduino type for flash string.
class __FlashStringHelper;
/**
* \class CharWriter
* \brief Character output - often serial port.
*/
class CharWriter {
public:
virtual size_t write(char c) = 0;
virtual size_t write(const char* s) = 0;
};
typedef Print print_t;
#endif // ARDUINO
//------------------------------------------------------------------------------
// Forward declaration of FatVolume.
class FatVolume;
@@ -38,21 +69,21 @@ class FatVolume;
* \brief Cache for an raw data block.
*/
union cache_t {
/** Used to access cached file data blocks. */
/** Used to access cached file data blocks. */
uint8_t data[512];
/** Used to access cached FAT16 entries. */
/** Used to access cached FAT16 entries. */
uint16_t fat16[256];
/** Used to access cached FAT32 entries. */
/** Used to access cached FAT32 entries. */
uint32_t fat32[128];
/** Used to access cached directory entries. */
/** Used to access cached directory entries. */
dir_t dir[16];
/** Used to access a cached Master Boot Record. */
/** Used to access a cached Master Boot Record. */
mbr_t mbr;
/** Used to access to a cached FAT boot sector. */
/** Used to access to a cached FAT boot sector. */
fat_boot_t fbs;
/** Used to access to a cached FAT32 boot sector. */
/** Used to access to a cached FAT32 boot sector. */
fat32_boot_t fbs32;
/** Used to access to a cached FAT32 FSINFO sector. */
/** Used to access to a cached FAT32 FSINFO sector. */
fat32_fsinfo_t fsinfo;
};
//==============================================================================
@@ -68,7 +99,7 @@ class FatCache {
static const uint8_t CACHE_STATUS_MIRROR_FAT = 2;
/** Cache block status bits */
static const uint8_t CACHE_STATUS_MASK
= CACHE_STATUS_DIRTY | CACHE_STATUS_MIRROR_FAT;
= CACHE_STATUS_DIRTY | CACHE_STATUS_MIRROR_FAT;
/** Sync existing block but do not read new block. */
static const uint8_t CACHE_OPTION_NO_READ = 4;
/** Cache block for read. */
@@ -77,11 +108,15 @@ class FatCache {
static uint8_t const CACHE_FOR_WRITE = CACHE_STATUS_DIRTY;
/** Reserve cache block for write - do not read from block device. */
static uint8_t const CACHE_RESERVE_FOR_WRITE
= CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ;
= CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ;
/** \return Cache block address. */
cache_t* block() {return &m_block;}
cache_t* block() {
return &m_block;
}
/** Set current block dirty. */
void dirty() {m_status |= CACHE_STATUS_DIRTY;}
void dirty() {
m_status |= CACHE_STATUS_DIRTY;
}
/** Initialize the cache.
* \param[in] vol FatVolume that owns this FatCache.
*/
@@ -95,7 +130,9 @@ class FatCache {
m_lbn = 0XFFFFFFFF;
}
/** \return Logical block number for cached block. */
uint32_t lbn() {return m_lbn;}
uint32_t lbn() {
return m_lbn;
}
/** Read a block into the cache.
* \param[in] lbn Block to read.
* \param[in] option mode for cached block.
@@ -124,29 +161,47 @@ class FatVolume {
FatVolume() : m_fatType(0) {}

/** \return The volume's cluster size in blocks. */
uint8_t blocksPerCluster() const {return m_blocksPerCluster;}
uint8_t blocksPerCluster() const {
return m_blocksPerCluster;
}
/** \return The number of blocks in one FAT. */
uint32_t blocksPerFat() const {return m_blocksPerFat;}
uint32_t blocksPerFat() const {
return m_blocksPerFat;
}
/** 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.
*/
cache_t* cacheClear() {
if (!cacheSync()) return 0;
if (!cacheSync()) {
return 0;
}
m_cache.invalidate();
return m_cache.block();
}
/** \return The total number of clusters in the volume. */
uint32_t clusterCount() const {return m_lastCluster - 1;}
uint32_t clusterCount() const {
return m_lastCluster - 1;
}
/** \return The shift count required to multiply by blocksPerCluster. */
uint8_t clusterSizeShift() const {return m_clusterSizeShift;}
uint8_t clusterSizeShift() const {
return m_clusterSizeShift;
}
/** \return The logical block number for the start of file data. */
uint32_t dataStartBlock() const {return m_dataStartBlock;}
uint32_t dataStartBlock() const {
return m_dataStartBlock;
}
/** \return The number of File Allocation Tables. */
uint8_t fatCount() {return 2;}
uint8_t fatCount() {
return 2;
}
/** \return The logical block number for the start of the first FAT. */
uint32_t fatStartBlock() const {return m_fatStartBlock;}
uint32_t fatStartBlock() const {
return m_fatStartBlock;
}
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
uint8_t fatType() const {return m_fatType;}
uint8_t fatType() const {
return m_fatType;
}
/** Volume free space in clusters.
*
* \return Count of free clusters for success or -1 if an error occurs.
@@ -155,12 +210,12 @@ class FatVolume {
/** Initialize a FAT volume. Try partition one first then try super
* floppy format.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. Reasons for
* failure include not finding a valid partition, not finding a valid
* FAT file system or an I/O error.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool init() { return init(1) ? true : init(0);}
bool init() {
return init(1) ? true : init(0);
}
/** Initialize a FAT volume.

* \param[in] part The partition to be used. Legal values for \a part are
@@ -168,24 +223,33 @@ class FatVolume {
* a MBR, Master Boot Record, or zero if the device is formatted as
* a super floppy with the FAT boot sector in block zero.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. Reasons for
* failure include not finding a valid partition, not finding a valid
* FAT file system in the specified partition or an I/O error.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool init(uint8_t part);
/** \return The number of entries in the root directory for FAT16 volumes. */
uint32_t rootDirEntryCount() const {return m_rootDirEntryCount;}
uint16_t rootDirEntryCount() const {
return m_rootDirEntryCount;
}
/** \return The logical block number for the start of the root directory
on FAT16 volumes or the first cluster number on FAT32 volumes. */
uint32_t rootDirStart() const {return m_rootDirStart;}
uint32_t rootDirStart() const {
return m_rootDirStart;
}
/** Wipe all data from the volume.
* \param[in] pr print stream for status dots.
* \return true for success else false.
*/
bool wipe(print_t* pr = 0);
/** Debug access to FAT table
*
* \param[in] n cluster number.
* \param[out] v value of entry
* \return true for success or false for failure
*/
bool dbgFat(uint32_t n, uint32_t* v) {return fatGet(n, v);}
int8_t dbgFat(uint32_t n, uint32_t* v) {
return fatGet(n, v);
}
//------------------------------------------------------------------------------
private:
// Allow FatFile and FatCache access to FatVolume private functions.
@@ -212,13 +276,17 @@ class FatVolume {
return m_fatCache.read(blockNumber,
options | FatCache::CACHE_STATUS_MIRROR_FAT);
}
bool cacheSync() {return m_cache.sync() && m_fatCache.sync();}
bool cacheSync() {
return m_cache.sync() && m_fatCache.sync();
}
#else //
cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options) {
return cacheFetchData(blockNumber,
options | FatCache::CACHE_STATUS_MIRROR_FAT);
}
bool cacheSync() {return m_cache.sync();}
bool cacheSync() {
return m_cache.sync();
}
#endif // USE_SEPARATE_FAT_CACHE
cache_t* cacheFetchData(uint32_t blockNumber, uint8_t options) {
return m_cache.read(blockNumber, options);
@@ -226,17 +294,26 @@ class FatVolume {
void cacheInvalidate() {
m_cache.invalidate();
}
bool cacheSyncData() {return m_cache.sync();}
cache_t *cacheAddress() {return m_cache.block();}
uint32_t cacheBlockNumber() {return m_cache.lbn();}
void cacheDirty() {m_cache.dirty();}
bool cacheSyncData() {
return m_cache.sync();
}
cache_t *cacheAddress() {
return m_cache.block();
}
uint32_t cacheBlockNumber() {
return m_cache.lbn();
}
void cacheDirty() {
m_cache.dirty();
}
//------------------------------------------------------------------------------
bool allocateCluster(uint32_t current, uint32_t* next);
bool allocContiguous(uint32_t count, uint32_t* firstCluster);
uint8_t blockOfCluster(uint32_t position) const {
return (position >> 9) & m_clusterBlockMask;}
return (position >> 9) & m_clusterBlockMask;
}
uint32_t clusterStartBlock(uint32_t cluster) const;
bool fatGet(uint32_t cluster, uint32_t* value);
int8_t fatGet(uint32_t cluster, uint32_t* value);
bool fatPut(uint32_t cluster, uint32_t value);
bool fatPutEOC(uint32_t cluster) {
return fatPut(cluster, 0x0FFFFFFF);
@@ -248,10 +325,10 @@ class FatVolume {
//----------------------------------------------------------------------------
// Virtual block I/O functions.
virtual bool readBlock(uint32_t block, uint8_t* dst) = 0;
virtual bool writeBlock(uint32_t block, const uint8_t* dst) = 0;
virtual bool writeBlock(uint32_t block, const uint8_t* src) = 0;
#if USE_MULTI_BLOCK_IO
virtual bool readBlocks(uint32_t block, uint8_t* dst, size_t nb) = 0;
virtual bool writeBlocks(uint32_t block, const uint8_t* dst, size_t nb) = 0;
virtual bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb) = 0;
#endif // USE_MULTI_BLOCK_IO
};
#endif // FatVolume

+ 64
- 24
SdFat/utility/FmtNumber.cpp Переглянути файл

@@ -170,9 +170,13 @@ float scale10(float v, int8_t n) {
n &= 63;
for (uint8_t i = 0; n; n >>= 1, i++) {
#ifdef __AVR__
if (n & 1) v *= pgm_read_float(&s[i]);
if (n & 1) {
v *= pgm_read_float(&s[i]);
}
#else // __AVR__
if (n & 1) v *= s[i];
if (n & 1) {
v *= s[i];
}
#endif // __AVR__
}
return v;
@@ -229,7 +233,9 @@ char* fmtDec(uint32_t n, char* p) {
//------------------------------------------------------------------------------
char* fmtFloat(float value, char* p, uint8_t prec) {
char sign = value < 0 ? '-' : 0;
if (sign) value = -value;
if (sign) {
value = -value;
}

if (isnan(value)) {
*--p = 'n';
@@ -249,7 +255,9 @@ char* fmtFloat(float value, char* p, uint8_t prec) {
*--p = 'o';
return p;
}
if (prec > 9) prec = 9;
if (prec > 9) {
prec = 9;
}
value += scale10(0.5, -prec);

uint32_t whole = value;
@@ -257,11 +265,15 @@ char* fmtFloat(float value, char* p, uint8_t prec) {
char* tmp = p - prec;
uint32_t fraction = scale10(value - whole, prec);
p = fmtDec(fraction, p);
while (p > tmp) *--p = '0';
while (p > tmp) {
*--p = '0';
}
*--p = '.';
}
p = fmtDec(whole, p);
if (sign) *--p = sign;
if (sign) {
*--p = sign;
}
return p;
}
//------------------------------------------------------------------------------
@@ -274,7 +286,9 @@ char* fmtFloat(float value, char* p, uint8_t prec) {
*/
char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar) {
bool neg = value < 0;
if (neg) value = -value;
if (neg) {
value = -value;
}

// check for nan inf ovf
if (isnan(value)) {
@@ -295,7 +309,9 @@ char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar) {
*--ptr = 'o';
return ptr;
}
if (prec > 9) prec = 9;
if (prec > 9) {
prec = 9;
}
float round = scale10(0.5, -prec);
if (expChar) {
int8_t exp = 0;
@@ -315,10 +331,14 @@ char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar) {
exp++;
}
expNeg = exp < 0;
if (expNeg) exp = -exp;
if (expNeg) {
exp = -exp;
}
}
ptr = fmtDec((uint16_t)exp, ptr);
if (exp < 10) *--ptr = '0';
if (exp < 10) {
*--ptr = '0';
}
*--ptr = expNeg ? '-' : '+';
*--ptr = expChar;
} else {
@@ -330,11 +350,15 @@ char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar) {
char* tmp = ptr - prec;
uint32_t fraction = scale10(value - whole, prec);
ptr = fmtDec(fraction, ptr);
while (ptr > tmp) *--ptr = '0';
while (ptr > tmp) {
*--ptr = '0';
}
*--ptr = '.';
}
ptr = fmtDec(whole, ptr);
if (neg) *--ptr = '-';
if (neg) {
*--ptr = '-';
}
return ptr;
}
//------------------------------------------------------------------------------
@@ -359,31 +383,43 @@ float scanFloat(const char* str, char** ptr) {
float v;
const char* successPtr;

if (ptr) *ptr = const_cast<char*>(str);
if (ptr) {
*ptr = const_cast<char*>(str);
}

while (isspace((c = *str++))) {}
while (isSpace((c = *str++))) {}
neg = c == '-';
if (c == '-' || c == '+') c = *str++;
if (c == '-' || c == '+') {
c = *str++;
}
// Skip leading zeros
while (c == '0') {
c = *str++;
digit = true;
}
for (;;) {
if (isdigit(c)) {
if (isDigit(c)) {
digit = true;
if (nd < 9) {
fract = 10*fract + c - '0';
nd++;
if (dot) fracExp--;
if (dot) {
fracExp--;
}
} else {
if (!dot) fracExp++;
if (!dot) {
fracExp++;
}
}
} else if (c == '.') {
if (dot) goto fail;
if (dot) {
goto fail;
}
dot = true;
} else {
if (!digit) goto fail;
if (!digit) {
goto fail;
}
break;
}
successPtr = str;
@@ -396,19 +432,23 @@ float scanFloat(const char* str, char** ptr) {
if (c == '-' || c == '+') {
c = *str++;
}
while (isdigit(c)) {
if (exp > EXP_LIMIT) goto fail;
while (isDigit(c)) {
if (exp > EXP_LIMIT) {
goto fail;
}
exp = 10*exp + c - '0';
successPtr = str;
c = *str++;
}
fracExp += expNeg ? -exp : exp;
}
if (ptr) *ptr = const_cast<char*>(successPtr);
if (ptr) {
*ptr = const_cast<char*>(successPtr);
}
v = scale10(static_cast<float>(fract), fracExp);
return neg ? -v: v;

fail:
fail:
return 0;
}


+ 7
- 1
SdFat/utility/FmtNumber.h Переглянути файл

@@ -19,7 +19,13 @@
*/
#ifndef FmtNumber_h
#define FmtNumber_h
#include <ctype.h>
// #include <ctype.h>
inline bool isDigit(char c) {
return '0' <= c && c <= '9';
}
inline bool isSpace(char c) {
return c == ' ' || (0X9 <= c && c <= 0XD);
}
#include <math.h>
#include <stdint.h>
char* fmtDec(uint16_t n, char* p);

+ 16
- 8
SdFat/utility/SoftSPI.h Переглянути файл

@@ -18,7 +18,7 @@
* <http://www.gnu.org/licenses/>.
*/
/**
* @file
* @file
* @brief Software SPI.
*
* @defgroup softSPI Software SPI
@@ -110,9 +110,13 @@ class SoftSPI {
private:
//----------------------------------------------------------------------------
inline __attribute__((always_inline))
bool MODE_CPHA(uint8_t mode) {return (mode & 1) != 0;}
bool MODE_CPHA(uint8_t mode) {
return (mode & 1) != 0;
}
inline __attribute__((always_inline))
bool MODE_CPOL(uint8_t mode) {return (mode & 2) != 0;}
bool MODE_CPOL(uint8_t mode) {
return (mode & 2) != 0;
}
inline __attribute__((always_inline))
void receiveBit(uint8_t bit, uint8_t* data) {
if (MODE_CPHA(Mode)) {
@@ -121,8 +125,10 @@ class SoftSPI {
nop;
nop;
fastDigitalWrite(SckPin,
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
if (fastDigitalRead(MisoPin)) *data |= 1 << bit;
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
if (fastDigitalRead(MisoPin)) {
*data |= 1 << bit;
}
if (!MODE_CPHA(Mode)) {
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
}
@@ -135,7 +141,7 @@ class SoftSPI {
}
fastDigitalWrite(MosiPin, data & (1 << bit));
fastDigitalWrite(SckPin,
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
nop;
nop;
if (!MODE_CPHA(Mode)) {
@@ -150,8 +156,10 @@ class SoftSPI {
}
fastDigitalWrite(MosiPin, txData & (1 << bit));
fastDigitalWrite(SckPin,
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
if (fastDigitalRead(MisoPin)) *rxData |= 1 << bit;
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
if (fastDigitalRead(MisoPin)) {
*rxData |= 1 << bit;
}
if (!MODE_CPHA(Mode)) {
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
}

+ 132
- 54
SdFat/utility/StdioStream.cpp Переглянути файл

@@ -26,9 +26,13 @@ int StdioStream::fclose() {
return EOF;
}
if (m_flags & F_SWR) {
if (!flushBuf()) rtn = EOF;
if (!flushBuf()) {
rtn = EOF;
}
}
if (!FatFile::close()) {
rtn = EOF;
}
if (!FatFile::close()) rtn = EOF;
m_r = 0;
m_w = 0;
m_flags = 0;
@@ -37,7 +41,9 @@ int StdioStream::fclose() {
//------------------------------------------------------------------------------
int StdioStream::fflush() {
if ((m_flags & (F_SWR | F_SRW)) && !(m_flags & F_SRD)) {
if (flushBuf() && FatFile::sync()) return 0;
if (flushBuf() && FatFile::sync()) {
return 0;
}
}
return EOF;
}
@@ -45,16 +51,22 @@ int StdioStream::fflush() {
char* StdioStream::fgets(char* str, size_t num, size_t* len) {
char* s = str;
size_t n;
if (num-- == 0) return 0;
if (num-- == 0) {
return 0;
}
while (num) {
if ((n = m_r) == 0) {
if (!fillBuf()) {
if (s == str) return 0;
if (s == str) {
return 0;
}
break;
}
n = m_r;
}
if (n > num) n = num;
if (n > num) {
n = num;
}
uint8_t* end = reinterpret_cast<uint8_t*>(memchr(m_p, '\n', n));
if (end != 0) {
n = ++end - m_p;
@@ -71,7 +83,9 @@ char* StdioStream::fgets(char* str, size_t num, size_t* len) {
num -= n;
}
*s = 0;
if (len) *len = s - str;
if (len) {
*len = s - str;
}
return str;
}
//------------------------------------------------------------------------------
@@ -114,14 +128,18 @@ bool StdioStream::fopen(const char* filename, const char* mode) {
goto fail;
}
}
if ((oflag & O_EXCL) && !(oflag & O_WRITE)) goto fail;
if (!FatFile::open(filename, oflag)) goto fail;
if ((oflag & O_EXCL) && !(oflag & O_WRITE)) {
goto fail;
}
if (!FatFile::open(filename, oflag)) {
goto fail;
}
m_r = 0;
m_w = 0;
m_p = m_buf;
return true;

fail:
fail:
m_flags = 0;
return false;
}
@@ -134,7 +152,9 @@ int StdioStream::fputs(const char* str) {
int StdioStream::fputs_P(PGM_P str) {
PGM_P bgn = str;
for (char c; (c = pgm_read_byte(str)); str++) {
if (putc(c) < 0) return EOF;
if (putc(c) < 0) {
return EOF;
}
}
return str - bgn;
}
@@ -142,7 +162,9 @@ int StdioStream::fputs_P(PGM_P str) {
size_t StdioStream::fread(void* ptr, size_t size, size_t count) {
uint8_t* dst = reinterpret_cast<uint8_t*>(ptr);
size_t total = size*count;
if (total == 0) return 0;
if (total == 0) {
return 0;
}
size_t need = total;
while (need > m_r) {
memcpy(dst, m_p, m_r);
@@ -197,14 +219,16 @@ int StdioStream::fseek(int32_t offset, int origin) {
m_p = m_buf;
return 0;

fail:
fail:
return EOF;
}
//------------------------------------------------------------------------------
int32_t StdioStream::ftell() {
uint32_t pos = FatFile::curPosition();
if (m_flags & F_SRD) {
if (m_r > pos) return -1L;
if (m_r > pos) {
return -1L;
}
pos -= m_r;
} else if (m_flags & F_SWR) {
pos += m_p - m_buf;
@@ -217,7 +241,9 @@ size_t StdioStream::fwrite(const void* ptr, size_t size, size_t count) {
#if 0 ////////////////////////////////////////////////////////////////////////////////////
const uint8_t* src = static_cast<const uint8_t*>(ptr);
size_t total = count*size;
if (total == 0) return 0;
if (total == 0) {
return 0;
}
size_t todo = total;

while (todo > m_w) {
@@ -236,7 +262,7 @@ size_t StdioStream::fwrite(const void* ptr, size_t size, size_t count) {
#endif //////////////////////////////////////////////////////////////////////////////////
}
//------------------------------------------------------------------------------
int StdioStream::write(const void* buf, size_t count) {
int StdioStream::write(const void* buf, size_t count) {
const uint8_t* src = static_cast<const uint8_t*>(buf);
size_t todo = count;

@@ -245,7 +271,9 @@ size_t StdioStream::fwrite(const void* ptr, size_t size, size_t count) {
m_p += m_w;
src += m_w;
todo -= m_w;
if (!flushBuf()) return EOF;
if (!flushBuf()) {
return EOF;
}
}
memcpy(m_p, src, todo);
m_p += todo;
@@ -257,7 +285,9 @@ size_t StdioStream::print(const __FlashStringHelper *str) {
const char *p = (const char PROGMEM *)str;
uint8_t c;
while ((c = pgm_read_byte(p))) {
if (putc(c) < 0) return 0;
if (putc(c) < 0) {
return 0;
}
p++;
}
return p - (const char PROGMEM *)str;
@@ -281,56 +311,76 @@ int StdioStream::printDec(float value, uint8_t prec) {
}
// check for NaN INF OVF
if (isnan(value)) {
if (fputs_P(PSTR("nan")) < 0) return -1;
if (fputs_P(PSTR("nan")) < 0) {
return -1;
}
rtn += 3;
} else if (isinf(value)) {
if (fputs_P(PSTR("inf")) < 0) return -1;
if (fputs_P(PSTR("inf")) < 0) {
return -1;
}
rtn += 3;
} else if (value > 4294967040.0) {
if (fputs_P(PSTR("ovf")) < 0) return -1;;
if (fputs_P(PSTR("ovf")) < 0) {
return -1;
}
rtn += 3;
} else {
if (sign) {
if (putc(sign) < 0) return -1;
if (putc(sign) < 0) {
return -1;
}
rtn++;
}
if (prec > 9) prec = 9;
if (prec > 9) {
prec = 9;
}

/*
uint32_t s = 1;
for (uint8_t i = 0; i < prec; i++) {
// s *= 10;
s = ((s << 2) + s) << 1;
}
// round value
value += 0.5/s;
*/
/*
uint32_t s = 1;
for (uint8_t i = 0; i < prec; i++) {
// s *= 10;
s = ((s << 2) + s) << 1;
}
// round value
value += 0.5/s;
*/
value += scale10(0.5, -prec);
uint32_t whole = value;
int np;
if ((np = printDec(whole)) < 0) return -1;
if ((np = printDec(whole)) < 0) {
return -1;
}
rtn += np;
if (prec) {
if (putc('.') < 0) return -1;
if (putc('.') < 0) {
return -1;
}
char* str = fmtSpace(prec);
if (!str) return -1;
if (!str) {
return -1;
}
char* tmp = str - prec;

// uint32_t fraction = s*(value - whole);
// uint32_t fraction = s*(value - whole);
uint32_t fraction = scale10(value - whole, prec);
ptr = fmtDec(fraction, str);
while (ptr > tmp) *--ptr = '0';
while (ptr > tmp) {
*--ptr = '0';
}
rtn += prec + 1;
}
}
return rtn;
#endif
#endif
}
//------------------------------------------------------------------------------
int StdioStream::printDec(signed char n) {
uint8_t s = 0;
if (n < 0) {
if (fputc('-') < 0) return -1;
if (fputc('-') < 0) {
return -1;
}
n = -n;
s = 1;
}
@@ -341,11 +391,15 @@ int StdioStream::printDec(int16_t n) {
int s;
uint8_t rtn = 0;
if (n < 0) {
if (fputc('-') < 0) return -1;
if (fputc('-') < 0) {
return -1;
}
n = -n;
rtn++;
}
if ((s = printDec((uint16_t)n)) < 0) return s;
if ((s = printDec((uint16_t)n)) < 0) {
return s;
}
return rtn;
}
//------------------------------------------------------------------------------
@@ -364,7 +418,9 @@ int StdioStream::printDec(uint16_t n) {
len = n < 1000 ? 3 : n < 10000 ? 4 : 5;
}
char* str = fmtSpace(len);
if (!str) return -1;
if (!str) {
return -1;
}
fmtDec(n, str);
return len;
#endif
@@ -373,7 +429,9 @@ int StdioStream::printDec(uint16_t n) {
int StdioStream::printDec(int32_t n) {
uint8_t s = 0;
if (n < 0) {
if (fputc('-') < 0) return -1;
if (fputc('-') < 0) {
return -1;
}
n = -n;
s = 1;
}
@@ -399,7 +457,9 @@ int StdioStream::printDec(uint32_t n) {
}

char* str = fmtSpace(len);
if (!str) return -1;
if (!str) {
return -1;
}
fmtDec(n, str);
return len;
#endif
@@ -419,7 +479,9 @@ int StdioStream::printHex(uint32_t n) {
len = n < 0X100000 ? 5 : n < 0X1000000 ? 6 : n < 0X10000000 ? 7 : 8;
}
char* str = fmtSpace(len);
if (!str) return -1;
if (!str) {
return -1;
}

do {
uint8_t h = n & 0XF;
@@ -432,7 +494,9 @@ int StdioStream::printHex(uint32_t n) {
//------------------------------------------------------------------------------
bool StdioStream::rewind() {
if (m_flags & F_SWR) {
if (!flushBuf()) return false;
if (!flushBuf()) {
return false;
}
}
FatFile::seekSet(0);
m_r = 0;
@@ -441,11 +505,17 @@ bool StdioStream::rewind() {
//------------------------------------------------------------------------------
int StdioStream::ungetc(int c) {
// error if EOF.
if (c == EOF) return EOF;
if (c == EOF) {
return EOF;
}
// error if not reading.
if ((m_flags & F_SRD) == 0) return EOF;
if ((m_flags & F_SRD) == 0) {
return EOF;
}
// error if no space.
if (m_p == m_buf) return EOF;
if (m_p == m_buf) {
return EOF;
}
m_r++;
m_flags &= ~F_EOF;
return *--m_p = (uint8_t)c;
@@ -463,7 +533,8 @@ int StdioStream::fillGet() {
//------------------------------------------------------------------------------
// private
bool StdioStream::fillBuf() {
if (!(m_flags & F_SRD)) { /////////////check for F_ERR and F_EOF ??/////////////////
if (!(m_flags &
F_SRD)) { /////////////check for F_ERR and F_EOF ??/////////////////
if (!(m_flags & F_SRW)) {
m_flags |= F_ERR;
return false;
@@ -490,7 +561,8 @@ bool StdioStream::fillBuf() {
//------------------------------------------------------------------------------
// private
bool StdioStream::flushBuf() {
if (!(m_flags & F_SWR)) { /////////////////check for F_ERR ??////////////////////////
if (!(m_flags &
F_SWR)) { /////////////////check for F_ERR ??////////////////////////
if (!(m_flags & F_SRW)) {
m_flags |= F_ERR;
return false;
@@ -505,13 +577,17 @@ bool StdioStream::flushBuf() {
uint8_t n = m_p - m_buf;
m_p = m_buf;
m_w = sizeof(m_buf);
if (FatFile::write(m_buf, n) == n) return true;
if (FatFile::write(m_buf, n) == n) {
return true;
}
m_flags |= F_ERR;
return false;
}
//------------------------------------------------------------------------------
int StdioStream::flushPut(uint8_t c) {
if (!flushBuf()) return EOF;
if (!flushBuf()) {
return EOF;
}
m_w--;
return *m_p++ = c;
}
@@ -522,7 +598,9 @@ char* StdioStream::fmtSpace(uint8_t len) {
return 0;
}
}
if (len > m_w) return 0;
if (len > m_w) {
return 0;
}
m_p += len;
m_w -= len;
return reinterpret_cast<char*>(m_p);

+ 44
- 28
SdFat/utility/StdioStream.h Переглянути файл

@@ -106,9 +106,9 @@ const uint8_t UNGETC_BUF_SIZE = 2;
*/
class StdioStream : private FatFile {
public:
/** Constructor
*
*/
/** Constructor
*
*/
StdioStream() {
m_w = m_r = 0;
m_p = m_buf;
@@ -116,7 +116,9 @@ class StdioStream : private FatFile {
}
//----------------------------------------------------------------------------
/** Clear the stream's end-of-file and error indicators. */
void clearerr() {m_flags &= ~(F_ERR | F_EOF);}
void clearerr() {
m_flags &= ~(F_ERR | F_EOF);
}
//----------------------------------------------------------------------------
/** Close a stream.
*
@@ -134,12 +136,16 @@ class StdioStream : private FatFile {
/** Test the stream's end-of-file indicator.
* \return non-zero if and only if the end-of-file indicator is set.
*/
int feof() {return (m_flags & F_EOF) != 0;}
int feof() {
return (m_flags & F_EOF) != 0;
}
//----------------------------------------------------------------------------
/** Test the stream's error indicator.
* \return return non-zero if and only if the error indicator is set.
*/
int ferror() {return (m_flags & F_ERR) != 0;}
int ferror() {
return (m_flags & F_ERR) != 0;
}
//----------------------------------------------------------------------------
/** Flush the stream.
*
@@ -160,7 +166,9 @@ class StdioStream : private FatFile {
* set and the fgetc function returns EOF. Otherwise, the fgetc function
* returns the next character from the input stream.
*/
int fgetc() {return m_r-- == 0 ? fillGet() : *m_p++;}
int fgetc() {
return m_r-- == 0 ? fillGet() : *m_p++;
}
//----------------------------------------------------------------------------
/** Get a string from a stream.
*
@@ -256,7 +264,9 @@ class StdioStream : private FatFile {
* has written. Otherwise, it returns EOF and sets the error indicator for
* the stream.
*/
int fputc(int c) {return m_w-- == 0 ? flushPut(c) : *m_p++ = c;}
int fputc(int c) {
return m_w-- == 0 ? flushPut(c) : *m_p++ = c;
}
//----------------------------------------------------------------------------
/** Write a string to a stream.
*
@@ -348,7 +358,9 @@ class StdioStream : private FatFile {
* returns the next character from the input stream.
*/
inline __attribute__((always_inline))
int getc() {return m_r-- == 0 ? fillGet() : *m_p++;}
int getc() {
return m_r-- == 0 ? fillGet() : *m_p++;
}
//----------------------------------------------------------------------------
/** Write a byte to a stream.
*
@@ -362,7 +374,9 @@ class StdioStream : private FatFile {
* the stream.
*/
inline __attribute__((always_inline))
int putc(int c) {return m_w-- == 0 ? flushPut(c) : *m_p++ = c;}
int putc(int c) {
return m_w-- == 0 ? flushPut(c) : *m_p++ = c;
}
//----------------------------------------------------------------------------
/** Write a CR/LF.
*
@@ -371,7 +385,9 @@ class StdioStream : private FatFile {
inline __attribute__((always_inline))
int putCRLF() {
if (m_w < 2) {
if (!flushBuf()) return -1;
if (!flushBuf()) {
return -1;
}
}
*m_p++ = '\r';
*m_p++ = '\n';
@@ -554,32 +570,32 @@ class StdioStream : private FatFile {
*/
int printDec(float value, uint8_t prec);
//----------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
int printField(double value, char term, uint8_t prec = 2) {
return printField(static_cast<float>(value), term, prec) > 0;
}
//----------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
int printField(float value, char term, uint8_t prec = 2) {
int rtn = printDec(value, prec);
return rtn < 0 || putc(term) < 0 ? -1 : rtn + 1;
}
//----------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \return The number of bytes written or -1 if an error occurs.
*/
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \return The number of bytes written or -1 if an error occurs.
*/
template <typename T>
int printField(T value, char term) {
int rtn = printDec(value);

+ 25
- 9
SdFat/utility/bufstream.h Переглянути файл

@@ -39,7 +39,7 @@ class ibufstream : public istream {
* Warning: The string will not be copied so must stay in scope.
*/
explicit ibufstream(const char* str) {
init(str);
init(str);
}
/** Initialize an ibufstream
* \param[in] str pointer to string to be parsed
@@ -55,14 +55,18 @@ class ibufstream : public istream {
protected:
/// @cond SHOW_PROTECTED
int16_t getch() {
if (m_pos < m_len) return m_buf[m_pos++];
if (m_pos < m_len) {
return m_buf[m_pos++];
}
setstate(eofbit);
return -1;
}
void getpos(FatPos_t *pos) {
pos->position = m_pos;
}
bool seekoff(off_type off, seekdir way) {return false;}
bool seekoff(off_type off, seekdir way) {
return false;
}
bool seekpos(pos_type pos) {
if (pos < m_len) {
m_pos = pos;
@@ -109,9 +113,13 @@ class obufstream : public ostream {
m_in = 0;
}
/** \return a pointer to the buffer */
char* buf() {return m_buf;}
char* buf() {
return m_buf;
}
/** \return the length of the formatted string */
size_t length() {return m_in;}
size_t length() {
return m_in;
}

protected:
/// @cond SHOW_PROTECTED
@@ -124,16 +132,24 @@ class obufstream : public ostream {
m_buf[m_in]= '\0';
}
void putstr(const char *str) {
while (*str) putch(*str++);
while (*str) {
putch(*str++);
}
}
bool seekoff(off_type off, seekdir way) {
return false;
}
bool seekoff(off_type off, seekdir way) {return false;}
bool seekpos(pos_type pos) {
if (pos > m_in) return false;
if (pos > m_in) {
return false;
}
m_in = pos;
m_buf[m_in] = '\0';
return true;
}
bool sync() {return true;}
bool sync() {
return true;
}

pos_type tellpos() {
return m_in;

+ 64
- 46
SdFat/utility/fstream.cpp Переглянути файл

@@ -19,7 +19,7 @@
*/
#include "fstream.h"
//==============================================================================
/// @cond SHOW_PROTECTED
/// @cond SHOW_PROTECTED
int16_t FatStreamBase::getch() {
uint8_t c;
int8_t s = read(&c, 1);
@@ -31,53 +31,63 @@ int16_t FatStreamBase::getch() {
}
return -1;
}
if (c != '\r' || (getmode() & ios::binary)) return c;
if (c != '\r' || (getmode() & ios::binary)) {
return c;
}
s = read(&c, 1);
if (s == 1 && c == '\n') return c;
if (s == 1) seekCur(-1);
if (s == 1 && c == '\n') {
return c;
}
if (s == 1) {
seekCur(-1);
}
return '\r';
}
//------------------------------------------------------------------------------
void FatStreamBase::open(const char* path, ios::openmode mode) {
uint8_t flags;
uint8_t flags;
switch (mode & (app | in | out | trunc)) {
case app | in:
case app | in | out:
flags = O_RDWR | O_APPEND | O_CREAT;
break;
case app | in:
case app | in | out:
flags = O_RDWR | O_APPEND | O_CREAT;
break;

case app:
case app | out:
flags = O_WRITE | O_APPEND | O_CREAT;
break;
case app:
case app | out:
flags = O_WRITE | O_APPEND | O_CREAT;
break;

case in:
flags = O_READ;
break;
case in:
flags = O_READ;
break;

case in | out:
flags = O_RDWR;
break;
case in | out:
flags = O_RDWR;
break;

case in | out | trunc:
flags = O_RDWR | O_TRUNC | O_CREAT;
break;
case in | out | trunc:
flags = O_RDWR | O_TRUNC | O_CREAT;
break;

case out:
case out | trunc:
flags = O_WRITE | O_TRUNC | O_CREAT;
break;
case out:
case out | trunc:
flags = O_WRITE | O_TRUNC | O_CREAT;
break;

default:
goto fail;
default:
goto fail;
}
if (mode & ios::ate) {
flags |= O_AT_END;
}
if (!FatFile::open(path, flags)) {
goto fail;
}
if (mode & ios::ate) flags |= O_AT_END;
if (!FatFile::open(path, flags)) goto fail;
setmode(mode);
clear();
return;

fail:
fail:
FatFile::close();
setstate(failbit);
return;
@@ -88,7 +98,9 @@ void FatStreamBase::putch(char c) {
write('\r');
}
write(c);
if (getWriteError()) setstate(badbit);
if (getWriteError()) {
setstate(badbit);
}
}
//------------------------------------------------------------------------------
void FatStreamBase::putstr(const char* str) {
@@ -96,15 +108,21 @@ void FatStreamBase::putstr(const char* str) {
while (1) {
char c = str[n];
if (c == '\0' || (c == '\n' && !(getmode() & ios::binary))) {
if (n > 0) write(str, n);
if (c == '\0') break;
if (n > 0) {
write(str, n);
}
if (c == '\0') {
break;
}
write('\r');
str += n;
n = 0;
}
n++;
}
if (getWriteError()) setstate(badbit);
if (getWriteError()) {
setstate(badbit);
}
}
//------------------------------------------------------------------------------
/** Internal do not use
@@ -114,20 +132,20 @@ void FatStreamBase::putstr(const char* str) {
bool FatStreamBase::seekoff(off_type off, seekdir way) {
pos_type pos;
switch (way) {
case beg:
pos = off;
break;
case beg:
pos = off;
break;

case cur:
pos = curPosition() + off;
break;
case cur:
pos = curPosition() + off;
break;

case end:
pos = fileSize() + off;
break;
case end:
pos = fileSize() + off;
break;

default:
return false;
default:
return false;
}
return seekpos(pos);
}

+ 81
- 29
SdFat/utility/fstream.h Переглянути файл

@@ -40,11 +40,15 @@ class FatStreamBase : protected FatFile, virtual public ios {
/** Internal do not use
* \return mode
*/
ios::openmode getmode() {return m_mode;}
ios::openmode getmode() {
return m_mode;
}
/** Internal do not use
* \param[in] mode
*/
void setmode(ios::openmode mode) {m_mode = mode;}
void setmode(ios::openmode mode) {
m_mode = mode;
}
bool seekoff(off_type off, seekdir way);
bool seekpos(pos_type pos);
int write(const void* buf, size_t n);
@@ -83,7 +87,9 @@ class fstream : public iostream, FatStreamBase {
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() {FatFile::close();}
void close() {
FatFile::close();
}
/** Open a fstream
* \param[in] path file to open
* \param[in] mode open mode
@@ -110,36 +116,54 @@ class fstream : public iostream, FatStreamBase {
FatStreamBase::open(path, mode);
}
/** \return True if stream is open else false. */
bool is_open () {return FatFile::isOpen();}
bool is_open() {
return FatFile::isOpen();
}

protected:
/// @cond SHOW_PROTECTED
/** Internal - do not use
* \return
*/
int16_t getch() {return FatStreamBase::getch();}
/** Internal - do not use
* \param[out] pos
*/
void getpos(FatPos_t* pos) {FatFile::getpos(pos);}
int16_t getch() {
return FatStreamBase::getch();
}
/** Internal - do not use
* \param[out] pos
*/
void getpos(FatPos_t* pos) {
FatFile::getpos(pos);
}
/** Internal - do not use
* \param[in] c
*/
void putch(char c) {FatStreamBase::putch(c);}
void putch(char c) {
FatStreamBase::putch(c);
}
/** Internal - do not use
* \param[in] str
*/
void putstr(const char *str) {FatStreamBase::putstr(str);}
void putstr(const char *str) {
FatStreamBase::putstr(str);
}
/** Internal - do not use
* \param[in] pos
*/
bool seekoff(off_type off, seekdir way) {
return FatStreamBase::seekoff(off, way);
}
bool seekpos(pos_type pos) {return FatStreamBase::seekpos(pos);}
void setpos(FatPos_t* pos) {FatFile::setpos(pos);}
bool sync() {return FatStreamBase::sync();}
pos_type tellpos() {return FatStreamBase::curPosition();}
bool seekpos(pos_type pos) {
return FatStreamBase::seekpos(pos);
}
void setpos(FatPos_t* pos) {
FatFile::setpos(pos);
}
bool sync() {
return FatStreamBase::sync();
}
pos_type tellpos() {
return FatStreamBase::curPosition();
}
/// @endcond
};
//==============================================================================
@@ -164,9 +188,13 @@ class ifstream : public istream, FatStreamBase {
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() {FatFile::close();}
void close() {
FatFile::close();
}
/** \return True if stream is open else false. */
bool is_open() {return FatFile::isOpen();}
bool is_open() {
return FatFile::isOpen();
}
/** Open an ifstream
* \param[in] path file to open
* \param[in] mode open mode
@@ -182,20 +210,30 @@ class ifstream : public istream, FatStreamBase {
/** Internal - do not use
* \return
*/
int16_t getch() {return FatStreamBase::getch();}
int16_t getch() {
return FatStreamBase::getch();
}
/** Internal - do not use
* \param[out] pos
*/
void getpos(FatPos_t* pos) {FatFile::getpos(pos);}
void getpos(FatPos_t* pos) {
FatFile::getpos(pos);
}
/** Internal - do not use
* \param[in] pos
*/
bool seekoff(off_type off, seekdir way) {
return FatStreamBase::seekoff(off, way);
}
bool seekpos(pos_type pos) {return FatStreamBase::seekpos(pos);}
void setpos(FatPos_t* pos) {FatFile::setpos(pos);}
pos_type tellpos() {return FatStreamBase::curPosition();}
bool seekpos(pos_type pos) {
return FatStreamBase::seekpos(pos);
}
void setpos(FatPos_t* pos) {
FatFile::setpos(pos);
}
pos_type tellpos() {
return FatStreamBase::curPosition();
}
/// @endcond
};
//==============================================================================
@@ -226,7 +264,9 @@ class ofstream : public ostream, FatStreamBase {
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() {FatFile::close();}
void close() {
FatFile::close();
}
/** Open an ofstream
* \param[in] path file to open
* \param[in] mode open mode
@@ -237,7 +277,9 @@ class ofstream : public ostream, FatStreamBase {
FatStreamBase::open(path, mode | out);
}
/** \return True if stream is open else false. */
bool is_open() {return FatFile::isOpen();}
bool is_open() {
return FatFile::isOpen();
}

protected:
/// @cond SHOW_PROTECTED
@@ -245,18 +287,28 @@ class ofstream : public ostream, FatStreamBase {
* Internal do not use
* \param[in] c
*/
void putch(char c) {FatStreamBase::putch(c);}
void putstr(const char* str) {FatStreamBase::putstr(str);}
void putch(char c) {
FatStreamBase::putch(c);
}
void putstr(const char* str) {
FatStreamBase::putstr(str);
}
bool seekoff(off_type off, seekdir way) {
return FatStreamBase::seekoff(off, way);
}
bool seekpos(pos_type pos) {return FatStreamBase::seekpos(pos);}
bool seekpos(pos_type pos) {
return FatStreamBase::seekpos(pos);
}
/**
* Internal do not use
* \param[in] b
*/
bool sync() {return FatStreamBase::sync();}
pos_type tellpos() {return FatStreamBase::curPosition();}
bool sync() {
return FatStreamBase::sync();
}
pos_type tellpos() {
return FatStreamBase::curPosition();
}
/// @endcond
};
//------------------------------------------------------------------------------

+ 37
- 13
SdFat/utility/ios.h Переглянути файл

@@ -21,7 +21,7 @@
#define ios_h
#include "FatFile.h"
/**
* \file
* \file
* \brief \ref ios_base and \ref ios classes
*/
//==============================================================================
@@ -116,7 +116,9 @@ class ios_base {
ios_base() : m_fill(' '), m_fmtflags(dec | right | skipws)
, m_precision(2), m_width(0) {}
/** \return fill character */
char fill() {return m_fill;}
char fill() {
return m_fill;
}
/** Set fill character
* \param[in] c new fill character
* \return old fill character
@@ -127,7 +129,9 @@ class ios_base {
return r;
}
/** \return format flags */
fmtflags flags() const {return m_fmtflags;}
fmtflags flags() const {
return m_fmtflags;
}
/** set format flags
* \param[in] fl new flag
* \return old flags
@@ -138,7 +142,9 @@ class ios_base {
return tmp;
}
/** \return precision */
int precision() const {return m_precision;}
int precision() const {
return m_precision;
}
/** set precision
* \param[in] n new precision
* \return old precision
@@ -176,7 +182,9 @@ class ios_base {
m_fmtflags &= ~fl;
}
/** \return width */
unsigned width() {return m_width;}
unsigned width() {
return m_width;
}
/** set width
* \param[in] n new width
* \return old width
@@ -360,11 +368,17 @@ class ios : public ios_base {
return !fail() ? reinterpret_cast<const void*>(this) : 0;
}
/** \return true if fail() else false. */
bool operator!() const {return fail();}
bool operator!() const {
return fail();
}
/** \return The iostate flags for this file. */
iostate rdstate() const {return m_iostate;}
iostate rdstate() const {
return m_iostate;
}
/** \return True if no iostate flags are set else false. */
bool good() const {return m_iostate == goodbit;}
bool good() const {
return m_iostate == goodbit;
}
/** \return true if end of file has been reached else false.
*
* Warning: An empty file returns false before the first read.
@@ -372,21 +386,31 @@ class ios : public ios_base {
* Moral: eof() is only useful in combination with fail(), to find out
* whether EOF was the cause for failure
*/
bool eof() const {return m_iostate & eofbit;}
bool eof() const {
return m_iostate & eofbit;
}
/** \return true if any iostate bit other than eof are set else false. */
bool fail() const {return m_iostate & (failbit | badbit);}
bool fail() const {
return m_iostate & (failbit | badbit);
}
/** \return true if bad bit is set else false. */
bool bad() const {return m_iostate & badbit;}
bool bad() const {
return m_iostate & badbit;
}
/** Clear iostate bits.
*
* \param[in] state The flags you want to set after clearing all flags.
**/
void clear(iostate state = goodbit) {m_iostate = state;}
void clear(iostate state = goodbit) {
m_iostate = state;
}
/** Set iostate bits.
*
* \param[in] state Bitts to set.
**/
void setstate(iostate state) {m_iostate |= state;}
void setstate(iostate state) {
m_iostate |= state;
}

private:
iostate m_iostate;

+ 53
- 19
SdFat/utility/istream.cpp Переглянути файл

@@ -17,7 +17,7 @@
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
// #include <ctype.h>
#include <float.h>
#include "istream.h"
//------------------------------------------------------------------------------
@@ -35,7 +35,9 @@ int istream::get() {
//------------------------------------------------------------------------------
istream& istream::get(char& c) {
int tmp = get();
if (tmp >= 0) c = tmp;
if (tmp >= 0) {
c = tmp;
}
return *this;
}
//------------------------------------------------------------------------------
@@ -54,8 +56,12 @@ istream& istream::get(char *str, streamsize n, char delim) {
}
str[m_gcount++] = c;
}
if (n > 0) str[m_gcount] = '\0';
if (m_gcount == 0) setstate(failbit);
if (n > 0) {
str[m_gcount] = '\0';
}
if (m_gcount == 0) {
setstate(failbit);
}
return *this;
}
//------------------------------------------------------------------------------
@@ -75,7 +81,9 @@ void istream::getBool(bool *b) {
while (1) {
falseOk = falseOk && c == pgm_read_byte(falsePtr + i);
trueOk = trueOk && c == pgm_read_byte(truePtr + i);
if (trueOk == false && falseOk == false) break;
if (trueOk == false && falseOk == false) {
break;
}
i++;
if (trueOk && i == true_len) {
*b = true;
@@ -128,19 +136,27 @@ bool istream::getDouble(double* value) {
got_digit = true;
if (frac < uint32_max/10) {
frac = frac * 10 + (c - '0');
if (got_dot) fracExp--;
if (got_dot) {
fracExp--;
}
} else {
if (!got_dot) fracExp++;
if (!got_dot) {
fracExp++;
}
}
} else if (!got_dot && c == '.') {
got_dot = true;
} else {
break;
}
if (fracExp < -EXP_LIMIT || fracExp > EXP_LIMIT) goto fail;
if (fracExp < -EXP_LIMIT || fracExp > EXP_LIMIT) {
goto fail;
}
c = getch(&endPos);
}
if (!got_digit) goto fail;
if (!got_digit) {
goto fail;
}
if (c == 'e' || c == 'E') {
c = getch();
expNeg = c == '-';
@@ -148,7 +164,9 @@ bool istream::getDouble(double* value) {
c = getch();
}
while (isdigit(c)) {
if (exp > EXP_LIMIT) goto fail;
if (exp > EXP_LIMIT) {
goto fail;
}
exp = exp * 10 + (c - '0');
c = getch(&endPos);
}
@@ -156,17 +174,23 @@ bool istream::getDouble(double* value) {
v = static_cast<double>(frac);
exp = expNeg ? fracExp - exp : fracExp + exp;
expNeg = exp < 0;
if (expNeg) exp = -exp;
if (expNeg) {
exp = -exp;
}
pow10 = 10.0;
while (exp) {
if (exp & 1) {
if (expNeg) {
// check for underflow
if (v < FLT_MIN * pow10 && frac != 0) goto fail;
if (v < FLT_MIN * pow10 && frac != 0) {
goto fail;
}
v /= pow10;
} else {
// check for overflow
if (v > FLT_MAX / pow10) goto fail;
if (v > FLT_MAX / pow10) {
goto fail;
}
v *= pow10;
}
}
@@ -177,7 +201,7 @@ bool istream::getDouble(double* value) {
*value = neg ? -v : v;
return true;

fail:
fail:
// error restore position to last good place
setpos(&endPos);
setstate(failbit);
@@ -189,7 +213,9 @@ istream& istream::getline(char *str, streamsize n, char delim) {
FatPos_t pos;
int c;
m_gcount = 0;
if (n > 0) str[0] = '\0';
if (n > 0) {
str[0] = '\0';
}
while (1) {
c = getch(&pos);
if (c < 0) {
@@ -207,7 +233,9 @@ istream& istream::getline(char *str, streamsize n, char delim) {
str[m_gcount++] = c;
str[m_gcount] = '\0';
}
if (m_gcount == 0) setstate(failbit);
if (m_gcount == 0) {
setstate(failbit);
}
return *this;
}
//------------------------------------------------------------------------------
@@ -295,7 +323,9 @@ void istream::getStr(char *str) {
}
}
str[i] = '\0';
if (i == 0) setstate(failbit);
if (i == 0) {
setstate(failbit);
}
width(0);
}
//------------------------------------------------------------------------------
@@ -308,7 +338,9 @@ istream& istream::ignore(streamsize n, int delim) {
break;
}
m_gcount++;
if (c == delim) break;
if (c == delim) {
break;
}
}
return *this;
}
@@ -320,7 +352,9 @@ int istream::peek() {
getpos(&pos);
c = getch();
if (c < 0) {
if (!bad()) setstate(eofbit);
if (!bad()) {
setstate(eofbit);
}
} else {
setpos(&pos);
}

+ 93
- 85
SdFat/utility/istream.h Переглянути файл

@@ -55,124 +55,124 @@ class istream : public virtual ios {
pf(*this);
return *this;
}
/**
* Extract a character string
* \param[out] str location to store the string.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a character string
* \param[out] str location to store the string.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(char *str) {
getStr(str);
return *this;
}
/**
* Extract a character
* \param[out] ch location to store the character.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a character
* \param[out] ch location to store the character.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(char& ch) {
getChar(&ch);
return *this;
}
/**
* Extract a character string
* \param[out] str location to store the string.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a character string
* \param[out] str location to store the string.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(signed char *str) {
getStr(reinterpret_cast<char*>(str));
return *this;
}
/**
* Extract a character
* \param[out] ch location to store the character.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a character
* \param[out] ch location to store the character.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(signed char& ch) {
getChar(reinterpret_cast<char*>(&ch));
return *this;
}
/**
* Extract a character string
* \param[out] str location to store the string.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a character string
* \param[out] str location to store the string.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(unsigned char *str) {
getStr(reinterpret_cast<char*>(str));
return *this;
}
/**
* Extract a character
* \param[out] ch location to store the character.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a character
* \param[out] ch location to store the character.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(unsigned char& ch) {
getChar(reinterpret_cast<char*>(&ch));
return *this;
}
/**
* Extract a value of type bool.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a value of type bool.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(bool& arg) {
getBool(&arg);
return *this;
}
/**
* Extract a value of type short.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a value of type short.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(short& arg) { // NOLINT
getNumber(&arg);
return *this;
}
/**
* Extract a value of type unsigned short.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a value of type unsigned short.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(unsigned short& arg) { // NOLINT
getNumber(&arg);
return *this;
}
/**
* Extract a value of type int.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a value of type int.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(int& arg) {
getNumber(&arg);
return *this;
}
/**
* Extract a value of type unsigned int.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a value of type unsigned int.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(unsigned int& arg) {
getNumber(&arg);
return *this;
}
/**
* Extract a value of type long.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a value of type long.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(long& arg) { // NOLINT
getNumber(&arg);
return *this;
}
/**
* Extract a value of type unsigned long.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a value of type unsigned long.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(unsigned long& arg) { // NOLINT
getNumber(&arg);
return *this;
}
/**
/**
* Extract a value of type double.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
@@ -181,11 +181,11 @@ class istream : public virtual ios {
getDouble(&arg);
return *this;
}
/**
* Extract a value of type float.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
/**
* Extract a value of type float.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>> (float& arg) {
double v;
getDouble(&v);
@@ -207,13 +207,15 @@ class istream : public virtual ios {
* \return The number of characters extracted by the last unformatted
* input function.
*/
streamsize gcount() const {return m_gcount;}
streamsize gcount() const {
return m_gcount;
}
/**
* Extract a character if one is available.
*
* \return The character or -1 if a failure occurs. A failure is indicated
* by the stream state.
*/
*/
int get();
/**
* Extract a character if one is available.
@@ -221,10 +223,10 @@ class istream : public virtual ios {
* \param[out] ch location to receive the extracted character.
*
* \return always returns *this. A failure is indicated by the stream state.
*/
*/
istream& get(char& ch);
/**
* Extract characters.
* Extract characters.
*
* \param[out] str Location to receive extracted characters.
* \param[in] n Size of str.
@@ -236,7 +238,7 @@ class istream : public virtual ios {
* failbit is set. If end-of-file occurs the eofbit is set.
*
* \return always returns *this. A failure is indicated by the stream state.
*/
*/
istream& get(char *str, streamsize n, char delim = '\n');
/**
* Extract characters
@@ -269,28 +271,32 @@ class istream : public virtual ios {
*
* \return *this
*
*/
*/
istream& ignore(streamsize n = 1, int delim= -1);
/**
* Return the next available character without consuming it.
*
* \return The character if the stream state is good else -1;
*
*/
*/
int peek();
// istream& read(char *str, streamsize count);
// streamsize readsome(char *str, streamsize count);
/**
* \return the stream position
*/
pos_type tellg() {return tellpos();}
pos_type tellg() {
return tellpos();
}
/**
* Set the stream position
* \param[in] pos The absolute position in which to move the read pointer.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& seekg(pos_type pos) {
if (!seekpos(pos)) setstate(failbit);
if (!seekpos(pos)) {
setstate(failbit);
}
return *this;
}
/**
@@ -302,17 +308,19 @@ class istream : public virtual ios {
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& seekg(off_type off, seekdir way) {
if (!seekoff(off, way)) setstate(failbit);
if (!seekoff(off, way)) {
setstate(failbit);
}
return *this;
}
void skipWhite();

protected:
/// @cond SHOW_PROTECTED
/**
* Internal - do not use
* \return
*/
/**
* Internal - do not use
* \return
*/
virtual int16_t getch() = 0;
/**
* Internal - do not use

+ 21
- 7
SdFat/utility/ostream.cpp Переглянути файл

@@ -24,7 +24,9 @@
#endif
//------------------------------------------------------------------------------
void ostream::do_fill(unsigned len) {
for (; len < width(); len++) putch(fill());
for (; len < width(); len++) {
putch(fill());
}
width(0);
}
//------------------------------------------------------------------------------
@@ -86,13 +88,17 @@ void ostream::putDouble(double n) {
return;
}
// round up and separate int and fraction parts
for (uint8_t i = 0; i < nd; ++i) round *= 0.1;
for (uint8_t i = 0; i < nd; ++i) {
round *= 0.1;
}
n += round;
uint32_t intPart = n;
double fractionPart = n - intPart;

// format intPart and decimal point
if (nd || (flags() & showpoint)) *--str = '.';
if (nd || (flags() & showpoint)) {
*--str = '.';
}
str = fmtNum(intPart, str, 10);

// calculate length for fill
@@ -102,12 +108,16 @@ void ostream::putDouble(double n) {
// extract adjust field
fmtflags adj = flags() & adjustfield;
if (adj == internal) {
if (sign) putch(sign);
if (sign) {
putch(sign);
}
do_fill(len);
} else {
// do fill for internal or right
fill_not_left(len);
if (sign) *--str = sign;
if (sign) {
*--str = sign;
}
}
putstr(str);
// output fraction
@@ -123,7 +133,9 @@ void ostream::putDouble(double n) {
//------------------------------------------------------------------------------
void ostream::putNum(int32_t n) {
bool neg = n < 0 && flagsToBase() == 10;
if (neg) n = -n;
if (neg) {
n = -n;
}
putNum(n, neg);
}
//------------------------------------------------------------------------------
@@ -150,7 +162,9 @@ void ostream::putNum(uint32_t n, bool neg) {
uint8_t len = end - str;
fmtflags adj = flags() & adjustfield;
if (adj == internal) {
while (str < num) putch(*str++);
while (str < num) {
putch(*str++);
}
}
if (adj != left) {
do_fill(len);

+ 12
- 4
SdFat/utility/ostream.h Переглянути файл

@@ -230,20 +230,26 @@ class ostream : public virtual ios {
* \return A reference to the ostream object.
*/
ostream& flush() {
if (!sync()) setstate(badbit);
if (!sync()) {
setstate(badbit);
}
return *this;
}
/**
* \return the stream position
*/
pos_type tellp() {return tellpos();}
pos_type tellp() {
return tellpos();
}
/**
* Set the stream position
* \param[in] pos The absolute position in which to move the write pointer.
* \return Is always *this. Failure is indicated by the state of *this.
*/
ostream& seekp(pos_type pos) {
if (!seekpos(pos)) setstate(failbit);
if (!seekpos(pos)) {
setstate(failbit);
}
return *this;
}
/**
@@ -255,7 +261,9 @@ class ostream : public virtual ios {
* \return Is always *this. Failure is indicated by the state of *this.
*/
ostream& seekp(off_type off, seekdir way) {
if (!seekoff(off, way)) setstate(failbit);
if (!seekoff(off, way)) {
setstate(failbit);
}
return *this;
}


+ 9
- 9
SdFatTestSuite/SdFatTestSuite.cpp Переглянути файл

@@ -36,7 +36,7 @@ void testBegin() {
while (Serial.read() <= 0) {}
delay(200); // Catch Due reset problem

print_P(testOut, PSTR("FreeRam: "));
testOut->print(F("FreeRam: "));
testOut->println(FreeRam());
testOut->println();
failCount = 0;
@@ -45,21 +45,21 @@ void testBegin() {
//------------------------------------------------------------------------------
void testEnd() {
testOut->println();
println_P(testOut, PSTR("Compiled: " __DATE__ " " __TIME__));
print_P(testOut, PSTR("FreeRam: "));
testOut->println(F("Compiled: " __DATE__ " " __TIME__));
testOut->print(F("FreeRam: "));
testOut->println(FreeRam());
print_P(testOut, PSTR("Test count: "));
testOut->print(F("Test count: "));
testOut->println(testCount);
print_P(testOut, PSTR("Fail count: "));
testOut->print(F("Fail count: "));
testOut->println(failCount);
}
//------------------------------------------------------------------------------
static void testResult(bool b, uint8_t n) {
while (n++ < 60) testOut->write(' ');
if (b) {
println_P(testOut, PSTR("..ok"));
testOut->println(F("..ok"));
} else {
println_P(testOut, PSTR("FAIL"));
testOut->println(F("FAIL"));
failCount++;
}
testCount++;
@@ -69,14 +69,14 @@ void testVerify_P(char* result, PGM_P expect) {
testOut->write('"');
testOut->print(result);
testOut->print("\",\"");
print_P(testOut, expect);
testOut->print((const __FlashStringHelper*)expect);
testOut->write('"');
uint8_t n = strlen(result) + strlenPGM(expect) + 5;
testResult(!strcmp_P(result, expect), n);
}
//------------------------------------------------------------------------------
void testVerify_P(bool b, PGM_P msg) {
print_P(testOut, msg);
testOut->print((const __FlashStringHelper*)msg);
uint8_t n = strlenPGM(msg);
testResult(b, n);
}

+ 9
- 7
SdFatTestSuite/examples/TestMkdir/TestMkdir.ino Переглянути файл

@@ -25,10 +25,10 @@ SdFat sd;
* create enough files to force a cluster to be allocated to dir.
*/
void dirAllocTest(SdBaseFile* dir) {
char buf[13], name[13];
char buf[32], name[32];
SdFile file;
uint16_t n;
uint32_t size = dir->fileSize();
uint32_t size = dir->dirSize();
// create files and write name to file
for (n = 0; ; n++){
@@ -61,7 +61,7 @@ void dirAllocTest(SdBaseFile* dir) {
Serial.println(t2 - t1);
// directory size will change when a cluster is added
if (dir->fileSize() != size) break;
if (dir->curPosition() > size) break;
}

// read files and check content
@@ -76,7 +76,7 @@ void dirAllocTest(SdBaseFile* dir) {
// open end time and read start time
uint32_t t1 = millis();
int16_t nr = file.read(buf, 13);
int16_t nr = file.read(buf, sizeof(buf));
if (nr < 5) error("file.read failed");
// read end time
@@ -112,6 +112,7 @@ void setup() {
// try SPI_HALF_SPEED if bus errors occur.
if (!sd.begin(SD_CHIP_SELECT, SPI_FULL_SPEED)) sd.initErrorHalt();
uint32_t m = millis();
// write files to root if FAT32
if (sd.vol()->fatType() == 32) {
Serial.println(F("Writing files to root"));
@@ -129,8 +130,9 @@ void setup() {
if (!sub2.mkdir(&sub1, "SUB2")) error("mkdir SUB2 failed");
Serial.println(F("Writing files to SUB2"));
dirAllocTest(&sub2);
Serial.println(F("Done"));
m = millis() - m;
Serial.print(F("Done millis: "));
Serial.println(m);
}

void loop() { }
void loop() { }

+ 1
- 1
SdFatTestSuite/examples/TestRmdir/TestRmdir.ino Переглянути файл

@@ -21,7 +21,7 @@ SdFat sd;
* remove all files in dir.
*/
void deleteFiles(SdBaseFile* dir) {
char name[13];
char name[32];
SdFile file;
// open and delete files

+ 35
- 0
SdFatTestSuite/examples/lfnSize/lfnSize.ino Переглянути файл

@@ -0,0 +1,35 @@
// Program to compare size of SdFat with the SD.h library.
// Select the test library by commenting out one of the following two lines.
// #include <SD.h>
#include <SdFat.h>

// SD chip select pin.
const uint8_t SD_CS_PIN = SS;

#ifdef __SD_H__
File file;
#else // __SD_H__
SdFat SD;
SdFile file;
#endif // __SD_H__

void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo

if (!SD.begin(SD_CS_PIN)) {
Serial.println("begin failed");
return;
}
#ifdef __SD_H__
file = SD.open("SFN_file.txt", FILE_WRITE);
#else // __SD_H__
file.open("LFN_file.txt", O_RDWR | O_CREAT);
#endif // __SD_H__
file.println("Hello");
file.close();
Serial.println("Done");
}
//------------------------------------------------------------------------------
void loop() {}

+ 235
- 0
SdFatTestSuite/examples/lfnTest/lfnTest.ino Переглянути файл

@@ -0,0 +1,235 @@
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
const uint8_t SD_CS_PIN = SS;
SdFat sd;
SdFile file;
char name[260];

//------------------------------------------------------------------------------
char* testName[] = {
"low.low",
"low.Mix",
"low.UP",
"Mix.low",
"Mix.Mix",
"Mix.UP",
"UP.low",
"UP.Mix",
"UP.UP",
".dot",
".dot.dot",
"A b c . txt",
" Leading space and no extension",
"Trailing dots and space . . .",
"Long extension.extension",
"Space after dot. txt",
"Dot.dot.test.txt",
"Dot.dot.test.seq.txt",
"LOW.LOW",
"MIX.MIX",
"Invalid character *.test"
};
//------------------------------------------------------------------------------
bool checkName(char first, size_t len) {
size_t i;
if (len < 5 || len > sizeof(name)) {
return false;
}
if ( name[0] != first) {
return false;
}
for (i = 1; i < (len - 4); i++) {
if (name[i] != ('0' + (i + 1) %10)) {
return false;
}
}
char* p = ".txt";
while (*p) {
if (name[i++] != *p++) {
return false;
}
}
return name[i] == 0;
}
//------------------------------------------------------------------------------
void makeName(char first, size_t len) {
size_t i;
if (len > sizeof(name)) {
len = 255;
}
if (len < 5) {
len = 5;
}
name[0] = first;
for (i = 1; i < (len - 4); i++) {
name[i] = '0' + (i + 1) %10;
}
char* p = ".txt";
while (*p) name[i++] = *p++;
name[i] = 0;
}
//------------------------------------------------------------------------------
// test open, remove, getFilename, and ls.
void basicTest() {
size_t i;
size_t n = sd.vol()->fatType() == 32 ? 255 : 99;
uint16_t index;
uint16_t maxIndex = 0;
makeName('Z', 256);
if (!file.open(name, O_RDWR | O_CREAT)) {
Serial.println(F("255 limit OK"));
} else {
sd.errorHalt(F("255 limit"));
}
for (i = 5; i <= n; i++) {
makeName('A', i);

if (!file.open(name, O_RDWR | O_CREAT)) {
sd.errorHalt(F("open A"));
}
file.println(name);
Serial.print(i);
Serial.write(' ');
Serial.print(file.dirIndex());
Serial.write(' ');
Serial.print(file.fileSize());
Serial.println(F(" open A"));
if (file.fileSize() != (i + 2)) {
sd.errorHalt(F("file size A"));
}
if (file.dirIndex() >= maxIndex) {
maxIndex = file.dirIndex();
} else {
Serial.print(maxIndex); Serial.print(',');Serial.println(file.dirIndex());
sd.errorHalt(F("dirIndex"));
}
file.close();
if (!file.open(sd.vwd(), maxIndex, O_READ)) {
sd.errorHalt(F("open by index"));
}
memset(name, 0, sizeof(name));
if (!file.getFilename(name, sizeof(name))) {
sd.errorHalt(F("getFilename"));
}
if (!checkName('A', i)) {
Serial.println(name);
sd.errorHalt(F("checkName"));
}
file.close();
}
for (i = n; i >= 5; i -= 2) {
makeName('A', i);
Serial.print(i);
Serial.println(F( " rm A"));
if (!sd.remove(name)) {
sd.errorHalt(F("remove A"));
}
}
for (i = n; i >= 5; i -= 2) {
makeName('B', i);
if (!file.open(name, O_RDWR | O_CREAT)) {
sd.errorHalt(F("open B"));
}
file.println(name);
Serial.print(i);
Serial.write(' ');
Serial.print(file.dirIndex());
Serial.write(' ');
Serial.print(file.fileSize());
Serial.println(F(" open B"));
if (file.fileSize() != (i + 2)) {
sd.errorHalt(F("file size B"));
}
if (file.dirIndex() > maxIndex) {
sd.errorHalt(F("maxIndex"));
}
file.close();
}
Serial.println(F("----- ls ------"));
sd.ls();
for (i = 5; i <= n; i++) {
char fc = i & 1 ? 'B' : 'A';
makeName(fc, i);
Serial.print(i);
Serial.print(F(" rm "));
Serial.println(fc);
if (!sd.remove(name)) {
sd.errorHalt(F("remove A/B"));
}
}
if (file.openNext(sd.vwd())) {
sd.errorHalt(F("remove all"));
}
Serial.println();
Serial.println(F("basicTest done"));
}
//------------------------------------------------------------------------------
void nameTest() {
Serial.println();
uint8_t n = sizeof(testName)/sizeof(char*);
for (uint8_t i = 0; i < n; i++) {
Serial.print(F("Name: "));
Serial.write('"');
Serial.print(testName[i]);
Serial.println('"');
if(!file.open(testName[i], O_CREAT | O_RDWR)) {
Serial.println(F("Open failed"));
} else {
file.println(testName[i]);
if (!file.getFilename(name, sizeof(name))) {
sd.errorHalt(F("getFilemame"));
}
file.println(name);
Serial.print(F("LFN: "));
Serial.write('"');
Serial.print(name);
Serial.println('"');
Serial.print(F("SFN: "));
Serial.write('"');
file.printSFN(&Serial);
Serial.println('"');
Serial.print(F("Index: "));
if (file.dirIndex() < 10) {
Serial.write(' ');
}
Serial.println(file.dirIndex());
file.close();
}
Serial.println();
}
Serial.println(F("----- ls ------"));
sd.ls();
Serial.println();
Serial.println(F("nameTest done"));
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while(!Serial);
Serial.print(F("\r\nFreeRam: "));
Serial.println(FreeRam());
Serial.println(F("Type any character to start."));
while (Serial.read() < 0) {}
if (!sd.begin(SD_CS_PIN)) sd.initErrorHalt();
if (file.openNext(sd.vwd())) {
file.close();
delay(100);
while (Serial.read() >= 0) {}
Serial.print(F("Type 'W' to wipe the card: "));
int c;
while ((c = Serial.read()) < 0) {}
if (c != 'W') {
sd.errorHalt(F("Invalid"));
}
Serial.println((char)c);
if (!sd.wipe(&Serial) || !sd.begin(SD_CS_PIN)) {
sd.errorHalt(F("wipe failed"));
}
}
basicTest();
nameTest();
}
//------------------------------------------------------------------------------
void loop() {}

+ 219
- 0
SdFatTestSuite/examples/lfnTestCout/lfnTestCout.ino Переглянути файл

@@ -0,0 +1,219 @@
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
const uint8_t SD_CS_PIN = SS;
SdFat sd;
SdFile file;
char name[260];

// Serial output stream
ArduinoOutStream cout(Serial);

// Serial in buffer.
char cinBuf[10];

// Serial input stream
ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));
//------------------------------------------------------------------------------
char* testName[] = {
"low.low",
"low.Mix",
"low.UP",
"Mix.low",
"Mix.Mix",
"Mix.UP",
"UP.low",
"UP.Mix",
"UP.UP",
".dot",
".dot.dot",
"A b c . txt",
" Leading space and no extension",
"Trailing dots and space . . .",
"Long extension.extension",
"Space after dot. txt",
"Dot.dot.test.txt",
"Dot.dot.test.seq.txt",
"LOW.LOW",
"MIX.MIX",
"Invalid character *.test"
};
//------------------------------------------------------------------------------
bool checkName(char first, size_t len) {
size_t i;
if (len < 5 || len > sizeof(name)) {
return false;
}
if ( name[0] != first) {
return false;
}
for (i = 1; i < (len - 4); i++) {
if (name[i] != ('0' + (i + 1) %10)) {
return false;
}
}
char* p = ".txt";
while (*p) {
if (name[i++] != *p++) {
return false;
}
}
return name[i] == 0;
}
//------------------------------------------------------------------------------
void makeName(char first, size_t len) {
size_t i;
if (len > sizeof(name)) {
len = 255;
}
if (len < 5) {
len = 5;
}
name[0] = first;
for (i = 1; i < (len - 4); i++) {
name[i] = '0' + (i + 1) %10;
}
char* p = ".txt";
while (*p) name[i++] = *p++;
name[i] = 0;
}
//------------------------------------------------------------------------------
// test open, remove, getFilename, and ls.
void basicTest() {
size_t i;
size_t n = sd.vol()->fatType() == 32 ? 255 : 99;
uint16_t index;
uint16_t maxIndex = 0;
makeName('Z', 256);
if (!file.open(name, O_RDWR | O_CREAT)) {
cout << F("255 limit OK") << endl;
} else {
sd.errorHalt(F("255 limit"));
}
for (i = 5; i <= n; i++) {
makeName('A', i);

if (!file.open(name, O_RDWR | O_CREAT)) {
sd.errorHalt(F("open A"));
}
file.println(name);
cout << setw(3) << i << setw(5) << file.dirIndex() << F(" open A") << endl;
if (file.fileSize() != (i + 2)) {
sd.errorHalt(F("file size A"));
}
if (file.dirIndex() >= maxIndex) {
maxIndex = file.dirIndex();
} else {
sd.errorHalt(F("dirIndex"));
}
file.close();
if (!file.open(sd.vwd(), maxIndex, O_READ)) {
sd.errorHalt(F("open by index"));
}
memset(name, 0, sizeof(name));
if (!file.getFilename(name, sizeof(name))) {
sd.errorHalt(F("getFilename"));
}
if (!checkName('A', i)) {
cout << name << endl;
sd.errorHalt(F("checkName"));
}
file.close();
}
for (i = n; i >= 5; i -= 2) {
makeName('A', i);
cout << setw(3) << i << F( " rm A") << endl;
if (!sd.remove(name)) {
sd.errorHalt(F("remove A"));
}
}
for (i = n; i >= 5; i -= 2) {
makeName('B', i);
if (!file.open(name, O_RDWR | O_CREAT)) {
sd.errorHalt(F("open B"));
}
file.println(name);
cout << setw(3) << i << setw(5) << file.dirIndex() << F(" open B") << endl;
if (file.fileSize() != (i + 2)) {
sd.errorHalt(F("file size B"));
}
if (file.dirIndex() > maxIndex) {
sd.errorHalt(F("maxIndex"));
}
file.close();
}
cout << endl << F("----- ls ------") << endl;
sd.ls();
for (i = 5; i <= n; i++) {
char fc = i & 1 ? 'B' : 'A';
makeName(fc, i);
cout << setw(3) << i << F(" rm ") << fc << endl;
if (!sd.remove(name)) {
sd.errorHalt(F("remove A/B"));
}
}
if (file.openNext(sd.vwd())) {
sd.errorHalt(F("remove all"));
}
cout << endl << F("basicTest done") << endl;
}
//------------------------------------------------------------------------------
void nameTest() {
cout << endl;
uint8_t n = sizeof(testName)/sizeof(char*);
for (uint8_t i = 0; i < n; i++) {
cout << F("Name: \"") << testName[i] << '"' << endl;
if(!file.open(testName[i], O_CREAT | O_RDWR)) {
cout <<F("Open failed") << endl;
} else {
file.println(testName[i]);
if (!file.getFilename(name, sizeof(name))) {
sd.errorHalt(F("getFilemame"));
}
cout << F("LFN: \"") << name << '"' << endl;
cout << F("SFN: \"");
file.printSFN(&Serial);
cout << '"' << endl;
cout <<F("Index: ") << setw(2) << file.dirIndex() << endl;
file.close();
}
cout << endl;
}
cout << F("----- ls ------") << endl;
sd.ls();
cout << endl << F("nameTest done") << endl;

}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while(!Serial); // Wait for USB Serial.
cout << endl << F("FreeRam: ") << FreeRam() << endl;
cout << F("Type any character to start.") << endl;
cin.readline();
if (!sd.begin(SD_CS_PIN)) {
sd.initErrorHalt();
}
if (file.openNext(sd.vwd())) {
file.close();
cout << F("Type 'W' to wipe the card: ");
cin.readline();
char c = cin.get();
cout << c << endl;
if (c != 'W') {
sd.errorHalt(F("Invalid"));
}
if (!sd.wipe(&Serial) || !sd.begin(SD_CS_PIN)) {
sd.errorHalt(F("wipe failed"));
}
}
basicTest();
nameTest();
}
//------------------------------------------------------------------------------
void loop() {}

BIN
SdLevel.png Переглянути файл

Before After
Width: 695  |  Height: 668  |  Size: 21KB

+ 0
- 15
SoftwareSPI.txt Переглянути файл

@@ -1,15 +0,0 @@
Software SPI is now supported on AVR, Due, and Teensy 3.x boards.

The most general approach is to set USE_MULTIPLE_SPI_TYPES nonzero
in SdFatConfig.h.
//------------------------------------------------------------------------------
/**
* Set USE_MULTIPLE_SPI_TYPES nonzero to enable the SdFatSoftSpi and
* SdFatLibSpi classes. SdFatSoftSpi uses software SPI and SdFatLibSpi
* uses the standard Arduino SPI library.
*/
#define USE_MULTIPLE_SPI_TYPES 0


You can also edit other configuration options in SdFatConfig.h to
change the type of SPI used by the SdFat class.

+ 0
- 44
WorkingDirectory.txt Переглянути файл

@@ -1,44 +0,0 @@
Relative paths in SdFat are resolved in a manner similar to Windows.

Each instance of SdFat has a current directory. In SdFat this directory
is called the volume working directory, vwd. Initially this directory is
the root directory for the volume.

The volume working directory is changed by calling SdFat::chdir(path).

The call sd.chdir("/2011") will change the volume working directory
for sd to "/2011", assuming "/2011" exists.

Relative paths for SdFat member functions are resolved by starting at
the volume working directory.

For example, the call sd.mkdir("APRIL") will create the directory
"/2011/APRIL" assuming the volume working directory is "/2011".

SdFat has a current working directory, cwd, that is used to resolve paths
for file.open() calls.

For a single SD card the current working directory is always the volume
working directory for that card.

For multiple SD cards the current working directory is set to the volume
working directory of a card by calling the SdFat::chvol() member function.
The chvol() call is like the Windows <drive letter>: command.

The call sd2.chvol() will set the current working directory to the volume
working directory for sd2.

If the volume working directory for sd2 is "/MUSIC" the call

file.open("BIGBAND.WAV", O_READ);

will then open "/MUSIC/BIGBAND.WAV" on sd2.

The following functions are used to change or get current directories.
See the html documentation for more information.

bool SdFat::chdir(bool set_cwd = false);
bool SdFat::chdir(const char* path, bool set_cwd = false);
void SdFat::chvol();
SdBaseFile* SdFat::vwd();
static SdBaseFile* SdBaseFile::cwd();

+ 4
- 0
changes.txt Переглянути файл

@@ -1,3 +1,7 @@
04 Dec 2014

Added support for Long File Names.

14 Nov 2014

Replaced the core SdFat code with FatLib, a generic FAT12/FAT16/FAT32

+ 2
- 2
html/_arduino_stream_8h.html Переглянути файл

@@ -100,7 +100,7 @@ Include dependency graph for ArduinoStream.h:</div>
<div class="dyncontent">
<div class="center"><img src="_arduino_stream_8h__incl.png" border="0" usemap="#_arduino_2libraries_2_sd_fat_2utility_2_arduino_stream_8h" alt=""/></div>
<map name="_arduino_2libraries_2_sd_fat_2utility_2_arduino_stream_8h" id="_arduino_2libraries_2_sd_fat_2utility_2_arduino_stream_8h">
<area shape="rect" id="node5" href="bufstream_8h.html" title="ibufstream and obufstream classes " alt="" coords="301,96,392,123"/> <area shape="rect" id="node9" href="iostream_8h.html" title="iostream class " alt="" coords="305,171,388,197"/> <area shape="rect" id="node11" href="istream_8h.html" title="istream class " alt="" coords="255,245,331,272"/> <area shape="rect" id="node38" href="ostream_8h.html" title="ostream class " alt="" coords="356,245,436,272"/> <area shape="rect" id="node13" href="ios_8h.html" title="ios_base and ios classes " alt="" coords="320,320,371,347"/> <area shape="rect" id="node15" href="_fat_file_8h.html" title="FatFile class. " alt="" coords="309,395,381,421"/> <area shape="rect" id="node24" href="_fat_lib_config_8h.html" title="configuration definitions " alt="" coords="425,544,529,571"/> <area shape="rect" id="node30" href="_fat_structs_8h.html" title="FAT file structures. " alt="" coords="115,544,209,571"/> <area shape="rect" id="node32" href="_fat_volume_8h.html" title="FatVolume class. " alt="" coords="157,469,253,496"/> <area shape="rect" id="node26" href="_sd_fat_config_8h.html" title="configuration definitions " alt="" coords="419,619,535,645"/> </map>
<area shape="rect" id="node5" href="bufstream_8h.html" title="ibufstream and obufstream classes " alt="" coords="80,96,171,123"/> <area shape="rect" id="node9" href="iostream_8h.html" title="iostream class " alt="" coords="151,171,233,197"/> <area shape="rect" id="node11" href="istream_8h.html" title="istream class " alt="" coords="255,245,331,272"/> <area shape="rect" id="node36" href="ostream_8h.html" title="ostream class " alt="" coords="151,245,231,272"/> <area shape="rect" id="node13" href="ios_8h.html" title="ios_base and ios classes " alt="" coords="256,320,307,347"/> <area shape="rect" id="node15" href="_fat_file_8h.html" title="FatFile class. " alt="" coords="245,395,317,421"/> <area shape="rect" id="node22" href="_fat_lib_config_8h.html" title="configuration definitions " alt="" coords="427,544,532,571"/> <area shape="rect" id="node28" href="_fat_structs_8h.html" title="FAT file structures. " alt="" coords="179,544,273,571"/> <area shape="rect" id="node30" href="_fat_volume_8h.html" title="FatVolume class. " alt="" coords="221,469,317,496"/> <area shape="rect" id="node24" href="_sd_fat_config_8h.html" title="configuration definitions " alt="" coords="422,619,537,645"/> </map>
</div>
</div><table class="memberdecls">
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="nested-classes"></a>
@@ -117,7 +117,7 @@ Classes</h2></td></tr>
</div></div><!-- contents -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Sat Nov 15 2014 10:05:35 for SdFat by &#160;<a href="http://www.doxygen.org/index.html">
Generated on Thu Dec 4 2014 08:53:20 for SdFat by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.8
</small></address>

BIN
html/_arduino_stream_8h__incl.png Переглянути файл

Before After
Width: 628  |  Height: 725  |  Size: 39KB Width: 543  |  Height: 725  |  Size: 33KB

+ 1
- 1
html/_digital_pin_8h.html Переглянути файл

@@ -151,7 +151,7 @@ Variables</h2></td></tr>
</div></div><!-- contents -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Sat Nov 15 2014 10:05:35 for SdFat by &#160;<a href="http://www.doxygen.org/index.html">
Generated on Thu Dec 4 2014 08:53:20 for SdFat by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.8
</small></address>

+ 98
- 14
html/_fat_file_8h.html Переглянути файл

@@ -87,7 +87,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
<div class="summary">
<a href="#nested-classes">Classes</a> &#124;
<a href="#define-members">Macros</a> &#124;
<a href="#typedef-members">Typedefs</a> </div>
<a href="#var-members">Variables</a> </div>
<div class="headertitle">
<div class="title">FatFile.h File Reference</div> </div>
</div><!--header-->
@@ -95,21 +95,19 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');

<p><a class="el" href="class_fat_file.html" title="Basic file class. ">FatFile</a> class.
<a href="#details">More...</a></p>
<div class="textblock"><code>#include &lt;ctype.h&gt;</code><br />
<code>#include &lt;string.h&gt;</code><br />
<div class="textblock"><code>#include &lt;string.h&gt;</code><br />
<code>#include &lt;stddef.h&gt;</code><br />
<code>#include &lt;limits.h&gt;</code><br />
<code>#include &quot;<a class="el" href="_fat_lib_config_8h.html">FatLibConfig.h</a>&quot;</code><br />
<code>#include &quot;FatApiConstants.h&quot;</code><br />
<code>#include &quot;<a class="el" href="_fat_structs_8h.html">FatStructs.h</a>&quot;</code><br />
<code>#include &quot;<a class="el" href="_fat_volume_8h.html">FatVolume.h</a>&quot;</code><br />
<code>#include &lt;Arduino.h&gt;</code><br />
</div><div class="textblock"><div class="dynheader">
Include dependency graph for FatFile.h:</div>
<div class="dyncontent">
<div class="center"><img src="_fat_file_8h__incl.png" border="0" usemap="#_arduino_2libraries_2_sd_fat_2utility_2_fat_file_8h" alt=""/></div>
<map name="_arduino_2libraries_2_sd_fat_2utility_2_fat_file_8h" id="_arduino_2libraries_2_sd_fat_2utility_2_fat_file_8h">
<area shape="rect" id="node11" href="_fat_lib_config_8h.html" title="configuration definitions " alt="" coords="249,171,353,197"/> <area shape="rect" id="node17" href="_fat_structs_8h.html" title="FAT file structures. " alt="" coords="378,171,472,197"/> <area shape="rect" id="node19" href="_fat_volume_8h.html" title="FatVolume class. " alt="" coords="235,96,331,123"/> <area shape="rect" id="node13" href="_sd_fat_config_8h.html" title="configuration definitions " alt="" coords="243,245,359,272"/> </map>
<area shape="rect" id="node9" href="_fat_lib_config_8h.html" title="configuration definitions " alt="" coords="106,171,211,197"/> <area shape="rect" id="node15" href="_fat_structs_8h.html" title="FAT file structures. " alt="" coords="338,171,432,197"/> <area shape="rect" id="node17" href="_fat_volume_8h.html" title="FatVolume class. " alt="" coords="196,96,292,123"/> <area shape="rect" id="node11" href="_sd_fat_config_8h.html" title="configuration definitions " alt="" coords="101,245,216,272"/> </map>
</div>
</div><div class="textblock"><div class="dynheader">
This graph shows which files directly or indirectly include this file:</div>
@@ -127,9 +125,14 @@ Classes</h2></td></tr>
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="struct_fat_pos__t.html">FatPos_t</a></td></tr>
<tr class="memdesc:"><td class="mdescLeft">&#160;</td><td class="mdescRight">Internal type for file position - do not use in user apps. <a href="struct_fat_pos__t.html#details">More...</a><br /></td></tr>
<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:"><td class="memItemLeft" align="right" valign="top">struct &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structfname__t.html">fname_t</a></td></tr>
<tr class="memdesc:"><td class="mdescLeft">&#160;</td><td class="mdescRight">Internal type for Short <a class="el" href="class_file.html" title="Arduino SD.h style File API. ">File</a> Name - do not use in user apps. <a href="structfname__t.html#details">More...</a><br /></td></tr>
<tr class="separator:"><td class="memSeparator" colspan="2">&#160;</td></tr>
</table><table class="memberdecls">
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="define-members"></a>
Macros</h2></td></tr>
<tr class="memitem:a9f85580ad6f1dfc86fff09a58ff0a1c0"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="_fat_file_8h.html#a9f85580ad6f1dfc86fff09a58ff0a1c0">isDirSeparator</a>(c)&#160;&#160;&#160;((c) == '/')</td></tr>
<tr class="separator:a9f85580ad6f1dfc86fff09a58ff0a1c0"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a963f816fc88a5d8479c285ed4c630229"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="_fat_file_8h.html#a963f816fc88a5d8479c285ed4c630229">PGM_P</a>&#160;&#160;&#160;const char*</td></tr>
<tr class="separator:a963f816fc88a5d8479c285ed4c630229"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a48c60b057902adf805797f183286728d"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="_fat_file_8h.html#a48c60b057902adf805797f183286728d">pgm_read_byte</a>(addr)&#160;&#160;&#160;(*(const unsigned char*)(addr))</td></tr>
@@ -141,14 +144,39 @@ Macros</h2></td></tr>
<tr class="memitem:a9c00057fd19e916cc1aa0a5949336beb"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="_fat_file_8h.html#a9c00057fd19e916cc1aa0a5949336beb">PSTR</a>(x)&#160;&#160;&#160;(x)</td></tr>
<tr class="separator:a9c00057fd19e916cc1aa0a5949336beb"><td class="memSeparator" colspan="2">&#160;</td></tr>
</table><table class="memberdecls">
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="typedef-members"></a>
Typedefs</h2></td></tr>
<tr class="memitem:ac62f6449331cfe1a71f29be30efe7890"><td class="memItemLeft" align="right" valign="top">typedef Print&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="_fat_file_8h.html#ac62f6449331cfe1a71f29be30efe7890">print_t</a></td></tr>
<tr class="separator:ac62f6449331cfe1a71f29be30efe7890"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="var-members"></a>
Variables</h2></td></tr>
<tr class="memitem:a79e43960e1b4eecf274f5faea9c3168c"><td class="memItemLeft" align="right" valign="top">const uint8_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="_fat_file_8h.html#a79e43960e1b4eecf274f5faea9c3168c">FNAME_FLAG_LC_BASE</a> = <a class="el" href="_fat_structs_8h.html#a39f9b8960dba007b537e9b71c25384fe">DIR_NT_LC_BASE</a></td></tr>
<tr class="separator:a79e43960e1b4eecf274f5faea9c3168c"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a135b7572768b09661aa38afaceec7296"><td class="memItemLeft" align="right" valign="top">const uint8_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="_fat_file_8h.html#a135b7572768b09661aa38afaceec7296">FNAME_FLAG_LC_EXT</a> = <a class="el" href="_fat_structs_8h.html#a8766a8bbab6ad3da38c1b308545d7572">DIR_NT_LC_EXT</a></td></tr>
<tr class="separator:a135b7572768b09661aa38afaceec7296"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:acd45286b7dfc5ba68be18c8c3a9d298d"><td class="memItemLeft" align="right" valign="top">const uint8_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="_fat_file_8h.html#acd45286b7dfc5ba68be18c8c3a9d298d">FNAME_FLAG_LOST_CHARS</a> = 0X01</td></tr>
<tr class="separator:acd45286b7dfc5ba68be18c8c3a9d298d"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a63994c21f3b723a55247f063a1b01c9c"><td class="memItemLeft" align="right" valign="top">const uint8_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="_fat_file_8h.html#a63994c21f3b723a55247f063a1b01c9c">FNAME_FLAG_MIXED_CASE</a> = 0X02</td></tr>
<tr class="separator:a63994c21f3b723a55247f063a1b01c9c"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:a1a041207a19d2fd9a1e2739343ccb29b"><td class="memItemLeft" align="right" valign="top">const uint8_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="_fat_file_8h.html#a1a041207a19d2fd9a1e2739343ccb29b">FNAME_FLAG_NEED_LFN</a></td></tr>
<tr class="separator:a1a041207a19d2fd9a1e2739343ccb29b"><td class="memSeparator" colspan="2">&#160;</td></tr>
</table>
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
<div class="textblock"><p><a class="el" href="class_fat_file.html" title="Basic file class. ">FatFile</a> class. </p>
</div><h2 class="groupheader">Macro Definition Documentation</h2>
<a class="anchor" id="a9f85580ad6f1dfc86fff09a58ff0a1c0"></a>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">#define isDirSeparator</td>
<td>(</td>
<td class="paramtype">&#160;</td>
<td class="paramname">c</td><td>)</td>
<td>&#160;&#160;&#160;((c) == '/')</td>
</tr>
</table>
</div><div class="memdoc">
<p>Expression for path name separator. </p>

</div>
</div>
<a class="anchor" id="a963f816fc88a5d8479c285ed4c630229"></a>
<div class="memitem">
<div class="memproto">
@@ -226,24 +254,80 @@ Typedefs</h2></td></tr>

</div>
</div>
<h2 class="groupheader">Typedef Documentation</h2>
<a class="anchor" id="ac62f6449331cfe1a71f29be30efe7890"></a>
<h2 class="groupheader">Variable Documentation</h2>
<a class="anchor" id="a79e43960e1b4eecf274f5faea9c3168c"></a>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">const uint8_t FNAME_FLAG_LC_BASE = <a class="el" href="_fat_structs_8h.html#a39f9b8960dba007b537e9b71c25384fe">DIR_NT_LC_BASE</a></td>
</tr>
</table>
</div><div class="memdoc">
<p>Filename base-name is all lower case </p>

</div>
</div>
<a class="anchor" id="a135b7572768b09661aa38afaceec7296"></a>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">const uint8_t FNAME_FLAG_LC_EXT = <a class="el" href="_fat_structs_8h.html#a8766a8bbab6ad3da38c1b308545d7572">DIR_NT_LC_EXT</a></td>
</tr>
</table>
</div><div class="memdoc">
<p>Filename extension is all lower case. </p>

</div>
</div>
<a class="anchor" id="acd45286b7dfc5ba68be18c8c3a9d298d"></a>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">const uint8_t FNAME_FLAG_LOST_CHARS = 0X01</td>
</tr>
</table>
</div><div class="memdoc">
<p>Derived from a LFN with loss or conversion of characters. </p>

</div>
</div>
<a class="anchor" id="a63994c21f3b723a55247f063a1b01c9c"></a>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">const uint8_t FNAME_FLAG_MIXED_CASE = 0X02</td>
</tr>
</table>
</div><div class="memdoc">
<p>Base-name or extension has mixed case. </p>

</div>
</div>
<a class="anchor" id="a1a041207a19d2fd9a1e2739343ccb29b"></a>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">typedef Print <a class="el" href="_fat_file_8h.html#ac62f6449331cfe1a71f29be30efe7890">print_t</a></td>
<td class="memname">const uint8_t FNAME_FLAG_NEED_LFN</td>
</tr>
</table>
</div><div class="memdoc">
<p>Use Print on Arduino </p>
<b>Initial value:</b><div class="fragment"><div class="line">=</div>
<div class="line"> <a class="code" href="_fat_file_8h.html#acd45286b7dfc5ba68be18c8c3a9d298d">FNAME_FLAG_LOST_CHARS</a> | <a class="code" href="_fat_file_8h.html#a63994c21f3b723a55247f063a1b01c9c">FNAME_FLAG_MIXED_CASE</a></div>
<div class="ttc" id="_fat_file_8h_html_a63994c21f3b723a55247f063a1b01c9c"><div class="ttname"><a href="_fat_file_8h.html#a63994c21f3b723a55247f063a1b01c9c">FNAME_FLAG_MIXED_CASE</a></div><div class="ttdeci">const uint8_t FNAME_FLAG_MIXED_CASE</div><div class="ttdef"><b>Definition:</b> FatFile.h:96</div></div>
<div class="ttc" id="_fat_file_8h_html_acd45286b7dfc5ba68be18c8c3a9d298d"><div class="ttname"><a href="_fat_file_8h.html#acd45286b7dfc5ba68be18c8c3a9d298d">FNAME_FLAG_LOST_CHARS</a></div><div class="ttdeci">const uint8_t FNAME_FLAG_LOST_CHARS</div><div class="ttdef"><b>Definition:</b> FatFile.h:94</div></div>
</div><!-- fragment --><p>LFN entries are required for file name. </p>

</div>
</div>
</div><!-- contents -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Sat Nov 15 2014 10:05:35 for SdFat by &#160;<a href="http://www.doxygen.org/index.html">
Generated on Thu Dec 4 2014 08:53:20 for SdFat by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.8
</small></address>

+ 0
- 0
html/_fat_file_8h__incl.png Переглянути файл

Before After
Width: 627  |  Height: 352  |  Size: 20KB Width: 437  |  Height: 352  |  Size: 19KB

Деякі файли не було показано, через те що забагато файлів було змінено

Завантаження…
Відмінити
Зберегти