瀏覽代碼

New core FAT implementation

main
Bill Greiman 10 年之前
父節點
當前提交
8408432732
共有 100 個檔案被更改,包括 4832 行新增3765 行删除
  1. +3
    -18
      SdFat/MinimumSerial.cpp
  2. +17
    -3
      SdFat/MinimumSerial.h
  3. +0
    -202
      SdFat/Sd2Card.h
  4. +0
    -289
      SdFat/SdBaseFile.h
  5. +0
    -351
      SdFat/SdBaseFilePrint.cpp
  6. +0
    -261
      SdFat/SdFat.cpp
  7. +273
    -73
      SdFat/SdFat.h
  8. +106
    -0
      SdFat/SdFatBase.cpp
  9. +42
    -55
      SdFat/SdFatConfig.h
  10. +0
    -145
      SdFat/SdFatErrorPrint.cpp
  11. +12
    -26
      SdFat/SdFatUtil.cpp
  12. +18
    -2
      SdFat/SdFatUtil.h
  13. +41
    -17
      SdFat/SdFatmainpage.h
  14. +0
    -83
      SdFat/SdFile.cpp
  15. +134
    -96
      SdFat/SdFile.h
  16. +90
    -12
      SdFat/SdInfo.h
  17. +250
    -59
      SdFat/SdSpi.h
  18. +0
    -86
      SdFat/SdSpiAVR.cpp
  19. +0
    -70
      SdFat/SdSpiArduino.cpp
  20. +84
    -174
      SdFat/SdSpiCard.cpp
  21. +281
    -0
      SdFat/SdSpiCard.h
  22. +3
    -3
      SdFat/SdSpiSAM3X.cpp
  23. +0
    -61
      SdFat/SdSpiSoft.cpp
  24. +4
    -4
      SdFat/SdSpiTeensy3.cpp
  25. +31
    -178
      SdFat/SdVolume.h
  26. +2
    -1
      SdFat/examples/#attic/AnalogLogger/AnalogLogger.ino
  27. +1
    -0
      SdFat/examples/#attic/HelloWorld/HelloWorld.ino
  28. +17
    -6
      SdFat/examples/#attic/MiniSerial/MiniSerial.ino
  29. +4
    -4
      SdFat/examples/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino
  30. +1
    -0
      SdFat/examples/#attic/SdFatSize/SdFatSize.ino
  31. +2
    -1
      SdFat/examples/#attic/append/append.ino
  32. +1
    -0
      SdFat/examples/#attic/average/average.ino
  33. +0
    -2
      SdFat/examples/#attic/benchSD/benchSD.ino
  34. +1
    -0
      SdFat/examples/#attic/bufstream/bufstream.ino
  35. +1
    -0
      SdFat/examples/#attic/eventlog/eventlog.ino
  36. +3
    -2
      SdFat/examples/#attic/fgetsRewrite/fgetsRewrite.ino
  37. +1
    -0
      SdFat/examples/#attic/readlog/readlog.ino
  38. +0
    -2
      SdFat/examples/#attic/readme.txt
  39. +8
    -4
      SdFat/examples/AnalogBinLogger/AnalogBinLogger.ino
  40. +87
    -0
      SdFat/examples/LongFileName/LongFileName.ino
  41. +4
    -0
      SdFat/examples/LongFileName/testFiles/A long name can be 255 characters.txt
  42. +1
    -0
      SdFat/examples/LongFileName/testFiles/LFN,NAME.TXT
  43. +5
    -0
      SdFat/examples/LongFileName/testFiles/MIXCASE.txt
  44. +2
    -0
      SdFat/examples/LongFileName/testFiles/Not_8_3.txt
  45. +1
    -0
      SdFat/examples/LongFileName/testFiles/OK%83.TXT
  46. +1
    -0
      SdFat/examples/LongFileName/testFiles/STD_8_3.TXT
  47. +2
    -0
      SdFat/examples/LongFileName/testFiles/With Blank.txt
  48. +2
    -0
      SdFat/examples/LongFileName/testFiles/With Two.dots.txt
  49. +5
    -0
      SdFat/examples/LongFileName/testFiles/lower.txt
  50. +5
    -0
      SdFat/examples/LongFileName/testFiles/mixed.TXT
  51. +5
    -3
      SdFat/examples/LowLatencyLogger/LowLatencyLogger.ino
  52. +1
    -0
      SdFat/examples/OpenNext/OpenNext.ino
  53. +3
    -2
      SdFat/examples/PrintBenchmark/PrintBenchmark.ino
  54. +41
    -42
      SdFat/examples/QuickStart/QuickStart.ino
  55. +5
    -11
      SdFat/examples/RawWrite/RawWrite.ino
  56. +1
    -0
      SdFat/examples/ReadWriteSdFat/ReadWriteSdFat.ino
  57. +3
    -2
      SdFat/examples/SdFormatter/SdFormatter.ino
  58. +49
    -31
      SdFat/examples/SdInfo/SdInfo.ino
  59. +46
    -0
      SdFat/examples/SoftwareSpi/SoftwareSpi.ino
  60. +4
    -1
      SdFat/examples/StdioBench/StdioBench.ino
  61. +14
    -7
      SdFat/examples/StreamParseInt/StreamParseInt.ino
  62. +188
    -0
      SdFat/examples/ThreeCards/ThreeCards.ino
  63. +7
    -6
      SdFat/examples/Timestamp/Timestamp.ino
  64. +16
    -18
      SdFat/examples/TwoCards/TwoCards.ino
  65. +2
    -1
      SdFat/examples/bench/bench.ino
  66. +1
    -0
      SdFat/examples/cin_cout/cin_cout.ino
  67. +2
    -5
      SdFat/examples/dataLogger/dataLogger.ino
  68. +2
    -5
      SdFat/examples/directoryFunctions/directoryFunctions.ino
  69. +3
    -2
      SdFat/examples/fgets/fgets.ino
  70. +1
    -0
      SdFat/examples/formatting/formatting.ino
  71. +1
    -0
      SdFat/examples/getline/getline.ino
  72. +2
    -1
      SdFat/examples/readCSV/readCSV.ino
  73. +2
    -1
      SdFat/examples/rename/rename.ino
  74. +8
    -5
      SdFat/utility/ArduinoStream.h
  75. +26
    -26
      SdFat/utility/DigitalPin.h
  76. +1
    -1
      SdFat/utility/FatApiConstants.h
  77. +335
    -792
      SdFat/utility/FatFile.cpp
  78. +857
    -0
      SdFat/utility/FatFile.h
  79. +302
    -0
      SdFat/utility/FatFileLFN.cpp
  80. +241
    -0
      SdFat/utility/FatFilePrint.cpp
  81. +247
    -0
      SdFat/utility/FatFileSystem.h
  82. +29
    -0
      SdFat/utility/FatLib.h
  83. +90
    -0
      SdFat/utility/FatLibConfig.h
  84. +98
    -14
      SdFat/utility/FatStructs.h
  85. +178
    -289
      SdFat/utility/FatVolume.cpp
  86. +257
    -0
      SdFat/utility/FatVolume.h
  87. +13
    -3
      SdFat/utility/FmtNumber.cpp
  88. +3
    -1
      SdFat/utility/FmtNumber.h
  89. +1
    -1
      SdFat/utility/SoftSPI.h
  90. +24
    -25
      SdFat/utility/StdioStream.cpp
  91. +8
    -10
      SdFat/utility/StdioStream.h
  92. +6
    -5
      SdFat/utility/bufstream.h
  93. +18
    -20
      SdFat/utility/fstream.cpp
  94. +50
    -50
      SdFat/utility/fstream.h
  95. +5
    -5
      SdFat/utility/ios.h
  96. +6
    -6
      SdFat/utility/iostream.h
  97. +7
    -72
      SdFat/utility/istream.cpp
  98. +70
    -6
      SdFat/utility/istream.h
  99. +7
    -6
      SdFat/utility/ostream.cpp
  100. +0
    -0
      SdFat/utility/ostream.h

+ 3
- 18
SdFat/MinimumSerial.cpp 查看文件

@@ -19,17 +19,13 @@
*/
#include <Arduino.h>
#if defined(UDR0) || defined(DOXYGEN)
#include <MinimumSerial.h>
#include "MinimumSerial.h"
const uint16_t MIN_2X_BAUD = F_CPU/(4*(2*0XFFF + 1)) + 1;
//------------------------------------------------------------------------------
/**
* Set baud rate for serial port zero and enable in non interrupt mode.
* Do not call this function if you use another serial library.
* \param[in] baud rate
*/
void MinimumSerial::begin(uint32_t baud) {
uint16_t baud_setting;
// don't worry, the compiler will squeeze out F_CPU != 16000000UL
if (F_CPU != 16000000UL || baud != 57600) {
if ((F_CPU != 16000000UL || baud != 57600) && baud > MIN_2X_BAUD) {
// Double the USART Transmission Speed
UCSR0A = 1 << U2X0;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
@@ -47,25 +43,14 @@ void MinimumSerial::begin(uint32_t baud) {
UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
}
//------------------------------------------------------------------------------
/**
* Unbuffered read
* \return -1 if no character is available or an available character.
*/
int MinimumSerial::read() {
if (UCSR0A & (1 << RXC0)) return UDR0;
return -1;
}
//------------------------------------------------------------------------------
/**
* Unbuffered write
*
* \param[in] b byte to write.
* \return 1
*/
size_t MinimumSerial::write(uint8_t b) {
while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {}
UDR0 = b;
return 1;
}
MinimumSerial MiniSerial;
#endif // defined(UDR0) || defined(DOXYGEN)

+ 17
- 3
SdFat/MinimumSerial.h 查看文件

@@ -19,18 +19,32 @@
*/
#ifndef MinimumSerial_h
#define MinimumSerial_h
#include <Arduino.h>
//==============================================================================
/**
* \class MinimumSerial
* \brief mini serial class for the %SdFat library.
*/
class MinimumSerial : public Print {
public:
/**
* Set baud rate for serial port zero and enable in non interrupt mode.
* Do not call this function if you use another serial library.
* \param[in] baud rate
*/
void begin(uint32_t baud);
/**
* 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
*/
size_t write(uint8_t b);
using Print::write;
};
#ifdef UDR0
extern MinimumSerial MiniSerial;
#endif // UDR0
#endif // MinimumSerial_h

+ 0
- 202
SdFat/Sd2Card.h 查看文件

@@ -1,202 +0,0 @@
/* Arduino Sd2Card Library
* Copyright (C) 2012 by William Greiman
*
* This file is part of the Arduino Sd2Card 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 Arduino Sd2Card Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SpiCard_h
#define SpiCard_h
/**
* \file
* \brief Sd2Card class for V2 SD/SDHC cards
*/
#include <Arduino.h>
#include <SdFatConfig.h>
#include <SdInfo.h>
#include <SdSpi.h>
//------------------------------------------------------------------------------
// SD card errors
/** timeout error for command CMD0 (initialize card in SPI mode) */
uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
/** CMD8 was not accepted - not a valid SD card*/
uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
/** card returned an error response for CMD12 (stop multiblock read) */
uint8_t const SD_CARD_ERROR_CMD12 = 0X3;
/** card returned an error response for CMD17 (read block) */
uint8_t const SD_CARD_ERROR_CMD17 = 0X4;
/** card returned an error response for CMD18 (read multiple block) */
uint8_t const SD_CARD_ERROR_CMD18 = 0X5;
/** card returned an error response for CMD24 (write block) */
uint8_t const SD_CARD_ERROR_CMD24 = 0X6;
/** WRITE_MULTIPLE_BLOCKS command failed */
uint8_t const SD_CARD_ERROR_CMD25 = 0X7;
/** card returned an error response for CMD58 (read OCR) */
uint8_t const SD_CARD_ERROR_CMD58 = 0X8;
/** SET_WR_BLK_ERASE_COUNT failed */
uint8_t const SD_CARD_ERROR_ACMD23 = 0X9;
/** ACMD41 initialization process timeout */
uint8_t const SD_CARD_ERROR_ACMD41 = 0XA;
/** card returned a bad CSR version field */
uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB;
/** erase block group command failed */
uint8_t const SD_CARD_ERROR_ERASE = 0XC;
/** card not capable of single block erase */
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD;
/** Erase sequence timed out */
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE;
/** card returned an error token instead of read data */
uint8_t const SD_CARD_ERROR_READ = 0XF;
/** read CID or CSD failed */
uint8_t const SD_CARD_ERROR_READ_REG = 0X10;
/** timeout while waiting for start of read data */
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11;
/** card did not accept STOP_TRAN_TOKEN */
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12;
/** card returned an error token as a response to a write operation */
uint8_t const SD_CARD_ERROR_WRITE = 0X13;
/** attempt to write protected block zero */
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14; // REMOVE - not used
/** card did not go ready for a multiple block write */
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15;
/** card returned an error to a CMD13 status check after a write */
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16;
/** timeout occurred during write programming */
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17;
/** incorrect rate selected */
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18;
/** init() not called */
uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
/** card returned an error for CMD59 (CRC_ON_OFF) */
uint8_t const SD_CARD_ERROR_CMD59 = 0X1A;
/** invalid read CRC */
uint8_t const SD_CARD_ERROR_READ_CRC = 0X1B;
/** SPI DMA error */
uint8_t const SD_CARD_ERROR_SPI_DMA = 0X1C;
//------------------------------------------------------------------------------
// card types
/** Standard capacity V1 SD card */
uint8_t const SD_CARD_TYPE_SD1 = 1;
/** Standard capacity V2 SD card */
uint8_t const SD_CARD_TYPE_SD2 = 2;
/** High Capacity SD card */
uint8_t const SD_CARD_TYPE_SDHC = 3;
//------------------------------------------------------------------------------
/**
* \class Sd2Card
* \brief Raw access to SD and SDHC flash memory cards.
*/
class Sd2Card {
public:
/** Construct an instance of Sd2Card. */
Sd2Card() : m_errorCode(SD_CARD_ERROR_INIT_NOT_CALLED), m_type(0) {}
bool begin(uint8_t chipSelectPin = SD_CHIP_SELECT_PIN,
uint8_t sckDivisor = SPI_FULL_SPEED);
uint32_t cardSize();
bool erase(uint32_t firstBlock, uint32_t lastBlock);
bool eraseSingleBlockEnable();
/**
* Set SD error code.
* \param[in] code value for error code.
*/
void error(uint8_t code) {m_errorCode = code;}
/**
* \return error code for last error. See Sd2Card.h for a list of error codes.
*/
int errorCode() const {return m_errorCode;}
/** \return error data for last error. */
int errorData() const {return m_status;}
/**
* Initialize an SD flash memory card.
*
* \param[in] chipSelectPin SD chip select pin number.
* \param[in] sckDivisor SPI SCK clock rate divisor.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. The reason for failure
* can be determined by calling errorCode() and errorData().
*/
bool init(uint8_t sckDivisor = SPI_FULL_SPEED,
uint8_t chipSelectPin = SD_CHIP_SELECT_PIN) {
return begin(chipSelectPin, sckDivisor);
}
bool isBusy();
bool readBlock(uint32_t block, uint8_t* dst);
/**
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
* number and Manufacturing date.
*
* \param[out] cid pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCID(cid_t* cid) {
return readRegister(CMD10, cid);
}
/**
* Read a card's CSD register. The CSD contains Card-Specific Data that
* provides information regarding access to the card's contents.
*
* \param[out] csd pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCSD(csd_t* csd) {
return readRegister(CMD9, csd);
}
bool readData(uint8_t *dst);
bool readOCR(uint32_t* ocr);
bool readStart(uint32_t blockNumber);
bool readStop();
/** Return SCK divisor.
*
* \return Requested SCK divisor.
*/
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;}
bool writeBlock(uint32_t blockNumber, const uint8_t* src);
bool writeData(const uint8_t* src);
bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
bool writeStop();

private:
//----------------------------------------------------------------------------
// private functions
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
cardCommand(CMD55, 0);
return cardCommand(cmd, arg);
}
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
bool readData(uint8_t* dst, size_t count);
bool readRegister(uint8_t cmd, void* buf);
void chipSelectHigh();
void chipSelectLow();
void spiYield();
void type(uint8_t value) {m_type = value;}
bool waitNotBusy(uint16_t timeoutMillis);
bool writeData(uint8_t token, const uint8_t* src);
// private data
static SdSpi m_spi;
uint8_t m_chipSelectPin;
uint8_t m_errorCode;
uint8_t m_sckDivisor;
uint8_t m_status;
uint8_t m_type;
};
#endif // SpiCard_h

+ 0
- 289
SdFat/SdBaseFile.h 查看文件

@@ -1,289 +0,0 @@
/* 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
* 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 Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SdBaseFile_h
#define SdBaseFile_h
/**
* \file
* \brief SdBaseFile class
*/
#ifdef __AVR__
#include <avr/pgmspace.h>
#else // __AVR__
#ifndef PGM_P
/** pointer to flash for ARM */
#define PGM_P const char*
#endif // PGM_P
#ifndef PSTR
/** store literal string in flash for ARM */
#define PSTR(x) (x)
#endif // PSTR
#ifndef pgm_read_byte
/** read 8-bits from flash for ARM */
#define pgm_read_byte(addr) (*(const unsigned char*)(addr))
#endif // pgm_read_byte
#ifndef pgm_read_word
/** read 16-bits from flash for ARM */
#define pgm_read_word(addr) (*(const uint16_t*)(addr))
#endif // pgm_read_word
#ifndef PROGMEM
/** store in flash for ARM */
#define PROGMEM const
#endif // PROGMEM
#endif // __AVR__
#include <Arduino.h>
#include <SdFatConfig.h>
#include <SdVolume.h>
#include <utility/FatApiConstants.h>
//------------------------------------------------------------------------------
/**
* \struct FatPos_t
* \brief internal type for istream
* do not use in user apps
*/
struct FatPos_t {
/** stream position */
uint32_t position;
/** cluster for position */
uint32_t cluster;
FatPos_t() : position(0), cluster(0) {}
};

// values for m_type
/** This file has not been opened. */
uint8_t const FAT_FILE_TYPE_CLOSED = 0;
/** A normal file */
uint8_t const FAT_FILE_TYPE_NORMAL = 1;
/** A FAT12 or FAT16 root directory */
uint8_t const FAT_FILE_TYPE_ROOT_FIXED = 2;
/** A FAT32 root directory */
uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
/** A subdirectory file*/
uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
/** Test value for directory type */
uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT_FIXED;

//------------------------------------------------------------------------------
/**
* \class SdBaseFile
* \brief Base class for SdFile with Print and C++ streams.
*/
class SdBaseFile {
public:
/** Create an instance. */
SdBaseFile() : writeError(false), m_type(FAT_FILE_TYPE_CLOSED) {}
SdBaseFile(const char* path, uint8_t oflag);
#if DESTRUCTOR_CLOSES_FILE
~SdBaseFile() {if(isOpen()) close();}
#endif // DESTRUCTOR_CLOSES_FILE
/**
* writeError is set to true if an error occurs during a write().
* Set writeError to false before calling print() and/or write() and check
* for true after calls to print() and/or write().
*/
bool writeError;
/** \return value of writeError */
bool getWriteError() {return writeError;}
/** Set writeError to zero */
void clearWriteError() {writeError = 0;}
//----------------------------------------------------------------------------
// helpers for stream classes
/** get position for streams
* \param[out] pos struct to receive position
*/
void getpos(FatPos_t* pos);
/** set position for streams
* \param[out] pos struct with value for new position
*/
void setpos(FatPos_t* pos);
//----------------------------------------------------------------------------
/** \return number of bytes available from yhe current position to EOF */
uint32_t available() {return fileSize() - curPosition();}
bool close();
bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
bool createContiguous(SdBaseFile* dirFile,
const char* path, uint32_t size);
/** \return The current cluster number for a file or directory. */
uint32_t curCluster() const {return m_curCluster;}
/** \return The current position for a file or directory. */
uint32_t curPosition() const {return m_curPosition;}
/** \return Current working directory */
static SdBaseFile* cwd() {return m_cwd;}
/** Set the date/time callback function
*
* \param[in] dateTime The user's call back function. The callback
* function is of the form:
*
* \code
* void dateTime(uint16_t* date, uint16_t* time) {
* uint16_t year;
* uint8_t month, day, hour, minute, second;
*
* // User gets date and time from GPS or real-time clock here
*
* // return date using FAT_DATE macro to format fields
* *date = FAT_DATE(year, month, day);
*
* // return time using FAT_TIME macro to format fields
* *time = FAT_TIME(hour, minute, second);
* }
* \endcode
*
* Sets the function that is called when a file is created or when
* a file's directory entry is modified by sync(). All timestamps,
* access, creation, and modify, are set when a file is created.
* sync() maintains the last access date and last modify date/time.
*
* See the timestamp() function.
*/
static void dateTimeCallback(
void (*dateTime)(uint16_t* date, uint16_t* time)) {
m_dateTime = dateTime;
}
/** Cancel the date/time callback function. */
static void dateTimeCallbackCancel() {m_dateTime = 0;}
bool dirEntry(dir_t* dir);
static void dirName(const dir_t& dir, char* name);
bool exists(const char* name);
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 first cluster number for a file or directory. */
uint32_t firstCluster() const {return m_firstCluster;}
bool getFilename(char* name);
/** \return True if this is a directory else false. */
bool isDir() const {return m_type >= FAT_FILE_TYPE_MIN_DIR;}
/** \return True if this is a normal file else false. */
bool isFile() const {return m_type == FAT_FILE_TYPE_NORMAL;}
/** \return True if this is an open file/directory else false. */
bool isOpen() const {return m_type != FAT_FILE_TYPE_CLOSED;}
/** \return True if this is a subdirectory else false. */
bool isSubDir() const {return m_type == FAT_FILE_TYPE_SUBDIR;}
/** \return True if this is the root directory. */
bool isRoot() const {
return m_type == FAT_FILE_TYPE_ROOT_FIXED || m_type == FAT_FILE_TYPE_ROOT32;
}
void ls(Print* pr, uint8_t flags = 0, uint8_t indent = 0);
void ls(uint8_t flags = 0);
bool mkdir(SdBaseFile* dir, const char* path, bool pFlag = true);
// alias for backward compactability
bool makeDir(SdBaseFile* dir, const char* path) {
return mkdir(dir, path, false);
}
bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag);
bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag);
bool open(const char* path, uint8_t oflag = O_READ);
bool openNext(SdBaseFile* dirFile, uint8_t oflag);
bool openRoot(SdVolume* vol);
int peek();
bool printCreateDateTime(Print* pr);
static void printFatDate(uint16_t fatDate);
static void printFatDate(Print* pr, uint16_t fatDate);
static void printFatTime(uint16_t fatTime);
static void printFatTime(Print* pr, uint16_t fatTime);
int printField(float value, char term, uint8_t prec = 2);
int printField(int16_t value, char term);
int printField(uint16_t value, char term);
int printField(int32_t value, char term);
int printField(uint32_t value, char term);
bool printModifyDateTime(Print* pr);
size_t printName();
size_t printName(Print* pr);
size_t printFileSize(Print* pr);
int16_t read();
int read(void* buf, size_t nbyte);
int8_t readDir(dir_t* dir);
static bool remove(SdBaseFile* dirFile, const char* path);
bool remove();
/** Set the file's current position to zero. */
void rewind() {seekSet(0);}
bool rename(SdBaseFile* dirFile, const char* newPath);
bool rmdir();
// for backward compatibility
bool rmDir() {return rmdir();}
bool rmRfStar();
/** Set the files position to current position + \a pos. See seekSet().
* \param[in] offset The new position in bytes from the current position.
* \return true for success or false for failure.
*/
bool seekCur(int32_t offset) {
return seekSet(m_curPosition + offset);
}
/** Set the files position to end-of-file + \a offset. See seekSet().
* \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 seekSet(uint32_t pos);
bool sync();
bool timestamp(SdBaseFile* file);
bool timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
uint8_t hour, uint8_t minute, uint8_t second);
/** Type of file. You should use isFile() or isDir() instead of type()
* if possible.
*
* \return The file or directory type.
*/
uint8_t type() const {return m_type;}
bool truncate(uint32_t size);
/** \return SdVolume that contains this file. */
SdVolume* volume() const {return m_vol;}
int write(const void* buf, size_t nbyte);
//------------------------------------------------------------------------------
private:
// allow SdFat to set m_cwd
friend class SdFat;
/** experimental don't use */
bool openParent(SdBaseFile* dir);

// private functions
bool addCluster();
cache_t* addDirCluster();
dir_t* cacheDirEntry(uint8_t action);
int8_t lsPrintNext(Print *pr, uint8_t flags, uint8_t indent);
static bool make83Name(const char* str, uint8_t* name, const char** ptr);
bool mkdir(SdBaseFile* parent, const uint8_t dname[11]);
bool open(SdBaseFile* dirFile, const uint8_t dname[11], uint8_t oflag);
bool openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
dir_t* readDirCache();
static void setCwd(SdBaseFile* cwd) {m_cwd = cwd;}
bool setDirSize();

// bits defined in m_flags
// should be 0X0F
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
// sync of directory entry required
static uint8_t const F_FILE_DIR_DIRTY = 0X80;

// global pointer to cwd dir
static SdBaseFile* m_cwd;
// data time callback function
static void (*m_dateTime)(uint16_t* date, uint16_t* time);
// private data
uint8_t m_flags; // See above for definition of m_flags bits
uint8_t m_type; // type of file see above for values
uint8_t m_dirIndex; // index of directory entry in dirBlock
SdVolume* m_vol; // volume where file is located
uint32_t m_curCluster; // cluster for current file position
uint32_t m_curPosition; // current file position in bytes from beginning
uint32_t m_dirBlock; // block for this files directory entry
uint32_t m_fileSize; // file size in bytes
uint32_t m_firstCluster; // first cluster of file
};
#endif // SdBaseFile_h

+ 0
- 351
SdFat/SdBaseFilePrint.cpp 查看文件

@@ -1,351 +0,0 @@
/* 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
* 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 Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdFat.h>
#include <utility/FmtNumber.h>
//------------------------------------------------------------------------------
/** List directory contents to stdOut.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*/
void SdBaseFile::ls(uint8_t flags) {
ls(SdFat::stdOut(), flags, 0);
}
//------------------------------------------------------------------------------
/** List directory contents.
*
* \param[in] pr Print stream for list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*
* \param[in] indent Amount of space before file name. Used for recursive
* list to indicate subdirectory level.
*/
void SdBaseFile::ls(Print* pr, uint8_t flags, uint8_t indent) {
if (!isDir()) {
pr->println(F("bad dir"));
return;
}
rewind();
int8_t status;
while ((status = lsPrintNext(pr, flags, indent))) {
if (status > 1 && (flags & LS_R)) {
uint16_t index = curPosition()/32 - 1;
SdBaseFile s;
if (s.open(this, index, O_READ)) s.ls(pr, flags, indent + 2);
seekSet(32 * (index + 1));
}
}
}
//------------------------------------------------------------------------------
// saves 32 bytes on stack for ls recursion
// return 0 - EOF, 1 - normal file, or 2 - directory
int8_t SdBaseFile::lsPrintNext(Print *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(' ');
pr->print(dir.fileSize);
}
pr->println();
return DIR_IS_FILE(&dir) ? 1 : 2;
}
//------------------------------------------------------------------------------
// print uint8_t with width 2
static void print2u(Print* pr, uint8_t v) {
if (v < 10) pr->write('0');
pr->print(v, DEC);
}
//------------------------------------------------------------------------------
/** Print a file's creation date and time
*
* \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.
*/
bool SdBaseFile::printCreateDateTime(Print* pr) {
dir_t dir;
if (!dirEntry(&dir)) {
DBG_FAIL_MACRO;
goto fail;
}
printFatDate(pr, dir.creationDate);
pr->write(' ');
printFatTime(pr, dir.creationTime);
return true;

fail:
return false;
}
//------------------------------------------------------------------------------
/** %Print a directory date field to stdOut.
*
* Format is yyyy-mm-dd.
*
* \param[in] fatDate The date field from a directory entry.
*/
void SdBaseFile::printFatDate(uint16_t fatDate) {
printFatDate(SdFat::stdOut(), fatDate);
}
//------------------------------------------------------------------------------
/** %Print a directory date field.
*
* Format is yyyy-mm-dd.
*
* \param[in] pr Print stream for output.
* \param[in] fatDate The date field from a directory entry.
*/
void SdBaseFile::printFatDate(Print* pr, uint16_t fatDate) {
pr->print(FAT_YEAR(fatDate));
pr->write('-');
print2u(pr, FAT_MONTH(fatDate));
pr->write('-');
print2u(pr, FAT_DAY(fatDate));
}
//------------------------------------------------------------------------------
/** %Print a directory time field to stdOut.
*
* Format is hh:mm:ss.
*
* \param[in] fatTime The time field from a directory entry.
*/
void SdBaseFile::printFatTime(uint16_t fatTime) {
printFatTime(SdFat::stdOut(), fatTime);
}
//------------------------------------------------------------------------------
/** %Print a directory time field.
*
* Format is hh:mm:ss.
*
* \param[in] pr Print stream for output.
* \param[in] fatTime The time field from a directory entry.
*/
void SdBaseFile::printFatTime(Print* pr, uint16_t fatTime) {
print2u(pr, FAT_HOUR(fatTime));
pr->write(':');
print2u(pr, FAT_MINUTE(fatTime));
pr->write(':');
print2u(pr, FAT_SECOND(fatTime));
}
//------------------------------------------------------------------------------
/** Template for SdBaseFile::printField() */
template <typename Type>
static int printFieldT(SdBaseFile* file, char sign, Type value, char term) {
char buf[3*sizeof(Type) + 3];
char* str = &buf[sizeof(buf)];

if (term) {
*--str = term;
if (term == '\n') {
*--str = '\r';
}
}
#ifdef OLD_FMT
do {
Type m = value;
value /= 10;
*--str = '0' + m - 10*value;
} while (value);
#else // OLD_FMT
str = fmtDec(value, str);
#endif // OLD_FMT
if (sign) {
*--str = sign;
}
return file->write(str, &buf[sizeof(buf)] - str);
}
//------------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator. Use '\\n' for CR LF.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
int SdBaseFile::printField(float value, char term, uint8_t prec) {
char buf[24];
char* str = &buf[sizeof(buf)];
if (term) {
*--str = term;
if (term == '\n') {
*--str = '\r';
}
}
str = fmtFloat(value, str, prec);
return write(str, buf + sizeof(buf) - str);
}
//------------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator. Use '\\n' for CR LF.
* \return The number of bytes written or -1 if an error occurs.
*/
int SdBaseFile::printField(uint16_t value, char term) {
return printFieldT(this, 0, value, term);
}
//------------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator. Use '\\n' for CR LF.
* \return The number of bytes written or -1 if an error occurs.
*/
int SdBaseFile::printField(int16_t value, char term) {
char sign = 0;
if (value < 0) {
sign = '-';
value = -value;
}
return printFieldT(this, sign, (uint16_t)value, term);
}
//------------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator. Use '\\n' for CR LF.
* \return The number of bytes written or -1 if an error occurs.
*/
int SdBaseFile::printField(uint32_t value, char term) {
return printFieldT(this, 0, value, term);
}
//------------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator. Use '\\n' for CR LF.
* \return The number of bytes written or -1 if an error occurs.
*/
int SdBaseFile::printField(int32_t value, char term) {
char sign = 0;
if (value < 0) {
sign = '-';
value = -value;
}
return printFieldT(this, sign, (uint32_t)value, term);
}
//------------------------------------------------------------------------------
/** Print a file's modify date and time
*
* \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.
*/
bool SdBaseFile::printModifyDateTime(Print* pr) {
dir_t dir;
if (!dirEntry(&dir)) {
DBG_FAIL_MACRO;
goto fail;
}
printFatDate(pr, dir.lastWriteDate);
pr->write(' ');
printFatTime(pr, dir.lastWriteTime);
return true;

fail:
return false;
}
//------------------------------------------------------------------------------
/** 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.
*/
size_t SdBaseFile::printName(Print* pr) {
char name[13];
if (!getFilename(name)) {
DBG_FAIL_MACRO;
goto fail;
}
return pr->print(name);

fail:
return 0;
}
//------------------------------------------------------------------------------
/** Print a file's name to stdOut
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
size_t SdBaseFile::printName() {
return printName(SdFat::stdOut());
}
//------------------------------------------------------------------------------
/** 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.
*/
size_t SdBaseFile::printFileSize(Print* pr) {
char buf[10];
char *ptr = fmtDec(fileSize(), buf + sizeof(buf));
while (ptr > buf) *--ptr = ' ';
return pr->write(reinterpret_cast<uint8_t *>(buf), sizeof(buf));
}

+ 0
- 261
SdFat/SdFat.cpp 查看文件

@@ -1,261 +0,0 @@
/* 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
* 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 Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdFat.h>
//------------------------------------------------------------------------------
#if USE_SERIAL_FOR_STD_OUT || !defined(UDR0)
Print* SdFat::m_stdOut = &Serial;
#else // USE_SERIAL_FOR_STD_OUT
#include <MinimumSerial.h>
Print* SdFat::m_stdOut = &MiniSerial;
#endif // USE_SERIAL_FOR_STD_OUT
//------------------------------------------------------------------------------
/**
* Initialize an SdFat object.
*
* Initializes the SD card, SD volume, and root directory.
*
* \param[in] chipSelectPin SD chip select pin. See Sd2Card::init().
* \param[in] sckDivisor value for SPI SCK divisor. See Sd2Card::init().
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool SdFat::begin(uint8_t chipSelectPin, uint8_t sckDivisor) {
return m_card.begin(chipSelectPin, sckDivisor)
&& m_vol.init(&m_card) && chdir(1);
}
//------------------------------------------------------------------------------
/** Change a volume's working directory to root
*
* Changes the volume's working directory to the SD's root directory.
* Optionally set the current working directory to the volume's
* working directory.
*
* \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.
*/
bool SdFat::chdir(bool set_cwd) {
if (set_cwd) SdBaseFile::setCwd(&m_vwd);
if (m_vwd.isOpen()) m_vwd.close();
return m_vwd.openRoot(&m_vol);
}
//------------------------------------------------------------------------------
/** Change a volume's working directory
*
* Changes the volume working directory to the \a path subdirectory.
* Optionally set the current working directory to the volume's
* working directory.
*
* Example: If the volume's working directory is "/DIR", chdir("SUB")
* will change the volume's working directory from "/DIR" to "/DIR/SUB".
*
* If path is "/", the volume's working directory will be changed to the
* root directory
*
* \param[in] path The name of the subdirectory.
*
* \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.
*/
bool SdFat::chdir(const char *path, bool set_cwd) {
SdBaseFile dir;
dir.open(&m_vwd, path, O_READ);
// Check for correctly open directory.
if (!dir.isDir()) goto fail;
m_vwd = dir;
if (set_cwd) SdBaseFile::setCwd(&m_vwd);
return true;

fail:
return false;
}
//------------------------------------------------------------------------------
/** Set the current working directory to a volume's working directory.
*
* This is useful with multiple SD cards.
*
* The current working directory is changed to this volume's working directory.
*
* This is like the Windows/DOS \<drive letter>: command.
*/
void SdFat::chvol() {
SdBaseFile::setCwd(&m_vwd);
}
//------------------------------------------------------------------------------
/**
* Test for the existence of a file.
*
* \param[in] name Name of the file to be tested for.
*
* \return true if the file exists else false.
*/
bool SdFat::exists(const char* name) {
return m_vwd.exists(name);
}
//------------------------------------------------------------------------------
/** List the directory contents of the volume working directory to stdOut.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*/
void SdFat::ls(uint8_t flags) {
m_vwd.ls(m_stdOut, flags);
}
//------------------------------------------------------------------------------
/** List the directory contents of the volume working directory to stdOut.
*
* \param[in] path directory to list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*/
void SdFat::ls(const char* path, uint8_t flags) {
ls(m_stdOut, path, flags);
}
//------------------------------------------------------------------------------
/** List the directory contents of the volume working directory.
*
* \param[in] pr Print stream for the list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*/
void SdFat::ls(Print* pr, uint8_t flags) {
m_vwd.ls(pr, flags);
}
//------------------------------------------------------------------------------
/** List the directory contents of the volume working directory to stdOut.
*
* \param[in] pr Print stream for the list.
*
* \param[in] path directory to list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*/
void SdFat::ls(Print* pr, const char* path, uint8_t flags) {
SdBaseFile dir(path, O_READ);
dir.ls(pr, flags);
}
//------------------------------------------------------------------------------
/** Make a subdirectory in the volume working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
*
* \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.
*/
bool SdFat::mkdir(const char* path, bool pFlag) {
SdBaseFile sub;
return sub.mkdir(&m_vwd, path, pFlag);
}
//------------------------------------------------------------------------------
/** Remove a file from the volume working directory.
*
* \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.
*/
bool SdFat::remove(const char* path) {
return SdBaseFile::remove(&m_vwd, path);
}
//------------------------------------------------------------------------------
/** Rename a file or subdirectory.
*
* \param[in] oldPath Path name to the file or subdirectory to be renamed.
*
* \param[in] newPath New path name of the file or subdirectory.
*
* The \a newPath object must not exist before the rename call.
*
* The file to be renamed must not be open. The directory entry may be
* 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.
*/
bool SdFat::rename(const char *oldPath, const char *newPath) {
SdBaseFile file;
if (!file.open(oldPath, O_READ)) return false;
return file.rename(&m_vwd, newPath);
}
//------------------------------------------------------------------------------
/** Remove a subdirectory from the volume's working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
*
* 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.
*/
bool SdFat::rmdir(const char* path) {
SdBaseFile sub;
if (!sub.open(path, O_READ)) return false;
return sub.rmdir();
}
//------------------------------------------------------------------------------
/** 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] 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.
*/
bool SdFat::truncate(const char* path, uint32_t length) {
SdBaseFile file;
if (!file.open(path, O_WRITE)) return false;
return file.truncate(length);
}

+ 273
- 73
SdFat/SdFat.h 查看文件

@@ -23,90 +23,290 @@
* \file
* \brief SdFat class
*/
//------------------------------------------------------------------------------
/** Macro for debug. */
#define DBG_FAIL_MACRO // Serial.print(__FILE__);Serial.println(__LINE__)
#include "SdSpiCard.h"
#include "SdFile.h"
#include "utility/FatLib.h"
//------------------------------------------------------------------------------
/** SdFat version YYYYMMDD */
#define SD_FAT_VERSION 20141025
//------------------------------------------------------------------------------
/** error if old IDE */
#if !defined(ARDUINO) || ARDUINO < 100
#error Arduino IDE must be 1.0 or greater
#endif // ARDUINO < 100
//------------------------------------------------------------------------------
#include <SdFile.h>
#include <SdStream.h>
#include <StdioStream.h>
#include <ArduinoStream.h>
#include <MinimumSerial.h>
//------------------------------------------------------------------------------
#define SD_FAT_VERSION 20141115
//==============================================================================
/**
* \class SdFat
* \brief Integration class for the %SdFat library.
* \class SdFatBase
* \brief Virtual base class for %SdFat library.
*/
class SdFat {
class SdFatBase : public FatFileSystem {
public:
SdFat() {}
/** \return a pointer to the Sd2Card object. */
Sd2Card* card() {return &m_card;}
bool chdir(bool set_cwd = false);
bool chdir(const char* path, bool set_cwd = false);
void chvol();
void errorHalt();
void errorHalt(char const *msg);
void errorPrint();
void errorPrint(char const *msg);
bool exists(const char* name);
bool begin(uint8_t chipSelectPin = SD_CHIP_SELECT_PIN,
uint8_t sckDivisor = SPI_FULL_SPEED);
void initErrorHalt();
void initErrorHalt(char const *msg);
void initErrorPrint();
void initErrorPrint(char const *msg);
void ls(uint8_t flags = 0);
void ls(const char* path, uint8_t flags = 0);
void ls(Print* pr, uint8_t flags = 0);
void ls(Print* pr, const char* path, uint8_t flags = 0);
bool mkdir(const char* path, bool pFlag = true);
bool remove(const char* path);
bool rename(const char *oldPath, const char *newPath);
bool rmdir(const char* path);
bool truncate(const char* path, uint32_t length);
/** \return a pointer to the SdVolume object. */
SdVolume* vol() {return &m_vol;}
/** \return a pointer to the volume working directory. */
SdBaseFile* vwd() {return &m_vwd;}
//----------------------------------------------------------------------------
void errorHalt_P(PGM_P msg);
void errorPrint_P(PGM_P msg);
void initErrorHalt_P(PGM_P msg);
void initErrorPrint_P(PGM_P msg);
//----------------------------------------------------------------------------
/**
* Set stdOut Print stream for messages.
* \param[in] stream The new Print stream.
*/
static void setStdOut(Print* stream) {m_stdOut = stream;}
/** \return Print stream for messages. */
static Print* stdOut() {return m_stdOut;}
//----------------------------------------------------------------------------
/** open a file
/** Initialize SD card and file system.
* \param[in] spi SPI object for the card.
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \return true for success else false.
*/
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);
}
/** \return Pointer to SD card object */
SdSpiCard *card() {return &m_sdCard;}
/** %Print any SD error code to Serial and halt. */
void errorHalt() {errorHalt(&Serial);}
/** %Print any SD error code and halt.
*
* \param[in] pr Print destination.
*/
void errorHalt(Print* pr);
/** %Print msg, any SD error code and halt.
*
* \param[in] msg Message to print.
*/
void errorHalt(char const* msg) {errorHalt(&Serial, msg);}
/** %Print msg, any SD error code, and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorHalt(Print* pr, char const* msg);
/** %Print msg, any SD error code, and halt.
*
* \param[in] msg Message to print.
*/
void errorHalt(const __FlashStringHelper* msg) {errorHalt(&Serial, msg);}
/** %Print msg, any SD error code, and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorHalt(Print* pr, const __FlashStringHelper* msg);
/** %Print any SD error code to Serial */
void errorPrint() {errorPrint(&Serial);}
/** %Print any SD error code.
* \param[in] pr Print device.
*/
void errorPrint(Print* pr);
/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
*/
void errorPrint(const char* 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, char const* msg);
/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
*/
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.
* \return true for success else false.
*/
bool fsBegin() {return FatFileSystem::begin(&m_vwd);}
/** %Print any SD error code and halt. */
void initErrorHalt() {initErrorHalt(&Serial);}
/** %Print error details and halt after begin fails.
*
* \param[in] pr Print destination.
*/
void initErrorHalt(Print* pr);
/**Print message, error details, and halt after SdFat::init() fails.
*
* \param[in] msg Message to print.
*/
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.
*/
void initErrorHalt(const __FlashStringHelper* msg) {
initErrorHalt(&Serial, msg);
}
void initErrorHalt(Print* pr, const __FlashStringHelper* msg);
/** Print error details after SdFat::init() fails. */
void initErrorPrint() {initErrorPrint(&Serial);}
/** Print error details after SdFatBase::init() fails.
*
* \param[in] pr Print destination.
*/
void initErrorPrint(Print* pr);
/**Print message and error details and halt after SdFat::init() fails.
*
* \param[in] msg Message to print.
*/
void initErrorPrint(char const *msg) {initErrorPrint(&Serial, msg);}
/**Print message and error details and halt after SdFatBase::init() fails.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorPrint(Print* pr, char const *msg);
/**Print message and error details and halt after SdFat::init() fails.
*
* \param[in] msg Message to print.
*/
void initErrorPrint(const __FlashStringHelper* msg) {
initErrorPrint(&Serial, msg);
}
/**Print message and error details and halt after SdFatBase::init() fails.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorPrint(Print* pr, const __FlashStringHelper* msg);
/** List the directory contents of the volume working directory to Serial.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*/
void ls(uint8_t flags = 0) {
ls(&Serial, flags);
}
/** List the directory contents of a directory to Serial.
*
* \param[in] path directory to list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*/
void ls(const char* path, uint8_t flags = 0) {
ls(&Serial, path, flags);
}
/** open a file
*
* \param[in] path location of file to be opened.
* \param[in] mode open mode flags.
* \return a File object.
*/
File open(const char *path, uint8_t mode = FILE_READ) {
File tmpFile;
tmpFile.open(&m_vwd, path, mode);
return tmpFile;
}
*/
File open(const char *path, uint8_t mode = FILE_READ);
/** \return a pointer to the volume working directory. */
SdBaseFile* vwd() {return &m_vwd;}
using FatFileSystem::ls;

private:
Sd2Card m_card;
SdVolume m_vol;
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);
}
bool writeBlock(uint32_t block, const uint8_t* src) {
return m_sdCard.writeBlock(block, src);
}
bool readBlocks(uint32_t block, uint8_t* dst, size_t n) {
return m_sdCard.readBlocks(block, dst, n);
}
bool writeBlocks(uint32_t block, const uint8_t* src, size_t n) {
return m_sdCard.writeBlocks(block, src, n);
}
SdBaseFile m_vwd;
static Print* m_stdOut;
SdSpiCard m_sdCard;
};
//==============================================================================
/**
* \class SdFat
* \brief Main file system class for %SdFat library.
*/
class SdFat : 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.
*/
bool begin(uint8_t csPin = SS, uint8_t divisor = 2) {
return SdFatBase::begin(&m_spi, csPin, divisor);
}
/** Initialize SD card - use for diagnostic purposes.
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \return true for success else false.
*/
bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) {
return card()->begin(&m_spi, csPin, divisor);
}
private:
SpiDefault_t m_spi;
};
//==============================================================================
#if USE_MULTIPLE_SPI_TYPES || 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.
*/
bool begin(uint8_t csPin = SS, uint8_t divisor = 2) {
return SdFatBase::begin(&m_spi, csPin, divisor);
}
/** Initialize SD card - use for diagnostic purposes.
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \return true for success else false.
*/
bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) {
return card()->begin(&m_spi, csPin, divisor);
}

private:
SdSpiLib m_spi;
};
//==============================================================================
/**
* \class SdFatSoftSpi
* \brief SdFat class using software SPI.
*/
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
class SdFatSoftSpi : 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.
*/
bool begin(uint8_t csPin = SS, uint8_t divisor = 2) {
return SdFatBase::begin(&m_spi, csPin, divisor);
}
/** Initialize SD card - use for diagnostic purposes.
* \param[in] csPin SD card chip select pin.
* \param[in] divisor SPI divisor.
* \return true for success else false.
*/
bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) {
return card()->begin(&m_spi, csPin, divisor);
}

private:
SdSpiSoft<MisoPin, MosiPin, SckPin> m_spi;
};
#endif // USE_MULTIPLE_SPI_TYPES
#endif // SdFat_h

+ 106
- 0
SdFat/SdFatBase.cpp 查看文件

@@ -0,0 +1,106 @@
/* 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
* 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 Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "SdFat.h"
//------------------------------------------------------------------------------
void SdFatBase::errorHalt(Print* pr) {
errorPrint(pr);
while (1) {}
}
//------------------------------------------------------------------------------
void SdFatBase::errorHalt(Print* pr, char const* msg) {
errorPrint(pr, msg);
while (1) {}
}
//------------------------------------------------------------------------------
void SdFatBase::errorHalt(Print* pr, const __FlashStringHelper* msg) {
errorPrint(pr, msg);
while (1) {}
}
//------------------------------------------------------------------------------
void SdFatBase::errorPrint(Print* pr) {
if (!cardErrorCode()) return;
pr->print(F("SD errorCode: 0X"));
pr->print(cardErrorCode(), HEX);
pr->print(F(",0X"));
pr->println(cardErrorData(), HEX);
}
//------------------------------------------------------------------------------
void SdFatBase::errorPrint(Print* pr, char const* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
//------------------------------------------------------------------------------
void SdFatBase::errorPrint(Print* pr, const __FlashStringHelper* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorHalt(Print* pr) {
initErrorPrint(pr);
while (1) {}
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorHalt(Print* pr, char const *msg) {
pr->println(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);
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorPrint(Print* pr) {
if (cardErrorCode()) {
pr->println(F("Can't access SD card. Do not reformat."));
if (cardErrorCode() == SD_CARD_ERROR_CMD0) {
pr->println(F("No card, wrong chip select pin, or SPI problem?"));
}
errorPrint(pr);
} else if (vol()->fatType() == 0) {
pr->println(F("Invalid format, reformat SD."));
} else if (!vwd()->isOpen()) {
pr->println(F("Can't open root directory."));
} else {
pr->println(F("No error found."));
}
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorPrint(Print* pr, char const *msg) {
pr->println(msg);
initErrorPrint(pr);
}
//------------------------------------------------------------------------------
void SdFatBase::initErrorPrint(Print* pr, const __FlashStringHelper* msg) {
pr->println(msg);
initErrorPrint(pr);
}
//------------------------------------------------------------------------------
File SdFatBase::open(const char *path, uint8_t mode) {
File tmpFile;
tmpFile.open(&m_vwd, path, mode);
return tmpFile;
}

+ 42
- 55
SdFat/SdFatConfig.h 查看文件

@@ -29,12 +29,11 @@
#endif // __AVR__
//------------------------------------------------------------------------------
/**
* 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.
* 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 SD_FILE_USES_STREAM 0

#define USE_MULTIPLE_SPI_TYPES 0
//------------------------------------------------------------------------------
/**
* To enable SD card CRC checking set USE_SD_CRC nonzero.
@@ -45,43 +44,6 @@
*/
#define USE_SD_CRC 0
//------------------------------------------------------------------------------
/**
* To use multiple SD cards set USE_MULTIPLE_CARDS nonzero.
*
* Using multiple cards costs about 200 bytes of flash.
*
* Each card requires about 550 bytes of SRAM so use of a Mega is recommended.
*/
#define USE_MULTIPLE_CARDS 0
//------------------------------------------------------------------------------
/**
* Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor.
*
* Causes use of lots of heap in ARM.
*/
#define DESTRUCTOR_CLOSES_FILE 0
//------------------------------------------------------------------------------
/**
* For AVR
*
* Set USE_SERIAL_FOR_STD_OUT nonzero to use Serial (the HardwareSerial class)
* for error messages and output from print functions like ls().
*
* If USE_SERIAL_FOR_STD_OUT is zero, a small non-interrupt driven class
* is used to output messages to serial port zero. This allows an alternate
* Serial library like SerialPort to be used with SdFat.
*
* You can redirect stdOut with SdFat::setStdOut(Print* stream) and
* get the current stream with SdFat::stdOut().
*/
#define USE_SERIAL_FOR_STD_OUT 0
//------------------------------------------------------------------------------
/**
* Set FAT12_SUPPORT nonzero to enable use if FAT12 volumes.
* FAT12 has not been well tested and requires additional flash.
*/
#define FAT12_SUPPORT 0
//------------------------------------------------------------------------------
/**
* Set ENABLE_SPI_TRANSACTION nonzero to enable the SPI transaction feature
* of the standard Arduino SPI library. You must include SPI.h in your
@@ -103,38 +65,45 @@
#define ENABLE_SPI_YIELD 0
//------------------------------------------------------------------------------
/**
* Set USE_ARDUINO_SPI_LIBRARY nonzero to force use of Arduino Standard
* SPI library. This will override native and software SPI for all boards.
* 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 on all AVR Arduinos.
* 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 on Due Arduinos.
* 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 on Leonardo Arduinos.
* 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 on Mega Arduinos.
* 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.
* on Mega Arduinos. Set the soft SPI pins below.
*/
#define MEGA_SOFT_SPI 0
//------------------------------------------------------------------------------
/**
* Set TEENSY3_SOFT_SPI nonzero to use software SPI on Teensy 3.x boards.
* 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
//------------------------------------------------------------------------------
@@ -143,8 +112,6 @@
* boards.
*/
// define software SPI pins
/** Default Software SPI chip select pin */
uint8_t const SOFT_SPI_CS_PIN = 10;
/** Software SPI Master Out Slave In pin */
uint8_t const SOFT_SPI_MOSI_PIN = 11;
/** Software SPI Master In Slave Out pin */
@@ -152,6 +119,19 @@ 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.
*/
#define FAT12_SUPPORT 0
//------------------------------------------------------------------------------
/**
* Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor.
*
* Causes use of lots of heap in ARM.
*/
#define DESTRUCTOR_CLOSES_FILE 0
//------------------------------------------------------------------------------
/**
* Call flush for endl if ENDL_CALLS_FLUSH is nonzero
*
@@ -171,6 +151,13 @@ uint8_t const SOFT_SPI_SCK_PIN = 13;
*/
#define ENDL_CALLS_FLUSH 0
//------------------------------------------------------------------------------
/**
* 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.
*/
#define SD_FILE_USES_STREAM 0
//------------------------------------------------------------------------------
/**
* SPI SCK divisor for SD initialization commands.
* or greater
@@ -198,8 +185,8 @@ const uint8_t SPI_SCK_INIT_DIVISOR = 128;
* Don't use mult-block read/write on small AVR boards.
*/
#if defined(RAMEND) && RAMEND < 3000
#define USE_MULTI_BLOCK_SD_IO 0
#define USE_MULTI_BLOCK_IO 0
#else // RAMEND
#define USE_MULTI_BLOCK_SD_IO 1
#define USE_MULTI_BLOCK_IO 1
#endif // RAMEND
#endif // SdFatConfig_h

+ 0
- 145
SdFat/SdFatErrorPrint.cpp 查看文件

@@ -1,145 +0,0 @@
/* 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
* 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 Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdFat.h>
#ifndef PSTR
#define PSTR(x) x
#define PGM_P const char*
#endif
//------------------------------------------------------------------------------
static void pstrPrint(PGM_P str) {
for (uint8_t c; (c = pgm_read_byte(str)); str++) SdFat::stdOut()->write(c);
}
//------------------------------------------------------------------------------
static void pstrPrintln(PGM_P str) {
pstrPrint(str);
SdFat::stdOut()->println();
}
//------------------------------------------------------------------------------
/** %Print any SD error code and halt. */
void SdFat::errorHalt() {
errorPrint();
while (1) {}
}
//------------------------------------------------------------------------------
/** %Print msg, any SD error code, and halt.
*
* \param[in] msg Message to print.
*/
void SdFat::errorHalt(char const* msg) {
errorPrint(msg);
while (1) {}
}
//------------------------------------------------------------------------------
/** %Print msg, any SD error code, and halt.
*
* \param[in] msg Message in program space (flash memory) to print.
*/
void SdFat::errorHalt_P(PGM_P msg) {
errorPrint_P(msg);
while (1) {}
}
//------------------------------------------------------------------------------
/** %Print any SD error code. */
void SdFat::errorPrint() {
if (!m_card.errorCode()) return;
pstrPrint(PSTR("SD errorCode: 0X"));
m_stdOut->print(m_card.errorCode(), HEX);
pstrPrint(PSTR(",0X"));
m_stdOut->println(m_card.errorData(), HEX);
}
//------------------------------------------------------------------------------
/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
*/
void SdFat::errorPrint(char const* msg) {
pstrPrint(PSTR("error: "));
m_stdOut->println(msg);
errorPrint();
}
//------------------------------------------------------------------------------
/** %Print msg, any SD error code.
*
* \param[in] msg Message in program space (flash memory) to print.
*/
void SdFat::errorPrint_P(PGM_P msg) {
pstrPrint(PSTR("error: "));
pstrPrintln(msg);
errorPrint();
}
//------------------------------------------------------------------------------
/** %Print error details and halt after SdFat::init() fails. */
void SdFat::initErrorHalt() {
initErrorPrint();
while (1) {}
}
//------------------------------------------------------------------------------
/**Print message, error details, and halt after SdFat::init() fails.
*
* \param[in] msg Message to print.
*/
void SdFat::initErrorHalt(char const *msg) {
m_stdOut->println(msg);
initErrorHalt();
}
//------------------------------------------------------------------------------
/**Print message, error details, and halt after SdFat::init() fails.
*
* \param[in] msg Message in program space (flash memory) to print.
*/
void SdFat::initErrorHalt_P(PGM_P msg) {
pstrPrintln(msg);
initErrorHalt();
}
//------------------------------------------------------------------------------
/** Print error details after SdFat::init() fails. */
void SdFat::initErrorPrint() {
if (m_card.errorCode()) {
pstrPrintln(PSTR("Can't access SD card. Do not reformat."));
if (m_card.errorCode() == SD_CARD_ERROR_CMD0) {
pstrPrintln(PSTR("No card, wrong chip select pin, or SPI problem?"));
}
errorPrint();
} else if (m_vol.fatType() == 0) {
pstrPrintln(PSTR("Invalid format, reformat SD."));
} else if (!m_vwd.isOpen()) {
pstrPrintln(PSTR("Can't open root directory."));
} else {
pstrPrintln(PSTR("No error found."));
}
}
//------------------------------------------------------------------------------
/**Print message and error details and halt after SdFat::init() fails.
*
* \param[in] msg Message to print.
*/
void SdFat::initErrorPrint(char const *msg) {
m_stdOut->println(msg);
initErrorPrint();
}
//------------------------------------------------------------------------------
/**Print message and error details after SdFat::init() fails.
*
* \param[in] msg Message in program space (flash memory) to print.
*/
void SdFat::initErrorPrint_P(PGM_P msg) {
pstrPrintln(msg);
initErrorHalt();
}

+ 12
- 26
SdFat/SdFatUtil.cpp 查看文件

@@ -18,27 +18,29 @@
* <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include "SdFat.h"
#include "SdFatUtil.h"
//------------------------------------------------------------------------------
#ifdef __arm__
// should use uinstd.h to define sbrk but Due causes a conflict
extern "C" char* sbrk(int incr);
#else // __ARM__
extern char *__brkval;
extern char __bss_end;
#endif // __arm__
//------------------------------------------------------------------------------
/** Amount of free RAM
* \return The number of free bytes.
*/
int SdFatUtil::FreeRam() {
char top;
#ifdef __arm__
return &top - reinterpret_cast<char*>(sbrk(0));
}
#else // __arm__
extern char *__brkval;
extern char __bss_end;
/** Amount of free RAM
* \return The number of free bytes.
*/
int SdFatUtil::FreeRam() {
char top;
return __brkval ? &top - __brkval : &top - &__bss_end;
#endif // __arm__
}
#endif // __arm
//------------------------------------------------------------------------------
/** %Print a string in flash memory.
*
@@ -58,19 +60,3 @@ void SdFatUtil::println_P(Print* pr, PGM_P str) {
print_P(pr, str);
pr->println();
}
//------------------------------------------------------------------------------
/** %Print a string in flash memory to Serial.
*
* \param[in] str Pointer to string stored in flash memory.
*/
void SdFatUtil::SerialPrint_P(PGM_P str) {
print_P(SdFat::stdOut(), str);
}
//------------------------------------------------------------------------------
/** %Print a string in flash memory to Serial followed by a CR/LF.
*
* \param[in] str Pointer to string stored in flash memory.
*/
void SdFatUtil::SerialPrintln_P(PGM_P str) {
println_P(SdFat::stdOut(), str);
}

+ 18
- 2
SdFat/SdFatUtil.h 查看文件

@@ -23,7 +23,7 @@
* \file
* \brief Useful utility functions.
*/
#include <SdFat.h>
#include "SdFat.h"
/** Store and print a string in flash memory.*/
#define PgmPrint(x) SerialPrint_P(PSTR(x))
/** Store and print a string in flash memory followed by a CR/LF.*/
@@ -33,8 +33,24 @@ namespace SdFatUtil {
int FreeRam();
void print_P(Print* pr, PGM_P str);
void println_P(Print* pr, PGM_P str);
//----------------------------------------------------------------------------
/** %Print a string in flash memory to Serial.
*
* \param[in] str Pointer to string stored in flash memory.
*/
inline void SerialPrint_P(PGM_P str) {
print_P(&Serial, str);
}
//----------------------------------------------------------------------------
/** %Print a string in flash memory to Serial followed by a CR/LF.
*
* \param[in] str Pointer to string stored in flash memory.
*/
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

+ 41
- 17
SdFat/SdFatmainpage.h 查看文件

@@ -31,13 +31,18 @@ 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.
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 main classes in %SdFat are SdFat, SdBaseFile, SdFile, File, StdioStream,
\ref fstream, \ref ifstream, and \ref ofstream.
The main classes in %SdFat are SdFat, SdFatSoftSpi, SdFatLibSpi,
SdBaseFile, SdFile, File, StdioStream, \ref fstream, \ref ifstream,
and \ref ofstream.

The SdFat class maintains a FAT volume, a current working directory,
and simplifies initialization of other classes.
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.

The SdBaseFile class provides basic file access functions such as open(),
binary read(), binary write(), close(), remove(), and sync(). SdBaseFile
@@ -60,6 +65,14 @@ 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
follow the C++ \ref iostream standard when possible.

There are many tutorials and much documentation about using C++ iostreams
on the web.

http://www.cplusplus.com/ is a good C++ site for learning iostreams.

The classes \ref ibufstream and \ref obufstream format and parse character
strings in memory buffers.

@@ -83,22 +96,22 @@ http://arduino.cc/en/Guide/Libraries
Several configuration options may be changed by editing the SdFatConfig.h
file in the SdFat folder.

Set SD_FILE_USES_STREAM nonzero to use Stream instead of Print for SdFile.
Using Stream will use more flash.
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.

To enable SD card CRC checking set USE_SD_CRC nonzero.

To use multiple SD cards set USE_MULTIPLE_CARDS 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 Arduino Standard
SPI library. This will override native and software SPI for all boards.
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 for selected boards by setting the symbols
AVR_SOFT_SPI, DUE_SOFT_SPI, LEONARDO_SOFT_SPI, MEGA_SOFT_SPI,
and TEENSY3_SOFT_SPI.
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
@@ -143,6 +156,13 @@ 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
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.
@@ -232,6 +252,8 @@ 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.

LowLatencyLogger - A modifiable data logger for higher data rates.

OpenNext - Open all files in the root dir and print their filename.
@@ -250,14 +272,16 @@ rename - A demo of SdFat::rename(old, new) and SdFile::rename(dirFile, newPath).

SdFormatter - This sketch 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.

StreamParseInt - Simple demo of parseInt() Stream member function.

StressTest - Create and write files until the SD is full.
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.

+ 0
- 83
SdFat/SdFile.cpp 查看文件

@@ -1,83 +0,0 @@
/* 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
* 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 Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdFile.h>
/** 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.
*
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
*/
SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) {
}
//------------------------------------------------------------------------------
/** Write data to an open file.
*
* \note Data is moved to the cache but may not be written to the
* storage device until sync() is called.
*
* \param[in] buf Pointer to the location of the data to be written.
*
* \param[in] nbyte Number of bytes to write.
*
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an I/O error.
*
*/
int SdFile::write(const void* buf, size_t nbyte) {
return SdBaseFile::write(buf, nbyte);
}
//------------------------------------------------------------------------------
/** 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 SdFile::write(uint8_t b) {
return SdBaseFile::write(&b, 1) == 1 ? 1 : 0;
}
//------------------------------------------------------------------------------
/** 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.
* \return count of characters written for success or -1 for failure.
*/
int SdFile::write(const char* str) {
return SdBaseFile::write(str, strlen(str));
}
//------------------------------------------------------------------------------
/** Write a PROGMEM string to a file.
* \param[in] str Pointer to the PROGMEM string.
* Use getWriteError to check for errors.
*/
void SdFile::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 SdFile::writeln_P(PGM_P str) {
write_P(str);
write_P(PSTR("\r\n"));
}

+ 134
- 96
SdFat/SdFile.h 查看文件

@@ -24,11 +24,74 @@
#ifndef SdFile_h
#define SdFile_h
#include <limits.h>
#include <SdBaseFile.h>
#include "utility/FatLib.h"
//------------------------------------------------------------------------------
/** Arduino SD.h style flag for open for read. */
#define FILE_READ O_READ
/** Arduino SD.h style flag for open at EOF for read/write with create. */
#define FILE_WRITE (O_RDWR | O_CREAT | O_AT_END)
//==============================================================================
/**
* \class SdBaseFile
* \brief SdBaseFile base for SdFile and File.
*/
class SdBaseFile : public FatFile {
public:
SdBaseFile() {}
/** Constructor with file open.
*
* \param[in] path File location and name.
* \param[in] oflag File open mode.
*/
SdBaseFile(const char* path, uint8_t oflag) {open(path, oflag);}
using FatFile::ls;
using FatFile::printFatDate;
using FatFile::printFatTime;
using FatFile::printName;
/** List directory contents.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*/
void ls(uint8_t flags = 0) {
ls(&Serial, flags);
}
/** %Print a directory date field.
*
* Format is yyyy-mm-dd.
*
* \param[in] fatDate The date field from a directory entry.
*/
static void printFatDate(uint16_t fatDate) {
printFatDate(&Serial, fatDate);
}
/** %Print a directory time field.
*
* Format is hh:mm:ss.
*
* \param[in] fatTime The time field from a directory entry.
*/
static void printFatTime(uint16_t fatTime) {
printFatTime(&Serial, fatTime);
}
/** Print a file's name.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
size_t printName() {
return FatFile::printName(&Serial);
}
};
//==============================================================================
/**
* \class SdFile
* \brief SdBaseFile with Arduino Stream.
* \brief SdFile SdBaseFile with Print.
*/
#if SD_FILE_USES_STREAM
class SdFile : public SdBaseFile, public Stream {
@@ -37,10 +100,22 @@ class SdFile : public SdBaseFile, public Print {
#endif // SD_FILE_USES_STREAM
public:
SdFile() {}
SdFile(const char* name, uint8_t oflag);
/** 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.
*
* \param[in] oflag Values for \a oflag are constructed by a
* bitwise-inclusive OR of open flags. see
* SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
*/
SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) {}
#if DESTRUCTOR_CLOSES_FILE
~SdFile() {}
#endif // DESTRUCTOR_CLOSES_FILE
using SdBaseFile::clearWriteError;
using SdBaseFile::getWriteError;
using SdBaseFile::read;
using SdBaseFile::write;
/** \return number of bytes available from the current position to EOF
* or INT_MAX if more than INT_MAX bytes are available.
*/
@@ -53,51 +128,28 @@ class SdFile : public SdBaseFile, public Print {
/** 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();}
/** 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();}
/** Read data from a file starting at the current position.
*
* \param[out] buf Pointer to the location that will receive the data.
*
* \param[in] nbyte Maximum number of bytes to read.
*
* \return For success read() returns the number of bytes read.
* A value less than \a nbyte, including zero, will be returned
* if end of file is reached.
* If an error occurs, read() returns -1. Possible errors include
* read() called before a file has been opened, corrupt file system
* or an I/O error occurred.
*/
int read(void* buf, size_t nbyte) {return SdBaseFile::read(buf, nbyte);}
/** \return value of writeError */
bool getWriteError() {return SdBaseFile::getWriteError();}
/** Set writeError to zero */
void clearWriteError() {SdBaseFile::clearWriteError();}
size_t write(uint8_t b);

int write(const char* str);
/** Write data to an open file.
*
* \note Data is moved to the cache but may not be written to the
* storage device until sync() is called.
*
* \param[in] buf Pointer to the location of the data to be written.
*
* \param[in] nbyte Number of bytes to write.
*
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an
* I/O error.
*/
int write(const void* buf, size_t nbyte);
/** 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);}
/** 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.
* \return count of characters written for success or -1 for failure.
*/
int write(const char* str) {
return SdBaseFile::write(str, strlen(str));
}
/** Write data to an open file. Form required by Print.
*
* \note Data is moved to the cache but may not be written to the
@@ -110,25 +162,47 @@ class SdFile : public SdBaseFile, public Print {
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an
* for a read-only file, device is full, a corrupt file system or an
* I/O error.
*/
*/
size_t write(const uint8_t *buf, size_t size) {
return SdBaseFile::write(buf, size);}
void write_P(PGM_P str);
void writeln_P(PGM_P str);
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"));
}
};
//------------------------------------------------------------------------------
/** Arduino SD.h style flag for open for read. */
#define FILE_READ O_READ
/** Arduino SD.h style flag for open at EOF for read/write with create. */
#define FILE_WRITE (O_RDWR | O_CREAT | O_AT_END)
//==============================================================================
/**
* \class File
* \brief Arduino SD.h style File API
*/
class File : public SdBaseFile, public Stream {
public:
File() {}
/** 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.
*
* \param[in] oflag Values for \a oflag are constructed by a
* bitwise-inclusive OR of open flags. see
* SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
*/
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.
@@ -141,15 +215,11 @@ class File : public SdBaseFile, public Stream {
uint32_t n = SdBaseFile::available();
return n > INT_MAX ? INT_MAX : n;
}
/** Set writeError to zero */
void clearWriteError() {SdBaseFile::clearWriteError();}
/** Ensure that any bytes written to the file are saved to the SD card. */
void flush() {sync();}
/** \return value of writeError */
bool getWriteError() {return SdBaseFile::getWriteError();}
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. */
char* name() {
@@ -160,7 +230,7 @@ class File : public SdBaseFile, public Stream {
/** 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();}
/** \return the current file position. */
uint32_t position() {return curPosition();}
@@ -178,27 +248,13 @@ 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();}
/** Read data from a file starting at the current position.
*
* \param[out] buf Pointer to the location that will receive the data.
*
* \param[in] nbyte Maximum number of bytes to read.
*
* \return For success read() returns the number of bytes read.
* A value less than \a nbyte, including zero, will be returned
* if end of file is reached.
* If an error occurs, read() returns -1. Possible errors include
* read() called before a file has been opened, corrupt file system
* or an I/O error occurred.
*/
int read(void* buf, size_t nbyte) {return SdBaseFile::read(buf, nbyte);}
/** Rewind a file if it is a directory */
void rewindDirectory() {
if (isDir()) rewind();
}
/**
/**
* Seek to a new position in the file, which must be between
* 0 and the size of the file (inclusive).
*
@@ -213,25 +269,7 @@ class File : public SdBaseFile, public Stream {
* Use getWriteError to check for errors.
* \return 1 for success and 0 for failure.
*/
size_t write(uint8_t b) {
return SdBaseFile::write(&b, 1) == 1 ? 1 : 0;
}
/** Write data to an open file.
*
* \note Data is moved to the cache but may not be written to the
* storage device until sync() is called.
*
* \param[in] buf Pointer to the location of the data to be written.
*
* \param[in] nbyte Number of bytes to write.
*
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an
* I/O error.
*/
int write(const void* buf, size_t nbyte);
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
@@ -244,9 +282,9 @@ class File : public SdBaseFile, public Stream {
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an
* for a read-only file, device is full, a corrupt file system or an
* I/O error.
*/
*/
size_t write(const uint8_t *buf, size_t size) {
return SdBaseFile::write(buf, size);
}

+ 90
- 12
SdFat/SdInfo.h 查看文件

@@ -1,7 +1,7 @@
/* Arduino Sd2Card Library
/* Arduino SdSpiCard Library
* Copyright (C) 2012 by William Greiman
*
* This file is part of the Arduino Sd2Card Library
* This file is part of the Arduino SdSpiCard 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
@@ -14,7 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino Sd2Card Library. If not, see
* along with the Arduino SdSpiCard Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SdInfo_h
@@ -31,6 +31,72 @@
//
// http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs
//------------------------------------------------------------------------------
// SD card errors
/** timeout error for command CMD0 (initialize card in SPI mode) */
uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
/** CMD8 was not accepted - not a valid SD card*/
uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
/** card returned an error response for CMD12 (stop multiblock read) */
uint8_t const SD_CARD_ERROR_CMD12 = 0X3;
/** card returned an error response for CMD17 (read block) */
uint8_t const SD_CARD_ERROR_CMD17 = 0X4;
/** card returned an error response for CMD18 (read multiple block) */
uint8_t const SD_CARD_ERROR_CMD18 = 0X5;
/** card returned an error response for CMD24 (write block) */
uint8_t const SD_CARD_ERROR_CMD24 = 0X6;
/** WRITE_MULTIPLE_BLOCKS command failed */
uint8_t const SD_CARD_ERROR_CMD25 = 0X7;
/** card returned an error response for CMD58 (read OCR) */
uint8_t const SD_CARD_ERROR_CMD58 = 0X8;
/** SET_WR_BLK_ERASE_COUNT failed */
uint8_t const SD_CARD_ERROR_ACMD23 = 0X9;
/** ACMD41 initialization process timeout */
uint8_t const SD_CARD_ERROR_ACMD41 = 0XA;
/** card returned a bad CSR version field */
uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB;
/** erase block group command failed */
uint8_t const SD_CARD_ERROR_ERASE = 0XC;
/** card not capable of single block erase */
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD;
/** Erase sequence timed out */
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE;
/** card returned an error token instead of read data */
uint8_t const SD_CARD_ERROR_READ = 0XF;
/** read CID or CSD failed */
uint8_t const SD_CARD_ERROR_READ_REG = 0X10;
/** timeout while waiting for start of read data */
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11;
/** card did not accept STOP_TRAN_TOKEN */
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12;
/** card returned an error token as a response to a write operation */
uint8_t const SD_CARD_ERROR_WRITE = 0X13;
/** attempt to write protected block zero */
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14; // REMOVE - not used
/** card did not go ready for a multiple block write */
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15;
/** card returned an error to a CMD13 status check after a write */
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16;
/** timeout occurred during write programming */
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17;
/** incorrect rate selected */
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18;
/** init() not called */
uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
/** card returned an error for CMD59 (CRC_ON_OFF) */
uint8_t const SD_CARD_ERROR_CMD59 = 0X1A;
/** invalid read CRC */
uint8_t const SD_CARD_ERROR_READ_CRC = 0X1B;
/** SPI DMA error */
uint8_t const SD_CARD_ERROR_SPI_DMA = 0X1C;
//------------------------------------------------------------------------------
// card types
/** Standard capacity V1 SD card */
uint8_t const SD_CARD_TYPE_SD1 = 1;
/** Standard capacity V2 SD card */
uint8_t const SD_CARD_TYPE_SD2 = 2;
/** High Capacity SD card */
uint8_t const SD_CARD_TYPE_SDHC = 3;
//------------------------------------------------------------------------------
// SPI divisor constants
/** Set SCK to max rate of F_CPU/2. */
uint8_t const SPI_FULL_SPEED = 2;
@@ -97,7 +163,7 @@ uint8_t const ACMD23 = 0X17;
/** SD_SEND_OP_COMD - Sends host capacity support information and
activates the card's initialization process */
uint8_t const ACMD41 = 0X29;
//------------------------------------------------------------------------------
//==============================================================================
/** status for card in the ready state */
uint8_t const R1_READY_STATE = 0X00;
/** status for card in the idle state */
@@ -114,8 +180,11 @@ uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
uint8_t const DATA_RES_MASK = 0X1F;
/** write data accepted token */
uint8_t const DATA_RES_ACCEPTED = 0X05;
//------------------------------------------------------------------------------
/** Card IDentification (CID) register */
//==============================================================================
/**
* \class CID
* \brief Card IDentification (CID) register.
*/
typedef struct CID {
// byte 0
/** Manufacturer ID */
@@ -150,8 +219,11 @@ typedef struct CID {
/** CRC7 checksum */
unsigned char crc : 7;
}__attribute__((packed)) cid_t;
//------------------------------------------------------------------------------
/** CSD for version 1.00 cards */
//==============================================================================
/**
* \class CSDV1
* \brief CSD register for version 1.00 cards .
*/
typedef struct CSDV1 {
// byte 0
unsigned char reserved1 : 6;
@@ -212,8 +284,11 @@ typedef struct CSDV1 {
unsigned char always1 : 1;
unsigned char crc : 7;
}__attribute__((packed)) csd1_t;
//------------------------------------------------------------------------------
/** CSD for version 2.00 cards */
//==============================================================================
/**
* \class CSDV2
* \brief CSD register for version 2.00 cards.
*/
typedef struct CSDV2 {
// byte 0
unsigned char reserved1 : 6;
@@ -294,8 +369,11 @@ typedef struct CSDV2 {
/** checksum */
unsigned char crc : 7;
}__attribute__((packed)) csd2_t;
//------------------------------------------------------------------------------
/** union of old and new style CSD register */
//==============================================================================
/**
* \class csd_t
* \brief Union of old and new style CSD register.
*/
union csd_t {
csd1_t v1;
csd2_t v2;

+ 250
- 59
SdFat/SdSpi.h 查看文件

@@ -24,8 +24,8 @@
#ifndef SdSpi_h
#define SdSpi_h
#include <Arduino.h>
#include <SdFatConfig.h>
#include "SdFatConfig.h"
#include "utility/SoftSPI.h"
#if !USE_ARDUINO_SPI_LIBRARY
// AVR Arduinos
#ifdef __AVR__
@@ -34,108 +34,298 @@
#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__))
|| defined(__AVR_ATmega2560__))
#define USE_SOFTWARE_SPI 1
#else // USE_SOFTWARE_SPI
#define USE_NATIVE_AVR_SPI 1
#endif // USE_SOFTWARE_SPI
#endif // __AVR__
// Due
#if defined(__arm__) && !defined(CORE_TEENSY)
#if DUE_SOFT_SPI
#if DUE_SOFT_SPI && defined(__arm__) && !defined(CORE_TEENSY)
#define USE_SOFTWARE_SPI 1
#else // DUE_SOFT_SPI
/** Nonzero - use native SAM3X SPI */
#define USE_NATIVE_SAM3X_SPI 1
#endif // DUE_SOFT_SPI
#endif // defined(__arm__) && !defined(CORE_TEENSY)
// Teensy 3.0
#if defined(__arm__) && defined(CORE_TEENSY)
#if TEENSY3_SOFT_SPI
#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
#else // TEENSY3_SOFT_SPI
/** Nonzero - use native MK20DX128 SPI */
#define USE_NATIVE_TEENSY3_SPI 1
#endif // TEENSY3_SOFT_SPI
#endif // defined(__arm__) && defined(CORE_TEENSY)
#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

#ifndef USE_NATIVE_AVR_SPI
#define USE_NATIVE_AVR_SPI 0
#endif

#ifndef USE_NATIVE_SAM3X_SPI
#define USE_NATIVE_SAM3X_SPI 0
#endif // USE_NATIVE_SAM3X_SPI

#ifndef USE_NATIVE_TEENSY3_SPI
#define USE_NATIVE_TEENSY3_SPI 0
#endif // USE_NATIVE_TEENSY3_SPI
//------------------------------------------------------------------------------
// define default chip select pin
//
#if !USE_SOFTWARE_SPI
/** The default chip select pin for the SD card is SS. */
uint8_t const SD_CHIP_SELECT_PIN = SS;
#else // USE_AVR_SOFTWARE_SPI
/** SPI chip select pin for software SPI. */
uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN;
#endif // USE_AVR_SOFTWARE_SPI

/**
* \class SdSpiBase
* \brief Virtual SPI class for access to SD and SDHC flash memory cards.
*/
class SdSpiBase {
public:
/** Initialize the SPI bus */
virtual void begin() = 0;
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] divisor SCK clock divider relative to the system clock.
*/
virtual void init(uint8_t divisor);
/** Receive a byte.
*
* \return The byte.
*/
virtual uint8_t receive() = 0;
/** 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.
*/
virtual uint8_t receive(uint8_t* buf, size_t n) = 0;
/** Send a byte.
*
* \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.
*/
virtual void send(const uint8_t* buf, size_t n) = 0;
/** \return true if hardware SPI else false */
virtual bool useSpiTransactions() = 0;
};
//------------------------------------------------------------------------------
/**
* \class SdSpi
* \brief SPI class for access to SD and SDHC flash memory cards.
*/
#if USE_MULTIPLE_SPI_TYPES
class SdSpi : public SdSpiBase {
#else
class SdSpi {
#endif
public:
/** Initialize the SPI bus */
void begin();
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] spiDivisor SCK clock divider relative to the system clock.
*
* \param[in] divisor SCK clock divider relative to the system clock.
*/
void init(uint8_t spiDivisor);
/** Receive a byte.
void init(uint8_t divisor);
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive();
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \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);
/** Send a byte.
*
* \param[in] data Byte to send
*/
void send(uint8_t data);
/** Send multiple bytes.
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
*/
void send(const uint8_t* buf, size_t n);
/** \return true - uses SPI transactions */
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
class SdSpiLib : public SdSpiBase {
#else
class SdSpiLib {
#endif
public:
/**
* Initialize SPI pins.
*/
void begin() {SPI.begin();}
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] divisor SCK clock divider relative to the system clock.
*/
void init(uint8_t divisor) {
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
#ifndef SPI_CLOCK_DIV128
SPI.setClockDivider(divisor);
#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;
SPI.setClockDivider(v);
#endif // SPI_CLOCK_DIV128
}
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive() {return SPI.transfer(0XFF);}
/** 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] = SPI.transfer(0XFF);
}
return 0;
}
/** Send a byte.
*
* \param[in] b Byte to send
*/
void send(uint8_t b) {
SPI.transfer(b);
}
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void send(const uint8_t* buf , size_t n) {
for (size_t i = 0; i < n; i++) {
SPI.transfer(buf[i]);
}
}
/** \return true - uses SPI transactions */
bool useSpiTransactions() {return true;}
};
#endif // USE_MULTIPLE_SPI_TYPES || USE_ARDUINO_SPI_LIBRARY
//------------------------------------------------------------------------------
/**
* \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();}
/**
* Initialize hardware SPI - dummy for soft SPI
* \param[in] divisor SCK divisor - ignored.
*/
void init(uint8_t divisor) {}
/** Receive a byte.
*
* \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(uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
buf[i] = receive();
}
return 0;
}
/** Send a byte.
*
* \param[in] data Byte to send
*/
void send(uint8_t data) {m_spi.send(data);}
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void send(const uint8_t* buf , size_t n) {
for (size_t i = 0; i < n; i++) {
send(buf[i]);
}
}
/** \return false - no SPI transactions */
bool useSpiTransactions() {return false;}
private:
SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi;
};
//------------------------------------------------------------------------------
// Use of inline for AVR results in up to 10% better write performance.
// Inline also save a little flash memory.
/** inline avr native functions if nonzero. */
#define USE_AVR_NATIVE_SPI_INLINE 1
#if USE_NATIVE_AVR_SPI && USE_AVR_NATIVE_SPI_INLINE
#if USE_ARDUINO_SPI_LIBRARY
/** Default is Arduino library SPI. */
typedef SdSpiLib SpiDefault_t;
#elif USE_SOFTWARE_SPI
/** 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
//------------------------------------------------------------------------------
// Use of in-line for AVR to save flash.
#ifdef __AVR__
//------------------------------------------------------------------------------
inline void SdSpi::begin() {
#ifdef __AVR_ATmega328P__
// Save a few bytes for 328 CPU - gcc optimizes single bit '|' to sbi.
PORTB |= 1 << 2; // SS high
DDRB |= 1 << 2; // SS output mode
DDRB |= 1 << 3; // MOSI output mode
DDRB |= 1 << 5; // SCK output mode
#else // __AVR_ATmega328P__

// set SS high - may be chip select for another SPI device
digitalWrite(SS, HIGH);

// SS must be in output mode even it is not chip select
pinMode(SS, OUTPUT);
pinMode(MOSI, OUTPUT);
pinMode(SCK, OUTPUT);
#endif // __AVR_ATmega328P__
}
//------------------------------------------------------------------------------
inline void SdSpi::init(uint8_t divisor) {
uint8_t b = 2;
uint8_t r = 0;

// See AVR processor documentation.
for (; divisor > b && r < 7; b <<= 1, r += r < 5 ? 1 : 2) {}
SPCR = (1 << SPE) | (1 << MSTR) | (r >> 1);
SPSR = r & 1 ? 0 : 1 << SPI2X;
}
//------------------------------------------------------------------------------
inline uint8_t SdSpi::receive() {
SPDR = 0XFF;
while (!(SPSR & (1 << SPIF))) {}
return SPDR;
}
//------------------------------------------------------------------------------
inline uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
if (n-- == 0) return 0;
SPDR = 0XFF;
@@ -149,10 +339,12 @@ inline uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
buf[n] = SPDR;
return 0;
}
//------------------------------------------------------------------------------
inline void SdSpi::send(uint8_t data) {
SPDR = data;
while (!(SPSR & (1 << SPIF))) {}
}
//------------------------------------------------------------------------------
inline void SdSpi::send(const uint8_t* buf , size_t n) {
if (n == 0) return;
SPDR = buf[0];
@@ -168,6 +360,5 @@ inline void SdSpi::send(const uint8_t* buf , size_t n) {
}
while (!(SPSR & (1 << SPIF))) {}
}
#endif // USE_NATIVE_AVR_SPI && USE_AVR_NATIVE_SPI_INLINE
#endif // __AVR__
#endif // SdSpi_h


+ 0
- 86
SdFat/SdSpiAVR.cpp 查看文件

@@ -1,86 +0,0 @@
/* Arduino SdSpi Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdSpi 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 Arduino SdSpi Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdSpi.h>
#if USE_NATIVE_AVR_SPI
//------------------------------------------------------------------------------
void SdSpi::begin() {
// set SS high - may be chip select for another SPI device
digitalWrite(SS, HIGH);

// SS must be in output mode even it is not chip select
pinMode(SS, OUTPUT);
pinMode(MISO, INPUT);
pinMode(MOSI, OUTPUT);
pinMode(SCK, OUTPUT);
}
//------------------------------------------------------------------------------
void SdSpi::init(uint8_t sckDivisor) {
uint8_t r = 0;

for (uint8_t b = 2; sckDivisor > b && r < 6; b <<= 1, r++) {}
// See avr processor documentation
SPCR = (1 << SPE) | (1 << MSTR) | (r >> 1);
SPSR = r & 1 || r == 6 ? 0 : 1 << SPI2X;
}
#if !USE_AVR_NATIVE_SPI_INLINE
//------------------------------------------------------------------------------
uint8_t SdSpi::receive() {
SPDR = 0XFF;
while (!(SPSR & (1 << SPIF))) {}
return SPDR;
}
//------------------------------------------------------------------------------
uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
if (n-- == 0) return 0;
SPDR = 0XFF;
for (size_t i = 0; i < n; i++) {
while (!(SPSR & (1 << SPIF))) {}
uint8_t b = SPDR;
SPDR = 0XFF;
buf[i] = b;
}
while (!(SPSR & (1 << SPIF))) {}
buf[n] = SPDR;
return 0;
}
//------------------------------------------------------------------------------
void SdSpi::send(uint8_t data) {
SPDR = data;
while (!(SPSR & (1 << SPIF))) {}
}
//------------------------------------------------------------------------------
void SdSpi::send(const uint8_t* buf , size_t n) {
if (n == 0) return;
SPDR = buf[0];
if (n > 1) {
uint8_t b = buf[1];
size_t i = 2;
while (1) {
while (!(SPSR & (1 << SPIF))) {}
SPDR = b;
if (i == n) break;
b = buf[i++];
}
}
while (!(SPSR & (1 << SPIF))) {}
}
#endif // !USE_AVR_NATIVE_SPI_INLINE
#endif // USE_NATIVE_AVR_SPI


+ 0
- 70
SdFat/SdSpiArduino.cpp 查看文件

@@ -1,70 +0,0 @@
/* Arduino SdSpi Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdSpi 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 Arduino SdSpi Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdSpi.h>
#if USE_ARDUINO_SPI_LIBRARY
#include <SPI.h>
//------------------------------------------------------------------------------
void SdSpi::begin() {
SPI.begin();
}
//------------------------------------------------------------------------------
void SdSpi::init(uint8_t sckDivisor) {
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
#ifndef SPI_CLOCK_DIV128
SPI.setClockDivider(sckDivisor);
#else // SPI_CLOCK_DIV128
int v;
if (sckDivisor <= 2) v = SPI_CLOCK_DIV2;
else if (sckDivisor <= 4) v = SPI_CLOCK_DIV4;
else if (sckDivisor <= 8) v = SPI_CLOCK_DIV8;
else if (sckDivisor <= 16) v = SPI_CLOCK_DIV16;
else if (sckDivisor <= 32) v = SPI_CLOCK_DIV32;
else if (sckDivisor <= 64) v = SPI_CLOCK_DIV64;
else v = SPI_CLOCK_DIV128;
SPI.setClockDivider(v);
#endif // SPI_CLOCK_DIV128
}
//------------------------------------------------------------------------------
/** SPI receive a byte */
uint8_t SdSpi::receive() {
return SPI.transfer(0XFF);
}
//------------------------------------------------------------------------------
/** SPI receive multiple bytes */
uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
buf[i] = SPI.transfer(0XFF);
}
return 0;
}
//------------------------------------------------------------------------------
/** SPI send a byte */
void SdSpi::send(uint8_t b) {
SPI.transfer(b);
}
//------------------------------------------------------------------------------
/** SPI send multiple bytes */
void SdSpi::send(const uint8_t* buf , size_t n) {
for (size_t i = 0; i < n; i++) {
SPI.transfer(buf[i]);
}
}
#endif // USE_ARDUINO_SPI_LIBRARY

SdFat/Sd2Card.cpp → SdFat/SdSpiCard.cpp 查看文件

@@ -1,7 +1,7 @@
/* Arduino Sd2Card Library
/* Arduino SdSpiCard Library
* Copyright (C) 2012 by William Greiman
*
* This file is part of the Arduino Sd2Card Library
* This file is part of the Arduino SdSpiCard 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
@@ -14,19 +14,17 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino Sd2Card Library. If not, see
* along with the Arduino SdSpiCard Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <Sd2Card.h>
#include <SdSpi.h>
#if !USE_SOFTWARE_SPI && ENABLE_SPI_TRANSACTION
#include "SdSpiCard.h"
#include "SdSpi.h"
#if ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
#include <SPI.h>
#endif // !USE_SOFTWARE_SPI && defined(SPI_HAS_TRANSACTION)
#endif // ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
// debug trace macro
#define SD_TRACE(m, b)
// #define SD_TRACE(m, b) Serial.print(m);Serial.println(b);
//------------------------------------------------------------------------------
SdSpi Sd2Card::m_spi;
//==============================================================================
#if USE_SD_CRC
// CRC functions
@@ -114,20 +112,11 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
#endif // CRC_CCITT
#endif // USE_SD_CRC
//==============================================================================
// Sd2Card member functions
// SdSpiCard member functions
//------------------------------------------------------------------------------
/**
* Initialize an SD flash memory card.
*
* \param[in] chipSelectPin SD chip select pin number.
* \param[in] sckDivisor SPI SCK clock rate divisor.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. The reason for failure
* can be determined by calling errorCode() and errorData().
*/
bool Sd2Card::begin(uint8_t chipSelectPin, uint8_t sckDivisor) {
bool SdSpiCard::begin(m_spi_t* spi, uint8_t chipSelectPin, uint8_t sckDivisor) {
m_errorCode = m_type = 0;
m_spi = spi;
m_chipSelectPin = chipSelectPin;
// 16-bit init start time allows over a minute
uint16_t t0 = (uint16_t)millis();
@@ -135,14 +124,14 @@ bool Sd2Card::begin(uint8_t chipSelectPin, uint8_t sckDivisor) {

pinMode(m_chipSelectPin, OUTPUT);
digitalWrite(m_chipSelectPin, HIGH);
m_spi.begin();
spiBegin();

// set SCK rate for initialization commands
m_sckDivisor = SPI_SCK_INIT_DIVISOR;
m_spi.init(m_sckDivisor);
spiInit(m_sckDivisor);

// must supply min of 74 clock cycles with CS high.
for (uint8_t i = 0; i < 10; i++) m_spi.send(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) {
@@ -163,7 +152,7 @@ bool Sd2Card::begin(uint8_t chipSelectPin, uint8_t sckDivisor) {
type(SD_CARD_TYPE_SD1);
break;
}
for (uint8_t i = 0; i < 4; i++) m_status = m_spi.receive();
for (uint8_t i = 0; i < 4; i++) m_status = spiReceive();
if (m_status == 0XAA) {
type(SD_CARD_TYPE_SD2);
break;
@@ -189,9 +178,9 @@ bool Sd2Card::begin(uint8_t chipSelectPin, uint8_t sckDivisor) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
if ((m_spi.receive() & 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++) m_spi.receive();
for (uint8_t i = 0; i < 3; i++) spiReceive();
}
chipSelectHigh();
m_sckDivisor = sckDivisor;
@@ -203,7 +192,7 @@ bool Sd2Card::begin(uint8_t chipSelectPin, uint8_t sckDivisor) {
}
//------------------------------------------------------------------------------
// send command and return error code. Return zero for OK
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
// select card
chipSelectLow();

@@ -220,34 +209,28 @@ uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
d[5] = CRC7(d, 5);

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

// send argument
for (int8_t i = 3; i >= 0; i--) m_spi.send(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
m_spi.send(cmd == CMD0 ? 0X95 : 0X87);
spiSend(cmd == CMD0 ? 0X95 : 0X87);
#endif // USE_SD_CRC

// skip stuff byte for stop read
if (cmd == CMD12) m_spi.receive();
if (cmd == CMD12) spiReceive();

// wait for response
for (uint8_t i = 0; ((m_status = m_spi.receive()) & 0X80) && i != 0XFF; i++) {
for (uint8_t i = 0; ((m_status = spiReceive()) & 0X80) && i != 0XFF; i++) {
}
return m_status;
}
//------------------------------------------------------------------------------
/**
* Determine the size of an SD flash memory card.
*
* \return The number of 512 byte data blocks in the card
* or zero if an error occurs.
*/
uint32_t Sd2Card::cardSize() {
uint32_t SdSpiCard::cardSize() {
csd_t csd;
if (!readCSD(&csd)) return 0;
if (csd.v1.csd_ver == 0) {
@@ -267,44 +250,31 @@ uint32_t Sd2Card::cardSize() {
}
}
//------------------------------------------------------------------------------
void Sd2Card::spiYield() {
#if ENABLE_SPI_YIELD && !USE_SOFTWARE_SPI && defined(SPI_HAS_TRANSACTION)
void SdSpiCard::spiYield() {
#if ENABLE_SPI_TRANSACTION && ENABLE_SPI_YIELD && defined(SPI_HAS_TRANSACTION)
chipSelectHigh();
chipSelectLow();
#endif // ENABLE_SPI_YIELD && !USE_SOFTWARE_SPI && defined(SPI_HAS_TRANSACTION)
#endif // ENABLE_SPI_TRANSACTION && ENABLE_SPI_YIELD && SPI_HAS_TRANSACTION
}
//------------------------------------------------------------------------------
void Sd2Card::chipSelectHigh() {
void SdSpiCard::chipSelectHigh() {
digitalWrite(m_chipSelectPin, HIGH);
// insure MISO goes high impedance
m_spi.send(0XFF);
#if !USE_SOFTWARE_SPI && defined(SPI_HAS_TRANSACTION)
SPI.endTransaction();
#endif // !USE_SOFTWARE_SPI && defined(SPI_HAS_TRANSACTION)
spiSend(0XFF);
#if ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
if (useSpiTransactions()) SPI.endTransaction();
#endif // ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
}
//------------------------------------------------------------------------------
void Sd2Card::chipSelectLow() {
#if !USE_SOFTWARE_SPI && defined(SPI_HAS_TRANSACTION)
SPI.beginTransaction(SPISettings());
#endif // !USE_SOFTWARE_SPI && defined(SPI_HAS_TRANSACTION)
m_spi.init(m_sckDivisor);
void SdSpiCard::chipSelectLow() {
#if ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
if (useSpiTransactions()) SPI.beginTransaction(SPISettings());
#endif // ENABLE_SPI_TRANSACTION && defined(SPI_HAS_TRANSACTION)
spiInit(m_sckDivisor);
digitalWrite(m_chipSelectPin, LOW);
}
//------------------------------------------------------------------------------
/** Erase a range of blocks.
*
* \param[in] firstBlock The address of the first block in the range.
* \param[in] lastBlock The address of the last block in the range.
*
* \note This function requests the SD card to do a flash erase for a
* range of blocks. The data on the card after an erase operation is
* 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.
*/
bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
bool SdSpiCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
csd_t csd;
if (!readCSD(&csd)) goto fail;
// check for single block erase
@@ -339,42 +309,23 @@ bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
return false;
}
//------------------------------------------------------------------------------
/** Determine if card supports single block erase.
*
* \return The value one, true, is returned if single block erase is supported.
* The value zero, false, is returned if single block erase is not supported.
*/
bool Sd2Card::eraseSingleBlockEnable() {
bool SdSpiCard::eraseSingleBlockEnable() {
csd_t csd;
return readCSD(&csd) ? csd.v1.erase_blk_en : false;
}
//------------------------------------------------------------------------------
/**
* Check for busy. MISO low indicates the card is busy.
*
* \return true if busy else false.
*/
bool Sd2Card::isBusy() {
bool SdSpiCard::isBusy() {
bool rtn;
chipSelectLow();
for (uint8_t i = 0; i < 8; i++) {
rtn = m_spi.receive() != 0XFF;
rtn = spiReceive() != 0XFF;
if (!rtn) break;
}
chipSelectHigh();
return rtn;
}
//------------------------------------------------------------------------------
/**
* Read a 512 byte block from an SD card.
*
* \param[in] blockNumber 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.
*/
bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
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;
@@ -389,52 +340,52 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
return false;
}
//------------------------------------------------------------------------------
/** Read one data block in a multiple block read sequence
*
* \param[in] 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.
*/
bool Sd2Card::readData(uint8_t *dst) {
bool SdSpiCard::readBlocks(uint32_t block, uint8_t* dst, size_t count) {
if (!readStart(block)) return false;
for (uint16_t b = 0; b < count; b++, dst += 512) {
if (!readData(dst)) return false;
}
return readStop();
}
//------------------------------------------------------------------------------
bool SdSpiCard::readData(uint8_t *dst) {
chipSelectLow();
return readData(dst, 512);
}
//------------------------------------------------------------------------------
bool Sd2Card::readData(uint8_t* dst, size_t count) {
bool SdSpiCard::readData(uint8_t* dst, size_t count) {
#if USE_SD_CRC
uint16_t crc;
#endif // USE_SD_CRC
// wait for start block token
uint16_t t0 = millis();
while ((m_status = m_spi.receive()) == 0XFF) {
while ((m_status = spiReceive()) == 0XFF) {
if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
error(SD_CARD_ERROR_READ_TIMEOUT);
goto fail;
}
spiYield();
}
if (m_status != DATA_START_BLOCK) {
error(SD_CARD_ERROR_READ);
goto fail;
}
// transfer data
if ((m_status = m_spi.receive(dst, count))) {
if ((m_status = spiReceive(dst, count))) {
error(SD_CARD_ERROR_SPI_DMA);
goto fail;
}

#if USE_SD_CRC
// get crc
crc = (m_spi.receive() << 8) | m_spi.receive();
crc = (spiReceive() << 8) | spiReceive();
if (crc != CRC_CCITT(dst, count)) {
error(SD_CARD_ERROR_READ_CRC);
goto fail;
}
#else
// discard crc
m_spi.receive();
m_spi.receive();
spiReceive();
spiReceive();
#endif // USE_SD_CRC
chipSelectHigh();
return true;
@@ -444,18 +395,13 @@ bool Sd2Card::readData(uint8_t* dst, size_t count) {
return false;
}
//------------------------------------------------------------------------------
/** Read OCR register.
*
* \param[out] ocr Value of OCR register.
* \return true for success else false.
*/
bool Sd2Card::readOCR(uint32_t* ocr) {
bool SdSpiCard::readOCR(uint32_t* ocr) {
uint8_t *p = reinterpret_cast<uint8_t*>(ocr);
if (cardCommand(CMD58, 0)) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
for (uint8_t i = 0; i < 4; i++) p[3-i] = m_spi.receive();
for (uint8_t i = 0; i < 4; i++) p[3-i] = spiReceive();

chipSelectHigh();
return true;
@@ -466,7 +412,7 @@ bool Sd2Card::readOCR(uint32_t* ocr) {
}
//------------------------------------------------------------------------------
/** read CID or CSR register */
bool Sd2Card::readRegister(uint8_t cmd, void* buf) {
bool SdSpiCard::readRegister(uint8_t cmd, void* buf) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
if (cardCommand(cmd, 0)) {
error(SD_CARD_ERROR_READ_REG);
@@ -479,17 +425,7 @@ bool Sd2Card::readRegister(uint8_t cmd, void* buf) {
return false;
}
//------------------------------------------------------------------------------
/** Start a read multiple blocks sequence.
*
* \param[in] blockNumber Address of first block in sequence.
*
* \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.
*/
bool Sd2Card::readStart(uint32_t blockNumber) {
bool SdSpiCard::readStart(uint32_t blockNumber) {
SD_TRACE("RS", blockNumber);
if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (cardCommand(CMD18, blockNumber)) {
@@ -504,12 +440,7 @@ bool Sd2Card::readStart(uint32_t blockNumber) {
return false;
}
//------------------------------------------------------------------------------
/** End a read multiple blocks sequence.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool Sd2Card::readStop() {
bool SdSpiCard::readStop() {
if (cardCommand(CMD12, 0)) {
error(SD_CARD_ERROR_CMD12);
goto fail;
@@ -523,9 +454,9 @@ bool Sd2Card::readStop() {
}
//------------------------------------------------------------------------------
// wait for card to go not busy
bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
bool SdSpiCard::waitNotBusy(uint16_t timeoutMillis) {
uint16_t t0 = millis();
while (m_spi.receive() != 0XFF) {
while (spiReceive() != 0XFF) {
if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail;
spiYield();
}
@@ -535,15 +466,7 @@ bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
return false;
}
//------------------------------------------------------------------------------
/**
* 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.
*/
bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
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;
@@ -561,7 +484,7 @@ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
goto fail;
}
// response is r2 so get and check two bytes for nonzero
if (cardCommand(CMD13, 0) || m_spi.receive()) {
if (cardCommand(CMD13, 0) || spiReceive()) {
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
goto fail;
}
@@ -575,12 +498,15 @@ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
return false;
}
//------------------------------------------------------------------------------
/** 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.
*/
bool Sd2Card::writeData(const uint8_t* src) {
bool SdSpiCard::writeBlocks(uint32_t block, const uint8_t* src, size_t count) {
if (!writeStart(block, count)) return false;
for (size_t b = 0; b < count; b++, src += 512) {
if (!writeData(src)) return false;
}
return writeStop();
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeData(const uint8_t* src) {
chipSelectLow();
// wait for previous write to finish
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
@@ -595,18 +521,18 @@ bool Sd2Card::writeData(const uint8_t* src) {
}
//------------------------------------------------------------------------------
// send one block of data for write block or write multiple blocks
bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
bool SdSpiCard::writeData(uint8_t token, const uint8_t* src) {
#if USE_SD_CRC
uint16_t crc = CRC_CCITT(src, 512);
#else // USE_SD_CRC
uint16_t crc = 0XFFFF;
#endif // USE_SD_CRC
m_spi.send(token);
m_spi.send(src, 512);
m_spi.send(crc >> 8);
m_spi.send(crc & 0XFF);
spiSend(token);
spiSend(src, 512);
spiSend(crc >> 8);
spiSend(crc & 0XFF);

m_status = m_spi.receive();
m_status = spiReceive();
if ((m_status & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
error(SD_CARD_ERROR_WRITE);
goto fail;
@@ -618,18 +544,7 @@ bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
return false;
}
//------------------------------------------------------------------------------
/** Start a write multiple blocks sequence.
*
* \param[in] blockNumber Address of first block in sequence.
* \param[in] eraseCount The number of blocks to be pre-erased.
*
* \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.
*/
bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
SD_TRACE("WS", blockNumber);
// send pre-erase count
if (cardAcmd(ACMD23, eraseCount)) {
@@ -650,15 +565,10 @@ bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
return false;
}
//------------------------------------------------------------------------------
/** End a write multiple blocks sequence.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool Sd2Card::writeStop() {
bool SdSpiCard::writeStop() {
chipSelectLow();
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
m_spi.send(STOP_TRAN_TOKEN);
spiSend(STOP_TRAN_TOKEN);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
chipSelectHigh();
return true;

+ 281
- 0
SdFat/SdSpiCard.h 查看文件

@@ -0,0 +1,281 @@
/* Arduino SdSpiCard Library
* Copyright (C) 2012 by William Greiman
*
* This file is part of the Arduino SdSpiCard 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 Arduino SdSpiCard Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SpiCard_h
#define SpiCard_h
/**
* \file
* \brief SdSpiCard class for V2 SD/SDHC cards
*/
#include <Arduino.h>
#include <SdFatConfig.h>
#include <SdInfo.h>
#include <SdSpi.h>
//==============================================================================
/**
* \class SdSpiCard
* \brief Raw access to SD and SDHC flash memory cards via SPI protocol.
*/
class SdSpiCard {
public:
/** typedef for SPI class. */
#if USE_MULTIPLE_SPI_TYPES
typedef SdSpiBase m_spi_t;
#else // USE_MULTIPLE_SPI_TYPES
typedef SpiDefault_t m_spi_t;
#endif // USE_MULTIPLE_SPI_TYPES
/** Construct an instance of SdSpiCard. */
SdSpiCard() : m_errorCode(SD_CARD_ERROR_INIT_NOT_CALLED), m_type(0) {}
/** Initialize the SD card.
* \param[in] spi SPI object.
* \param[in] chipSelectPin SD chip select pin.
* \param[in] sckDivisor SPI clock divisor.
* \return true for success else false.
*/
bool begin(m_spi_t* spi, uint8_t chipSelectPin = SS,
uint8_t sckDivisor = SPI_FULL_SPEED);
/**
* Determine the size of an SD flash memory card.
*
* \return The number of 512 byte data blocks in the card
* or zero if an error occurs.
*/
uint32_t cardSize();
/** Erase a range of blocks.
*
* \param[in] firstBlock The address of the first block in the range.
* \param[in] lastBlock The address of the last block in the range.
*
* \note This function requests the SD card to do a flash erase for a
* range of blocks. The data on the card after an erase operation is
* 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.
*/
bool erase(uint32_t firstBlock, uint32_t lastBlock);
/** Determine if card supports single block erase.
*
* \return true is returned if single block erase is supported.
* false is returned if single block erase is not supported.
*/
bool eraseSingleBlockEnable();
/**
* Set SD error code.
* \param[in] code value for error 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;}
/** \return error data for last error. */
int errorData() const {return m_status;}
/**
* Check for busy. MISO low indicates the card is busy.
*
* \return true if busy else false.
*/
bool isBusy();
/**
* Read a 512 byte block from an SD card.
*
* \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.
*/
bool readBlock(uint32_t block, uint8_t* dst);
/**
* Read multiple 512 byte blocks from an SD card.
*
* \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.
*/
bool readBlocks(uint32_t block, uint8_t* dst, size_t count);
/**
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
* number and Manufacturing date.
*
* \param[out] cid pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCID(cid_t* cid) {
return readRegister(CMD10, cid);
}
/**
* Read a card's CSD register. The CSD contains Card-Specific Data that
* provides information regarding access to the card's contents.
*
* \param[out] csd pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCSD(csd_t* csd) {
return readRegister(CMD9, csd);
}
/** Read one data block in a multiple block read sequence
*
* \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.
*/
bool readData(uint8_t *dst);
/** Read OCR register.
*
* \param[out] ocr Value of OCR register.
* \return true for success else false.
*/
bool readOCR(uint32_t* ocr);
/** Start a read multiple blocks sequence.
*
* \param[in] blockNumber Address of first block in sequence.
*
* \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.
*/
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.
*/
bool readStop();
/** Return SCK divisor.
*
* \return Requested SCK divisor.
*/
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;}
/**
* 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.
*/
bool writeBlock(uint32_t blockNumber, const uint8_t* src);
/**
* Write multiple 512 byte blocks to an SD card.
*
* \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.
*/
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.
*/
bool writeData(const uint8_t* src);
/** Start a write multiple blocks sequence.
*
* \param[in] blockNumber Address of first block in sequence.
* \param[in] eraseCount The number of blocks to be pre-erased.
*
* \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.
*/
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.
*/
bool writeStop();

private:
// private functions
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
cardCommand(CMD55, 0);
return cardCommand(cmd, arg);
}
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
bool readData(uint8_t* dst, size_t count);
bool readRegister(uint8_t cmd, void* buf);
void chipSelectHigh();
void chipSelectLow();
void spiYield();
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();}

m_spi_t* m_spi;
uint8_t m_chipSelectPin;
uint8_t m_errorCode;
uint8_t m_sckDivisor;
uint8_t m_status;
uint8_t m_type;
};
//==============================================================================
/**
* \class Sd2Card
* \brief Raw access to SD and SDHC card using default SPI library.
*/
class Sd2Card : public SdSpiCard {
public:
/** Initialize the SD card.
* \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);
}
/** Initialize the SD card. Obsolete form.
* \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;}
SpiDefault_t m_spi;
};
#endif // SpiCard_h

+ 3
- 3
SdFat/SdSpiSAM3X.cpp 查看文件

@@ -17,8 +17,8 @@
* along with the Arduino SdSpi Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdSpi.h>
#if USE_NATIVE_SAM3X_SPI
#include "SdSpi.h"
#if defined(__SAM3X8E__) || defined(__SAM3X8H__)
/** Use SAM3X DMAC if nonzero */
#define USE_SAM3X_DMAC 1
/** Use extra Bus Matrix arbitration fix if nonzero */
@@ -213,4 +213,4 @@ void SdSpi::send(const uint8_t* buf , size_t n) {
// leave RDR empty
uint8_t b = pSpi->SPI_RDR;
}
#endif // USE_NATIVE_SAM3X_SPI
#endif // defined(__SAM3X8E__) || defined(__SAM3X8H__)

+ 0
- 61
SdFat/SdSpiSoft.cpp 查看文件

@@ -1,61 +0,0 @@
/* Arduino SdSpi Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdSpi 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 Arduino SdSpi Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdSpi.h>
#if USE_SOFTWARE_SPI
#include <SoftSPI.h>
static
SoftSPI<SOFT_SPI_MISO_PIN, SOFT_SPI_MOSI_PIN, SOFT_SPI_SCK_PIN, 0> softSpiBus;
//------------------------------------------------------------------------------
/**
* initialize SPI pins
*/
void SdSpi::begin() {
softSpiBus.begin();
}
//------------------------------------------------------------------------------
/**
* Initialize hardware SPI - dummy for soft SPI
*/
void SdSpi::init(uint8_t sckDivisor) {}
//------------------------------------------------------------------------------
/** Soft SPI receive byte */
uint8_t SdSpi::receive() {
return softSpiBus.receive();
}
//------------------------------------------------------------------------------
/** Soft SPI read data */
uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
buf[i] = receive();
}
return 0;
}
//------------------------------------------------------------------------------
/** Soft SPI send byte */
void SdSpi::send(uint8_t data) {
softSpiBus.send(data);
}
//------------------------------------------------------------------------------
void SdSpi::send(const uint8_t* buf , size_t n) {
for (size_t i = 0; i < n; i++) {
send(buf[i]);
}
}
#endif // USE_SOFTWARE_SPI

+ 4
- 4
SdFat/SdSpiTeensy3.cpp 查看文件

@@ -17,10 +17,10 @@
* along with the Arduino SdSpi Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdSpi.h>
#if USE_NATIVE_TEENSY3_SPI
#include "SdSpi.h"
#if defined(__arm__) && defined(CORE_TEENSY)
// Teensy 3.0 functions
#include <mk20dx128.h>
#include "mk20dx128.h"
// use 16-bit frame if SPI_USE_8BIT_FRAME is zero
#define SPI_USE_8BIT_FRAME 0
// Limit initial fifo to three entries to avoid fifo overrun
@@ -220,4 +220,4 @@ void SdSpi::send(const uint8_t* buf , size_t n) {
}
#endif // SPI_USE_8BIT_FRAME
}
#endif // USE_NATIVE_TEENSY3_SPI
#endif // defined(__arm__) && defined(CORE_TEENSY)

+ 31
- 178
SdFat/SdVolume.h 查看文件

@@ -18,199 +18,52 @@
* <http://www.gnu.org/licenses/>.
*/
#ifndef SdVolume_h
#include "SdSpiCard.h"
#include "utility/FatLib.h"
#define SdVolume_h
/**
* \file
* \brief SdVolume class
*/
#include <SdFatConfig.h>
#include <Sd2Card.h>
#include <utility/FatStructs.h>
#ifndef USE_SD_VOLUME
#error SdVolume is deperacated. Remove this line to continue using this class.
#endif // USE_SD_VOLUME
//==============================================================================
// SdVolume class
/**
* \brief Cache for an SD data block
*/
union cache_t {
/** Used to access cached file data blocks. */
uint8_t data[512];
/** Used to access cached FAT16 entries. */
uint16_t fat16[256];
/** Used to access cached FAT32 entries. */
uint32_t fat32[128];
/** Used to access cached directory entries. */
dir_t dir[16];
/** Used to access a cached Master Boot Record. */
mbr_t mbr;
/** Used to access to a cached FAT boot sector. */
fat_boot_t fbs;
/** Used to access to a cached FAT32 boot sector. */
fat32_boot_t fbs32;
/** Used to access to a cached FAT32 FSINFO sector. */
fat32_fsinfo_t fsinfo;
};
//------------------------------------------------------------------------------
/**
* \class SdVolume
* \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
* \brief SdVolume used in Quick start. Soon to be removed.
*/
class SdVolume {
class SdVolume : public FatVolume {
public:
/** Create an instance of SdVolume */
SdVolume() : m_fatType(0) {}
/** Clear the cache and returns a pointer to the cache. Used by the WaveRP
* recorder to do raw write to the SD card. Not for normal apps.
* \return A pointer to the cache buffer or zero if an error occurs.
*/
cache_t* cacheClear() {
if (!cacheSync()) return 0;
m_cacheBlockNumber = 0XFFFFFFFF;
return &m_cacheBuffer;
}
/** Initialize a FAT volume. Try partition one first then try super
/** Initialize a FAT volume. Try partition one first then try super
* floppy format.
*
* \param[in] dev The Sd2Card where the volume is located.
*
* \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.
*/
bool init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
bool init(Sd2Card* dev, uint8_t part);

// inline functions that return volume info
/** \return The volume's cluster size in blocks. */
uint8_t blocksPerCluster() const {return m_blocksPerCluster;}
/** \return The number of blocks in one FAT. */
uint32_t blocksPerFat() const {return m_blocksPerFat;}
/** \return The total number of clusters in the volume. */
uint32_t clusterCount() const {return m_clusterCount;}
/** \return The shift count required to multiply by blocksPerCluster. */
uint8_t clusterSizeShift() const {return m_clusterSizeShift;}
/** \return The logical block number for the start of file data. */
uint32_t dataStartBlock() const {return clusterStartBlock(2);}
/** \return The number of FAT structures on the volume. */
uint8_t fatCount() const {return m_fatCount;}
/** \return The logical block number for the start of the first FAT. */
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;}
int32_t freeClusterCount();
/** \return The number of entries in the root directory for FAT16 volumes. */
uint32_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;}
/** Sd2Card object for this volume
* \return pointer to Sd2Card object.
* \return true for success else false.
*/
Sd2Card* sdCard() {return m_sdCard;}

/** Debug access to FAT table
bool init(Sd2Card* dev) {return init(dev, 1) ? true : init(dev, 0);}
/** Initialize a FAT volume.
*
* \param[in] n cluster number.
* \param[out] v value of entry
* \return true for success or false for failure
* \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 dbgFat(uint32_t n, uint32_t* v) {return fatGet(n, v);}
//------------------------------------------------------------------------------
private:
// Allow SdBaseFile access to SdVolume private data.
friend class SdBaseFile;
//------------------------------------------------------------------------------
uint32_t m_allocSearchStart; // Start cluster for alloc search.
uint8_t m_blocksPerCluster; // Cluster size in blocks.
uint8_t m_clusterBlockMask; // Mask to extract block of cluster.
uint32_t m_clusterCount; // Clusters in one FAT.
uint8_t m_clusterSizeShift; // Cluster count to block count shift.
uint32_t m_dataStartBlock; // First data block number.
uint32_t m_fatStartBlock; // Start block for first FAT.
uint8_t m_fatType; // Volume type (12, 16, OR 32).
uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
uint32_t m_rootDirStart; // Start block for FAT16, cluster for FAT32.
//------------------------------------------------------------------------------
// block caches
// use of static functions save a bit of flash - maybe not worth complexity
//
static const uint8_t CACHE_STATUS_DIRTY = 1;
static const uint8_t CACHE_STATUS_FAT_BLOCK = 2;
static const uint8_t CACHE_STATUS_MASK
= CACHE_STATUS_DIRTY | CACHE_STATUS_FAT_BLOCK;
static const uint8_t CACHE_OPTION_NO_READ = 4;
// value for option argument in cacheFetch to indicate read from cache
static uint8_t const CACHE_FOR_READ = 0;
// value for option argument in cacheFetch to indicate write to cache
static uint8_t const CACHE_FOR_WRITE = CACHE_STATUS_DIRTY;
// reserve cache block with no read
static uint8_t const CACHE_RESERVE_FOR_WRITE
= CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ;
#if USE_MULTIPLE_CARDS
uint8_t m_fatCount; // number of FATs on volume
uint32_t m_blocksPerFat; // FAT size in blocks
cache_t m_cacheBuffer; // 512 byte cache for device blocks
uint32_t m_cacheBlockNumber; // Logical number of block in the cache
Sd2Card* m_sdCard; // Sd2Card object for cache
uint8_t m_cacheStatus; // status of cache block
#if USE_SEPARATE_FAT_CACHE
cache_t m_cacheFatBuffer; // 512 byte cache for FAT
uint32_t m_cacheFatBlockNumber; // current Fat block number
uint8_t m_cacheFatStatus; // status of cache Fatblock
#endif // USE_SEPARATE_FAT_CACHE
#else // USE_MULTIPLE_CARDS
static uint8_t m_fatCount; // number of FATs on volume
static uint32_t m_blocksPerFat; // FAT size in blocks
static cache_t m_cacheBuffer; // 512 byte cache for device blocks
static uint32_t m_cacheBlockNumber; // Logical number of block in the cache
static uint8_t m_cacheStatus; // status of cache block
#if USE_SEPARATE_FAT_CACHE
static cache_t m_cacheFatBuffer; // 512 byte cache for FAT
static uint32_t m_cacheFatBlockNumber; // current Fat block number
static uint8_t m_cacheFatStatus; // status of cache Fatblock
#endif // USE_SEPARATE_FAT_CACHE
static Sd2Card* m_sdCard; // Sd2Card object for cache
#endif // USE_MULTIPLE_CARDS
bool init(Sd2Card* dev, uint8_t part) {
m_sdCard = dev;
return FatVolume::init(part);
}

cache_t *cacheAddress() {return &m_cacheBuffer;}
uint32_t cacheBlockNumber() {return m_cacheBlockNumber;}
#if USE_MULTIPLE_CARDS
cache_t* cacheFetch(uint32_t blockNumber, uint8_t options);
cache_t* cacheFetchData(uint32_t blockNumber, uint8_t options);
cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options);
void cacheInvalidate();
bool cacheSync();
bool cacheWriteData();
bool cacheWriteFat();
#else // USE_MULTIPLE_CARDS
static cache_t* cacheFetch(uint32_t blockNumber, uint8_t options);
static cache_t* cacheFetchData(uint32_t blockNumber, uint8_t options);
static cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options);
static void cacheInvalidate();
static bool cacheSync();
static bool cacheWriteData();
static bool cacheWriteFat();
#endif // USE_MULTIPLE_CARDS
//------------------------------------------------------------------------------
bool allocContiguous(uint32_t count, uint32_t* curCluster);
uint8_t blockOfCluster(uint32_t position) const {
return (position >> 9) & m_clusterBlockMask;}
uint32_t clusterStartBlock(uint32_t cluster) const;
bool fatGet(uint32_t cluster, uint32_t* value);
bool fatPut(uint32_t cluster, uint32_t value);
bool fatPutEOC(uint32_t cluster) {
return fatPut(cluster, 0x0FFFFFFF);
private:
// friend class FatFile;
bool readBlock(uint32_t block, uint8_t* dst) {
return m_sdCard->readBlock(block, dst);
}
bool freeChain(uint32_t cluster);
bool isEOC(uint32_t cluster) const {
if (FAT12_SUPPORT && m_fatType == 12) return cluster >= FAT12EOC_MIN;
if (m_fatType == 16) return cluster >= FAT16EOC_MIN;
return cluster >= FAT32EOC_MIN;
bool writeBlock(uint32_t block, const uint8_t* src) {
return m_sdCard->writeBlock(block, src);
}
bool readBlock(uint32_t block, uint8_t* dst) {
return m_sdCard->readBlock(block, dst);}
bool writeBlock(uint32_t block, const uint8_t* dst) {
return m_sdCard->writeBlock(block, dst);
bool readBlocks(uint32_t block, uint8_t* dst, size_t n) {
return m_sdCard->readBlocks(block, dst, n);
}
bool writeBlocks(uint32_t block, const uint8_t* src, size_t n) {
return m_sdCard->writeBlocks(block, src, n);
}
Sd2Card* m_sdCard; // Sd2Card object for cache
};
#endif // SdVolume
#endif // SdVolume_h

+ 2
- 1
SdFat/examples/#attic/AnalogLogger/AnalogLogger.ino 查看文件

@@ -1,5 +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 <SdFat.h>
#include <SdFatUtil.h> // define FreeRam()

@@ -28,7 +29,7 @@ char buf[80];
#endif // SENSOR_COUNT
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
#if USE_DS1307
// use RTClib from Adafruit

+ 1
- 0
SdFat/examples/#attic/HelloWorld/HelloWorld.ino 查看文件

@@ -1,3 +1,4 @@
#include <SPI.h>
#include <SdFat.h>

// create a serial output stream

+ 17
- 6
SdFat/examples/#attic/MiniSerial/MiniSerial.ino 查看文件

@@ -3,16 +3,27 @@
//
// This is useful for debug and saves RAM
// Will not work on Due, Leonardo, or Teensy

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#ifndef UDR0
#error no AVR serial port0
#endif
#ifdef UDR0 // Must be AVR with serial port zero.
#include <MinimumSerial.h>

MinimumSerial MiniSerial;

void setup() {
MiniSerial.begin(9600);
MiniSerial.println(FreeRam());
}
void loop() {
int c;
MiniSerial.println(F("Type any Character"));
while(MiniSerial.read() < 0) {}
MiniSerial.println(F("Done"));
while ((c = MiniSerial.read()) < 0) {}
MiniSerial.print(F("Read: "));
MiniSerial.println((char)c);
while (MiniSerial.read() >= 0) {}
}
void loop() {}
#else // UDR0
#error no AVR serial port 0
#endif // UDR0

+ 4
- 4
SdFat/examples/#attic/PrintBenchmarkSD/PrintBenchmarkSD.ino 查看文件

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

// SD chip select pin
const uint8_t chipSelect = SS;
@@ -79,9 +79,9 @@ void loop() {
break;
}

// if (file.writeError) {
// error("write failed");
// }
if (file.getWriteError()) {
error("write failed");
}
m = micros() - m;
if (maxLatency < m) maxLatency = m;
if (minLatency > m) minLatency = m;

+ 1
- 0
SdFat/examples/#attic/SdFatSize/SdFatSize.ino 查看文件

@@ -3,6 +3,7 @@
* See SD_Size.pde for Arduino SD sketch.
*
*/
#include <SPI.h>
#include <SdFat.h>

SdFat sd;

+ 2
- 1
SdFat/examples/#attic/append/append.ino 查看文件

@@ -5,6 +5,7 @@
* The sketch will append 100 line each time it opens the file.
* The sketch will open and close the file 100 times.
*/
#include <SPI.h>
#include <SdFat.h>

// SD chip select pin
@@ -17,7 +18,7 @@ SdFat sd;
ArduinoOutStream cout(Serial);

// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
void setup() {
// filename for this example

+ 1
- 0
SdFat/examples/#attic/average/average.ino 查看文件

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

// SD chip select pin

+ 0
- 2
SdFat/examples/#attic/benchSD/benchSD.ino 查看文件

@@ -5,7 +5,6 @@
#include <SPI.h>
#include <SD.h>


// SD chip select pin
const uint8_t chipSelect = SS;

@@ -15,7 +14,6 @@ const uint8_t chipSelect = SS;

uint8_t buf[BUF_SIZE];


// test file
File file;


+ 1
- 0
SdFat/examples/#attic/bufstream/bufstream.ino 查看文件

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

// create a serial output stream

+ 1
- 0
SdFat/examples/#attic/eventlog/eventlog.ino 查看文件

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

// SD chip select pin

+ 3
- 2
SdFat/examples/#attic/fgetsRewrite/fgetsRewrite.ino 查看文件

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

// SD card chip select pin
@@ -11,7 +12,7 @@ SdFat sd;
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// store error strings in flash memory
#define error(s) sd.errorHalt_P(PSTR(s))
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
void demoFgets() {
char line[25];
@@ -60,7 +61,7 @@ void makeTestFile() {
if (!wrfile.isOpen()) error("MakeTestFile");
// write test file
wrfile.write_P(PSTR(
wrfile.print(F(
"Line A\r\n"
"Line B\r\n"
"Line C\r\n"

+ 1
- 0
SdFat/examples/#attic/readlog/readlog.ino 查看文件

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

// SD chip select pin

+ 0
- 2
SdFat/examples/#attic/readme.txt 查看文件

@@ -26,5 +26,3 @@ readlog - Read file. Demo of pathnames and current working directory.
SD_Size - Determine flash used by SD.h example.

SdFatSize - Determine flash used by SdFat.

TestMkdirRmdir - Test mkdir, rmdir, and directory management.

+ 8
- 4
SdFat/examples/AnalogBinLogger/AnalogBinLogger.ino 查看文件

@@ -19,9 +19,10 @@
*
* Data is written to the file using a SD multiple block write command.
*/
#ifdef __AVR__
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <StdioStream.h>
#include "AnalogBinLogger.h"
//------------------------------------------------------------------------------
// Analog pin number list for a sample. Pins may be in any order and pin
@@ -247,10 +248,10 @@ ISR(TIMER1_COMPB_vect) {
}
//==============================================================================
// Error messages stored in flash.
#define error(msg) error_P(PSTR(msg))
#define error(msg) errorFlash(F(msg))
//------------------------------------------------------------------------------
void error_P(const char* msg) {
sd.errorPrint_P(msg);
void errorFlash(const __FlashStringHelper* msg) {
sd.errorPrint(msg);
fatalBlink();
}
//------------------------------------------------------------------------------
@@ -785,3 +786,6 @@ void loop(void) {
Serial.println(F("Invalid entry"));
}
}
#else // __AVR__
#error This program is only for AVR.
#endif // __AVR__

+ 87
- 0
SdFat/examples/LongFileName/LongFileName.ino 查看文件

@@ -0,0 +1,87 @@
// Example use of openNextLFN and open by index.
// You can use test files located in
// SdFat/examples/LongFileName/testFiles.
#include<SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>

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

SdFat sd;
SdFile file;

// Number of files found.
uint16_t n = 0;

// Max of ten files since files are selected with a single digit.
const uint16_t nMax = 10;

// Position of file's directory entry.
uint16_t dirIndex[nMax];
//------------------------------------------------------------------------------
void setup() {
const size_t NAME_DIM = 50;
char name[NAME_DIM];
dir_t dir;
Serial.begin(9600);
while (!Serial) {}
// Print the location of some test files.
Serial.println(F("\r\n"
"You can use test files located in\r\n"
"SdFat/examples/LongFileName/testFiles"));
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) {
// 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.close();
}
}
//------------------------------------------------------------------------------
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)) {
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();
file.close();
}

+ 4
- 0
SdFat/examples/LongFileName/testFiles/A long name can be 255 characters.txt 查看文件

@@ -0,0 +1,4 @@
This is "A long name can be 255 characters.txt"
This file has a typical Long File Name.

The maximum length of a Long File Name is 255 characters.

+ 1
- 0
SdFat/examples/LongFileName/testFiles/LFN,NAME.TXT 查看文件

@@ -0,0 +1 @@
LFN,NAME.TXT is not 8.3 since it has a comma.

+ 5
- 0
SdFat/examples/LongFileName/testFiles/MIXCASE.txt 查看文件

@@ -0,0 +1,5 @@
MIXCASE.txt does not have a Long File Name.

Starting with NT, file names of this form,
have the basename and extension character case
encoded in two bits of the 8.3 directory entry.

+ 2
- 0
SdFat/examples/LongFileName/testFiles/Not_8_3.txt 查看文件

@@ -0,0 +1,2 @@
Not_8_3.txt has a Long File Name
since the basename is mixed case.

+ 1
- 0
SdFat/examples/LongFileName/testFiles/OK%83.TXT 查看文件

@@ -0,0 +1 @@
OK%83.TXT is a valid 8.3 name.

+ 1
- 0
SdFat/examples/LongFileName/testFiles/STD_8_3.TXT 查看文件

@@ -0,0 +1 @@
STD_8_3.TXT - a vanilla 8.3 name.

+ 2
- 0
SdFat/examples/LongFileName/testFiles/With Blank.txt 查看文件

@@ -0,0 +1,2 @@
With Blank.txt
Just another example of a Long File Name.

+ 2
- 0
SdFat/examples/LongFileName/testFiles/With Two.dots.txt 查看文件

@@ -0,0 +1,2 @@
"With Two.dots.txt"
Lots of reasons this is a Long File Name.

+ 5
- 0
SdFat/examples/LongFileName/testFiles/lower.txt 查看文件

@@ -0,0 +1,5 @@
lower.txt does not have a Long File Name.

Starting with NT, file names of this form,
have the basename and extension character case
encoded in two bits of the 8.3 directory entry.

+ 5
- 0
SdFat/examples/LongFileName/testFiles/mixed.TXT 查看文件

@@ -0,0 +1,5 @@
mixed.TXT does not have a Long File Name.

Starting with NT, file names of this form,
have the basename and extension character case
encoded in two bits of the 8.3 directory entry.

+ 5
- 3
SdFat/examples/LowLatencyLogger/LowLatencyLogger.ino 查看文件

@@ -13,6 +13,7 @@
*
* Data is written to the file using a SD multiple block write command.
*/
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
//------------------------------------------------------------------------------
@@ -139,10 +140,10 @@ uint8_t fullTail;
inline uint8_t queueNext(uint8_t ht) {return ht < (QUEUE_DIM - 1) ? ht + 1 : 0;}
//==============================================================================
// Error messages stored in flash.
#define error(msg) error_P(PSTR(msg))
#define error(msg) errorFlash(F(msg))
//------------------------------------------------------------------------------
void error_P(const char* msg) {
sd.errorPrint_P(msg);
void errorFlash(const __FlashStringHelper* msg) {
sd.errorPrint(msg);
fatalBlink();
}
//------------------------------------------------------------------------------
@@ -481,6 +482,7 @@ void setup(void) {
pinMode(ERROR_LED_PIN, OUTPUT);
}
Serial.begin(9600);
while (!Serial) {}
Serial.print(F("FreeRam: "));
Serial.println(FreeRam());

+ 1
- 0
SdFat/examples/OpenNext/OpenNext.ino 查看文件

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

// SD chip select pin

+ 3
- 2
SdFat/examples/PrintBenchmark/PrintBenchmark.ino 查看文件

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

@@ -20,7 +21,7 @@ SdFile file;
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
@@ -117,7 +118,7 @@ void loop() {
file.printField((float)0.01*i, '\n');
break;
}
if (file.writeError) {
if (file.getWriteError()) {
error("write failed");
}
m = micros() - m;

+ 41
- 42
SdFat/examples/QuickStart/QuickStart.ino 查看文件

@@ -1,5 +1,6 @@
// Quick hardware test.
//
#include <SPI.h>
#include <SdFat.h>
//
// Set DISABLE_CHIP_SELECT to disable a second SPI device.
@@ -12,12 +13,8 @@ const int8_t DISABLE_CHIP_SELECT = -1;
// Use SPI_QUARTER_SPEED for even slower SPI bus speed
const uint8_t spiSpeed = SPI_HALF_SPEED;
//------------------------------------------------------------------------------
// Normally the SdFat class is used in applications in place
// of Sd2Card, SdVolume, and SdFile for root.
// These internal classes are used here to diagnose problems.
Sd2Card card;
SdVolume volume;
SdFile root;
// File system object.
SdFat sd;

// Serial streams
ArduinoOutStream cout(Serial);
@@ -43,12 +40,12 @@ void reformatMsg() {
void setup() {
Serial.begin(9600);
while (!Serial) {} // Wait for Leonardo.
delay(1000); // Delay for Due.
cout << pstr("\nSPI pins:\n");
cout << pstr("MISO: ") << int(MISO) << endl;
cout << pstr("MOSI: ") << int(MOSI) << endl;
cout << pstr("MISO: ") << int(MISO) << endl;
cout << pstr("SCK: ") << int(SCK) << endl;
cout << pstr("SS: ") << int(SS) << endl;
if (DISABLE_CHIP_SELECT < 0) {
cout << pstr(
@@ -74,6 +71,9 @@ void loop() {
firstTry = false;

cout << pstr("\nEnter the chip select pin number: ");
while (!Serial.available()) {}
delay(400); // catch Due restart problem
cin.readline();
if (cin >> chipSelect) {
cout << chipSelect << endl;
@@ -91,23 +91,39 @@ void loop() {
pinMode(DISABLE_CHIP_SELECT, OUTPUT);
digitalWrite(DISABLE_CHIP_SELECT, HIGH);
}
if (!card.init(spiSpeed, chipSelect)) {
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("errorCode: ") << hex << showbase << int(card.errorCode());
cout << pstr(", errorData: ") << int(card.errorData());
cout << dec << noshowbase << endl;
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 << int(sd.card()->errorCode());
cout << pstr(", errorData: ") << int(sd.card()->errorData());
cout << dec << noshowbase << endl;
return;
}
cout << pstr("\nCard successfully initialized.\n");
if (sd.vol()->fatType() == 0) {
cout << pstr("Can't find a valid FAT16/FAT32 partition.\n");
reformatMsg();
return;
}
if (!sd.vwd()->isOpen()) {
cout << pstr("Can't open root directory.\n");
reformatMsg();
return;
}
cout << pstr("Can't determine error type\n");
return;
}
cout << pstr("\nCard successfully initialized.\n");
cout << endl;

uint32_t size = card.cardSize();
uint32_t size = sd.card()->cardSize();
if (size == 0) {
cout << pstr("Can't determine the card size.\n");
cardOrSpeed();
@@ -117,32 +133,15 @@ void loop() {
cout << pstr("Card size: ") << sizeMB;
cout << pstr(" MB (MB = 1,000,000 bytes)\n");
cout << endl;

if (!volume.init(&card)) {
if (card.errorCode()) {
cout << pstr("Can't read the card.\n");
cardOrSpeed();
} else {
cout << pstr("Can't find a valid FAT16/FAT32 partition.\n");
reformatMsg();
}
return;
}
cout << pstr("Volume is FAT") << int(volume.fatType());
cout << pstr(", Cluster size (bytes): ") << 512L * volume.blocksPerCluster();
cout << pstr("Volume is FAT") << int(sd.vol()->fatType());
cout << pstr(", Cluster size (bytes): ") << 512L * sd.vol()->blocksPerCluster();
cout << endl << endl;

root.close();
if (!root.openRoot(&volume)) {
cout << pstr("Can't open root directory.\n");
reformatMsg();
return;
}
cout << pstr("Files found (name date time size):\n");
root.ls(LS_R | LS_DATE | LS_SIZE);
sd.ls(LS_R | LS_DATE | LS_SIZE);

if ((sizeMB > 1100 && volume.blocksPerCluster() < 64)
|| (sizeMB < 2200 && volume.fatType() == 32)) {
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");

+ 5
- 11
SdFat/examples/RawWrite/RawWrite.ino 查看文件

@@ -1,12 +1,6 @@
/*
* This sketch illustrates raw write functions in SdFat that
* can be used for high speed data logging. These functions
* are used in the WaveRP library to record audio with the
* Adafruit Wave Shield using the built-in Arduino ADC.
*
* The WaveRP library captures data from the ADC in an ISR
* that is driven driven by timer one. Data is collected in
* two 512 byte buffers and written to the SD card.
* can be used for high speed data logging.
*
* This sketch simulates logging from a source that produces
* data at a constant rate of one block every MICROS_PER_BLOCK.
@@ -15,12 +9,12 @@
* no overruns occur and the maximum block write time is
* under 2000 micros.
*
* Note: WaveRP creates a very large file then truncates it
* to the length that is used for a recording. It only takes
* Note: Apps should create a very large file then truncates it
* to the length that is used for a logging. It only takes
* 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 <SdFat.h>
#include <SdFatUtil.h>

@@ -46,7 +40,7 @@ uint32_t bgnBlock, endBlock;
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
// log of first overruns
#define OVER_DIM 20

+ 1
- 0
SdFat/examples/ReadWriteSdFat/ReadWriteSdFat.ino 查看文件

@@ -20,6 +20,7 @@ const int chipSelect = 4;
This example code is in the public domain.
*/
#include <SPI.h>
#include <SdFat.h>
SdFat sd;
SdFile myFile;

+ 3
- 2
SdFat/examples/SdFormatter/SdFormatter.ino 查看文件

@@ -13,6 +13,7 @@
*/
// Print extra info for debug if DEBUG_PRINT is nonzero
#define DEBUG_PRINT 0
#include <SPI.h>
#include <SdFat.h>
#if DEBUG_PRINT
#include <SdFatUtil.h>
@@ -461,12 +462,12 @@ void setup() {
return;
}

if (!card.init(spiSpeed, chipSelect)) {
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");
sdError("card.init failed");
sdError("card.begin failed");
}
cardSizeBlocks = card.cardSize();
if (cardSizeBlocks == 0) sdError("cardSize");

+ 49
- 31
SdFat/examples/SdInfo/SdInfo.ino 查看文件

@@ -1,6 +1,7 @@
/*
* This sketch attempts to initialize an SD card and analyze its structure.
*/
#include <SPI.h>
#include <SdFat.h>
/*
* SD chip select pin. Common values are:
@@ -10,10 +11,14 @@
* Adafruit SD shields and modules, pin 10.
* Default SD chip select is the SPI SS pin.
*/
const uint8_t SdChipSelect = SS;

Sd2Card card;
SdVolume vol;
const uint8_t SD_CHIP_SELECT = SS;
/*
* Set DISABLE_CHIP_SELECT to disable a second SPI device.
* For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
* to 10 to disable the Ethernet controller.
*/
const int8_t DISABLE_CHIP_SELECT = -1;
SdFat sd;

// serial output steam
ArduinoOutStream cout(Serial);
@@ -28,17 +33,17 @@ uint32_t eraseSize;
#define sdErrorMsg(msg) sdErrorMsg_P(PSTR(msg));
void sdErrorMsg_P(const char* str) {
cout << pgm(str) << endl;
if (card.errorCode()) {
if (sd.card()->errorCode()) {
cout << pstr("SD errorCode: ");
cout << hex << int(card.errorCode()) << endl;
cout << hex << int(sd.card()->errorCode()) << endl;
cout << pstr("SD errorData: ");
cout << int(card.errorData()) << dec << endl;
cout << int(sd.card()->errorData()) << dec << endl;
}
}
//------------------------------------------------------------------------------
uint8_t cidDmp() {
cid_t cid;
if (!card.readCID(&cid)) {
if (!sd.card()->readCID(&cid)) {
sdErrorMsg("readCID failed");
return false;
}
@@ -62,7 +67,7 @@ uint8_t cidDmp() {
uint8_t csdDmp() {
csd_t csd;
uint8_t eraseSingleBlock;
if (!card.readCSD(&csd)) {
if (!sd.card()->readCSD(&csd)) {
sdErrorMsg("readCSD failed");
return false;
}
@@ -92,12 +97,12 @@ uint8_t csdDmp() {
//------------------------------------------------------------------------------
// print partition table
uint8_t partDmp() {
cache_t *p = vol.cacheClear();
cache_t *p = sd.vol()->cacheClear();
if (!p) {
sdErrorMsg("cacheClear failed");
return false;
}
if (!card.readBlock(0, p->data)) {
if (!sd.card()->readBlock(0, p->data)) {
sdErrorMsg("read MBR failed");
return false;
}
@@ -119,21 +124,22 @@ uint8_t partDmp() {
}
//------------------------------------------------------------------------------
void volDmp() {
cout << pstr("\nVolume is FAT") << int(vol.fatType()) << endl;
cout << pstr("blocksPerCluster: ") << int(vol.blocksPerCluster()) << endl;
cout << pstr("clusterCount: ") << vol.clusterCount() << endl;
uint32_t volFree = vol.freeClusterCount();
cout << pstr("freeClusters: ") << volFree << endl;
float fs = 0.000512*volFree*vol.blocksPerCluster();
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: ");
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: ") << vol.fatStartBlock() << endl;
cout << pstr("fatCount: ") << int(vol.fatCount()) << endl;
cout << pstr("blocksPerFat: ") << vol.blocksPerFat() << endl;
cout << pstr("rootDirStart: ") << vol.rootDirStart() << endl;
cout << pstr("dataStartBlock: ") << vol.dataStartBlock() << endl;
if (vol.dataStartBlock() % eraseSize) {
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;
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.sdcard.org/consumer!\n");
cout << pstr("Download and use formatter from www.sdsd.card()->org/consumer!\n");
}
}
//------------------------------------------------------------------------------
@@ -146,6 +152,18 @@ void setup() {

// pstr stores strings in flash to save RAM
cout << pstr("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");
} else {
cout << pstr("\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");
}
//------------------------------------------------------------------------------
void loop() {
@@ -160,20 +178,20 @@ void loop() {
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.
if (!card.init(SPI_HALF_SPEED, SdChipSelect)) {
sdErrorMsg("\ncard.init failed");
if (!sd.cardBegin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
sdErrorMsg("\ncardBegin failed");
return;
}
t = millis() - t;
cardSize = card.cardSize();
cardSize = sd.card()->cardSize();
if (cardSize == 0) {
sdErrorMsg("cardSize failed");
return;
}
cout << pstr("\ninit time: ") << t << " ms" << endl;
cout << pstr("\nCard type: ");
switch (card.type()) {
switch (sd.card()->type()) {
case SD_CARD_TYPE_SD1:
cout << pstr("SD1\n");
break;
@@ -196,14 +214,14 @@ void loop() {
if (!cidDmp()) return;
if (!csdDmp()) return;
uint32_t ocr;
if (!card.readOCR(&ocr)) {
if (!sd.card()->readOCR(&ocr)) {
sdErrorMsg("\nreadOCR failed");
return;
}
cout << pstr("OCR: ") << hex << ocr << dec << endl;
if (!partDmp()) return;
if (!vol.init(&card)) {
sdErrorMsg("\nvol.init failed");
if (!sd.fsBegin()) {
sdErrorMsg("\nFile System initialization failed.\n");
return;
}
volDmp();

+ 46
- 0
SdFat/examples/SoftwareSpi/SoftwareSpi.ino 查看文件

@@ -0,0 +1,46 @@
// An example of the SdFatSoftSpi template class.
// This example is for an Adafruit Data Logging Shield on a Mega.
// Software SPI is required on Mega since this shield connects to pins 10-13.
// This example will also run on an Uno and other boards using software SPI.
//
#include <SPI.h>
#include <SdFat.h>
#if USE_MULTIPLE_SPI_TYPES // Must be nonzero in SdFat/SdFatConfig.h
//
// Pin numbers in templates must be constants.
const uint8_t SOFT_MISO_PIN = 12;
const uint8_t SOFT_MOSI_PIN = 11;
const uint8_t SOFT_SCK_PIN = 13;
//
// Chip select may be constant or RAM variable.
const uint8_t SD_CHIP_SELECT_PIN = 10;

// SdFat software SPI template
SdFatSoftSpi<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> sd;

// Test file.
SdFile file;

void setup() {
Serial.begin(9600);
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)) {
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

+ 4
- 1
SdFat/examples/StdioBench/StdioBench.ino 查看文件

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

// Define PRINT_FIELD nonzero to use printField.
@@ -29,13 +30,15 @@ void setup() {
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();

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

for (uint8_t dataType = 0; dataType < 5; dataType++) {

+ 14
- 7
SdFat/examples/StreamParseInt/StreamParseInt.ino 查看文件

@@ -1,34 +1,41 @@
// Simple demo of the Stream parsInt() member function.
#include <SPI.h>
// The next two lines replace #include <SD.h>.
#include <SdFat.h>
SdFat SD;

// SD card chip select pin - Modify the value of csPin for your SD module.
const uint8_t csPin = 10;

SdFat SD;
File file;
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);

// Wait for USB Serial.
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.
if (!file.open("stream.txt", O_RDWR|O_CREAT|O_TRUNC)) {
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.rewind();
file.seek(0);
int i = file.parseInt();
Serial.print(F("parseInt: "));
Serial.println(i);
file.close();
}

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

+ 188
- 0
SdFat/examples/ThreeCards/ThreeCards.ino 查看文件

@@ -0,0 +1,188 @@
/*
* Example use of three SD cards.
*/
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#if USE_MULTIPLE_SPI_TYPES // Must be nonzero 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;
const uint8_t SD2_CS = 4;

// SD3 is a Adafruit data logging shield on pins 10-13
// Using Software SPI
SdFatSoftSpi<12, 11, 13> sd3;
const uint8_t SD3_CS = 10;

const uint8_t BUF_DIM = 100;
uint8_t buf[BUF_DIM];

const uint32_t FILE_SIZE = 1000000;
const uint16_t NWRITE = FILE_SIZE/BUF_DIM;
//------------------------------------------------------------------------------
// print error msg, any SD error codes, and halt.
// store messages in flash
#define errorExit(msg) errorHalt(F(msg))
#define initError(msg) initErrorHalt(F(msg))
//------------------------------------------------------------------------------
void list() {
// list current directory on both 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("---------------------"));
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
Serial.print(F("FreeRam: "));

Serial.println(FreeRam());
// fill buffer with known data
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:");
// initialize the second card
if (!sd2.begin(SD2_CS)) sd2.initError("sd2:");
// initialize the third card
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");
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");
}
Serial.println("Initial SD directories");
list();

// 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)) {
sd1.errorExit("file1");
}
Serial.println(F("Writing SD1:/DIR1/TEST1.BIN"));
// 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");
}
}
file1.sync();
list();
// 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)) {
sd2.errorExit("file2");
}
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");
}
t = millis() - t;
file2.sync();
Serial.print(F("File size: "));
Serial.println(file2.fileSize());
Serial.print(F("Copy time: "));
Serial.print(t);
Serial.println(F(" millis"));
list();
// 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)) {
sd3.errorExit("file3");
}
file2.rewind();
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");
}
file3.sync();
list();
// Verify content of file3
file3.rewind();
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");
}
}
Serial.println(F("Done - Verify OK"));
file1.close();
file2.close();
file3.close();
}
//------------------------------------------------------------------------------
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

+ 7
- 6
SdFat/examples/Timestamp/Timestamp.ino 查看文件

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

SdFat sd;
@@ -15,14 +16,14 @@ const uint8_t chipSelect = SS;
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
/*
* date/time values for debug
* normally supplied by a real-time clock or GPS
*/
// date 1-Oct-09
uint16_t year = 2009;
// date 1-Oct-14
uint16_t year = 2014;
uint8_t month = 10;
uint8_t day = 1;

@@ -147,15 +148,15 @@ void setup(void) {
error("open STAMP.TXT failed");
}
// set creation date time
if (!file.timestamp(T_CREATE, 2009, 11, 10, 1, 2, 3)) {
if (!file.timestamp(T_CREATE, 2014, 11, 10, 1, 2, 3)) {
error("set create time failed");
}
// set write/modification date time
if (!file.timestamp(T_WRITE, 2009, 11, 11, 4, 5, 6)) {
if (!file.timestamp(T_WRITE, 2014, 11, 11, 4, 5, 6)) {
error("set write time failed");
}
// set access date
if (!file.timestamp(T_ACCESS, 2009, 11, 12, 7, 8, 9)) {
if (!file.timestamp(T_ACCESS, 2014, 11, 12, 7, 8, 9)) {
error("set access time failed");
}
cout << pstr("\nTimes after timestamp() calls\n");

+ 16
- 18
SdFat/examples/TwoCards/TwoCards.ino 查看文件

@@ -1,11 +1,9 @@
/*
* Example use of two SD cards.
*/
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#if !USE_MULTIPLE_CARDS
#error You must set USE_MULTIPLE_CARDS nonzero in SdFatConfig.h
#endif

SdFat sd1;
const uint8_t SD1_CS = 10; // chip select for sd1
@@ -21,20 +19,20 @@ const uint16_t NWRITE = FILE_SIZE/BUF_DIM;
//------------------------------------------------------------------------------
// print error msg, any SD error codes, and halt.
// store messages in flash
#define errorExit(msg) errorHalt_P(PSTR(msg))
#define initError(msg) initErrorHalt_P(PSTR(msg))
#define errorExit(msg) errorHalt(F(msg))
#define initError(msg) initErrorHalt(F(msg))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial) {} // wait for Leonardo
PgmPrint("FreeRam: ");
Serial.print(F("FreeRam: "));

Serial.println(FreeRam());
// fill buffer with known data
for (int i = 0; i < sizeof(buf); i++) buf[i] = i;
PgmPrintln("type any character to start");
Serial.println(F("type any character to start"));
while (Serial.read() <= 0) {}
delay(400); // catch Due reset problem

@@ -59,9 +57,9 @@ void setup() {
if (!sd2.mkdir("/DIR2")) sd2.errorExit("sd2.mkdir");
}
// list root directory on both cards
PgmPrintln("------sd1 root-------");
Serial.println(F("------sd1 root-------"));
sd1.ls();
PgmPrintln("------sd2 root-------");
Serial.println(F("------sd2 root-------"));
sd2.ls();

// make /DIR1 the default directory for sd1
@@ -71,11 +69,11 @@ void setup() {
if (!sd2.chdir("/DIR2")) sd2.errorExit("sd2.chdir");
// list current directory on both cards
PgmPrintln("------sd1 DIR1-------");
Serial.println(F("------sd1 DIR1-------"));
sd1.ls();
PgmPrintln("------sd2 DIR2-------");
Serial.println(F("------sd2 DIR2-------"));
sd2.ls();
PgmPrintln("---------------------");
Serial.println(F("---------------------"));
// remove RENAME.BIN from /DIR2 directory of sd2
if (sd2.exists("RENAME.BIN")) {
@@ -91,7 +89,7 @@ void setup() {
if (!file1.open("TEST.BIN", O_RDWR | O_CREAT | O_TRUNC)) {
sd1.errorExit("file1");
}
PgmPrintln("Writing TEST.BIN to sd1");
Serial.println(F("Writing TEST.BIN to sd1"));
// write data to /DIR1/TEST.BIN on sd1
for (int i = 0; i < NWRITE; i++) {
@@ -107,7 +105,7 @@ void setup() {
if (!file2.open("COPY.BIN", O_WRITE | O_CREAT | O_TRUNC)) {
sd2.errorExit("file2");
}
PgmPrintln("Copying TEST.BIN to COPY.BIN");
Serial.println(F("Copying TEST.BIN to COPY.BIN"));
// copy file1 to file2
file1.rewind();
@@ -120,11 +118,11 @@ void setup() {
if (file2.write(buf, n) != n) sd2.errorExit("write2");
}
t = millis() - t;
PgmPrint("File size: ");
Serial.print(F("File size: "));
Serial.println(file2.fileSize());
PgmPrint("Copy time: ");
Serial.print(F("Copy time: "));
Serial.print(t);
PgmPrintln(" millis");
Serial.println(F(" millis"));
// close TEST.BIN
file1.close();
@@ -134,7 +132,7 @@ void setup() {
if (!sd2.rename("COPY.BIN", "RENAME.BIN")) {
sd2.errorExit("sd2.rename");
}
PgmPrintln("Done");
Serial.println(F("Done"));
}
//------------------------------------------------------------------------------
void loop() {}

+ 2
- 1
SdFat/examples/bench/bench.ino 查看文件

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

@@ -36,7 +37,7 @@ SdFile file;
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
void cidDmp() {
cid_t cid;

+ 1
- 0
SdFat/examples/cin_cout/cin_cout.ino 查看文件

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

// create serial output stream

+ 2
- 5
SdFat/examples/dataLogger/dataLogger.ino 查看文件

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

// SD chip select pin. Be sure to disable any other SPI devices such as Enet.
@@ -59,11 +60,7 @@ void logData() {
}
//==============================================================================
// Error messages stored in flash.
#define error(msg) error_P(PSTR(msg))
//------------------------------------------------------------------------------
void error_P(const char* msg) {
sd.errorHalt_P(msg);
}
#define error(msg) sd.errorHalt(F(msg))
//------------------------------------------------------------------------------
void setup() {
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;

+ 2
- 5
SdFat/examples/directoryFunctions/directoryFunctions.ino 查看文件

@@ -1,6 +1,7 @@
/*
* Example use of chdir(), ls(), mkdir(), and rmdir().
*/
#include <SPI.h>
#include <SdFat.h>
// SD card chip select pin.
const uint8_t SD_CHIP_SELECT = SS;
@@ -24,11 +25,7 @@ char cinBuf[40];
ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));
//==============================================================================
// Error messages stored in flash.
#define error(msg) error_P(PSTR(msg))
//------------------------------------------------------------------------------
void error_P(const char* msg) {
sd.errorHalt_P(msg);
}
#define error(msg) sd.errorHalt(F(msg))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);

+ 3
- 2
SdFat/examples/fgets/fgets.ino 查看文件

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

// SD chip select pin
@@ -9,7 +10,7 @@ SdFat sd;
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// store error strings in flash memory
#define error(s) sd.errorHalt_P(PSTR(s))
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
void demoFgets() {
char line[25];
@@ -43,7 +44,7 @@ void makeTestFile() {
if (!wrfile.isOpen()) error("MakeTestFile");
// write test file
wrfile.write_P(PSTR(
wrfile.print(F(
"Line with CRLF\r\n"
"Line with only LF\n"
"Long line that will require an extra read\n"

+ 1
- 0
SdFat/examples/formatting/formatting.ino 查看文件

@@ -2,6 +2,7 @@
* Print a table with various formatting options
* Format dates
*/
#include <SPI.h>
#include <SdFat.h>

// create Serial stream

+ 1
- 0
SdFat/examples/getline/getline.ino 查看文件

@@ -6,6 +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 <SdFat.h>

// SD chip select pin

+ 2
- 1
SdFat/examples/readCSV/readCSV.ino 查看文件

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

// SD chip select pin
@@ -16,7 +17,7 @@ ArduinoOutStream cout(Serial);
char fileName[] = "TESTFILE.CSV";
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
// read and print CSV test file
void readFile() {

+ 2
- 1
SdFat/examples/rename/rename.ino 查看文件

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

// SD chip select pin
@@ -14,7 +15,7 @@ SdFat sd;
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
#define error(s) sd.errorHalt(F(s))
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);

SdFat/ArduinoStream.h → SdFat/utility/ArduinoStream.h 查看文件

@@ -1,7 +1,7 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
/* FatLib Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdFat Library
* 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
@@ -14,7 +14,7 @@
* 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
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef ArduinoStream_h
@@ -23,7 +23,9 @@
* \file
* \brief ArduinoInStream and ArduinoOutStream classes
*/
#include <bufstream.h>
#if defined(ARDUINO) || defined(DOXYGEN)
#include <Arduino.h>
#include "bufstream.h"
//==============================================================================
/**
* \class ArduinoInStream
@@ -116,4 +118,5 @@ class ArduinoOutStream : public ostream {
ArduinoOutStream() {}
Print* m_pr;
};
#endif // ARDUINO
#endif // ArduinoStream_h

+ 26
- 26
SdFat/utility/DigitalPin.h 查看文件

@@ -46,11 +46,11 @@ bool fastDigitalRead(uint8_t pin) {
*/
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, bool value) {
if (value) {
*portSetRegister(pin) = 1;
} else {
*portClearRegister(pin) = 1;
}
if (value) {
*portSetRegister(pin) = 1;
} else {
*portClearRegister(pin) = 1;
}
}
#else // CORE_TEENSY
//------------------------------------------------------------------------------
@@ -59,7 +59,7 @@ void fastDigitalWrite(uint8_t pin, bool value) {
* @return value read
*/
static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin){
bool fastDigitalRead(uint8_t pin) {
return g_APinDescription[pin].pPort->PIO_PDSR & g_APinDescription[pin].ulPin;
}
//------------------------------------------------------------------------------
@@ -68,8 +68,8 @@ bool fastDigitalRead(uint8_t pin){
* @param[in] level value to write
*/
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, bool value){
if(value) {
void fastDigitalWrite(uint8_t pin, bool value) {
if (value) {
g_APinDescription[pin].pPort->PIO_SODR = g_APinDescription[pin].ulPin;
} else {
g_APinDescription[pin].pPort->PIO_CODR = g_APinDescription[pin].ulPin;
@@ -78,8 +78,8 @@ void fastDigitalWrite(uint8_t pin, bool value){
#endif // CORE_TEENSY
//------------------------------------------------------------------------------
inline void fastDigitalToggle(uint8_t pin) {
fastDigitalWrite(pin, !fastDigitalRead(pin));
}
fastDigitalWrite(pin, !fastDigitalRead(pin));
}
//------------------------------------------------------------------------------
inline void fastPinMode(uint8_t pin, bool mode) {pinMode(pin, mode);}
#else // __arm__
@@ -101,7 +101,7 @@ struct pin_map_t {
||defined(__AVR_ATmega168P__)\
||defined(__AVR_ATmega328P__)
// 168 and 328 Arduinos
const static pin_map_t pinMap[] = {
static const pin_map_t pinMap[] = {
{&DDRD, &PIND, &PORTD, 0}, // D0 0
{&DDRD, &PIND, &PORTD, 1}, // D1 1
{&DDRD, &PIND, &PORTD, 2}, // D2 2
@@ -469,7 +469,7 @@ void badPinCheck(uint8_t pin) {
static inline __attribute__((always_inline))
void fastBitWriteSafe(volatile uint8_t* address, uint8_t bit, bool level) {
uint8_t oldSREG;
if (address > (uint8_t*)0X5F) {
if (address > reinterpret_cast<uint8_t*>(0X5F)) {
oldSREG = SREG;
cli();
}
@@ -478,7 +478,7 @@ void fastBitWriteSafe(volatile uint8_t* address, uint8_t bit, bool level) {
} else {
*address &= ~(1 << bit);
}
if (address > (uint8_t*)0X5F) {
if (address > reinterpret_cast<uint8_t*>(0X5F)) {
SREG = oldSREG;
}
}
@@ -497,12 +497,12 @@ bool fastDigitalRead(uint8_t pin) {
* @param[in] pin Arduino pin number
*
* If the pin is in output mode toggle the pin level.
* If the pin is in input mode toggle the state of the 20K pullup.
* If the pin is in input mode toggle the state of the 20K pull-up.
*/
static inline __attribute__((always_inline))
void fastDigitalToggle(uint8_t pin) {
badPinCheck(pin);
if (pinMap[pin].pin > (uint8_t*)0X5F) {
if (pinMap[pin].pin > reinterpret_cast<uint8_t*>(0X5F)) {
// must write bit to high address port
*pinMap[pin].pin = 1 << pinMap[pin].bit;
} else {
@@ -525,7 +525,7 @@ void fastDigitalWrite(uint8_t pin, bool level) {
* @param[in] pin Arduino pin number
* @param[in] mode if true set output mode else input mode
*
* fastPinMode does not enable or disable the 20K pullup for input mode.
* fastPinMode does not enable or disable the 20K pull-up for input mode.
*/
static inline __attribute__((always_inline))
void fastPinMode(uint8_t pin, bool mode) {
@@ -539,7 +539,7 @@ void fastPinMode(uint8_t pin, bool mode) {
* @param[in] pin Arduino pin number
* @param[in] mode If true set output mode else input mode
* @param[in] level If mode is output, set level high/low.
* If mode is input, enable or disable the pin's 20K pullup.
* If mode is input, enable or disable the pin's 20K pull-up.
*/
static inline __attribute__((always_inline))
void fastPinConfig(uint8_t pin, bool mode, bool level) {
@@ -568,7 +568,7 @@ class DigitalPin {
/** Constructor
* @param[in] mode If true set output mode else input mode
* @param[in] level If mode is output, set level high/low.
* If mode is input, enable or disable the pin's 20K pullup.
* If mode is input, enable or disable the pin's 20K pull-up.
*/
DigitalPin(bool mode, bool level) {
config(mode, level);
@@ -588,14 +588,14 @@ class DigitalPin {
/** Parenthesis operator
* @return Pin's level
*/
inline operator bool () const __attribute__((always_inline)) {
inline operator bool() const __attribute__((always_inline)) {
return read();
}
//----------------------------------------------------------------------------
/** 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 is input, enable or disable the pin's 20K pullup.
* @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))
void config(bool mode, bool level) {
@@ -603,13 +603,13 @@ class DigitalPin {
}
//----------------------------------------------------------------------------
/**
* Set pin level high if output mode or enable 20K pullup if input mode.
* Set pin level high if output mode or enable 20K pull-up if input mode.
*/
inline __attribute__((always_inline))
void high() {write(true);}
//----------------------------------------------------------------------------
/**
* Set pin level low if output mode or disable 20K pullup if input mode.
* Set pin level low if output mode or disable 20K pull-up if input mode.
*/
inline __attribute__((always_inline))
void low() {write(false);}
@@ -618,7 +618,7 @@ class DigitalPin {
* Set pin mode
* @param[in] pinMode if true set output mode else input mode.
*
* mode() does not enable or disable the 20K pullup for input mode.
* mode() does not enable or disable the 20K pull-up for input mode.
*/
inline __attribute__((always_inline))
void mode(bool pinMode) {
@@ -634,7 +634,7 @@ class DigitalPin {
/** toggle a pin
*
* If the pin is in output mode toggle the pin's level.
* If the pin is in input mode toggle the state of the 20K pullup.
* If the pin is in input mode toggle the state of the 20K pull-up.
*/
inline __attribute__((always_inline))
void toggle() {
@@ -651,4 +651,4 @@ class DigitalPin {
}
};
#endif // DigitalPin_h
/** @} */
/** @} */

+ 1
- 1
SdFat/utility/FatApiConstants.h 查看文件

@@ -46,7 +46,7 @@ uint8_t const O_CREAT = 0X40;
/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
uint8_t const O_EXCL = 0X80;

// SdBaseFile class static and const definitions
// FatFile class static and const definitions
// flags for ls()
/** ls() flag to print modify date */
uint8_t const LS_DATE = 1;

SdFat/utility/FatFile.cpp
文件差異過大導致無法顯示
查看文件


+ 857
- 0
SdFat/utility/FatFile.h 查看文件

@@ -0,0 +1,857 @@
/* 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/>.
*/
#ifndef FatFile_h
#define FatFile_h
/**
* \file
* \brief FatFile class
*/
#include <ctype.h>
#include <string.h>
#include <stddef.h>
#include <limits.h>
#include "FatLibConfig.h"
#include "FatApiConstants.h"
#include "FatStructs.h"
#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>
#else // __AVR__
#ifndef PGM_P
/** pointer to flash for ARM */
#define PGM_P const char*
#endif // PGM_P
#ifndef PSTR
/** store literal string in flash for ARM */
#define PSTR(x) (x)
#endif // PSTR
#ifndef pgm_read_byte
/** read 8-bits from flash for ARM */
#define pgm_read_byte(addr) (*(const unsigned char*)(addr))
#endif // pgm_read_byte
#ifndef pgm_read_word
/** read 16-bits from flash for ARM */
#define pgm_read_word(addr) (*(const uint16_t*)(addr))
#endif // pgm_read_word
#ifndef PROGMEM
/** store in flash for ARM */
#define PROGMEM const
#endif // PROGMEM
#endif // __AVR__
//------------------------------------------------------------------------------
/**
* \struct FatPos_t
* \brief Internal type for file position - do not use in user apps.
*/
struct FatPos_t {
/** stream position */
uint32_t position;
/** cluster for position */
uint32_t cluster;
FatPos_t() : position(0), cluster(0) {}
};
//==============================================================================
/**
* \class FatFile
* \brief Basic file class.
*/
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) {}
/** 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.
*
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of open flags. see FatFile::open(FatFile*, const char*, uint8_t).
*/
FatFile(const char* path, uint8_t oflag) {
m_attr = FILE_ATTR_CLOSED;
m_writeError = false;
open(path, oflag);
}
#if DESTRUCTOR_CLOSES_FILE
~FatFile() {if(isOpen()) close();}
#endif // DESTRUCTOR_CLOSES_FILE

/** \return value of writeError */
bool getWriteError() {return m_writeError;}
/** Set writeError to zero */
void clearWriteError() {m_writeError = 0;}
//----------------------------------------------------------------------------
// helpers for stream classes
/** get position for streams
* \param[out] pos struct to receive position
*/
void getpos(FatPos_t* pos);
/** set position for streams
* \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();}
/** 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.
*/
bool close();
/** Check for contiguous file and return its raw block range.
*
* \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.
*/
bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
/** Create and open a new contiguous file of a specified size.
*
* \note This function only supports short DOS 8.3 names.
* See open() for more information.
*
* \param[in] dirFile The directory where the file will be created.
* \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.
*
*/
bool createContiguous(FatFile* dirFile,
const char* path, uint32_t size);
/** \return The current cluster number for a file or directory. */
uint32_t curCluster() const {return m_curCluster;}
/** \return The current position for a file or directory. */
uint32_t curPosition() const {return m_curPosition;}
/** \return Current working directory */
static FatFile* cwd() {return m_cwd;}
/** Set the date/time callback function
*
* \param[in] dateTime The user's call back function. The callback
* function is of the form:
*
* \code
* void dateTime(uint16_t* date, uint16_t* time) {
* uint16_t year;
* uint8_t month, day, hour, minute, second;
*
* // User gets date and time from GPS or real-time clock here
*
* // return date using FAT_DATE macro to format fields
* *date = FAT_DATE(year, month, day);
*
* // return time using FAT_TIME macro to format fields
* *time = FAT_TIME(hour, minute, second);
* }
* \endcode
*
* Sets the function that is called when a file is created or when
* a file's directory entry is modified by sync(). All timestamps,
* access, creation, and modify, are set when a file is created.
* sync() maintains the last access date and last modify date/time.
*
* See the timestamp() function.
*/
static void dateTimeCallback(
void (*dateTime)(uint16_t* date, uint16_t* time)) {
m_dateTime = dateTime;
}
/** Cancel the date/time callback function. */
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.
*/
bool dirEntry(dir_t* dir);

/**
* \return The index of this file in it's directory.
*/
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.
*
* \param[in] dir The directory structure containing the name.
* \param[out] name A 13 byte char array for the formatted name.
* \return length of the name.
*/
static uint8_t dirName(const dir_t* dir, char* name);
/** Test for the existence of a file in a directory
*
* \param[in] path Path of the file to be tested for.
*
* The calling instance must be an open directory file.
*
* dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory
* dirFile.
*
* \return true if the file exists else false.
*/
bool exists(const char* path) {
FatFile file;
return file.open(this, path, O_READ);
}
/**
* Get a string from a file.
*
* fgets() reads bytes from a file into the array pointed to by \a str, until
* \a num - 1 bytes are read, or a delimiter is read and transferred to \a str,
* or end-of-file is encountered. The string is then terminated
* with a null byte.
*
* fgets() deletes CR, '\\r', from the string. This insures only a '\\n'
* terminates the string for Windows text files which use CRLF for newline.
*
* \param[out] str Pointer to the array where the string is stored.
* \param[in] num Maximum number of characters to be read
* (including the final null byte). Usually the length
* of the array \a str is used.
* \param[in] delim Optional set of delimiters. The default is "\n".
*
* \return For success fgets() returns the length of the string in \a str.
* If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
*/
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 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.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool getFilename(char* name);

/** \return True if this is a directory else false. */
bool isDir() const {return m_attr & FILE_ATTR_DIR;}
/** \return True if this is a normal file else false. */
bool isFile() const {return !isDir();}
/** \return True if this is a hidden file else false. */
bool isHidden() const {return m_attr & FILE_ATTR_HIDDEN;}
/** \return True if this is an open file/directory else false. */
bool isOpen() const {return m_attr & FILE_ATTR_IS_OPEN;}
/** \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;}
/** \return True if this is the FAT12 of FAT16 root directory. */
bool isRootFixed() const {return m_attr & FILE_ATTR_ROOT_FIXED;}
/** \return True if this is a subdirectory else false. */
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;}

/** List directory contents.
*
* \param[in] pr Print stream for list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*
* \param[in] indent Amount of space before file name. Used for recursive
* list to indicate subdirectory level.
*/
void ls(print_t* pr, uint8_t flags = 0, uint8_t indent = 0);
/** Make a new directory.
*
* \param[in] dir An open FatFile instance for the directory that will
* contain the new directory.
*
* \param[in] path A path with a valid 8.3 DOS name for the new directory.
*
* \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.
*/
bool mkdir(FatFile* dir, const char* path, bool pFlag = true);
/** Open a file in the volume working directory of a FatFileSystem.
*
* \param[in] fs File System where the file is located.
*
* \param[in] path with a valid 8.3 DOS name for a file to be opened.
*
* \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.
*/
bool open(FatFileSystem* fs, const char* path, uint8_t oflag);
/** Open a file by index.
*
* \param[in] dirFile An open FatFile instance for the directory.
*
* \param[in] index The \a index of the directory entry for the file to be
* opened. The value for \a index is (directory file position)/32.
*
* \param[in] oflag bitwise-inclusive OR of open mode flags.
* See see FatFile::open(FatFile*, const char*, uint8_t).
*
* See open() by path for definition of flags.
* \return true for success or false for failure.
*/
bool open(FatFile* dirFile, uint16_t index, uint8_t oflag);
/** Open a file or directory by name.
*
* \param[in] dirFile An open FatFile instance for the directory containing
* the file to be opened.
*
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a
* bitwise-inclusive OR of flags from the following list
*
* O_READ - Open for reading.
*
* O_RDONLY - Same as O_READ.
*
* O_WRITE - Open for writing.
*
* O_WRONLY - Same as O_WRITE.
*
* O_RDWR - Open for reading and writing.
*
* O_APPEND - If set, the file offset shall be set to the end of the
* file prior to each write.
*
* O_AT_END - Set the initial position at the end of the file.
*
* O_CREAT - If the file exists, this flag has no effect except as noted
* under O_EXCL below. Otherwise, the file shall be created
*
* O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
*
* O_SYNC - Call sync() after each write. This flag should not be used with
* write(uint8_t) or any functions do character at a time writes since sync()
* will be called after each byte.
*
* O_TRUNC - If the file exists and is a regular file, and the file is
* successfully opened and is not read only, its length shall be truncated to 0.
*
* WARNING: A given file must not be opened by more than one FatFile object
* or file corruption may occur.
*
* \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.
*/
bool open(FatFile* dirFile, const char* path, uint8_t oflag);
/** Open a file in the current working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
*
* \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.
*/
bool open(const char* path, uint8_t oflag = O_READ) {
return open(m_cwd, path, oflag);
}
/** Open the next file or subdirectory in a directory.
*
* \param[in] dirFile An open FatFile instance for the directory
* containing the file to be opened.
*
* \param[in] oflag bitwise-inclusive OR of open mode flags.
* See see FatFile::open(FatFile*, const char*, uint8_t).
*
* \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.
*/
bool openRoot(FatVolume* vol);
/** Return the next available byte without consuming it.
*
* \return The byte if no error and not at eof else -1;
*/
int peek();
/** Print a file's creation date and time
*
* \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.
*/
bool printCreateDateTime(print_t* pr);
/** %Print a directory date field.
*
* Format is yyyy-mm-dd.
*
* \param[in] pr Print stream for output.
* \param[in] fatDate The date field from a directory entry.
*/
static void printFatDate(print_t* pr, uint16_t fatDate);
/** %Print a directory time field.
*
* Format is hh:mm:ss.
*
* \param[in] pr Print stream for output.
* \param[in] fatTime The time field from a directory entry.
*/
static void printFatTime(print_t* pr, uint16_t fatTime);
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator. Use '\\n' for CR LF.
* \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);
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator. Use '\\n' for CR LF.
* \return The number of bytes written or -1 if an error occurs.
*/
int printField(int16_t value, char term);
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator. Use '\\n' for CR LF.
* \return The number of bytes written or -1 if an error occurs.
*/
int printField(uint16_t value, char term);
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator. Use '\\n' for CR LF.
* \return The number of bytes written or -1 if an error occurs.
*/
int printField(int32_t value, char term);
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator. Use '\\n' for CR LF.
* \return The number of bytes written or -1 if an error occurs.
*/
int printField(uint32_t value, char term);
/** Print a file's modify date and time
*
* \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.
*/
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.
*/
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.
*/
size_t printFileSize(print_t* pr);
/** Read the next byte from a file.
*
* \return For success read returns the next byte in the file as an int.
* If an error occurs or end of file is reached -1 is returned.
*/
int read() {
uint8_t b;
return read(&b, 1) == 1 ? b : -1;
}
/** Read data from a file starting at the current position.
*
* \param[out] buf Pointer to the location that will receive the data.
*
* \param[in] nbyte Maximum number of bytes to read.
*
* \return For success read() returns the number of bytes read.
* A value less than \a nbyte, including zero, will be returned
* if end of file is reached.
* If an error occurs, read() returns -1. Possible errors include
* read() called before a file has been opened, corrupt file system
* or an I/O error occurred.
*/
int read(void* buf, size_t nbyte);
/** Read the next directory entry from a directory file.
*
* \param[out] dir The dir_t struct that will receive the data.
*
* \return For success readDir() returns the number of bytes read.
* A value of zero will be returned if end of file is reached.
* If an error occurs, readDir() returns -1. Possible errors include
* readDir() called before a directory has been opened, this is not
* a directory file or an I/O error occurred.
*/
int8_t readDir(dir_t* dir);
/** Remove a file.
*
* The directory entry and all data for the file are deleted.
*
* \note This function should not be used to delete the 8.3 version of a
* 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.
*/
bool remove();
/** Remove a file.
*
* The directory entry and all data for the file are deleted.
*
* \param[in] dirFile The directory that contains the file.
* \param[in] path Path for the file to be removed.
*
* \note This function should not be used to delete the 8.3 version of a
* 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.
*/
static bool remove(FatFile* dirFile, const char* path);
/** Set the file's current position to zero. */
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.
*/
bool rename(FatFile* dirFile, const char* newPath);
/** Remove a directory file.
*
* The directory file will be removed only if it is empty and is not the
* root directory. rmdir() follows DOS and Windows and ignores the
* read-only attribute for the directory.
*
* \note This function should not be used to delete the 8.3 version of a
* 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.
*/
bool rmdir();
/** Recursively delete a directory and all contained files.
*
* This is like the Unix/Linux 'rm -rf *' if called with the root directory
* hence the name.
*
* Warning - This will remove all contents of the directory including
* subdirectories. The directory will then be removed if it is not root.
* The read-only attribute for files will be ignored.
*
* \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.
*/
bool rmRfStar();
/** Set the files position to current position + \a pos. See seekSet().
* \param[in] offset The new position in bytes from the current position.
* \return true for success or false for failure.
*/
bool seekCur(int32_t offset) {
return seekSet(m_curPosition + offset);
}
/** Set the files position to end-of-file + \a offset. See seekSet().
* \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);}
/** 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.
*/
bool seekSet(uint32_t pos);
/** Set the current working directory.
*
* \param[in] dir New current working directory.
*
* \return true for success else false.
*/
static bool setCwd(FatFile* dir) {
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.
*/
bool sync();
/** Copy a file's timestamps
*
* \param[in] file File to copy timestamps from.
*
* \note
* 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.
*/
bool timestamp(FatFile* file);
/** Set a file's timestamps in its directory entry.
*
* \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
* OR of flags from the following list
*
* T_ACCESS - Set the file's last access date.
*
* T_CREATE - Set the file's creation date and time.
*
* T_WRITE - Set the file's last write/modification date and time.
*
* \param[in] year Valid range 1980 - 2107 inclusive.
*
* \param[in] month Valid range 1 - 12 inclusive.
*
* \param[in] day Valid range 1 - 31 inclusive.
*
* \param[in] hour Valid range 0 - 23 inclusive.
*
* \param[in] minute Valid range 0 - 59 inclusive.
*
* \param[in] second Valid range 0 - 59 inclusive
*
* \note It is possible to set an invalid date since there is no check for
* the number of days in a month.
*
* \note
* 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.
*/
bool timestamp(uint8_t flags, uint16_t year, uint8_t month, uint8_t day,
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;}
/** 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.
*/
bool truncate(uint32_t length);
/** \return FatVolume that contains this file. */
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);}
/** Write data to an open file.
*
* \note Data is moved to the cache but may not be written to the
* storage device until sync() is called.
*
* \param[in] buf Pointer to the location of the data to be written.
*
* \param[in] nbyte Number of bytes to write.
*
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an I/O error.
*
*/
int write(const void* buf, size_t nbyte);
//------------------------------------------------------------------------------
private:
/** This file has not been opened. */
static const uint8_t FILE_ATTR_CLOSED = 0;
/** File is read-only. */
static const uint8_t FILE_ATTR_READ_ONLY = DIR_ATT_READ_ONLY;
/** File should be hidden in directory listings. */
static const uint8_t FILE_ATTR_HIDDEN = DIR_ATT_HIDDEN;
/** 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;
/** Entry is for a subdirectory */
static const uint8_t FILE_ATTR_SUBDIR = DIR_ATT_DIRECTORY;
/** A FAT12 or FAT16 root directory */
static const uint8_t FILE_ATTR_ROOT_FIXED = 0X20;
/** A FAT32 root directory */
static const uint8_t FILE_ATTR_ROOT32 = 0X40;
/** Entry is for root. */
static const uint8_t FILE_ATTR_ROOT = FILE_ATTR_ROOT_FIXED | FILE_ATTR_ROOT32;
/** Directory type bits */
static const uint8_t FILE_ATTR_DIR = FILE_ATTR_SUBDIR | FILE_ATTR_ROOT;
/** Attributes to copy from directory entry */
static const uint8_t FILE_ATTR_COPY = DIR_ATT_READ_ONLY | DIR_ATT_HIDDEN |
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);
bool readLBN(uint32_t* lbn);
dir_t* readDirCache();
bool setDirSize();

// bits defined in m_flags
// should be 0X0F
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
// sync of directory entry required
static uint8_t const F_FILE_DIR_DIRTY = 0X80;

// global pointer to cwd dir
static FatFile* m_cwd;
// 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
uint8_t m_attr; // File attributes
uint8_t m_flags; // See above for definition of m_flags bits
uint16_t m_dirIndex; // index of directory entry in dir file
FatVolume* m_vol; // volume where file is located
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
};
#endif // FatFile_h

+ 302
- 0
SdFat/utility/FatFileLFN.cpp 查看文件

@@ -0,0 +1,302 @@
/* 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/>.
*/
#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()) {
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++;
}
// 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;
}
}
}

fail:
*index = free;
return false;
}
//------------------------------------------------------------------------------
bool FatFile::createLfn(FatFile* dirFile,
uint16_t bgnIndex, char* name, uint8_t oflag) {
return false;
}
//------------------------------------------------------------------------------
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;
uint8_t freeNeed;
dir_t* dir;
size_t len;
bool is83;
bool foundFree = false;
const char* ptr;
uint8_t name83[11];
if (!isDir()) {
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();
while (1) {
curIndex = m_curPosition/32;
if (m_curPosition == m_fileSize) {
DBG_FAIL_MACRO;
goto fail;
}
// read entry into cache
dir = readDirCache();
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
#if 1
if (dir->name[0] == DIR_NAME_DELETED) {
if (!foundFree) {
if (freeIndex == 0XFFFF) {
freeIndex = curIndex;
freeCount = 0;
}
if (++freeCount == freeNeed) {
foundFree = true;
}
}
continue;
} else {
if (!foundFree) freeIndex = 0XFFFF;
}
#endif
if (dir->name[0] == DIR_NAME_FREE) {
DBG_FAIL_MACRO;
goto fail;
}
// skip empty slot or '.' or '..'
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') {
haveLong = false;
continue;
}
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;
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;
}
fill = false;
}
if (u > 255 || toupper(u) != toupper(name[nOff + i])) {
haveLong = false;
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 (haveLong) goto done;
if (is83 && !memcmp(dir->name, name83, sizeof(name83))) {
goto done;
}
} else {
haveLong = false;
}
}

done:
*bgnIndex = haveLong ? lfnBgn : curIndex;
*endIndex = curIndex;
return true;

fail:
*bgnIndex = foundFree ? freeIndex : curIndex;
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;
dir_t* dir;
uint16_t index;
int rtn;

// Check for valid directory and file is not open.
if (!dirFile->isDir() || isOpen() || size < 13) {
DBG_FAIL_MACRO;
goto fail;
}

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) {
DBG_FAIL_MACRO;
goto fail;
}

// done if last entry
if (dir->name[0] == DIR_NAME_FREE) {
DBG_FAIL_MACRO;
return 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)) {
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;
}
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;
}
} 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 (!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);
}
}
}
}
if (!openCachedEntry(dirFile, index, oflag)) {
DBG_FAIL_MACRO;
goto fail;
}
return rtn;
} else {
haveLong = false;
}
}

done:
return 0;

fail:
return -1;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS

+ 241
- 0
SdFat/utility/FatFilePrint.cpp 查看文件

@@ -0,0 +1,241 @@
/* 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 <math.h>
#include "FatFile.h"
#include "FmtNumber.h"
//------------------------------------------------------------------------------
// print uint8_t with width 2
static void print2u(print_t* pr, uint8_t v) {
char c0 = '?';
char c1 = '?';
if (v < 100) {
c1 = v/10;
c0 = v - 10*c1 + '0';
c1 += '0';
}
pr->write(c1);
pr->write(c0);
}
//------------------------------------------------------------------------------
static void printU32(print_t* pr, uint32_t v) {
char buf[11];
char* ptr = buf + sizeof(buf);
*--ptr = 0;
pr->write(fmtDec(v, ptr));
}
//------------------------------------------------------------------------------
void FatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) {
if (!isDir()) return;
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));
}
}
}
//------------------------------------------------------------------------------
// 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)) {
DBG_FAIL_MACRO;
goto fail;
}
printFatDate(pr, dir.creationDate);
pr->write(' ');
printFatTime(pr, dir.creationTime);
return true;

fail:
return false;
}
//------------------------------------------------------------------------------
void FatFile::printFatDate(print_t* pr, uint16_t fatDate) {
printU32(pr, FAT_YEAR(fatDate));
pr->write('-');
print2u(pr, FAT_MONTH(fatDate));
pr->write('-');
print2u(pr, FAT_DAY(fatDate));
}
//------------------------------------------------------------------------------
void FatFile::printFatTime(print_t* pr, uint16_t fatTime) {
print2u(pr, FAT_HOUR(fatTime));
pr->write(':');
print2u(pr, FAT_MINUTE(fatTime));
pr->write(':');
print2u(pr, FAT_SECOND(fatTime));
}
//------------------------------------------------------------------------------
/** Template for FatFile::printField() */
template <typename Type>
static int printFieldT(FatFile* file, char sign, Type value, char term) {
char buf[3*sizeof(Type) + 3];
char* str = &buf[sizeof(buf)];

if (term) {
*--str = term;
if (term == '\n') {
*--str = '\r';
}
}
#ifdef OLD_FMT
do {
Type m = value;
value /= 10;
*--str = '0' + m - 10*value;
} while (value);
#else // OLD_FMT
str = fmtDec(value, str);
#endif // OLD_FMT
if (sign) {
*--str = sign;
}
return file->write(str, &buf[sizeof(buf)] - str);
}
//------------------------------------------------------------------------------

int FatFile::printField(float value, char term, uint8_t prec) {
char buf[24];
char* str = &buf[sizeof(buf)];
if (term) {
*--str = term;
if (term == '\n') {
*--str = '\r';
}
}
str = fmtFloat(value, str, prec);
return write(str, buf + sizeof(buf) - str);
}
//------------------------------------------------------------------------------
int FatFile::printField(uint16_t value, char term) {
return printFieldT(this, 0, value, term);
}
//------------------------------------------------------------------------------
int FatFile::printField(int16_t value, char term) {
char sign = 0;
if (value < 0) {
sign = '-';
value = -value;
}
return printFieldT(this, sign, (uint16_t)value, term);
}
//------------------------------------------------------------------------------
int FatFile::printField(uint32_t value, char term) {
return printFieldT(this, 0, value, term);
}
//------------------------------------------------------------------------------
int FatFile::printField(int32_t value, char term) {
char sign = 0;
if (value < 0) {
sign = '-';
value = -value;
}
return printFieldT(this, sign, (uint32_t)value, term);
}
//------------------------------------------------------------------------------
bool FatFile::printModifyDateTime(print_t* pr) {
dir_t dir;
if (!dirEntry(&dir)) {
DBG_FAIL_MACRO;
goto fail;
}
printFatDate(pr, dir.lastWriteDate);
pr->write(' ');
printFatTime(pr, dir.lastWriteTime);
return true;

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 = ' ';
return pr->write(buf);
}

+ 247
- 0
SdFat/utility/FatFileSystem.h 查看文件

@@ -0,0 +1,247 @@
/* FatLib Library
* Copyright (C) 2013 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/>.
*/
#ifndef FatFileSystem_h
#define FatFileSystem_h
#include "FatVolume.h"
#include "FatFile.h"
/**
* \file
* \brief FatFileSystem class
*/
//------------------------------------------------------------------------------
/** FatFileSystem version YYYYMMDD */
#define FAT_LIB_VERSION 20141115
//------------------------------------------------------------------------------
/**
* \class FatFileSystem
* \brief Integration class for the FatLib library.
*/
class FatFileSystem : protected FatVolume {
protected:
/**
* 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.
*/
bool begin(FatFile* d) {
m_vwd = d;
m_vwd->close();
return init() && vwd()->openRoot(this) && FatFile::setCwd(vwd());
}

public:
/** Change a volume's working directory to root
*
* Changes the volume's working directory to the SD's root directory.
* Optionally set the current working directory to the volume's
* working directory.
*
* \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.
*/
bool chdir(bool set_cwd = false) {
vwd()->close();
return vwd()->openRoot(this) && (set_cwd ? FatFile::setCwd(vwd()) : true);
}
/** Change a volume's working directory
*
* Changes the volume working directory to the \a path subdirectory.
* Optionally set the current working directory to the volume's
* working directory.
*
* Example: If the volume's working directory is "/DIR", chdir("SUB")
* will change the volume's working directory from "/DIR" to "/DIR/SUB".
*
* If path is "/", the volume's working directory will be changed to the
* root directory
*
* \param[in] path The name of the subdirectory.
*
* \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.
*/
//----------------------------------------------------------------------------
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;
*m_vwd = dir;
if (set_cwd) FatFile::setCwd(vwd());
return true;

fail:
return false;
}
//----------------------------------------------------------------------------
/** Set the current working directory to a volume's working directory.
*
* This is useful with multiple SD cards.
*
* The current working directory is changed to this
* volume's working directory.
*
* This is like the Windows/DOS \<drive letter>: command.
*/
void chvol() {
FatFile::setCwd(vwd());
}
//----------------------------------------------------------------------------
/**
* Test for the existence of a file.
*
* \param[in] path Path of the file to be tested for.
*
* \return true if the file exists else false.
*/
bool exists(const char* path) {
return vwd()->exists(path);
}
//----------------------------------------------------------------------------
/** List the directory contents of the volume working directory.
*
* \param[in] pr Print stream for list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*/
void ls(print_t* pr, uint8_t flags) {
vwd()->ls(pr, flags);
}
//----------------------------------------------------------------------------
/** List the directory contents of a directory.
*
* \param[in] pr Print stream for list.
*
* \param[in] path directory to list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*/
void ls(print_t* pr, const char* path, uint8_t flags) {
FatFile dir;
dir.open(vwd(), path, O_READ);
dir.ls(pr, flags);
}
//----------------------------------------------------------------------------
/** Make a subdirectory in the volume working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
*
* \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.
*/
bool mkdir(const char* path, bool pFlag = true) {
FatFile sub;
return sub.mkdir(vwd(), path, pFlag);
}
//----------------------------------------------------------------------------
/** Remove a file from the volume working directory.
*
* \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.
*/
bool remove(const char* path) {
return FatFile::remove(vwd(), path);
}
//----------------------------------------------------------------------------
/** Rename a file or subdirectory.
*
* \param[in] oldPath Path name to the file or subdirectory to be renamed.
*
* \param[in] newPath New path name of the file or subdirectory.
*
* The \a newPath object must not exist before the rename call.
*
* The file to be renamed must not be open. The directory entry may be
* 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.
*/
bool rename(const char *oldPath, const char *newPath) {
FatFile file;
if (!file.open(vwd(), oldPath, O_READ)) return false;
return file.rename(vwd(), newPath);
}
//----------------------------------------------------------------------------
/** Remove a subdirectory from the volume's working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
*
* 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.
*/
bool rmdir(const char* path) {
FatFile sub;
if (!sub.open(vwd(), path, O_READ)) return false;
return sub.rmdir();
}
//----------------------------------------------------------------------------
/** 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] 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.
*/
bool truncate(const char* path, uint32_t length) {
FatFile file;
if (!file.open(vwd(), path, O_WRITE)) return false;
return file.truncate(length);
}
/** \return a pointer to the FatVolume object. */
FatVolume* vol() {return this;}
/** \return a pointer to the volume working directory. */
FatFile* vwd() {return m_vwd;}

private:
FatFile* m_vwd;
};
#endif // FatFileSystem_h

+ 29
- 0
SdFat/utility/FatLib.h 查看文件

@@ -0,0 +1,29 @@
/* FatLib Library
* Copyright (C) 2013 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/>.
*/
#ifndef FatLib_h
#define FatLib_h
#include "ArduinoStream.h"
#include "FatFileSystem.h"
#include "FatLibConfig.h"
#include "FatVolume.h"
#include "FatFile.h"
#include "StdioStream.h"
#include "fstream.h"
#endif // FatLib_h

+ 90
- 0
SdFat/utility/FatLibConfig.h 查看文件

@@ -0,0 +1,90 @@
/* FatLib Library
* Copyright (C) 2013 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/>.
*/
/**
* \file
* \brief configuration definitions
*/
#ifndef FatLibConfig_h
#define FatLibConfig_h
/** Use SdFatConfig.h if nonzero */
#define USE_SDFAT_CONFIG 1
#if USE_SDFAT_CONFIG
#include "../SdFatConfig.h"
#else // USE_SDFAT_CONFIG
#include <stdint.h>
#ifdef __AVR__
#include <avr/io.h>
#endif // __AVR__
//------------------------------------------------------------------------------
/**
* 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__
#define USE_SEPARATE_FAT_CACHE 0
#endif // __arm__
//------------------------------------------------------------------------------
/**
* Set USE_MULTI_BLOCK_IO non-zero to use multi-block SD read/write.
*
* Don't use mult-block read/write on small AVR boards.
*/
#if defined(RAMEND) && RAMEND < 3000
#define USE_MULTI_BLOCK_IO 0
#else
#define USE_MULTI_BLOCK_IO 1
#endif
//------------------------------------------------------------------------------
/**
* Set DESTRUCTOR_CLOSES_FILE non-zero to close a file in its destructor.
*
* Causes use of lots of heap in ARM.
*/
#define DESTRUCTOR_CLOSES_FILE 0
//------------------------------------------------------------------------------
/**
* Call flush for endl if ENDL_CALLS_FLUSH is non-zero
*
* The standard for iostreams is to call flush. This is very costly for
* SdFat. Each call to flush causes 2048 bytes of I/O to the SD.
*
* SdFat has a single 512 byte buffer for I/O so it must write the current
* data block to the SD, read the directory block from the SD, update the
* directory entry, write the directory block to the SD and read the data
* block back into the buffer.
*
* The SD flash memory controller is not designed for this many rewrites
* so performance may be reduced by more than a factor of 100.
*
* If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force
* all data to be written to the SD.
*/
#define ENDL_CALLS_FLUSH 0
//------------------------------------------------------------------------------
/**
* Allow FAT12 volumes if FAT12_SUPPORT is non-zero.
* FAT12 has not been well tested.
*/
#define FAT12_SUPPORT 0
#endif // USE_SDFAT_CONFIG
#endif // FatLibConfig_h

+ 98
- 14
SdFat/utility/FatStructs.h 查看文件

@@ -182,7 +182,7 @@ struct fat_boot {
/**
* 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 (nonremovable) media. For removable media, 0xF0 is
* for fixed (non-removable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
uint8_t mediaType;
@@ -537,11 +537,11 @@ struct directoryEntry {
/** 32-bit unsigned holding this file's size in bytes. */
uint32_t fileSize;
}__attribute__((packed));
/** Type name for directoryEntry */
typedef struct directoryEntry dir_t;
//------------------------------------------------------------------------------
// Definitions for directory entries
//
/** Type name for directoryEntry */
typedef struct directoryEntry dir_t;
/** escape for name[0] = 0XE5 */
uint8_t const DIR_NAME_0XE5 = 0X05;
/** name[0] value for entry that is free after being "deleted" */
@@ -550,7 +550,7 @@ uint8_t const DIR_NAME_DELETED = 0XE5;
uint8_t const DIR_NAME_FREE = 0X00;
/** file is read-only */
uint8_t const DIR_ATT_READ_ONLY = 0X01;
/** File should hidden in directory listings */
/** File should e hidden in directory listings */
uint8_t const DIR_ATT_HIDDEN = 0X02;
/** Entry is for a system file */
uint8_t const DIR_ATT_SYSTEM = 0X04;
@@ -567,6 +567,26 @@ uint8_t const DIR_ATT_LONG_NAME = 0X0F;
uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
/** defined attribute bits */
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);

/** Directory entry is for a file
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for a normal file else false.
*/
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
}
/** Directory entry is for a file or subdirectory
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for a normal file or subdirectory else false.
*/
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
}
/** Directory entry is part of a long name
* \param[in] dir Pointer to a directory entry.
*
@@ -575,15 +595,13 @@ uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
}
/** Mask for file/subdirectory tests */
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
/** Directory entry is for a file
/** Directory entry is hidden
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for a normal file else false.
* \return true if the entry is hidden else false.
*/
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
static inline uint8_t DIR_IS_HIDDEN(const dir_t* dir) {
return dir->attributes & DIR_ATT_HIDDEN;
}
/** Directory entry is for a subdirectory
* \param[in] dir Pointer to a directory entry.
@@ -593,13 +611,13 @@ static inline uint8_t DIR_IS_FILE(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 for a file or subdirectory
/** Directory entry is system type
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for a normal file or subdirectory else false.
* \return true if the entry is system else false.
*/
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
static inline uint8_t DIR_IS_SYSTEM(const dir_t* dir) {
return dir->attributes & DIR_ATT_SYSTEM;
}
/** date field for FAT directory entry
* \param[in] year [1980,2107]
@@ -675,4 +693,70 @@ static inline uint8_t FAT_SECOND(uint16_t fatTime) {
uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
/** Default time for file timestamp is 1 am */
uint16_t const FAT_DEFAULT_TIME = (1 << 11);
//------------------------------------------------------------------------------
/** Dimension of first name field in long directory entry */
const uint8_t LDIR_NAME1_DIM = 5;
/** Dimension of first name field in long directory entry */
const uint8_t LDIR_NAME2_DIM = 6;
/** Dimension of first name field in long directory entry */
const uint8_t LDIR_NAME3_DIM = 2;
/**
* \struct longDirectoryEntry
* \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.
*/
uint8_t ord;
/** Characters 1-5 of the long-name sub-component in this entry. */
uint16_t name1[LDIR_NAME1_DIM];
/** 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.
*/
uint8_t type;
/**
* 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. */
uint16_t name2[LDIR_NAME2_DIM];
/** 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. */
uint16_t name3[LDIR_NAME3_DIM];
}__attribute__((packed));
/** Type name for longDirectoryEntry */
typedef struct longDirectoryEntry ldir_t;
/**
* Ord mast that 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.
*/
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

SdFat/SdVolume.cpp → SdFat/utility/FatVolume.cpp 查看文件

@@ -1,7 +1,7 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
/* FatLib Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdFat Library
* 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
@@ -14,282 +14,202 @@
* 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
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdFat.h>
#include "FatVolume.h"
//------------------------------------------------------------------------------
#if !USE_MULTIPLE_CARDS
// raw block cache
uint8_t SdVolume::m_fatCount; // number of FATs on volume
uint32_t SdVolume::m_blocksPerFat; // FAT size in blocks
cache_t SdVolume::m_cacheBuffer; // 512 byte cache for Sd2Card
uint32_t SdVolume::m_cacheBlockNumber; // current block number
uint8_t SdVolume::m_cacheStatus; // status of cache block
#if USE_SEPARATE_FAT_CACHE
cache_t SdVolume::m_cacheFatBuffer; // 512 byte cache for FAT
uint32_t SdVolume::m_cacheFatBlockNumber; // current Fat block number
uint8_t SdVolume::m_cacheFatStatus; // status of cache Fatblock
#endif // USE_SEPARATE_FAT_CACHE
Sd2Card* SdVolume::m_sdCard; // pointer to SD card object
#endif // USE_MULTIPLE_CARDS
//------------------------------------------------------------------------------
// find a contiguous group of clusters
bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
// start of group
uint32_t bgnCluster;
// end of group
uint32_t endCluster;
// last cluster of FAT
uint32_t fatEnd = m_clusterCount + 1;

// flag to save place to start next search
bool setStart;

// set search start cluster
if (*curCluster) {
// try to make file contiguous
bgnCluster = *curCluster + 1;

// don't save new start location
setStart = false;
} else {
// start at likely place for free cluster
bgnCluster = m_allocSearchStart;

// save next search start if no holes.
setStart = true;
}
// end of group
endCluster = bgnCluster;

// search the FAT for free clusters
for (uint32_t n = 0;; n++, endCluster++) {
// can't find space checked all clusters
if (n >= m_clusterCount) {
DBG_FAIL_MACRO;
goto fail;
}
// past end - start from beginning of FAT
if (endCluster > fatEnd) {
bgnCluster = endCluster = 2;
}
uint32_t f;
if (!fatGet(endCluster, &f)) {
DBG_FAIL_MACRO;
goto fail;
}

if (f != 0) {
// don't update search start if unallocated clusters before endCluster.
if (bgnCluster != endCluster) setStart = false;
// cluster in use try next cluster as bgnCluster
bgnCluster = endCluster + 1;
} else if ((endCluster - bgnCluster + 1) == count) {
// done - found space
break;
}
}
// remember possible next free cluster
if (setStart) m_allocSearchStart = endCluster + 1;

// mark end of chain
if (!fatPutEOC(endCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
// link clusters
while (endCluster > bgnCluster) {
if (!fatPut(endCluster - 1, endCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
endCluster--;
}
if (*curCluster != 0) {
// connect chains
if (!fatPut(*curCluster, bgnCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
}
// return first cluster number to caller
*curCluster = bgnCluster;
return true;

fail:
return false;
}
//==============================================================================
// cache functions
#if USE_SEPARATE_FAT_CACHE
//------------------------------------------------------------------------------
cache_t* SdVolume::cacheFetch(uint32_t blockNumber, uint8_t options) {
return cacheFetchData(blockNumber, options);
}
//------------------------------------------------------------------------------
cache_t* SdVolume::cacheFetchData(uint32_t blockNumber, uint8_t options) {
if (m_cacheBlockNumber != blockNumber) {
if (!cacheWriteData()) {
cache_t* FatCache::read(uint32_t lbn, uint8_t option) {
if (m_lbn != lbn) {
if (!sync()) {
DBG_FAIL_MACRO;
goto fail;
}
if (!(options & CACHE_OPTION_NO_READ)) {
if (!m_sdCard->readBlock(blockNumber, m_cacheBuffer.data)) {
if (!(option & CACHE_OPTION_NO_READ)) {
if (!m_vol->readBlock(lbn, m_block.data)) {
DBG_FAIL_MACRO;
goto fail;
}
}
m_cacheStatus = 0;
m_cacheBlockNumber = blockNumber;
m_status = 0;
m_lbn = lbn;
}
m_cacheStatus |= options & CACHE_STATUS_MASK;
return &m_cacheBuffer;
m_status |= option & CACHE_STATUS_MASK;
return &m_block;

fail:
return 0;
}
//------------------------------------------------------------------------------
cache_t* SdVolume::cacheFetchFat(uint32_t blockNumber, uint8_t options) {
if (m_cacheFatBlockNumber != blockNumber) {
if (!cacheWriteFat()) {
bool FatCache::sync() {
if (m_status & CACHE_STATUS_DIRTY) {
if (!m_vol->writeBlock(m_lbn, m_block.data)) {
DBG_FAIL_MACRO;
goto fail;
}
if (!(options & CACHE_OPTION_NO_READ)) {
if (!m_sdCard->readBlock(blockNumber, m_cacheFatBuffer.data)) {
// mirror second FAT
if (m_status & CACHE_STATUS_MIRROR_FAT) {
uint32_t lbn = m_lbn + m_vol->blocksPerFat();
if (!m_vol->writeBlock(lbn, m_block.data)) {
DBG_FAIL_MACRO;
goto fail;
}
}
m_cacheFatStatus = 0;
m_cacheFatBlockNumber = blockNumber;
m_status &= ~CACHE_STATUS_DIRTY;
}
m_cacheFatStatus |= options & CACHE_STATUS_MASK;
return &m_cacheFatBuffer;
return true;

fail:
return 0;
}
//------------------------------------------------------------------------------
bool SdVolume::cacheSync() {
return cacheWriteData() && cacheWriteFat();
return false;
}
//------------------------------------------------------------------------------
bool SdVolume::cacheWriteData() {
if (m_cacheStatus & CACHE_STATUS_DIRTY) {
if (!m_sdCard->writeBlock(m_cacheBlockNumber, m_cacheBuffer.data)) {
bool FatVolume::allocateCluster(uint32_t current, uint32_t* next) {
uint32_t find = current ? current : m_allocSearchStart;
uint32_t start = find;
while (1) {
find++;
// If at end of FAT go to beginning of FAT.
if (find > m_lastCluster) find = 2;

uint32_t f;
if (!fatGet(find, &f)) {
DBG_FAIL_MACRO;
goto fail;
}
m_cacheStatus &= ~CACHE_STATUS_DIRTY;
}
return true;

fail:
return false;
}
//------------------------------------------------------------------------------
bool SdVolume::cacheWriteFat() {
if (m_cacheFatStatus & CACHE_STATUS_DIRTY) {
if (!m_sdCard->writeBlock(m_cacheFatBlockNumber, m_cacheFatBuffer.data)) {
if (f == 0) break;
if (find == start) {
// Can't find space checked all clusters.
DBG_FAIL_MACRO;
goto fail;
}
// mirror second FAT
if (m_fatCount > 1) {
uint32_t lbn = m_cacheFatBlockNumber + m_blocksPerFat;
if (!m_sdCard->writeBlock(lbn, m_cacheFatBuffer.data)) {
DBG_FAIL_MACRO;
goto fail;
}
}
// mark end of chain
if (!fatPutEOC(find)) {
DBG_FAIL_MACRO;
goto fail;
}
if (current) {
// link clusters
if (!fatPut(current, find)) {
DBG_FAIL_MACRO;
goto fail;
}
m_cacheFatStatus &= ~CACHE_STATUS_DIRTY;
} else {
// Remember place for search start.
m_allocSearchStart = find;
}
*next = find;
return true;

fail:
return false;
}
#else // USE_SEPARATE_FAT_CACHE
//------------------------------------------------------------------------------
cache_t* SdVolume::cacheFetch(uint32_t blockNumber, uint8_t options) {
if (m_cacheBlockNumber != blockNumber) {
if (!cacheSync()) {
// find a contiguous group of clusters
bool FatVolume::allocContiguous(uint32_t count, uint32_t* firstCluster) {
// flag to save place to start next search
bool setStart = true;
// start of group
uint32_t bgnCluster;
// end of group
uint32_t endCluster;
// Start at cluster after last allocated cluster.
uint32_t startCluster = m_allocSearchStart;
endCluster = bgnCluster = startCluster + 1;

// search the FAT for free clusters
while (1) {
// If past end - start from beginning of FAT.
if (endCluster > m_lastCluster) {
bgnCluster = endCluster = 2;
}
uint32_t f;
if (!fatGet(endCluster, &f)) {
DBG_FAIL_MACRO;
goto fail;
}
if (!(options & CACHE_OPTION_NO_READ)) {
if (!m_sdCard->readBlock(blockNumber, m_cacheBuffer.data)) {
DBG_FAIL_MACRO;
goto fail;
}
if (f != 0) {
// don't update search start if unallocated clusters before endCluster.
if (bgnCluster != endCluster) setStart = false;

// cluster in use try next cluster as bgnCluster
bgnCluster = endCluster + 1;
} else if ((endCluster - bgnCluster + 1) == count) {
// done - found space
break;
}
m_cacheStatus = 0;
m_cacheBlockNumber = blockNumber;
// Can't find space if all clusters checked.
if (startCluster == endCluster) {
DBG_FAIL_MACRO;
goto fail;
}
endCluster++;
}
m_cacheStatus |= options & CACHE_STATUS_MASK;
return &m_cacheBuffer;
// remember possible next free cluster
if (setStart) m_allocSearchStart = endCluster + 1;

fail:
return 0;
}
//------------------------------------------------------------------------------
cache_t* SdVolume::cacheFetchFat(uint32_t blockNumber, uint8_t options) {
return cacheFetch(blockNumber, options | CACHE_STATUS_FAT_BLOCK);
}
//------------------------------------------------------------------------------
bool SdVolume::cacheSync() {
if (m_cacheStatus & CACHE_STATUS_DIRTY) {
if (!m_sdCard->writeBlock(m_cacheBlockNumber, m_cacheBuffer.data)) {
// mark end of chain
if (!fatPutEOC(endCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
// link clusters
while (endCluster > bgnCluster) {
if (!fatPut(endCluster - 1, endCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
// mirror second FAT
if ((m_cacheStatus & CACHE_STATUS_FAT_BLOCK) && m_fatCount > 1) {
uint32_t lbn = m_cacheBlockNumber + m_blocksPerFat;
if (!m_sdCard->writeBlock(lbn, m_cacheBuffer.data)) {
DBG_FAIL_MACRO;
goto fail;
}
}
m_cacheStatus &= ~CACHE_STATUS_DIRTY;
endCluster--;
}
// return first cluster number to caller
*firstCluster = bgnCluster;
return true;

fail:
return false;
}
//------------------------------------------------------------------------------
bool SdVolume::cacheWriteData() {
return cacheSync();
}
#endif // USE_SEPARATE_FAT_CACHE
//------------------------------------------------------------------------------
void SdVolume::cacheInvalidate() {
m_cacheBlockNumber = 0XFFFFFFFF;
m_cacheStatus = 0;
}
//==============================================================================
//------------------------------------------------------------------------------
uint32_t SdVolume::clusterStartBlock(uint32_t cluster) const {
uint32_t FatVolume::clusterStartBlock(uint32_t cluster) const {
return m_dataStartBlock + ((cluster - 2) << m_clusterSizeShift);
}
//------------------------------------------------------------------------------
// Fetch a FAT entry
bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
bool FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
uint32_t lba;
cache_t* pc;

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

if (m_fatType == 32) {
lba = m_fatStartBlock + (cluster >> 7);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
*value = pc->fat32[cluster & 0X7F] & FAT32MASK;
return true;
}

if (m_fatType == 16) {
lba = m_fatStartBlock + ((cluster >> 8) & 0XFF);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
*value = pc->fat16[cluster & 0XFF];
return true;
}
if (FAT12_SUPPORT && m_fatType == 12) {
uint16_t index = cluster;
index += index >> 1;
lba = m_fatStartBlock + (index >> 9);
pc = cacheFetchFat(lba, CACHE_FOR_READ);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
@@ -298,7 +218,7 @@ bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
uint16_t tmp = pc->data[index];
index++;
if (index == 512) {
pc = cacheFetchFat(lba + 1, CACHE_FOR_READ);
pc = cacheFetchFat(lba + 1, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
@@ -308,45 +228,53 @@ bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
tmp |= pc->data[index] << 8;
*value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
return true;
}
if (m_fatType == 16) {
lba = m_fatStartBlock + (cluster >> 8);
} else if (m_fatType == 32) {
lba = m_fatStartBlock + (cluster >> 7);
} else {
DBG_FAIL_MACRO;
goto fail;
}
pc = cacheFetchFat(lba, CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
if (m_fatType == 16) {
*value = pc->fat16[cluster & 0XFF];
} else {
*value = pc->fat32[cluster & 0X7F] & FAT32MASK;
}
return true;

fail:
return false;
}
//------------------------------------------------------------------------------
// Store a FAT entry
bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
bool FatVolume::fatPut(uint32_t cluster, uint32_t value) {
uint32_t lba;
cache_t* pc;

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

if (m_fatType == 32) {
lba = m_fatStartBlock + (cluster >> 7);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
pc->fat32[cluster & 0X7F] = value;
return true;
}

if (m_fatType == 16) {
lba = m_fatStartBlock + ((cluster >> 8) & 0XFF);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
pc->fat16[cluster & 0XFF] = value;
return true;
}

if (FAT12_SUPPORT && m_fatType == 12) {
uint16_t index = cluster;
index += index >> 1;
lba = m_fatStartBlock + (index >> 9);
pc = cacheFetchFat(lba, CACHE_FOR_WRITE);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
@@ -362,7 +290,7 @@ bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
if (index == 512) {
lba++;
index = 0;
pc = cacheFetchFat(lba, CACHE_FOR_WRITE);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
@@ -374,34 +302,17 @@ bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
}
pc->data[index] = tmp;
return true;
}
if (m_fatType == 16) {
lba = m_fatStartBlock + (cluster >> 8);
} else if (m_fatType == 32) {
lba = m_fatStartBlock + (cluster >> 7);
} else {
DBG_FAIL_MACRO;
goto fail;
}
pc = cacheFetchFat(lba, CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
// store entry
if (m_fatType == 16) {
pc->fat16[cluster & 0XFF] = value;
} else {
pc->fat32[cluster & 0X7F] = value;
}
return true;

fail:
return false;
}
//------------------------------------------------------------------------------
// free a cluster chain
bool SdVolume::freeChain(uint32_t cluster) {
bool FatVolume::freeChain(uint32_t cluster) {
uint32_t next;

do {
@@ -424,14 +335,10 @@ bool SdVolume::freeChain(uint32_t cluster) {
return false;
}
//------------------------------------------------------------------------------
/** Volume free space in clusters.
*
* \return Count of free clusters for success or -1 if an error occurs.
*/
int32_t SdVolume::freeClusterCount() {
int32_t FatVolume::freeClusterCount() {
uint32_t free = 0;
uint32_t lba;
uint32_t todo = m_clusterCount + 2;
uint32_t todo = m_lastCluster + 1;
uint16_t n;

if (FAT12_SUPPORT && m_fatType == 12) {
@@ -446,7 +353,7 @@ int32_t SdVolume::freeClusterCount() {
} else if (m_fatType == 16 || m_fatType == 32) {
lba = m_fatStartBlock;
while (todo) {
cache_t* pc = cacheFetchFat(lba++, CACHE_FOR_READ);
cache_t* pc = cacheFetchFat(lba++, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
@@ -475,35 +382,21 @@ int32_t SdVolume::freeClusterCount() {
return -1;
}
//------------------------------------------------------------------------------
/** Initialize a FAT volume.
*
* \param[in] dev The SD card where the volume is located.
*
* \param[in] part The partition to be used. Legal values for \a part are
* 1-4 to use the corresponding partition on a device formatted with
* 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.
*/
bool SdVolume::init(Sd2Card* dev, uint8_t part) {
uint8_t tmp;
bool FatVolume::init(uint8_t part) {
uint32_t clusterCount;
uint32_t totalBlocks;
uint32_t volumeStartBlock = 0;
fat32_boot_t* fbs;
cache_t* pc;
m_sdCard = dev;
uint8_t tmp;
m_fatType = 0;
m_allocSearchStart = 2;
m_cacheStatus = 0; // cacheSync() will write block if true
m_cacheBlockNumber = 0XFFFFFFFF;
m_allocSearchStart = 1;

m_cache.init(this);
#if USE_SEPARATE_FAT_CACHE
m_cacheFatStatus = 0; // cacheSync() will write block if true
m_cacheFatBlockNumber = 0XFFFFFFFF;
m_fatCache.init(this);
#endif // USE_SEPARATE_FAT_CACHE

// if part == 0 assume super floppy with FAT boot sector in block zero
// if part > 0 assume mbr volume with partition table
if (part) {
@@ -511,7 +404,7 @@ bool SdVolume::init(Sd2Card* dev, uint8_t part) {
DBG_FAIL_MACRO;
goto fail;
}
pc = cacheFetch(volumeStartBlock, CACHE_FOR_READ);
pc = cacheFetchData(volumeStartBlock, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
@@ -524,28 +417,25 @@ bool SdVolume::init(Sd2Card* dev, uint8_t part) {
}
volumeStartBlock = p->firstSector;
}
pc = cacheFetch(volumeStartBlock, CACHE_FOR_READ);
pc = cacheFetchData(volumeStartBlock, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
fbs = &(pc->fbs32);
if (fbs->bytesPerSector != 512 ||
fbs->fatCount == 0 ||
fbs->fatCount != 2 ||
fbs->reservedSectorCount == 0) {
// not valid FAT volume
DBG_FAIL_MACRO;
goto fail;
}
m_fatCount = fbs->fatCount;
m_blocksPerCluster = fbs->sectorsPerCluster;

m_clusterBlockMask = m_blocksPerCluster - 1;

// determine shift that is same as multiply by m_blocksPerCluster
m_clusterSizeShift = 0;
for (tmp = 1; m_blocksPerCluster != tmp; m_clusterSizeShift++) {
tmp <<= 1;
for (tmp = 1; m_blocksPerCluster != tmp; tmp <<= 1, m_clusterSizeShift++) {
if (tmp == 0) {
DBG_FAIL_MACRO;
goto fail;
@@ -561,8 +451,7 @@ bool SdVolume::init(Sd2Card* dev, uint8_t part) {
m_rootDirEntryCount = fbs->rootDirEntryCount;

// directory start for FAT16 dataStart for FAT32
m_rootDirStart = m_fatStartBlock + fbs->fatCount * m_blocksPerFat;

m_rootDirStart = m_fatStartBlock + 2 * m_blocksPerFat;
// data start for FAT16 and FAT32
m_dataStartBlock = m_rootDirStart + ((32 * fbs->rootDirEntryCount + 511)/512);

@@ -570,19 +459,19 @@ bool SdVolume::init(Sd2Card* dev, uint8_t part) {
totalBlocks = fbs->totalSectors16 ?
fbs->totalSectors16 : fbs->totalSectors32;
// total data blocks
m_clusterCount = totalBlocks - (m_dataStartBlock - volumeStartBlock);
clusterCount = totalBlocks - (m_dataStartBlock - volumeStartBlock);

// divide by cluster size to get cluster count
m_clusterCount >>= m_clusterSizeShift;
clusterCount >>= m_clusterSizeShift;
m_lastCluster = clusterCount + 1;
// FAT type is determined by cluster count
if (m_clusterCount < 4085) {
if (clusterCount < 4085) {
m_fatType = 12;
if (!FAT12_SUPPORT) {
DBG_FAIL_MACRO;
goto fail;
}
} else if (m_clusterCount < 65525) {
} else if (clusterCount < 65525) {
m_fatType = 16;
} else {
m_rootDirStart = fbs->fat32RootCluster;

+ 257
- 0
SdFat/utility/FatVolume.h 查看文件

@@ -0,0 +1,257 @@
/* FatLib Library
* Copyright (C) 2013 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/>.
*/
#ifndef FatVolume_h
#define FatVolume_h
/**
* \file
* \brief FatVolume class
*/
#include <stddef.h>
#include "FatLibConfig.h"
#include "FatStructs.h"
//------------------------------------------------------------------------------
/** Macro for debug. */
// #include <Arduino.h>
#define DBG_FAIL_MACRO // Serial.print(__FILE__);Serial.println(__LINE__)
//------------------------------------------------------------------------------
// Forward declaration of FatVolume.
class FatVolume;
//------------------------------------------------------------------------------
/**
* \brief Cache for an raw data block.
*/
union cache_t {
/** Used to access cached file data blocks. */
uint8_t data[512];
/** Used to access cached FAT16 entries. */
uint16_t fat16[256];
/** Used to access cached FAT32 entries. */
uint32_t fat32[128];
/** Used to access cached directory entries. */
dir_t dir[16];
/** Used to access a cached Master Boot Record. */
mbr_t mbr;
/** Used to access to a cached FAT boot sector. */
fat_boot_t fbs;
/** Used to access to a cached FAT32 boot sector. */
fat32_boot_t fbs32;
/** Used to access to a cached FAT32 FSINFO sector. */
fat32_fsinfo_t fsinfo;
};
//==============================================================================
/**
* \class FatCache
* \brief Block cache.
*/
class FatCache {
public:
/** Cached block is dirty */
static const uint8_t CACHE_STATUS_DIRTY = 1;
/** Cashed block is FAT entry and must be mirrored in second FAT. */
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;
/** Sync existing block but do not read new block. */
static const uint8_t CACHE_OPTION_NO_READ = 4;
/** Cache block for read. */
static uint8_t const CACHE_FOR_READ = 0;
/** Cache block for write. */
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;
/** \return Cache block address. */
cache_t* block() {return &m_block;}
/** Set current block dirty. */
void dirty() {m_status |= CACHE_STATUS_DIRTY;}
/** Initialize the cache.
* \param[in] vol FatVolume that owns this FatCache.
*/
void init(FatVolume *vol) {
m_vol = vol;
invalidate();
}
/** Invalidate current cache block. */
void invalidate() {
m_status = 0;
m_lbn = 0XFFFFFFFF;
}
/** \return Logical block number for cached block. */
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.
* \return Address of cached block. */
cache_t* read(uint32_t lbn, uint8_t option);
/** Write current block if dirty.
* \return true for success else false.
*/
bool sync();

private:
uint8_t m_status;
FatVolume* m_vol;
uint32_t m_lbn;
cache_t m_block;
};
//==============================================================================
/**
* \class FatVolume
* \brief Access FAT16 and FAT32 volumes on raw file devices.
*/
class FatVolume {
public:
/** Create an instance of FatVolume
*/
FatVolume() : m_fatType(0) {}

/** \return The volume's cluster size in blocks. */
uint8_t blocksPerCluster() const {return m_blocksPerCluster;}
/** \return The number of blocks in one FAT. */
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;
m_cache.invalidate();
return m_cache.block();
}
/** \return The total number of clusters in the volume. */
uint32_t clusterCount() const {return m_lastCluster - 1;}
/** \return The shift count required to multiply by blocksPerCluster. */
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;}
/** \return The number of File Allocation Tables. */
uint8_t fatCount() {return 2;}
/** \return The logical block number for the start of the first FAT. */
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;}
/** Volume free space in clusters.
*
* \return Count of free clusters for success or -1 if an error occurs.
*/
int32_t freeClusterCount();
/** 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.
*/
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
* 1-4 to use the corresponding partition on a device formatted with
* 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.
*/
bool init(uint8_t part);
/** \return The number of entries in the root directory for FAT16 volumes. */
uint32_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;}
/** 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);}
//------------------------------------------------------------------------------
private:
// Allow FatFile and FatCache access to FatVolume private functions.
friend class FatCache;
friend class FatFile;
//------------------------------------------------------------------------------
uint8_t m_blocksPerCluster; // Cluster size in blocks.
uint8_t m_clusterBlockMask; // Mask to extract block of cluster.
uint8_t m_clusterSizeShift; // Cluster count to block count shift.
uint8_t m_fatType; // Volume type (12, 16, OR 32).
uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
uint32_t m_allocSearchStart; // Start cluster for alloc search.
uint32_t m_blocksPerFat; // FAT size in blocks
uint32_t m_dataStartBlock; // First data block number.
uint32_t m_fatStartBlock; // Start block for first FAT.
uint32_t m_lastCluster; // Last cluster number in FAT.
uint32_t m_rootDirStart; // Start block for FAT16, cluster for FAT32.
//------------------------------------------------------------------------------
// block caches
FatCache m_cache;
#if USE_SEPARATE_FAT_CACHE
FatCache m_fatCache;
cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options) {
return m_fatCache.read(blockNumber,
options | FatCache::CACHE_STATUS_MIRROR_FAT);
}
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();}
#endif // USE_SEPARATE_FAT_CACHE
cache_t* cacheFetchData(uint32_t blockNumber, uint8_t options) {
return m_cache.read(blockNumber, options);
}
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 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;}
uint32_t clusterStartBlock(uint32_t cluster) const;
bool fatGet(uint32_t cluster, uint32_t* value);
bool fatPut(uint32_t cluster, uint32_t value);
bool fatPutEOC(uint32_t cluster) {
return fatPut(cluster, 0x0FFFFFFF);
}
bool freeChain(uint32_t cluster);
bool isEOC(uint32_t cluster) const {
return cluster > m_lastCluster;
}
//----------------------------------------------------------------------------
// 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;
#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;
#endif // USE_MULTI_BLOCK_IO
};
#endif // FatVolume

+ 13
- 3
SdFat/utility/FmtNumber.cpp 查看文件

@@ -17,10 +17,10 @@
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <avr/pgmspace.h>
#include <FmtNumber.h>
#include "FmtNumber.h"
// Use Stimmer div/mod 10 on avr
#ifdef __AVR__
#include <avr/pgmspace.h>
#define USE_STIMMER
#endif // __AVR__
//------------------------------------------------------------------------------
@@ -149,9 +149,15 @@ unsigned divu10(unsigned n) {
}
*/
//------------------------------------------------------------------------------

#ifndef DOXYGEN_SHOULD_SKIP_THIS
#ifdef __AVR__
static const float m[] PROGMEM = {1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32};
static const float p[] PROGMEM = {1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32};
#else // __AVR__
static const float m[] = {1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32};
static const float p[] = {1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32};
#endif // __AVR__
#endif // DOXYGEN_SHOULD_SKIP_THIS
// scale float v by power of ten. return v*10^n
float scale10(float v, int8_t n) {
const float *s;
@@ -163,7 +169,11 @@ 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]);
#else // __AVR__
if (n & 1) v *= s[i];
#endif // __AVR__
}
return v;
}

+ 3
- 1
SdFat/utility/FmtNumber.h 查看文件

@@ -19,7 +19,9 @@
*/
#ifndef FmtNumber_h
#define FmtNumber_h
#include <Arduino.h>
#include <ctype.h>
#include <math.h>
#include <stdint.h>
char* fmtDec(uint16_t n, char* p);
char* fmtDec(uint32_t n, char* p);
char* fmtFloat(float value, char* p, uint8_t prec);

+ 1
- 1
SdFat/utility/SoftSPI.h 查看文件

@@ -28,7 +28,7 @@

#ifndef SoftSPI_h
#define SoftSPI_h
#include <DigitalPin.h>
#include "DigitalPin.h"
//------------------------------------------------------------------------------
/** Nop for timing. */
#define nop asm volatile ("nop\n\t")

SdFat/StdioStream.cpp → SdFat/utility/StdioStream.cpp 查看文件

@@ -17,9 +17,8 @@
* along with the Arduino RamDisk Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include <StdioStream.h>
#include <utility/FmtNumber.h>
#include "StdioStream.h"
#include "FmtNumber.h"
//------------------------------------------------------------------------------
int StdioStream::fclose() {
int rtn = 0;
@@ -29,7 +28,7 @@ int StdioStream::fclose() {
if (m_flags & F_SWR) {
if (!flushBuf()) rtn = EOF;
}
if (!SdBaseFile::close()) rtn = EOF;
if (!FatFile::close()) rtn = EOF;
m_r = 0;
m_w = 0;
m_flags = 0;
@@ -38,15 +37,15 @@ int StdioStream::fclose() {
//------------------------------------------------------------------------------
int StdioStream::fflush() {
if ((m_flags & (F_SWR | F_SRW)) && !(m_flags & F_SRD)) {
if (flushBuf() && SdBaseFile::sync()) return 0;
if (flushBuf() && FatFile::sync()) return 0;
}
return EOF;
}
//------------------------------------------------------------------------------
char* StdioStream::fgets(char* str, int num, size_t* len) {
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()) {
@@ -77,21 +76,21 @@ char* StdioStream::fgets(char* str, int num, size_t* len) {
}
//------------------------------------------------------------------------------
bool StdioStream::fopen(const char* filename, const char* mode) {
uint8_t oflags;
uint8_t oflag;
switch (*mode++) {
case 'a':
m_flags = F_SWR;
oflags = O_WRITE | O_CREAT | O_APPEND | O_AT_END;
oflag = O_WRITE | O_CREAT | O_APPEND | O_AT_END;
break;

case 'r':
m_flags = F_SRD;
oflags = O_READ;
oflag = O_READ;
break;

case 'w':
m_flags = F_SWR;
oflags = O_WRITE | O_CREAT | O_TRUNC;
oflag = O_WRITE | O_CREAT | O_TRUNC;
break;

default:
@@ -101,22 +100,22 @@ bool StdioStream::fopen(const char* filename, const char* mode) {
switch (*mode++) {
case '+':
m_flags |= F_SRW;
oflags |= O_RDWR;
oflag |= O_RDWR;
break;

case 'b':
break;

case 'x':
oflags |= O_EXCL;
oflag |= O_EXCL;
break;

default:
goto fail;
}
}
if ((oflags & O_EXCL) && !(oflags & O_WRITE)) goto fail;
if (!SdBaseFile::open(filename, oflags)) 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;
@@ -174,19 +173,19 @@ int StdioStream::fseek(int32_t offset, int origin) {
goto fail;
}
pos += offset;
if (!SdBaseFile::seekCur(pos)) {
if (!FatFile::seekCur(pos)) {
goto fail;
}
break;

case SEEK_SET:
if (!SdBaseFile::seekSet(offset)) {
if (!FatFile::seekSet(offset)) {
goto fail;
}
break;

case SEEK_END:
if (!SdBaseFile::seekEnd(offset)) {
if (!FatFile::seekEnd(offset)) {
goto fail;
}
break;
@@ -203,7 +202,7 @@ int StdioStream::fseek(int32_t offset, int origin) {
}
//------------------------------------------------------------------------------
int32_t StdioStream::ftell() {
uint32_t pos = SdBaseFile::curPosition();
uint32_t pos = FatFile::curPosition();
if (m_flags & F_SRD) {
if (m_r > pos) return -1L;
pos -= m_r;
@@ -255,9 +254,9 @@ size_t StdioStream::fwrite(const void* ptr, size_t size, size_t count) {
}
//------------------------------------------------------------------------------
size_t StdioStream::print(const __FlashStringHelper *str) {
const char PROGMEM *p = (const char PROGMEM *)str;
const char *p = (const char PROGMEM *)str;
uint8_t c;
while (c = pgm_read_byte(p)) {
while ((c = pgm_read_byte(p))) {
if (putc(c) < 0) return 0;
p++;
}
@@ -335,7 +334,7 @@ int StdioStream::printDec(signed char n) {
n = -n;
s = 1;
}
printDec((unsigned char)n);
return printDec((unsigned char)n);
}
//------------------------------------------------------------------------------
int StdioStream::printDec(int16_t n) {
@@ -435,7 +434,7 @@ bool StdioStream::rewind() {
if (m_flags & F_SWR) {
if (!flushBuf()) return false;
}
SdBaseFile::seekSet(0);
FatFile::seekSet(0);
m_r = 0;
return true;
}
@@ -479,7 +478,7 @@ bool StdioStream::fillBuf() {
}
}
m_p = m_buf + UNGETC_BUF_SIZE;
int nr = SdBaseFile::read(m_p, sizeof(m_buf) - UNGETC_BUF_SIZE);
int nr = FatFile::read(m_p, sizeof(m_buf) - UNGETC_BUF_SIZE);
if (nr <= 0) {
m_flags |= nr < 0 ? F_ERR : F_EOF;
m_r = 0;
@@ -506,7 +505,7 @@ bool StdioStream::flushBuf() {
uint8_t n = m_p - m_buf;
m_p = m_buf;
m_w = sizeof(m_buf);
if (SdBaseFile::write(m_buf, n) == n) return true;
if (FatFile::write(m_buf, n) == n) return true;
m_flags |= F_ERR;
return false;
}

SdFat/StdioStream.h → SdFat/utility/StdioStream.h 查看文件

@@ -24,9 +24,7 @@
* \brief StdioStream class
*/
#include <limits.h>
#include <Arduino.h>
#include <SdFat.h>
#include <SdBaseFile.h>
#include "FatFile.h"
//------------------------------------------------------------------------------
/** Total size of stream buffer. The entire buffer is used for output.
* During input UNGETC_BUF_SIZE of this space is reserved for ungetc.
@@ -106,7 +104,7 @@ const uint8_t UNGETC_BUF_SIZE = 2;
*
* StdioStream does not support subdirectories or long file names.
*/
class StdioStream : private SdBaseFile {
class StdioStream : private FatFile {
public:
/** Constructor
*
@@ -186,7 +184,7 @@ class StdioStream : private SdBaseFile {
* occurs during the operation, the array contents are indeterminate
* and a null pointer is returned.
*/
char* fgets(char* str, int num, size_t* len = 0);
char* fgets(char* str, size_t num, size_t* len = 0);
//----------------------------------------------------------------------------
/** Open a stream.
*
@@ -244,7 +242,7 @@ class StdioStream : private SdBaseFile {
* function or to a file positioning function (fseek, or rewind), and
* input shall not be directly followed by output without an intervening
* call to a file positioning function, unless the input operation
* encounters endof-file.
* encounters end-of-file.
*
* \return true for success or false for failure.
*/
@@ -334,14 +332,14 @@ class StdioStream : private SdBaseFile {
* \param[in] count the number of elements to be written.
*
* \return number of elements successfully written. if this number is
* less than count, an error has occured. If size or count is zero,
* less than count, an error has occurred. If size or count is zero,
* fwrite returns zero.
*/
size_t fwrite(const void * ptr, size_t size, size_t count);
//----------------------------------------------------------------------------
/** Get a byte from the stream.
*
* getc and fgetc are equivalent but getc is inline so it is faster but
* getc and fgetc are equivalent but getc is in-line so it is faster but
* require more flash memory.
*
* \return If the end-of-file indicator for the stream is set, or if the
@@ -354,7 +352,7 @@ class StdioStream : private SdBaseFile {
//----------------------------------------------------------------------------
/** Write a byte to a stream.
*
* putc and fputc are equivalent but putc is inline so it is faster but
* putc and fputc are equivalent but putc is in-line so it is faster but
* require more flash memory.
*
* \param[in] c the byte to be written (converted to an unsigned char).
@@ -619,7 +617,7 @@ class StdioStream : private SdBaseFile {
*
* \param[in] c the byte (converted to an unsigned char) to be pushed back.
*
* One character of pushback is guaranteed. If the ungetc function is
* One character of push-back is guaranteed. If the ungetc function is
* called too many times without an intervening read or file positioning
* operation on that stream, the operation may fail.
*

SdFat/bufstream.h → SdFat/utility/bufstream.h 查看文件

@@ -1,7 +1,7 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
/* FatLib Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdFat Library
* 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
@@ -14,7 +14,7 @@
* 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
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef bufstream_h
@@ -23,7 +23,8 @@
* \file
* \brief \ref ibufstream and \ref obufstream classes
*/
#include <iostream.h>
#include <string.h>
#include "iostream.h"
//==============================================================================
/**
* \class ibufstream

SdFat/SdStream.cpp → SdFat/utility/fstream.cpp 查看文件

@@ -1,7 +1,7 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
/* FatLib Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdFat Library
* 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
@@ -14,15 +14,13 @@
* 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
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/

#include <SdFat.h>

#include "fstream.h"
//==============================================================================
/// @cond SHOW_PROTECTED
int16_t SdStreamBase::getch() {
int16_t FatStreamBase::getch() {
uint8_t c;
int8_t s = read(&c, 1);
if (s != 1) {
@@ -40,7 +38,7 @@ int16_t SdStreamBase::getch() {
return '\r';
}
//------------------------------------------------------------------------------
void SdStreamBase::open(const char* path, ios::openmode mode) {
void FatStreamBase::open(const char* path, ios::openmode mode) {
uint8_t flags;
switch (mode & (app | in | out | trunc)) {
case app | in:
@@ -74,26 +72,26 @@ uint8_t flags;
goto fail;
}
if (mode & ios::ate) flags |= O_AT_END;
if (!SdBaseFile::open(path, flags)) goto fail;
if (!FatFile::open(path, flags)) goto fail;
setmode(mode);
clear();
return;

fail:
SdBaseFile::close();
FatFile::close();
setstate(failbit);
return;
}
//------------------------------------------------------------------------------
void SdStreamBase::putch(char c) {
void FatStreamBase::putch(char c) {
if (c == '\n' && !(getmode() & ios::binary)) {
write('\r');
}
write(c);
if (writeError) setstate(badbit);
if (getWriteError()) setstate(badbit);
}
//------------------------------------------------------------------------------
void SdStreamBase::putstr(const char* str) {
void FatStreamBase::putstr(const char* str) {
size_t n = 0;
while (1) {
char c = str[n];
@@ -106,14 +104,14 @@ void SdStreamBase::putstr(const char* str) {
}
n++;
}
if (writeError) setstate(badbit);
if (getWriteError()) setstate(badbit);
}
//------------------------------------------------------------------------------
/** Internal do not use
* \param[in] off
* \param[in] way
*/
bool SdStreamBase::seekoff(off_type off, seekdir way) {
bool FatStreamBase::seekoff(off_type off, seekdir way) {
pos_type pos;
switch (way) {
case beg:
@@ -137,15 +135,15 @@ bool SdStreamBase::seekoff(off_type off, seekdir way) {
/** Internal do not use
* \param[in] pos
*/
bool SdStreamBase::seekpos(pos_type pos) {
bool FatStreamBase::seekpos(pos_type pos) {
return seekSet(pos);
}
//------------------------------------------------------------------------------
int SdStreamBase::write(const void* buf, size_t n) {
return SdBaseFile::write(buf, n);
int FatStreamBase::write(const void* buf, size_t n) {
return FatFile::write(buf, n);
}
//------------------------------------------------------------------------------
void SdStreamBase::write(char c) {
void FatStreamBase::write(char c) {
write(&c, 1);
}
/// @endcond

SdFat/SdStream.h → SdFat/utility/fstream.h 查看文件

@@ -1,7 +1,7 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
/* FatLib Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdFat Library
* 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
@@ -14,23 +14,23 @@
* 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
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SdStream_h
#define SdStream_h
#ifndef fstream_h
#define fstream_h
/**
* \file
* \brief \ref fstream, \ref ifstream, and \ref ofstream classes
*/
#include <SdBaseFile.h>
#include <iostream.h>
#include "FatFile.h"
#include "iostream.h"
//==============================================================================
/**
* \class SdStreamBase
* \brief Base class for SD streams
* \class FatStreamBase
* \brief Base class for C++ style streams
*/
class SdStreamBase : protected SdBaseFile, virtual public ios {
class FatStreamBase : protected FatFile, virtual public ios {
protected:
/// @cond SHOW_PROTECTED
int16_t getch();
@@ -56,9 +56,9 @@ class SdStreamBase : protected SdBaseFile, virtual public ios {
//==============================================================================
/**
* \class fstream
* \brief SD file input/output stream.
* \brief file input/output stream.
*/
class fstream : public iostream, SdStreamBase {
class fstream : public iostream, FatStreamBase {
public:
using iostream::peek;
fstream() {}
@@ -78,12 +78,12 @@ class fstream : public iostream, SdStreamBase {
*/
void clear(iostate state = goodbit) {
ios::clear(state);
SdBaseFile::writeError = false;
FatFile::clearWriteError();
}
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() {SdBaseFile::close();}
void close() {FatFile::close();}
/** Open a fstream
* \param[in] path file to open
* \param[in] mode open mode
@@ -107,47 +107,47 @@ class fstream : public iostream, SdStreamBase {
* create text file for update, writing at end of file.
*/
void open(const char* path, openmode mode = in | out) {
SdStreamBase::open(path, mode);
FatStreamBase::open(path, mode);
}
/** \return True if stream is open else false. */
bool is_open () {return SdBaseFile::isOpen();}
bool is_open () {return FatFile::isOpen();}

protected:
/// @cond SHOW_PROTECTED
/** Internal - do not use
* \return
*/
int16_t getch() {return SdStreamBase::getch();}
int16_t getch() {return FatStreamBase::getch();}
/** Internal - do not use
* \param[out] pos
*/
void getpos(FatPos_t* pos) {SdBaseFile::getpos(pos);}
void getpos(FatPos_t* pos) {FatFile::getpos(pos);}
/** Internal - do not use
* \param[in] c
*/
void putch(char c) {SdStreamBase::putch(c);}
void putch(char c) {FatStreamBase::putch(c);}
/** Internal - do not use
* \param[in] str
*/
void putstr(const char *str) {SdStreamBase::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 SdStreamBase::seekoff(off, way);
return FatStreamBase::seekoff(off, way);
}
bool seekpos(pos_type pos) {return SdStreamBase::seekpos(pos);}
void setpos(FatPos_t* pos) {SdBaseFile::setpos(pos);}
bool sync() {return SdStreamBase::sync();}
pos_type tellpos() {return SdStreamBase::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
};
//==============================================================================
/**
* \class ifstream
* \brief SD file input stream.
* \brief file input stream.
*/
class ifstream : public istream, SdStreamBase {
class ifstream : public istream, FatStreamBase {
public:
using istream::peek;
ifstream() {}
@@ -164,9 +164,9 @@ class ifstream : public istream, SdStreamBase {
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() {SdBaseFile::close();}
void close() {FatFile::close();}
/** \return True if stream is open else false. */
bool is_open() {return SdBaseFile::isOpen();}
bool is_open() {return FatFile::isOpen();}
/** Open an ifstream
* \param[in] path file to open
* \param[in] mode open mode
@@ -174,7 +174,7 @@ class ifstream : public istream, SdStreamBase {
* \a mode See fstream::open() for valid modes.
*/
void open(const char* path, openmode mode = in) {
SdStreamBase::open(path, mode | in);
FatStreamBase::open(path, mode | in);
}

protected:
@@ -182,28 +182,28 @@ class ifstream : public istream, SdStreamBase {
/** Internal - do not use
* \return
*/
int16_t getch() {return SdStreamBase::getch();}
int16_t getch() {return FatStreamBase::getch();}
/** Internal - do not use
* \param[out] pos
*/
void getpos(FatPos_t* pos) {SdBaseFile::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 SdStreamBase::seekoff(off, way);
return FatStreamBase::seekoff(off, way);
}
bool seekpos(pos_type pos) {return SdStreamBase::seekpos(pos);}
void setpos(FatPos_t* pos) {SdBaseFile::setpos(pos);}
pos_type tellpos() {return SdStreamBase::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
};
//==============================================================================
/**
* \class ofstream
* \brief SD card output stream.
* \brief file output stream.
*/
class ofstream : public ostream, SdStreamBase {
class ofstream : public ostream, FatStreamBase {
public:
ofstream() {}
/** Constructor with open
@@ -221,12 +221,12 @@ class ofstream : public ostream, SdStreamBase {
*/
void clear(iostate state = goodbit) {
ios::clear(state);
SdBaseFile::writeError = false;
FatFile::clearWriteError();
}
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() {SdBaseFile::close();}
void close() {FatFile::close();}
/** Open an ofstream
* \param[in] path file to open
* \param[in] mode open mode
@@ -234,10 +234,10 @@ class ofstream : public ostream, SdStreamBase {
* \a mode See fstream::open() for valid modes.
*/
void open(const char* path, openmode mode = out) {
SdStreamBase::open(path, mode | out);
FatStreamBase::open(path, mode | out);
}
/** \return True if stream is open else false. */
bool is_open() {return SdBaseFile::isOpen();}
bool is_open() {return FatFile::isOpen();}

protected:
/// @cond SHOW_PROTECTED
@@ -245,19 +245,19 @@ class ofstream : public ostream, SdStreamBase {
* Internal do not use
* \param[in] c
*/
void putch(char c) {SdStreamBase::putch(c);}
void putstr(const char* str) {SdStreamBase::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 SdStreamBase::seekoff(off, way);
return FatStreamBase::seekoff(off, way);
}
bool seekpos(pos_type pos) {return SdStreamBase::seekpos(pos);}
bool seekpos(pos_type pos) {return FatStreamBase::seekpos(pos);}
/**
* Internal do not use
* \param[in] b
*/
bool sync() {return SdStreamBase::sync();}
pos_type tellpos() {return SdStreamBase::curPosition();}
bool sync() {return FatStreamBase::sync();}
pos_type tellpos() {return FatStreamBase::curPosition();}
/// @endcond
};
//------------------------------------------------------------------------------
#endif // SdStream_h
#endif // fstream_h

SdFat/ios.h → SdFat/utility/ios.h 查看文件

@@ -1,7 +1,7 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
/* FatLib Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdFat Library
* 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
@@ -14,12 +14,12 @@
* 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
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef ios_h
#define ios_h
#include <SdBaseFile.h>
#include "FatFile.h"
/**
* \file
* \brief \ref ios_base and \ref ios classes

SdFat/iostream.h → SdFat/utility/iostream.h 查看文件

@@ -1,7 +1,7 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
/* FatLib Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdFat Library
* 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
@@ -14,7 +14,7 @@
* 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
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef iostream_h
@@ -23,8 +23,8 @@
* \file
* \brief \ref iostream class
*/
#include <istream.h>
#include <ostream.h>
#include "istream.h"
#include "ostream.h"
/** Skip white space
* \param[in] is the Stream
* \return The stream

SdFat/istream.cpp → SdFat/utility/istream.cpp 查看文件

@@ -1,7 +1,7 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
/* FatLib Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdFat Library
* 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
@@ -14,18 +14,13 @@
* 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
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include <float.h>
#include <istream.h>
#include "istream.h"
//------------------------------------------------------------------------------
/**
* 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 istream::get() {
int c;
m_gcount = 0;
@@ -38,33 +33,12 @@ int istream::get() {
return c;
}
//------------------------------------------------------------------------------
/**
* Extract a character if one is available.
*
* \param[out] c location to receive the extracted character.
*
* \return always returns *this. A failure is indicated by the stream state.
*/
istream& istream::get(char& c) {
int tmp = get();
if (tmp >= 0) c = tmp;
return *this;
}
//------------------------------------------------------------------------------
/**
* Extract characters.
*
* \param[out] str Location to receive extracted characters.
* \param[in] n Size of str.
* \param[in] delim Delimiter
*
* Characters are extracted until extraction fails, n is less than 1,
* n-1 characters are extracted, or the next character equals
* \a delim (delim is not extracted). If no characters are extracted
* 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& istream::get(char *str, streamsize n, char delim) {
int c;
FatPos_t pos;
@@ -210,22 +184,7 @@ bool istream::getDouble(double* value) {
return false;
}
//------------------------------------------------------------------------------
/**
* Extract characters
*
* \param[out] str Location to receive extracted characters.
* \param[in] n Size of str.
* \param[in] delim Delimiter
*
* Characters are extracted until extraction fails,
* the next character equals \a delim (delim is extracted), or n-1
* characters are extracted.
*
* The failbit is set if no characters are extracted or n-1 characters
* are extracted. If end-of-file occurs the eofbit is set.
*
* \return always returns *this. A failure is indicated by the stream state.
*/

istream& istream::getline(char *str, streamsize n, char delim) {
FatPos_t pos;
int c;
@@ -315,9 +274,6 @@ bool istream::getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num) {
return false;
}
//------------------------------------------------------------------------------
/**
*
*/
void istream::getStr(char *str) {
FatPos_t pos;
uint16_t i = 0;
@@ -343,21 +299,6 @@ void istream::getStr(char *str) {
width(0);
}
//------------------------------------------------------------------------------
/**
* Extract characters and discard them.
*
* \param[in] n maximum number of characters to ignore.
* \param[in] delim Delimiter.
*
* Characters are extracted until extraction fails, \a n characters
* are extracted, or the next input character equals \a delim
* (the delimiter is extracted). If end-of-file occurs the eofbit is set.
*
* Failures are indicated by the state of the stream.
*
* \return *this
*
*/
istream& istream::ignore(streamsize n, int delim) {
int c;
m_gcount = 0;
@@ -372,12 +313,6 @@ istream& istream::ignore(streamsize n, int delim) {
return *this;
}
//------------------------------------------------------------------------------
/**
* Return the next available character without consuming it.
*
* \return The character if the stream state is good else -1;
*
*/
int istream::peek() {
int16_t c;
FatPos_t pos;

SdFat/istream.h → SdFat/utility/istream.h 查看文件

@@ -1,7 +1,7 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
/* FatLib Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdFat Library
* 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
@@ -14,7 +14,7 @@
* 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
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef istream_h
@@ -23,7 +23,7 @@
* \file
* \brief \ref istream class
*/
#include <ios.h>
#include "ios.h"

/**
* \class istream
@@ -208,11 +208,75 @@ class istream : public virtual ios {
* input function.
*/
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.
*
* \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.
*
* \param[out] str Location to receive extracted characters.
* \param[in] n Size of str.
* \param[in] delim Delimiter
*
* Characters are extracted until extraction fails, n is less than 1,
* n-1 characters are extracted, or the next character equals
* \a delim (delim is not extracted). If no characters are extracted
* 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');
istream& getline(char *str, streamsize count, char delim = '\n');
/**
* Extract characters
*
* \param[out] str Location to receive extracted characters.
* \param[in] n Size of str.
* \param[in] delim Delimiter
*
* Characters are extracted until extraction fails,
* the next character equals \a delim (delim is extracted), or n-1
* characters are extracted.
*
* The failbit is set if no characters are extracted or n-1 characters
* are extracted. If end-of-file occurs the eofbit is set.
*
* \return always returns *this. A failure is indicated by the stream state.
*/
istream& getline(char *str, streamsize n, char delim = '\n');
/**
* Extract characters and discard them.
*
* \param[in] n maximum number of characters to ignore.
* \param[in] delim Delimiter.
*
* Characters are extracted until extraction fails, \a n characters
* are extracted, or the next input character equals \a delim
* (the delimiter is extracted). If end-of-file occurs the eofbit is set.
*
* Failures are indicated by the state of the stream.
*
* \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);

SdFat/ostream.cpp → SdFat/utility/ostream.cpp 查看文件

@@ -1,7 +1,7 @@
/* Arduino SdFat Library
* Copyright (C) 2012 by William Greiman
/* FatLib Library
* Copyright (C) 2013 by William Greiman
*
* This file is part of the Arduino SdFat Library
* 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
@@ -14,10 +14,11 @@
* 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
* along with the FatLib Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <ostream.h>
#include <string.h>
#include "ostream.h"
#ifndef PSTR
#define PSTR(x) x
#endif
@@ -84,7 +85,7 @@ void ostream::putDouble(double n) {
putPgm(PSTR("BIG FLT"));
return;
}
// round up and separate in and fraction parts
// round up and separate int and fraction parts
for (uint8_t i = 0; i < nd; ++i) round *= 0.1;
n += round;
uint32_t intPart = n;

SdFat/ostream.h → SdFat/utility/ostream.h 查看文件


部分文件因文件數量過多而無法顯示

Loading…
取消
儲存