updated to sdfatlib2010902
This commit is contained in:
		| @@ -4,8 +4,8 @@ | ||||
|  | ||||
|  | ||||
| // This determines the communication speed of the printer | ||||
| #define BAUDRATE 250000 | ||||
| //#define BAUDRATE 115200 | ||||
| //#define BAUDRATE 250000 | ||||
| #define BAUDRATE 115200 | ||||
| //#define BAUDRATE 230400 | ||||
|  | ||||
|  | ||||
| @@ -277,7 +277,7 @@ const bool ENDSTOPS_INVERTING = true; // set to true to invert the logic of the | ||||
|  | ||||
| #define ULTIPANEL | ||||
| #ifdef ULTIPANEL | ||||
| //  #define NEWPANEL  //enable this if you have a click-encoder panel | ||||
|   #define NEWPANEL  //enable this if you have a click-encoder panel | ||||
|   #define SDSUPPORT | ||||
|   #define ULTRA_LCD | ||||
|   #define LCD_WIDTH 20 | ||||
|   | ||||
| @@ -26,6 +26,7 @@ | ||||
|  */ | ||||
|  | ||||
| #include <EEPROM.h> | ||||
|  | ||||
| #include "EEPROMwrite.h" | ||||
| #include "fastio.h" | ||||
| #include "Configuration.h" | ||||
| @@ -391,9 +392,15 @@ inline void get_command() | ||||
|   while( !card.eof()  && buflen < BUFSIZE) { | ||||
|     int16_t n=card.get(); | ||||
|     serial_char = (char)n; | ||||
| //     Serial.print((char)serial_char); | ||||
| //     Serial.print(" "); | ||||
| //     Serial.println((int)serial_count); | ||||
|     if(serial_char == '\n' || serial_char == '\r' || serial_char == ':' || serial_count >= (MAX_CMD_SIZE - 1)||n==-1)  | ||||
|     { | ||||
|       | ||||
| //       if(serial_char == '\n' || serial_char == '\r' ) | ||||
| //         Serial.println("newline or :"); | ||||
| //       if(serial_count >= (MAX_CMD_SIZE - 1)) | ||||
| //         Serial.println("too long line"); | ||||
|       if(card.eof()){ | ||||
|         card.sdprinting = false; | ||||
|         SERIAL_PROTOCOLLNPGM("Done printing file"); | ||||
| @@ -409,15 +416,20 @@ inline void get_command() | ||||
|         LCD_MESSAGE(time); | ||||
|         card.checkautostart(true); | ||||
|       } | ||||
|       if(!serial_count)  | ||||
| 	return; //if empty line | ||||
|       if(serial_char=='\n') | ||||
|          comment_mode = false; //for new command | ||||
|       if(!serial_count) | ||||
|       { | ||||
| // 	Serial.println("empty line"); | ||||
|         return; //if empty line | ||||
|       } | ||||
|       cmdbuffer[bufindw][serial_count] = 0; //terminate string | ||||
|       if(!comment_mode){ | ||||
|         fromsd[bufindw] = true; | ||||
|         buflen += 1; | ||||
|         bufindw = (bufindw + 1)%BUFSIZE; | ||||
|       } | ||||
|       comment_mode = false; //for new command | ||||
|       | ||||
|       serial_count = 0; //clear buffer | ||||
|     } | ||||
|     else | ||||
|   | ||||
| @@ -17,28 +17,77 @@ | ||||
|  * along with the Arduino Sd2Card Library.  If not, see | ||||
|  * <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| #if ARDUINO < 100 | ||||
| #include <WProgram.h> | ||||
| #else  // ARDUINO | ||||
| #include <Arduino.h> | ||||
| #endif  // ARDUINO | ||||
| #include "Sd2Card.h" | ||||
| //------------------------------------------------------------------------------ | ||||
| #ifndef SOFTWARE_SPI | ||||
| // functions for hardware SPI | ||||
| /** Send a byte to the card */ | ||||
| //------------------------------------------------------------------------------ | ||||
| // make sure SPCR rate is in expected bits | ||||
| #if (SPR0 != 0 || SPR1 != 1) | ||||
| #error unexpected SPCR bits | ||||
| #endif | ||||
| /** | ||||
|  * Initialize hardware SPI | ||||
|  * Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6] | ||||
|  */ | ||||
| static void spiInit(uint8_t spiRate) { | ||||
|   // See avr processor documentation | ||||
|   SPCR = (1 << SPE) | (1 << MSTR) | (spiRate >> 1); | ||||
|   SPSR = spiRate & 1 || spiRate == 6 ? 0 : 1 << SPI2X; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** SPI receive a byte */ | ||||
| static uint8_t spiRec() { | ||||
|   SPDR = 0XFF; | ||||
|   while (!(SPSR & (1 << SPIF))); | ||||
|   return SPDR; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** SPI read data - only one call so force inline */ | ||||
| static inline __attribute__((always_inline)) | ||||
|   void spiRead(uint8_t* buf, uint16_t nbyte) { | ||||
|   if (nbyte-- == 0) return; | ||||
|   SPDR = 0XFF; | ||||
|   for (uint16_t i = 0; i < nbyte; i++) { | ||||
|     while (!(SPSR & (1 << SPIF))); | ||||
|     buf[i] = SPDR; | ||||
|     SPDR = 0XFF; | ||||
|   } | ||||
|   while (!(SPSR & (1 << SPIF))); | ||||
|   buf[nbyte] = SPDR; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** SPI send a byte */ | ||||
| static void spiSend(uint8_t b) { | ||||
|   SPDR = b; | ||||
|   while (!(SPSR & (1 << SPIF))); | ||||
| } | ||||
| /** Receive a byte from the card */ | ||||
| static  uint8_t spiRec(void) { | ||||
|   spiSend(0XFF); | ||||
|   return SPDR; | ||||
| //------------------------------------------------------------------------------ | ||||
| /** SPI send block - only one call so force inline */ | ||||
| static inline __attribute__((always_inline)) | ||||
|   void spiSendBlock(uint8_t token, const uint8_t* buf) { | ||||
|   SPDR = token; | ||||
|   for (uint16_t i = 0; i < 512; i += 2) { | ||||
|     while (!(SPSR & (1 << SPIF))); | ||||
|     SPDR = buf[i]; | ||||
|     while (!(SPSR & (1 << SPIF))); | ||||
|     SPDR = buf[i + 1]; | ||||
|   } | ||||
|   while (!(SPSR & (1 << SPIF))); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| #else  // SOFTWARE_SPI | ||||
| //------------------------------------------------------------------------------ | ||||
| /** nop to tune soft SPI timing */ | ||||
| #define nop asm volatile ("nop\n\t") | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Soft SPI receive */ | ||||
| uint8_t spiRec(void) { | ||||
| /** Soft SPI receive byte */ | ||||
| static uint8_t spiRec() { | ||||
|   uint8_t data = 0; | ||||
|   // no interrupts during byte receive - about 8 us | ||||
|   cli(); | ||||
| @@ -63,8 +112,15 @@ uint8_t spiRec(void) { | ||||
|   return data; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Soft SPI send */ | ||||
| void spiSend(uint8_t data) { | ||||
| /** Soft SPI read data */ | ||||
| static void spiRead(uint8_t* buf, uint16_t nbyte) { | ||||
|   for (uint16_t i = 0; i < nbyte; i++) { | ||||
|     buf[i] = spiRec(); | ||||
|   } | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Soft SPI send byte */ | ||||
| static void spiSend(uint8_t data) { | ||||
|   // no interrupts during byte send - about 8 us | ||||
|   cli(); | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
| @@ -86,13 +142,18 @@ void spiSend(uint8_t data) { | ||||
|   // enable interrupts | ||||
|   sei(); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Soft SPI send block */ | ||||
|   void spiSendBlock(uint8_t token, const uint8_t* buf) { | ||||
|   spiSend(token); | ||||
|   for (uint16_t i = 0; i < 512; i++) { | ||||
|     spiSend(buf[i]); | ||||
|   } | ||||
| } | ||||
| #endif  // SOFTWARE_SPI | ||||
| //------------------------------------------------------------------------------ | ||||
| // send command and return error code.  Return zero for OK | ||||
| uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { | ||||
|   // end read if in partialBlockRead mode | ||||
|   readEnd(); | ||||
|  | ||||
|   // select card | ||||
|   chipSelectLow(); | ||||
|  | ||||
| @@ -111,6 +172,9 @@ uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { | ||||
|   if (cmd == CMD8) crc = 0X87;  // correct crc for CMD8 with arg 0X1AA | ||||
|   spiSend(crc); | ||||
|  | ||||
|   // skip stuff byte for stop read | ||||
|   if (cmd == CMD12) spiRec(); | ||||
|  | ||||
|   // wait for response | ||||
|   for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++); | ||||
|   return status_; | ||||
| @@ -122,7 +186,7 @@ uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { | ||||
|  * \return The number of 512 byte data blocks in the card | ||||
|  *         or zero if an error occurs. | ||||
|  */ | ||||
| uint32_t Sd2Card::cardSize(void) { | ||||
| uint32_t Sd2Card::cardSize() { | ||||
|   csd_t csd; | ||||
|   if (!readCSD(&csd)) return 0; | ||||
|   if (csd.v1.csd_ver == 0) { | ||||
| @@ -142,11 +206,14 @@ uint32_t Sd2Card::cardSize(void) { | ||||
|   } | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| void Sd2Card::chipSelectHigh(void) { | ||||
| void Sd2Card::chipSelectHigh() { | ||||
|   digitalWrite(chipSelectPin_, HIGH); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| void Sd2Card::chipSelectLow(void) { | ||||
| void Sd2Card::chipSelectLow() { | ||||
| #ifndef SOFTWARE_SPI | ||||
|   spiInit(spiRate_); | ||||
| #endif  // SOFTWARE_SPI | ||||
|   digitalWrite(chipSelectPin_, LOW); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| @@ -163,10 +230,18 @@ void Sd2Card::chipSelectLow(void) { | ||||
|  * \return The value one, true, is returned for success and | ||||
|  * the value zero, false, is returned for failure. | ||||
|  */ | ||||
| uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { | ||||
|   if (!eraseSingleBlockEnable()) { | ||||
|     error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); | ||||
|     goto fail; | ||||
| bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { | ||||
|   csd_t csd; | ||||
|   if (!readCSD(&csd)) goto fail; | ||||
|   // check for single block erase | ||||
|   if (!csd.v1.erase_blk_en) { | ||||
|     // erase size mask | ||||
|     uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low; | ||||
|     if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { | ||||
|       // error card can't erase specified area | ||||
|       error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); | ||||
|       goto fail; | ||||
|     } | ||||
|   } | ||||
|   if (type_ != SD_CARD_TYPE_SDHC) { | ||||
|     firstBlock <<= 9; | ||||
| @@ -195,9 +270,9 @@ uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { | ||||
|  * \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. | ||||
|  */ | ||||
| uint8_t Sd2Card::eraseSingleBlockEnable(void) { | ||||
| bool Sd2Card::eraseSingleBlockEnable() { | ||||
|   csd_t csd; | ||||
|   return readCSD(&csd) ? csd.v1.erase_blk_en : 0; | ||||
|   return readCSD(&csd) ? csd.v1.erase_blk_en : false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
| @@ -210,8 +285,8 @@ uint8_t Sd2Card::eraseSingleBlockEnable(void) { | ||||
|  * the value zero, false, is returned for failure.  The reason for failure | ||||
|  * can be determined by calling errorCode() and errorData(). | ||||
|  */ | ||||
| uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { | ||||
|   errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; | ||||
| bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { | ||||
|   errorCode_ = type_ = 0; | ||||
|   chipSelectPin_ = chipSelectPin; | ||||
|   // 16-bit init start time allows over a minute | ||||
|   uint16_t t0 = (uint16_t)millis(); | ||||
| @@ -227,17 +302,18 @@ uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { | ||||
| #ifndef SOFTWARE_SPI | ||||
|   // SS must be in output mode even it is not chip select | ||||
|   pinMode(SS_PIN, OUTPUT); | ||||
|   // Enable SPI, Master, clock rate f_osc/128 | ||||
|   SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); | ||||
|   // clear double speed | ||||
|   SPSR &= ~(1 << SPI2X); | ||||
|   // set SS high - may be chip select for another SPI device | ||||
| #if SET_SPI_SS_HIGH | ||||
|   digitalWrite(SS_PIN, HIGH); | ||||
| #endif  // SET_SPI_SS_HIGH | ||||
|   // set SCK rate for initialization commands | ||||
|   spiRate_ = SPI_SD_INIT_RATE; | ||||
|   spiInit(spiRate_); | ||||
| #endif  // SOFTWARE_SPI | ||||
|  | ||||
|   // must supply min of 74 clock cycles with CS high. | ||||
|   for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); | ||||
|  | ||||
|   chipSelectLow(); | ||||
|  | ||||
|   // command to go idle in SPI mode | ||||
|   while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { | ||||
|     if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { | ||||
| @@ -291,105 +367,60 @@ uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Enable or disable partial block reads. | ||||
|  * Read a 512 byte block from an SD card. | ||||
|  * | ||||
|  * Enabling partial block reads improves performance by allowing a block | ||||
|  * to be read over the SPI bus as several sub-blocks.  Errors may occur | ||||
|  * if the time between reads is too long since the SD card may timeout. | ||||
|  * The SPI SS line will be held low until the entire block is read or | ||||
|  * readEnd() is called. | ||||
|  * | ||||
|  * Use this for applications like the Adafruit Wave Shield. | ||||
|  * | ||||
|  * \param[in] value The value TRUE (non-zero) or FALSE (zero).) | ||||
|  */ | ||||
| void Sd2Card::partialBlockRead(uint8_t value) { | ||||
|   readEnd(); | ||||
|   partialBlockRead_ = value; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Read a 512 byte block from an SD card device. | ||||
|  * | ||||
|  * \param[in] block Logical block to be read. | ||||
|  * \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. | ||||
|  */ | ||||
| uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst) { | ||||
|   return readData(block, 0, 512, dst); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Read part of a 512 byte block from an SD card. | ||||
|  * | ||||
|  * \param[in] block Logical block to be read. | ||||
|  * \param[in] offset Number of bytes to skip at start of block | ||||
|  * \param[out] dst Pointer to the location that will receive the data. | ||||
|  * \param[in] count Number of bytes to read | ||||
|  * \return The value one, true, is returned for success and | ||||
|  * the value zero, false, is returned for failure. | ||||
|  */ | ||||
| uint8_t Sd2Card::readData(uint32_t block, | ||||
|         uint16_t offset, uint16_t count, uint8_t* dst) { | ||||
|   uint16_t n; | ||||
|   if (count == 0) return true; | ||||
|   if ((count + offset) > 512) { | ||||
| bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { | ||||
|   // use address if not SDHC card | ||||
|   if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; | ||||
|   if (cardCommand(CMD17, blockNumber)) { | ||||
|     error(SD_CARD_ERROR_CMD17); | ||||
|     goto fail; | ||||
|   } | ||||
|   if (!inBlock_ || block != block_ || offset < offset_) { | ||||
|     block_ = block; | ||||
|     // use address if not SDHC card | ||||
|     if (type()!= SD_CARD_TYPE_SDHC) block <<= 9; | ||||
|     if (cardCommand(CMD17, block)) { | ||||
|       error(SD_CARD_ERROR_CMD17); | ||||
|   return readData(dst, 512); | ||||
|  | ||||
|  fail: | ||||
|   chipSelectHigh(); | ||||
|   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) { | ||||
|   chipSelectLow(); | ||||
|   return readData(dst, 512); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| bool Sd2Card::readData(uint8_t* dst, uint16_t count) { | ||||
|   // wait for start block token | ||||
|   uint16_t t0 = millis(); | ||||
|   while ((status_ = spiRec()) == 0XFF) { | ||||
|     if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { | ||||
|       error(SD_CARD_ERROR_READ_TIMEOUT); | ||||
|       goto fail; | ||||
|     } | ||||
|     if (!waitStartBlock()) { | ||||
|       goto fail; | ||||
|     } | ||||
|     offset_ = 0; | ||||
|     inBlock_ = 1; | ||||
|   } | ||||
|  | ||||
| #ifdef OPTIMIZE_HARDWARE_SPI | ||||
|   // start first spi transfer | ||||
|   SPDR = 0XFF; | ||||
|  | ||||
|   // skip data before offset | ||||
|   for (;offset_ < offset; offset_++) { | ||||
|     while (!(SPSR & (1 << SPIF))); | ||||
|     SPDR = 0XFF; | ||||
|   if (status_ != DATA_START_BLOCK) { | ||||
|     error(SD_CARD_ERROR_READ); | ||||
|     goto fail; | ||||
|   } | ||||
|   // transfer data | ||||
|   n = count - 1; | ||||
|   for (uint16_t i = 0; i < n; i++) { | ||||
|     while (!(SPSR & (1 << SPIF))); | ||||
|     dst[i] = SPDR; | ||||
|     SPDR = 0XFF; | ||||
|   } | ||||
|   // wait for last byte | ||||
|   while (!(SPSR & (1 << SPIF))); | ||||
|   dst[n] = SPDR; | ||||
|   spiRead(dst, count); | ||||
|  | ||||
| #else  // OPTIMIZE_HARDWARE_SPI | ||||
|  | ||||
|   // skip data before offset | ||||
|   for (;offset_ < offset; offset_++) { | ||||
|     spiRec(); | ||||
|   } | ||||
|   // transfer data | ||||
|   for (uint16_t i = 0; i < count; i++) { | ||||
|     dst[i] = spiRec(); | ||||
|   } | ||||
| #endif  // OPTIMIZE_HARDWARE_SPI | ||||
|  | ||||
|   offset_ += count; | ||||
|   if (!partialBlockRead_ || offset_ >= 512) { | ||||
|     // read rest of data, checksum and set chip select high | ||||
|     readEnd(); | ||||
|   } | ||||
|   // discard CRC | ||||
|   spiRec(); | ||||
|   spiRec(); | ||||
|   chipSelectHigh(); | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
| @@ -397,39 +428,55 @@ uint8_t Sd2Card::readData(uint32_t block, | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Skip remaining data in a block when in partial block read mode. */ | ||||
| void Sd2Card::readEnd(void) { | ||||
|   if (inBlock_) { | ||||
|       // skip data and crc | ||||
| #ifdef OPTIMIZE_HARDWARE_SPI | ||||
|     // optimize skip for hardware | ||||
|     SPDR = 0XFF; | ||||
|     while (offset_++ < 513) { | ||||
|       while (!(SPSR & (1 << SPIF))); | ||||
|       SPDR = 0XFF; | ||||
|     } | ||||
|     // wait for last crc byte | ||||
|     while (!(SPSR & (1 << SPIF))); | ||||
| #else  // OPTIMIZE_HARDWARE_SPI | ||||
|     while (offset_++ < 514) spiRec(); | ||||
| #endif  // OPTIMIZE_HARDWARE_SPI | ||||
|     chipSelectHigh(); | ||||
|     inBlock_ = 0; | ||||
|   } | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** read CID or CSR register */ | ||||
| uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) { | ||||
| bool Sd2Card::readRegister(uint8_t cmd, void* buf) { | ||||
|   uint8_t* dst = reinterpret_cast<uint8_t*>(buf); | ||||
|   if (cardCommand(cmd, 0)) { | ||||
|     error(SD_CARD_ERROR_READ_REG); | ||||
|     goto fail; | ||||
|   } | ||||
|   if (!waitStartBlock()) goto fail; | ||||
|   // transfer data | ||||
|   for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec(); | ||||
|   spiRec();  // get first crc byte | ||||
|   spiRec();  // get second crc byte | ||||
|   return readData(dst, 16); | ||||
|  | ||||
|  fail: | ||||
|   chipSelectHigh(); | ||||
|   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) { | ||||
|   if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; | ||||
|   if (cardCommand(CMD18, blockNumber)) { | ||||
|     error(SD_CARD_ERROR_CMD18); | ||||
|     goto fail; | ||||
|   } | ||||
|   chipSelectHigh(); | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   chipSelectHigh(); | ||||
|   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() { | ||||
|   chipSelectLow(); | ||||
|   if (cardCommand(CMD12, 0)) { | ||||
|     error(SD_CARD_ERROR_CMD12); | ||||
|     goto fail; | ||||
|   } | ||||
|   chipSelectHigh(); | ||||
|   return true; | ||||
|  | ||||
| @@ -450,50 +497,24 @@ uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) { | ||||
|  * \return The value one, true, is returned for success and the value zero, | ||||
|  * false, is returned for an invalid value of \a sckRateID. | ||||
|  */ | ||||
| uint8_t Sd2Card::setSckRate(uint8_t sckRateID) { | ||||
| bool Sd2Card::setSckRate(uint8_t sckRateID) { | ||||
|   if (sckRateID > 6) { | ||||
|     error(SD_CARD_ERROR_SCK_RATE); | ||||
|     return false; | ||||
|   } | ||||
|   // see avr processor datasheet for SPI register bit definitions | ||||
|   if ((sckRateID & 1) || sckRateID == 6) { | ||||
|     SPSR &= ~(1 << SPI2X); | ||||
|   } else { | ||||
|     SPSR |= (1 << SPI2X); | ||||
|   } | ||||
|   SPCR &= ~((1 <<SPR1) | (1 << SPR0)); | ||||
|   SPCR |= (sckRateID & 4 ? (1 << SPR1) : 0) | ||||
|     | (sckRateID & 2 ? (1 << SPR0) : 0); | ||||
|   spiRate_ = sckRateID; | ||||
|   return true; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| // wait for card to go not busy | ||||
| uint8_t Sd2Card::waitNotBusy(uint16_t timeoutMillis) { | ||||
| bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) { | ||||
|   uint16_t t0 = millis(); | ||||
|   do { | ||||
|     if (spiRec() == 0XFF) return true; | ||||
|   } | ||||
|   while (((uint16_t)millis() - t0) < timeoutMillis); | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Wait for start block token */ | ||||
| uint8_t Sd2Card::waitStartBlock(void) { | ||||
|   uint16_t t0 = millis(); | ||||
|   while ((status_ = spiRec()) == 0XFF) { | ||||
|     if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { | ||||
|       error(SD_CARD_ERROR_READ_TIMEOUT); | ||||
|       goto fail; | ||||
|     } | ||||
|   } | ||||
|   if (status_ != DATA_START_BLOCK) { | ||||
|     error(SD_CARD_ERROR_READ); | ||||
|     goto fail; | ||||
|   while (spiRec() != 0XFF) { | ||||
|     if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail; | ||||
|   } | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   chipSelectHigh(); | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| @@ -505,15 +526,7 @@ uint8_t Sd2Card::waitStartBlock(void) { | ||||
|  * \return The value one, true, is returned for success and | ||||
|  * the value zero, false, is returned for failure. | ||||
|  */ | ||||
| uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { | ||||
| #if SD_PROTECT_BLOCK_ZERO | ||||
|   // don't allow write to first block | ||||
|   if (blockNumber == 0) { | ||||
|     error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); | ||||
|     goto fail; | ||||
|   } | ||||
| #endif  // SD_PROTECT_BLOCK_ZERO | ||||
|  | ||||
| bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { | ||||
|   // use address if not SDHC card | ||||
|   if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; | ||||
|   if (cardCommand(CMD24, blockNumber)) { | ||||
| @@ -540,51 +553,42 @@ uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Write one data block in a multiple block write sequence */ | ||||
| uint8_t Sd2Card::writeData(const uint8_t* src) { | ||||
| /** 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) { | ||||
|   chipSelectLow(); | ||||
|   // wait for previous write to finish | ||||
|   if (!waitNotBusy(SD_WRITE_TIMEOUT)) { | ||||
|     error(SD_CARD_ERROR_WRITE_MULTIPLE); | ||||
|     chipSelectHigh(); | ||||
|     return false; | ||||
|   } | ||||
|   return writeData(WRITE_MULTIPLE_TOKEN, src); | ||||
|   if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; | ||||
|   if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail; | ||||
|   chipSelectHigh(); | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   error(SD_CARD_ERROR_WRITE_MULTIPLE); | ||||
|   chipSelectHigh(); | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| // send one block of data for write block or write multiple blocks | ||||
| uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { | ||||
| #ifdef OPTIMIZE_HARDWARE_SPI | ||||
| bool Sd2Card::writeData(uint8_t token, const uint8_t* src) { | ||||
|   spiSendBlock(token, src); | ||||
|  | ||||
|   // send data - optimized loop | ||||
|   SPDR = token; | ||||
|  | ||||
|   // send two byte per iteration | ||||
|   for (uint16_t i = 0; i < 512; i += 2) { | ||||
|     while (!(SPSR & (1 << SPIF))); | ||||
|     SPDR = src[i]; | ||||
|     while (!(SPSR & (1 << SPIF))); | ||||
|     SPDR = src[i+1]; | ||||
|   } | ||||
|  | ||||
|   // wait for last data byte | ||||
|   while (!(SPSR & (1 << SPIF))); | ||||
|  | ||||
| #else  // OPTIMIZE_HARDWARE_SPI | ||||
|   spiSend(token); | ||||
|   for (uint16_t i = 0; i < 512; i++) { | ||||
|     spiSend(src[i]); | ||||
|   } | ||||
| #endif  // OPTIMIZE_HARDWARE_SPI | ||||
|   spiSend(0xff);  // dummy crc | ||||
|   spiSend(0xff);  // dummy crc | ||||
|  | ||||
|   status_ = spiRec(); | ||||
|   if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { | ||||
|     error(SD_CARD_ERROR_WRITE); | ||||
|     chipSelectHigh(); | ||||
|     return false; | ||||
|     goto fail; | ||||
|   } | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   chipSelectHigh(); | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Start a write multiple blocks sequence. | ||||
| @@ -598,14 +602,7 @@ uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { | ||||
|  * \return The value one, true, is returned for success and | ||||
|  * the value zero, false, is returned for failure. | ||||
|  */ | ||||
| uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { | ||||
| #if SD_PROTECT_BLOCK_ZERO | ||||
|   // don't allow write to first block | ||||
|   if (blockNumber == 0) { | ||||
|     error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); | ||||
|     goto fail; | ||||
|   } | ||||
| #endif  // SD_PROTECT_BLOCK_ZERO | ||||
| bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { | ||||
|   // send pre-erase count | ||||
|   if (cardAcmd(ACMD23, eraseCount)) { | ||||
|     error(SD_CARD_ERROR_ACMD23); | ||||
| @@ -617,6 +614,7 @@ uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { | ||||
|     error(SD_CARD_ERROR_CMD25); | ||||
|     goto fail; | ||||
|   } | ||||
|   chipSelectHigh(); | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
| @@ -629,7 +627,8 @@ uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { | ||||
| * \return The value one, true, is returned for success and | ||||
|  * the value zero, false, is returned for failure. | ||||
|  */ | ||||
| uint8_t Sd2Card::writeStop(void) { | ||||
| bool Sd2Card::writeStop() { | ||||
|   chipSelectLow(); | ||||
|   if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; | ||||
|   spiSend(STOP_TRAN_TOKEN); | ||||
|   if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; | ||||
|   | ||||
							
								
								
									
										253
									
								
								Marlin/Sd2Card.h
									
									
									
									
									
								
							
							
						
						
									
										253
									
								
								Marlin/Sd2Card.h
									
									
									
									
									
								
							| @@ -21,67 +21,24 @@ | ||||
| #define Sd2Card_h | ||||
| /** | ||||
|  * \file | ||||
|  * Sd2Card class | ||||
|  * \brief Sd2Card class for V2 SD/SDHC cards | ||||
|  */ | ||||
| #include "SdFatConfig.h" | ||||
| #include "Sd2PinMap.h" | ||||
| #include "SdInfo.h" | ||||
| //------------------------------------------------------------------------------ | ||||
| // SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6 | ||||
| /** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */ | ||||
| uint8_t const SPI_FULL_SPEED = 0; | ||||
| /** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */ | ||||
| uint8_t const SPI_HALF_SPEED = 1; | ||||
| /** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */ | ||||
| /** Set SCK rate to F_CPU/8. See Sd2Card::setSckRate(). */ | ||||
| uint8_t const SPI_QUARTER_SPEED = 2; | ||||
| /** | ||||
|  * Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos. | ||||
|  * Pins used are SS 10, MOSI 11, MISO 12, and SCK 13. | ||||
|  * | ||||
|  * MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used | ||||
|  * on Mega Arduinos.  Software SPI works well with GPS Shield V1.1 | ||||
|  * but many SD cards will fail with GPS Shield V1.0. | ||||
|  */ | ||||
| #define MEGA_SOFT_SPI 0 | ||||
| /** Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). */ | ||||
| uint8_t const SPI_EIGHTH_SPEED = 3; | ||||
| /** Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). */ | ||||
| uint8_t const SPI_SIXTEENTH_SPEED = 4; | ||||
| //------------------------------------------------------------------------------ | ||||
| #if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)) | ||||
| #define SOFTWARE_SPI | ||||
| #endif  // MEGA_SOFT_SPI | ||||
| //------------------------------------------------------------------------------ | ||||
| // SPI pin definitions | ||||
| // | ||||
| #ifndef SOFTWARE_SPI | ||||
| // hardware pin defs | ||||
| /** | ||||
|  * SD Chip Select pin | ||||
|  * | ||||
|  * Warning if this pin is redefined the hardware SS will pin will be enabled | ||||
|  * as an output by init().  An avr processor will not function as an SPI | ||||
|  * master unless SS is set to output mode. | ||||
|  */ | ||||
| /** The default chip select pin for the SD card is SS. */ | ||||
| uint8_t const  SD_CHIP_SELECT_PIN = SS_PIN; | ||||
| // The following three pins must not be redefined for hardware SPI. | ||||
| /** SPI Master Out Slave In pin */ | ||||
| uint8_t const  SPI_MOSI_PIN = MOSI_PIN; | ||||
| /** SPI Master In Slave Out pin */ | ||||
| uint8_t const  SPI_MISO_PIN = MISO_PIN; | ||||
| /** SPI Clock pin */ | ||||
| uint8_t const  SPI_SCK_PIN = SCK_PIN; | ||||
| /** optimize loops for hardware SPI */ | ||||
| #define OPTIMIZE_HARDWARE_SPI | ||||
|  | ||||
| #else  // SOFTWARE_SPI | ||||
| // define software SPI pins so Mega can use unmodified GPS Shield | ||||
| /** SPI chip select pin */ | ||||
| uint8_t const SD_CHIP_SELECT_PIN = 10; | ||||
| /** SPI Master Out Slave In pin */ | ||||
| uint8_t const SPI_MOSI_PIN = 11; | ||||
| /** SPI Master In Slave Out pin */ | ||||
| uint8_t const SPI_MISO_PIN = 12; | ||||
| /** SPI Clock pin */ | ||||
| uint8_t const SPI_SCK_PIN = 13; | ||||
| #endif  // SOFTWARE_SPI | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Protect block zero from write if nonzero */ | ||||
| #define SD_PROTECT_BLOCK_ZERO 1 | ||||
| /** init timeout ms */ | ||||
| uint16_t const SD_INIT_TIMEOUT = 2000; | ||||
| /** erase timeout ms */ | ||||
| @@ -92,58 +49,99 @@ uint16_t const SD_READ_TIMEOUT = 300; | ||||
| uint16_t const SD_WRITE_TIMEOUT = 600; | ||||
| //------------------------------------------------------------------------------ | ||||
| // SD card errors | ||||
| /** timeout error for command CMD0 */ | ||||
| /** 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 (write stop) */ | ||||
| uint8_t const SD_CARD_ERROR_CMD12 = 0X3; | ||||
| /** card returned an error response for CMD17 (read block) */ | ||||
| uint8_t const SD_CARD_ERROR_CMD17 = 0X3; | ||||
| 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 = 0X4; | ||||
| uint8_t const SD_CARD_ERROR_CMD24 = 0X6; | ||||
| /**  WRITE_MULTIPLE_BLOCKS command failed */ | ||||
| uint8_t const SD_CARD_ERROR_CMD25 = 0X05; | ||||
| uint8_t const SD_CARD_ERROR_CMD25 = 0X7; | ||||
| /** card returned an error response for CMD58 (read OCR) */ | ||||
| uint8_t const SD_CARD_ERROR_CMD58 = 0X06; | ||||
| uint8_t const SD_CARD_ERROR_CMD58 = 0X8; | ||||
| /** SET_WR_BLK_ERASE_COUNT failed */ | ||||
| uint8_t const SD_CARD_ERROR_ACMD23 = 0X07; | ||||
| /** card's ACMD41 initialization process timeout */ | ||||
| uint8_t const SD_CARD_ERROR_ACMD41 = 0X08; | ||||
| 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 = 0X09; | ||||
| uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB; | ||||
| /** erase block group command failed */ | ||||
| uint8_t const SD_CARD_ERROR_ERASE = 0X0A; | ||||
| uint8_t const SD_CARD_ERROR_ERASE = 0XC; | ||||
| /** card not capable of single block erase */ | ||||
| uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0X0B; | ||||
| uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD; | ||||
| /** Erase sequence timed out */ | ||||
| uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0X0C; | ||||
| 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 = 0X0D; | ||||
| uint8_t const SD_CARD_ERROR_READ = 0XF; | ||||
| /** read CID or CSD failed */ | ||||
| uint8_t const SD_CARD_ERROR_READ_REG = 0X0E; | ||||
| 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 = 0X0F; | ||||
| uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11; | ||||
| /** card did not accept STOP_TRAN_TOKEN */ | ||||
| uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X10; | ||||
| 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 = 0X11; | ||||
| uint8_t const SD_CARD_ERROR_WRITE = 0X13; | ||||
| /** attempt to write protected block zero */ | ||||
| uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X12; | ||||
| 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 = 0X13; | ||||
| 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 = 0X14; | ||||
| uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16; | ||||
| /** timeout occurred during write programming */ | ||||
| uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X15; | ||||
| uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17; | ||||
| /** incorrect rate selected */ | ||||
| uint8_t const SD_CARD_ERROR_SCK_RATE = 0X16; | ||||
| uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18; | ||||
| /** init() not called */ | ||||
| uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19; | ||||
| //------------------------------------------------------------------------------ | ||||
| // card types | ||||
| /** Standard capacity V1 SD card */ | ||||
| uint8_t const SD_CARD_TYPE_SD1 = 1; | ||||
| uint8_t const SD_CARD_TYPE_SD1  = 1; | ||||
| /** Standard capacity V2 SD card */ | ||||
| uint8_t const SD_CARD_TYPE_SD2 = 2; | ||||
| uint8_t const SD_CARD_TYPE_SD2  = 2; | ||||
| /** High Capacity SD card */ | ||||
| uint8_t const SD_CARD_TYPE_SDHC = 3; | ||||
| /** | ||||
|  * define SOFTWARE_SPI to use bit-bang SPI | ||||
|  */ | ||||
| //------------------------------------------------------------------------------ | ||||
| #if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)) | ||||
| #define SOFTWARE_SPI | ||||
| #elif USE_SOFTWARE_SPI | ||||
| #define SOFTWARE_SPI | ||||
| #endif  // MEGA_SOFT_SPI | ||||
| //------------------------------------------------------------------------------ | ||||
| // SPI pin definitions - do not edit here - change in SdFatConfig.h | ||||
| // | ||||
| #ifndef SOFTWARE_SPI | ||||
| // hardware pin defs | ||||
| /** The default chip select pin for the SD card is SS. */ | ||||
| uint8_t const  SD_CHIP_SELECT_PIN = SS_PIN; | ||||
| // The following three pins must not be redefined for hardware SPI. | ||||
| /** SPI Master Out Slave In pin */ | ||||
| uint8_t const  SPI_MOSI_PIN = MOSI_PIN; | ||||
| /** SPI Master In Slave Out pin */ | ||||
| uint8_t const  SPI_MISO_PIN = MISO_PIN; | ||||
| /** SPI Clock pin */ | ||||
| uint8_t const  SPI_SCK_PIN = SCK_PIN; | ||||
|  | ||||
| #else  // SOFTWARE_SPI | ||||
|  | ||||
| /** SPI chip select pin */ | ||||
| uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN; | ||||
| /** SPI Master Out Slave In pin */ | ||||
| uint8_t const SPI_MOSI_PIN = SOFT_SPI_MOSI_PIN; | ||||
| /** SPI Master In Slave Out pin */ | ||||
| uint8_t const SPI_MISO_PIN = SOFT_SPI_MISO_PIN; | ||||
| /** SPI Clock pin */ | ||||
| uint8_t const SPI_SCK_PIN = SOFT_SPI_SCK_PIN; | ||||
| #endif  // SOFTWARE_SPI | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * \class Sd2Card | ||||
| @@ -152,66 +150,70 @@ uint8_t const SD_CARD_TYPE_SDHC = 3; | ||||
| class Sd2Card { | ||||
|  public: | ||||
|   /** Construct an instance of Sd2Card. */ | ||||
|   Sd2Card(void) : errorCode_(0), inBlock_(0), partialBlockRead_(0), type_(0) {} | ||||
|   uint32_t cardSize(void); | ||||
|   uint8_t erase(uint32_t firstBlock, uint32_t lastBlock); | ||||
|   uint8_t eraseSingleBlockEnable(void); | ||||
|   Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0) {} | ||||
|   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) {errorCode_ = code;} | ||||
|   /** | ||||
|    * \return error code for last error. See Sd2Card.h for a list of error codes. | ||||
|    */ | ||||
|   uint8_t errorCode(void) const {return errorCode_;} | ||||
|   int errorCode() const {return errorCode_;} | ||||
|   /** \return error data for last error. */ | ||||
|   uint8_t errorData(void) const {return status_;} | ||||
|   int errorData() const {return status_;} | ||||
|   /** | ||||
|    * Initialize an SD flash memory card with default clock rate and chip | ||||
|    * select pin.  See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). | ||||
|    * | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   uint8_t init(void) { | ||||
|     return init(SPI_FULL_SPEED, SD_CHIP_SELECT_PIN); | ||||
|   } | ||||
|   bool init(uint8_t sckRateID = SPI_FULL_SPEED, | ||||
|     uint8_t chipSelectPin = SD_CHIP_SELECT_PIN); | ||||
|   bool readBlock(uint32_t block, uint8_t* dst); | ||||
|   /** | ||||
|    * Initialize an SD flash memory card with the selected SPI clock rate | ||||
|    * and the default SD chip select pin. | ||||
|    * See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). | ||||
|    */ | ||||
|   uint8_t init(uint8_t sckRateID) { | ||||
|     return init(sckRateID, SD_CHIP_SELECT_PIN); | ||||
|   } | ||||
|   uint8_t init(uint8_t sckRateID, uint8_t chipSelectPin); | ||||
|   void partialBlockRead(uint8_t value); | ||||
|   /** Returns the current value, true or false, for partial block read. */ | ||||
|   uint8_t partialBlockRead(void) const {return partialBlockRead_;} | ||||
|   uint8_t readBlock(uint32_t block, uint8_t* dst); | ||||
|   uint8_t readData(uint32_t block, | ||||
|           uint16_t offset, uint16_t count, uint8_t* dst); | ||||
|   /** | ||||
|    * Read a cards CID register. The CID contains card identification | ||||
|    * Read a card's CID register. The CID contains card identification | ||||
|    * information such as Manufacturer ID, Product name, Product serial | ||||
|    * number and Manufacturing date. */ | ||||
|   uint8_t readCID(cid_t* cid) { | ||||
|    * 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 cards CSD register. The CSD contains Card-Specific Data that | ||||
|    * provides information regarding access to the card's contents. */ | ||||
|   uint8_t readCSD(csd_t* csd) { | ||||
|    * 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); | ||||
|   } | ||||
|   void readEnd(void); | ||||
|   uint8_t setSckRate(uint8_t sckRateID); | ||||
|   /** Return the card type: SD V1, SD V2 or SDHC */ | ||||
|   uint8_t type(void) const {return type_;} | ||||
|   uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src); | ||||
|   uint8_t writeData(const uint8_t* src); | ||||
|   uint8_t writeStart(uint32_t blockNumber, uint32_t eraseCount); | ||||
|   uint8_t writeStop(void); | ||||
|   bool readData(uint8_t *dst); | ||||
|   bool readStart(uint32_t blockNumber); | ||||
|   bool readStop(); | ||||
|   bool setSckRate(uint8_t sckRateID); | ||||
|   /** Return the card type: SD V1, SD V2 or SDHC | ||||
|    * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. | ||||
|    */ | ||||
|   int type() const {return 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: | ||||
|   uint32_t block_; | ||||
|   //---------------------------------------------------------------------------- | ||||
|   uint8_t chipSelectPin_; | ||||
|   uint8_t errorCode_; | ||||
|   uint8_t inBlock_; | ||||
|   uint16_t offset_; | ||||
|   uint8_t partialBlockRead_; | ||||
|   uint8_t spiRate_; | ||||
|   uint8_t status_; | ||||
|   uint8_t type_; | ||||
|   // private functions | ||||
| @@ -220,14 +222,13 @@ class Sd2Card { | ||||
|     return cardCommand(cmd, arg); | ||||
|   } | ||||
|   uint8_t cardCommand(uint8_t cmd, uint32_t arg); | ||||
|   void error(uint8_t code) {errorCode_ = code;} | ||||
|   uint8_t readRegister(uint8_t cmd, void* buf); | ||||
|   uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount); | ||||
|   void chipSelectHigh(void); | ||||
|   void chipSelectLow(void); | ||||
|  | ||||
|   bool readData(uint8_t* dst, uint16_t count); | ||||
|   bool readRegister(uint8_t cmd, void* buf); | ||||
|   void chipSelectHigh(); | ||||
|   void chipSelectLow(); | ||||
|   void type(uint8_t value) {type_ = value;} | ||||
|   uint8_t waitNotBusy(uint16_t timeoutMillis); | ||||
|   uint8_t writeData(uint8_t token, const uint8_t* src); | ||||
|   uint8_t waitStartBlock(void); | ||||
|   bool waitNotBusy(uint16_t timeoutMillis); | ||||
|   bool writeData(uint8_t token, const uint8_t* src); | ||||
| }; | ||||
| #endif  // Sd2Card_h | ||||
|   | ||||
| @@ -21,7 +21,6 @@ | ||||
| #ifndef Sd2PinMap_h | ||||
| #define Sd2PinMap_h | ||||
| #include <avr/io.h> | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| /** struct for mapping digital pins */ | ||||
| struct pin_map_t { | ||||
| @@ -31,18 +30,19 @@ struct pin_map_t { | ||||
|   uint8_t bit; | ||||
| }; | ||||
| //------------------------------------------------------------------------------ | ||||
| #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | ||||
| #if defined(__AVR_ATmega1280__)\ | ||||
| || defined(__AVR_ATmega2560__) | ||||
| // Mega | ||||
|  | ||||
| // Two Wire (aka I2C) ports | ||||
| uint8_t const SDA_PIN = 20; | ||||
| uint8_t const SCL_PIN = 21; | ||||
| uint8_t const SDA_PIN = 20;  // D1 | ||||
| uint8_t const SCL_PIN = 21;  // D0 | ||||
|  | ||||
| // SPI port | ||||
| uint8_t const SS_PIN = 53; | ||||
| uint8_t const MOSI_PIN = 51; | ||||
| uint8_t const MISO_PIN = 50; | ||||
| uint8_t const SCK_PIN = 52; | ||||
| uint8_t const SS_PIN = 53;    // B0 | ||||
| uint8_t const MOSI_PIN = 51;  // B2 | ||||
| uint8_t const MISO_PIN = 50;  // B3 | ||||
| uint8_t const SCK_PIN = 52;   // B1 | ||||
|  | ||||
| static const pin_map_t digitalPinMap[] = { | ||||
|   {&DDRE, &PINE, &PORTE, 0},  // E0  0 | ||||
| @@ -117,18 +117,20 @@ static const pin_map_t digitalPinMap[] = { | ||||
|   {&DDRK, &PINK, &PORTK, 7}   // K7 69 | ||||
| }; | ||||
| //------------------------------------------------------------------------------ | ||||
| #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) | ||||
| #elif defined(__AVR_ATmega644P__)\ | ||||
| || defined(__AVR_ATmega644__)\ | ||||
| || defined(__AVR_ATmega1284P__) | ||||
| // Sanguino | ||||
|  | ||||
| // Two Wire (aka I2C) ports | ||||
| uint8_t const SDA_PIN = 17; | ||||
| uint8_t const SCL_PIN = 18; | ||||
| uint8_t const SDA_PIN = 17;  // C1 | ||||
| uint8_t const SCL_PIN = 18;  // C2 | ||||
|  | ||||
| // SPI port | ||||
| uint8_t const SS_PIN = 4; | ||||
| uint8_t const MOSI_PIN = 5; | ||||
| uint8_t const MISO_PIN = 6; | ||||
| uint8_t const SCK_PIN = 7; | ||||
| uint8_t const SS_PIN = 4;    // B4 | ||||
| uint8_t const MOSI_PIN = 5;  // B5 | ||||
| uint8_t const MISO_PIN = 6;  // B6 | ||||
| uint8_t const SCK_PIN = 7;   // B7 | ||||
|  | ||||
| static const pin_map_t digitalPinMap[] = { | ||||
|   {&DDRB, &PINB, &PORTB, 0},  // B0  0 | ||||
| @@ -169,14 +171,14 @@ static const pin_map_t digitalPinMap[] = { | ||||
| // Teensy 2.0 | ||||
|  | ||||
| // Two Wire (aka I2C) ports | ||||
| uint8_t const SDA_PIN = 6; | ||||
| uint8_t const SCL_PIN = 5; | ||||
| uint8_t const SDA_PIN = 6;  // D1 | ||||
| uint8_t const SCL_PIN = 5;  // D0 | ||||
|  | ||||
| // SPI port | ||||
| uint8_t const SS_PIN = 0; | ||||
| uint8_t const MOSI_PIN = 2; | ||||
| uint8_t const MISO_PIN = 3; | ||||
| uint8_t const SCK_PIN = 1; | ||||
| uint8_t const SS_PIN = 0;    // B0 | ||||
| uint8_t const MOSI_PIN = 2;  // B2 | ||||
| uint8_t const MISO_PIN = 3;  // B3 | ||||
| uint8_t const SCK_PIN = 1;   // B1 | ||||
|  | ||||
| static const pin_map_t digitalPinMap[] = { | ||||
|   {&DDRB, &PINB, &PORTB, 0},  // B0  0 | ||||
| @@ -206,18 +208,19 @@ static const pin_map_t digitalPinMap[] = { | ||||
|   {&DDRE, &PINE, &PORTE, 6}   // E6 24 | ||||
| }; | ||||
| //------------------------------------------------------------------------------ | ||||
| #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | ||||
| #elif defined(__AVR_AT90USB646__)\ | ||||
| || defined(__AVR_AT90USB1286__) | ||||
| // Teensy++ 1.0 & 2.0 | ||||
|  | ||||
| // Two Wire (aka I2C) ports | ||||
| uint8_t const SDA_PIN = 1; | ||||
| uint8_t const SCL_PIN = 0; | ||||
| uint8_t const SDA_PIN = 1;  // D1 | ||||
| uint8_t const SCL_PIN = 0;  // D0 | ||||
|  | ||||
| // SPI port | ||||
| uint8_t const SS_PIN = 20; | ||||
| uint8_t const MOSI_PIN = 22; | ||||
| uint8_t const MISO_PIN = 23; | ||||
| uint8_t const SCK_PIN = 21; | ||||
| uint8_t const SS_PIN = 20;    // B0 | ||||
| uint8_t const MOSI_PIN = 22;  // B2 | ||||
| uint8_t const MISO_PIN = 23;  // B3 | ||||
| uint8_t const SCK_PIN = 21;   // B1 | ||||
|  | ||||
| static const pin_map_t digitalPinMap[] = { | ||||
|   {&DDRD, &PIND, &PORTD, 0},  // D0  0 | ||||
| @@ -268,18 +271,20 @@ static const pin_map_t digitalPinMap[] = { | ||||
|   {&DDRF, &PINF, &PORTF, 7}   // F7 45 | ||||
| }; | ||||
| //------------------------------------------------------------------------------ | ||||
| #else  // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | ||||
| #elif defined(__AVR_ATmega168__)\ | ||||
| ||defined(__AVR_ATmega168P__)\ | ||||
| ||defined(__AVR_ATmega328P__) | ||||
| // 168 and 328 Arduinos | ||||
|  | ||||
| // Two Wire (aka I2C) ports | ||||
| uint8_t const SDA_PIN = 18; | ||||
| uint8_t const SCL_PIN = 19; | ||||
| uint8_t const SDA_PIN = 18;  // C4 | ||||
| uint8_t const SCL_PIN = 19;  // C5 | ||||
|  | ||||
| // SPI port | ||||
| uint8_t const SS_PIN = 10; | ||||
| uint8_t const MOSI_PIN = 11; | ||||
| uint8_t const MISO_PIN = 12; | ||||
| uint8_t const SCK_PIN = 13; | ||||
| uint8_t const SS_PIN = 10;    // B2 | ||||
| uint8_t const MOSI_PIN = 11;  // B3 | ||||
| uint8_t const MISO_PIN = 12;  // B4 | ||||
| uint8_t const SCK_PIN = 13;   // B5 | ||||
|  | ||||
| static const pin_map_t digitalPinMap[] = { | ||||
|   {&DDRD, &PIND, &PORTD, 0},  // D0  0 | ||||
| @@ -303,7 +308,9 @@ static const pin_map_t digitalPinMap[] = { | ||||
|   {&DDRC, &PINC, &PORTC, 4},  // C4 18 | ||||
|   {&DDRC, &PINC, &PORTC, 5}   // C5 19 | ||||
| }; | ||||
| #endif  // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | ||||
| #else  // defined(__AVR_ATmega1280__) | ||||
| #error unknown chip | ||||
| #endif  // defined(__AVR_ATmega1280__) | ||||
| //------------------------------------------------------------------------------ | ||||
| static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t); | ||||
|  | ||||
| @@ -311,7 +318,7 @@ uint8_t badPinNumber(void) | ||||
|   __attribute__((error("Pin number is too large or not a constant"))); | ||||
|  | ||||
| static inline __attribute__((always_inline)) | ||||
|   uint8_t getPinMode(uint8_t pin) { | ||||
|   bool getPinMode(uint8_t pin) { | ||||
|   if (__builtin_constant_p(pin) && pin < digitalPinCount) { | ||||
|     return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1; | ||||
|   } else { | ||||
| @@ -331,7 +338,7 @@ static inline __attribute__((always_inline)) | ||||
|   } | ||||
| } | ||||
| static inline __attribute__((always_inline)) | ||||
|   uint8_t fastDigitalRead(uint8_t pin) { | ||||
|   bool fastDigitalRead(uint8_t pin) { | ||||
|   if (__builtin_constant_p(pin) && pin < digitalPinCount) { | ||||
|     return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1; | ||||
|   } else { | ||||
|   | ||||
							
								
								
									
										1818
									
								
								Marlin/SdBaseFile.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1818
									
								
								Marlin/SdBaseFile.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										489
									
								
								Marlin/SdBaseFile.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										489
									
								
								Marlin/SdBaseFile.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,489 @@ | ||||
| /* Arduino SdFat Library | ||||
|  * Copyright (C) 2009 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 | ||||
|  */ | ||||
| #include <avr/pgmspace.h> | ||||
| #if ARDUINO < 100 | ||||
| #include <WProgram.h> | ||||
| #else  // ARDUINO | ||||
| #include <Arduino.h> | ||||
| #endif  // ARDUINO | ||||
| #include "SdFatConfig.h" | ||||
| #include "SdVolume.h" | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * \struct fpos_t | ||||
|  * \brief internal type for istream | ||||
|  * do not use in user apps | ||||
|  */ | ||||
| struct fpos_t { | ||||
|   /** stream position */ | ||||
|   uint32_t position; | ||||
|   /** cluster for position */ | ||||
|   uint32_t cluster; | ||||
|   fpos_t() : position(0), cluster(0) {} | ||||
| }; | ||||
|  | ||||
| // use the gnu style oflag in open() | ||||
| /** open() oflag for reading */ | ||||
| uint8_t const O_READ = 0X01; | ||||
| /** open() oflag - same as O_IN */ | ||||
| uint8_t const O_RDONLY = O_READ; | ||||
| /** open() oflag for write */ | ||||
| uint8_t const O_WRITE = 0X02; | ||||
| /** open() oflag - same as O_WRITE */ | ||||
| uint8_t const O_WRONLY = O_WRITE; | ||||
| /** open() oflag for reading and writing */ | ||||
| uint8_t const O_RDWR = (O_READ | O_WRITE); | ||||
| /** open() oflag mask for access modes */ | ||||
| uint8_t const O_ACCMODE = (O_READ | O_WRITE); | ||||
| /** The file offset shall be set to the end of the file prior to each write. */ | ||||
| uint8_t const O_APPEND = 0X04; | ||||
| /** synchronous writes - call sync() after each write */ | ||||
| uint8_t const O_SYNC = 0X08; | ||||
| /** truncate the file to zero length */ | ||||
| uint8_t const O_TRUNC = 0X10; | ||||
| /** set the initial position at the end of the file */ | ||||
| uint8_t const O_AT_END = 0X20; | ||||
| /** create the file if nonexistent */ | ||||
| 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 | ||||
| // flags for ls() | ||||
| /** ls() flag to print modify date */ | ||||
| uint8_t const LS_DATE = 1; | ||||
| /** ls() flag to print file size */ | ||||
| uint8_t const LS_SIZE = 2; | ||||
| /** ls() flag for recursive list of subdirectories */ | ||||
| uint8_t const LS_R = 4; | ||||
|  | ||||
|  | ||||
| // flags for timestamp | ||||
| /** set the file's last access date */ | ||||
| uint8_t const T_ACCESS = 1; | ||||
| /** set the file's creation date and time */ | ||||
| uint8_t const T_CREATE = 2; | ||||
| /** Set the file's write date and time */ | ||||
| uint8_t const T_WRITE = 4; | ||||
| // values for 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; | ||||
|  | ||||
| /** date field for FAT directory entry | ||||
|  * \param[in] year [1980,2107] | ||||
|  * \param[in] month [1,12] | ||||
|  * \param[in] day [1,31] | ||||
|  * | ||||
|  * \return Packed date for dir_t entry. | ||||
|  */ | ||||
| static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { | ||||
|   return (year - 1980) << 9 | month << 5 | day; | ||||
| } | ||||
| /** year part of FAT directory date field | ||||
|  * \param[in] fatDate Date in packed dir format. | ||||
|  * | ||||
|  * \return Extracted year [1980,2107] | ||||
|  */ | ||||
| static inline uint16_t FAT_YEAR(uint16_t fatDate) { | ||||
|   return 1980 + (fatDate >> 9); | ||||
| } | ||||
| /** month part of FAT directory date field | ||||
|  * \param[in] fatDate Date in packed dir format. | ||||
|  * | ||||
|  * \return Extracted month [1,12] | ||||
|  */ | ||||
| static inline uint8_t FAT_MONTH(uint16_t fatDate) { | ||||
|   return (fatDate >> 5) & 0XF; | ||||
| } | ||||
| /** day part of FAT directory date field | ||||
|  * \param[in] fatDate Date in packed dir format. | ||||
|  * | ||||
|  * \return Extracted day [1,31] | ||||
|  */ | ||||
| static inline uint8_t FAT_DAY(uint16_t fatDate) { | ||||
|   return fatDate & 0X1F; | ||||
| } | ||||
| /** time field for FAT directory entry | ||||
|  * \param[in] hour [0,23] | ||||
|  * \param[in] minute [0,59] | ||||
|  * \param[in] second [0,59] | ||||
|  * | ||||
|  * \return Packed time for dir_t entry. | ||||
|  */ | ||||
| static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { | ||||
|   return hour << 11 | minute << 5 | second >> 1; | ||||
| } | ||||
| /** hour part of FAT directory time field | ||||
|  * \param[in] fatTime Time in packed dir format. | ||||
|  * | ||||
|  * \return Extracted hour [0,23] | ||||
|  */ | ||||
| static inline uint8_t FAT_HOUR(uint16_t fatTime) { | ||||
|   return fatTime >> 11; | ||||
| } | ||||
| /** minute part of FAT directory time field | ||||
|  * \param[in] fatTime Time in packed dir format. | ||||
|  * | ||||
|  * \return Extracted minute [0,59] | ||||
|  */ | ||||
| static inline uint8_t FAT_MINUTE(uint16_t fatTime) { | ||||
|   return(fatTime >> 5) & 0X3F; | ||||
| } | ||||
| /** second part of FAT directory time field | ||||
|  * Note second/2 is stored in packed time. | ||||
|  * | ||||
|  * \param[in] fatTime Time in packed dir format. | ||||
|  * | ||||
|  * \return Extracted second [0,58] | ||||
|  */ | ||||
| static inline uint8_t FAT_SECOND(uint16_t fatTime) { | ||||
|   return 2*(fatTime & 0X1F); | ||||
| } | ||||
| /** Default date for file timestamps is 1 Jan 2000 */ | ||||
| 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); | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * \class SdBaseFile | ||||
|  * \brief Base class for SdFile with Print and C++ streams. | ||||
|  */ | ||||
| class SdBaseFile { | ||||
|  public: | ||||
|   /** Create an instance. */ | ||||
|   SdBaseFile() : writeError(false), type_(FAT_FILE_TYPE_CLOSED) {} | ||||
|   SdBaseFile(const char* path, uint8_t oflag); | ||||
|   ~SdBaseFile() {if(isOpen()) close();} | ||||
|   /** | ||||
|    * 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; | ||||
|   //---------------------------------------------------------------------------- | ||||
|   // helpers for stream classes | ||||
|   /** get position for streams | ||||
|    * \param[out] pos struct to receive position | ||||
|    */ | ||||
|   void getpos(fpos_t* pos); | ||||
|   /** set position for streams | ||||
|    * \param[out] pos struct with value for new position | ||||
|    */ | ||||
|   void setpos(fpos_t* pos); | ||||
|   //---------------------------------------------------------------------------- | ||||
|   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 curCluster_;} | ||||
|   /** \return The current position for a file or directory. */ | ||||
|   uint32_t curPosition() const {return curPosition_;} | ||||
|   /** \return Current working directory */ | ||||
|   static SdBaseFile* cwd() {return 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)) { | ||||
|     dateTime_ = dateTime; | ||||
|   } | ||||
|   /**  Cancel the date/time callback function. */ | ||||
|   static void dateTimeCallbackCancel() {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 fileSize_;} | ||||
|   /** \return The first cluster number for a file or directory. */ | ||||
|   uint32_t firstCluster() const {return firstCluster_;} | ||||
|   bool getFilename(char* name); | ||||
|   /** \return True if this is a directory else false. */ | ||||
|   bool isDir() const {return type_ >= FAT_FILE_TYPE_MIN_DIR;} | ||||
|   /** \return True if this is a normal file else false. */ | ||||
|   bool isFile() const {return type_ == FAT_FILE_TYPE_NORMAL;} | ||||
|   /** \return True if this is an open file/directory else false. */ | ||||
|   bool isOpen() const {return type_ != FAT_FILE_TYPE_CLOSED;} | ||||
|   /** \return True if this is a subdirectory else false. */ | ||||
|   bool isSubDir() const {return type_ == FAT_FILE_TYPE_SUBDIR;} | ||||
|   /** \return True if this is the root directory. */ | ||||
|   bool isRoot() const { | ||||
|     return type_ == FAT_FILE_TYPE_ROOT_FIXED || 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(); | ||||
|   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); | ||||
|   bool printName(); | ||||
|   int16_t read(); | ||||
|   int16_t read(void* buf, uint16_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(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(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 type_;} | ||||
|   bool truncate(uint32_t size); | ||||
|   /** \return SdVolume that contains this file. */ | ||||
|   SdVolume* volume() const {return vol_;} | ||||
|   int16_t write(const void* buf, uint16_t nbyte); | ||||
| //------------------------------------------------------------------------------ | ||||
|  private: | ||||
|   // allow SdFat to set cwd_ | ||||
|   friend class SdFat; | ||||
|   // global pointer to cwd dir | ||||
|   static SdBaseFile* cwd_; | ||||
|   // data time callback function | ||||
|   static void (*dateTime_)(uint16_t* date, uint16_t* time); | ||||
|   // bits defined in 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; | ||||
|  | ||||
|   // private data | ||||
|   uint8_t   flags_;         // See above for definition of flags_ bits | ||||
|   uint8_t   fstate_;        // error and eof indicator | ||||
|   uint8_t   type_;          // type of file see above for values | ||||
|   uint32_t  curCluster_;    // cluster for current file position | ||||
|   uint32_t  curPosition_;   // current file position in bytes from beginning | ||||
|   uint32_t  dirBlock_;      // block for this files directory entry | ||||
|   uint8_t   dirIndex_;      // index of directory entry in dirBlock | ||||
|   uint32_t  fileSize_;      // file size in bytes | ||||
|   uint32_t  firstCluster_;  // first cluster of file | ||||
|   SdVolume* vol_;           // volume where file is located | ||||
|  | ||||
|   /** experimental don't use */ | ||||
|   bool openParent(SdBaseFile* dir); | ||||
|   // private functions | ||||
|   bool addCluster(); | ||||
|   bool 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(); | ||||
| //------------------------------------------------------------------------------ | ||||
| // to be deleted | ||||
|   static void printDirName(const dir_t& dir, | ||||
|     uint8_t width, bool printSlash); | ||||
|   static void printDirName(Print* pr, const dir_t& dir, | ||||
|     uint8_t width, bool printSlash); | ||||
| //------------------------------------------------------------------------------ | ||||
| // Deprecated functions  - suppress cpplint warnings with NOLINT comment | ||||
| #if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN) | ||||
|  public: | ||||
|   /** \deprecated Use: | ||||
|    * bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); | ||||
|    * \param[out] bgnBlock the first block address for the file. | ||||
|    * \param[out] endBlock the last  block address for the file. | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   bool contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) {  // NOLINT | ||||
|     return contiguousRange(&bgnBlock, &endBlock); | ||||
|   } | ||||
|  /** \deprecated Use: | ||||
|    * bool createContiguous(SdBaseFile* dirFile, | ||||
|    *   const char* path, uint32_t size) | ||||
|    * \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 true for success or false for failure. | ||||
|    */ | ||||
|   bool createContiguous(SdBaseFile& dirFile,  // NOLINT | ||||
|     const char* path, uint32_t size) { | ||||
|     return createContiguous(&dirFile, path, size); | ||||
|   } | ||||
|   /** \deprecated Use: | ||||
|    * static void dateTimeCallback( | ||||
|    *   void (*dateTime)(uint16_t* date, uint16_t* time)); | ||||
|    * \param[in] dateTime The user's call back function. | ||||
|    */ | ||||
|   static void dateTimeCallback( | ||||
|     void (*dateTime)(uint16_t& date, uint16_t& time)) {  // NOLINT | ||||
|     oldDateTime_ = dateTime; | ||||
|     dateTime_ = dateTime ? oldToNew : 0; | ||||
|   } | ||||
|   /** \deprecated Use: bool dirEntry(dir_t* dir); | ||||
|    * \param[out] dir Location for return of the file's directory entry. | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   bool dirEntry(dir_t& dir) {return dirEntry(&dir);}  // NOLINT | ||||
|   /** \deprecated Use: | ||||
|    * bool mkdir(SdBaseFile* dir, const char* path); | ||||
|    * \param[in] dir An open SdFat 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. | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   bool mkdir(SdBaseFile& dir, const char* path) {  // NOLINT | ||||
|     return mkdir(&dir, path); | ||||
|   } | ||||
|   /** \deprecated Use: | ||||
|    * bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag); | ||||
|    * \param[in] dirFile An open SdFat instance for the directory containing the | ||||
|    * file to be opened. | ||||
|    * \param[in] path A path with a valid 8.3 DOS name for the file. | ||||
|    * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive | ||||
|    * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   bool open(SdBaseFile& dirFile, // NOLINT | ||||
|     const char* path, uint8_t oflag) { | ||||
|     return open(&dirFile, path, oflag); | ||||
|   } | ||||
|   /** \deprecated  Do not use in new apps | ||||
|    * \param[in] dirFile An open SdFat 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. | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   bool open(SdBaseFile& dirFile, const char* path) {  // NOLINT | ||||
|     return open(dirFile, path, O_RDWR); | ||||
|   } | ||||
|   /** \deprecated Use: | ||||
|    * bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag); | ||||
|    * \param[in] dirFile An open SdFat 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 Values for \a oflag are constructed by a bitwise-inclusive | ||||
|    * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   bool open(SdBaseFile& dirFile, uint16_t index, uint8_t oflag) {  // NOLINT | ||||
|     return open(&dirFile, index, oflag); | ||||
|   } | ||||
|   /** \deprecated Use: bool openRoot(SdVolume* vol); | ||||
|    * \param[in] vol The FAT volume containing the root directory to be opened. | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   bool openRoot(SdVolume& vol) {return openRoot(&vol);}  // NOLINT | ||||
|   /** \deprecated Use: int8_t readDir(dir_t* dir); | ||||
|    * \param[out] dir The dir_t struct that will receive the data. | ||||
|    * \return bytes read for success zero for eof or -1 for failure. | ||||
|    */ | ||||
|   int8_t readDir(dir_t& dir) {return readDir(&dir);}  // NOLINT | ||||
|   /** \deprecated Use: | ||||
|    * static uint8_t remove(SdBaseFile* dirFile, const char* path); | ||||
|    * \param[in] dirFile The directory that contains the file. | ||||
|    * \param[in] path The name of the file to be removed. | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   static bool remove(SdBaseFile& dirFile, const char* path) {  // NOLINT | ||||
|     return remove(&dirFile, path); | ||||
|   } | ||||
| //------------------------------------------------------------------------------ | ||||
| // rest are private | ||||
|  private: | ||||
|   static void (*oldDateTime_)(uint16_t& date, uint16_t& time);  // NOLINT | ||||
|   static void oldToNew(uint16_t* date, uint16_t* time) { | ||||
|     uint16_t d; | ||||
|     uint16_t t; | ||||
|     oldDateTime_(d, t); | ||||
|     *date = d; | ||||
|     *time = t; | ||||
|   } | ||||
| #endif  // ALLOW_DEPRECATED_FUNCTIONS | ||||
| }; | ||||
|  | ||||
| #endif  // SdBaseFile_h | ||||
							
								
								
									
										329
									
								
								Marlin/SdFat.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								Marlin/SdFat.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,329 @@ | ||||
| /* Arduino SdFat Library | ||||
|  * Copyright (C) 2009 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 "SdFatUtil.h" | ||||
| //------------------------------------------------------------------------------ | ||||
| /** 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::cwd_ = &vwd_; | ||||
|   vwd_.close(); | ||||
|   return vwd_.openRoot(&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; | ||||
|   if (path[0] == '/' && path[1] == '\0') return chdir(set_cwd); | ||||
|   if (!dir.open(&vwd_, path, O_READ)) goto fail; | ||||
|   if (!dir.isDir()) goto fail; | ||||
|   vwd_ = dir; | ||||
|   if (set_cwd) SdBaseFile::cwd_ = &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::cwd_ = &vwd_; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** %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 (!card_.errorCode()) return; | ||||
|   PgmPrint("SD errorCode: 0X"); | ||||
|   Serial.println(card_.errorCode(), HEX); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** %Print msg, any SD error code. | ||||
|  * | ||||
|  * \param[in] msg Message to print. | ||||
|  */ | ||||
| void SdFat::errorPrint(char const* msg) { | ||||
|   PgmPrint("error: "); | ||||
|   Serial.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) { | ||||
|   PgmPrint("error: "); | ||||
|   SerialPrintln_P(msg); | ||||
|   errorPrint(); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * 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 vwd_.exists(name); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Initialize an SdFat object. | ||||
|  * | ||||
|  * Initializes the SD card, SD volume, and root directory. | ||||
|  * | ||||
|  * \param[in] sckRateID value for SPI SCK rate. See Sd2Card::init(). | ||||
|  * \param[in] chipSelectPin SD chip select pin. See Sd2Card::init(). | ||||
|  * | ||||
|  * \return The value one, true, is returned for success and | ||||
|  * the value zero, false, is returned for failure. | ||||
|  */ | ||||
| bool SdFat::init(uint8_t sckRateID, uint8_t chipSelectPin) { | ||||
|   return card_.init(sckRateID, chipSelectPin) && vol_.init(&card_) && chdir(1); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** %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) { | ||||
|   Serial.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) { | ||||
|   SerialPrintln_P(msg); | ||||
|   initErrorHalt(); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Print error details after SdFat::init() fails. */ | ||||
| void SdFat::initErrorPrint() { | ||||
|   if (card_.errorCode()) { | ||||
|     PgmPrintln("Can't access SD card. Do not reformat."); | ||||
|     if (card_.errorCode() == SD_CARD_ERROR_CMD0) { | ||||
|       PgmPrintln("No card, wrong chip select pin, or SPI problem?"); | ||||
|     } | ||||
|     errorPrint(); | ||||
|   } else if (vol_.fatType() == 0) { | ||||
|     PgmPrintln("Invalid format, reformat SD."); | ||||
|   } else if (!vwd_.isOpen()) { | ||||
|     PgmPrintln("Can't open root directory."); | ||||
|   } else { | ||||
|     PgmPrintln("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) { | ||||
|   Serial.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) { | ||||
|   SerialPrintln_P(msg); | ||||
|   initErrorHalt(); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** 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 SdFat::ls(uint8_t flags) { | ||||
|   vwd_.ls(&Serial, flags); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** List the directory contents of the volume working directory to Serial. | ||||
|  * | ||||
|  * \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 SdFat::ls(Print* pr, uint8_t flags) { | ||||
|   vwd_.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(&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(&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(&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); | ||||
| } | ||||
							
								
								
									
										561
									
								
								Marlin/SdFat.h
									
									
									
									
									
								
							
							
						
						
									
										561
									
								
								Marlin/SdFat.h
									
									
									
									
									
								
							| @@ -21,527 +21,56 @@ | ||||
| #define SdFat_h | ||||
| /** | ||||
|  * \file | ||||
|  * SdFile and SdVolume classes | ||||
|  * \brief SdFat class | ||||
|  */ | ||||
| #include <avr/pgmspace.h> | ||||
| #include "Sd2Card.h" | ||||
| #include "FatStructs.h" | ||||
| #include "Print.h" | ||||
| #include "SdFile.h" | ||||
| //#include <SdStream.h> | ||||
| //#include <ArduinoStream.h> | ||||
| //------------------------------------------------------------------------------ | ||||
| /** SdFat version YYYYMMDD */ | ||||
| #define SD_FAT_VERSION 20110902 | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Allow use of deprecated functions if non-zero | ||||
|  * \class SdFat | ||||
|  * \brief Integration class for the %SdFat library. | ||||
|  */ | ||||
| #define ALLOW_DEPRECATED_FUNCTIONS 1 | ||||
| //------------------------------------------------------------------------------ | ||||
| // forward declaration since SdVolume is used in SdFile | ||||
| class SdVolume; | ||||
| //============================================================================== | ||||
| // SdFile class | ||||
|  | ||||
| // flags for ls() | ||||
| /** ls() flag to print modify date */ | ||||
| uint8_t const LS_DATE = 1; | ||||
| /** ls() flag to print file size */ | ||||
| uint8_t const LS_SIZE = 2; | ||||
| /** ls() flag for recursive list of subdirectories */ | ||||
| uint8_t const LS_R = 4; | ||||
|  | ||||
| // use the gnu style oflag in open() | ||||
| /** open() oflag for reading */ | ||||
| uint8_t const O_READ = 0X01; | ||||
| /** open() oflag - same as O_READ */ | ||||
| uint8_t const O_RDONLY = O_READ; | ||||
| /** open() oflag for write */ | ||||
| uint8_t const O_WRITE = 0X02; | ||||
| /** open() oflag - same as O_WRITE */ | ||||
| uint8_t const O_WRONLY = O_WRITE; | ||||
| /** open() oflag for reading and writing */ | ||||
| uint8_t const O_RDWR = (O_READ | O_WRITE); | ||||
| /** open() oflag mask for access modes */ | ||||
| uint8_t const O_ACCMODE = (O_READ | O_WRITE); | ||||
| /** The file offset shall be set to the end of the file prior to each write. */ | ||||
| uint8_t const O_APPEND = 0X04; | ||||
| /** synchronous writes - call sync() after each write */ | ||||
| uint8_t const O_SYNC = 0X08; | ||||
| /** create the file if nonexistent */ | ||||
| uint8_t const O_CREAT = 0X10; | ||||
| /** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */ | ||||
| uint8_t const O_EXCL = 0X20; | ||||
| /** truncate the file to zero length */ | ||||
| uint8_t const O_TRUNC = 0X40; | ||||
|  | ||||
| // flags for timestamp | ||||
| /** set the file's last access date */ | ||||
| uint8_t const T_ACCESS = 1; | ||||
| /** set the file's creation date and time */ | ||||
| uint8_t const T_CREATE = 2; | ||||
| /** Set the file's write date and time */ | ||||
| uint8_t const T_WRITE = 4; | ||||
| // values for type_ | ||||
| /** This SdFile has not been opened. */ | ||||
| uint8_t const FAT_FILE_TYPE_CLOSED = 0; | ||||
| /** SdFile for a file */ | ||||
| uint8_t const FAT_FILE_TYPE_NORMAL = 1; | ||||
| /** SdFile for a FAT16 root directory */ | ||||
| uint8_t const FAT_FILE_TYPE_ROOT16 = 2; | ||||
| /** SdFile for a FAT32 root directory */ | ||||
| uint8_t const FAT_FILE_TYPE_ROOT32 = 3; | ||||
| /** SdFile for a subdirectory */ | ||||
| uint8_t const FAT_FILE_TYPE_SUBDIR = 4; | ||||
| /** Test value for directory type */ | ||||
| uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16; | ||||
|  | ||||
| /** date field for FAT directory entry */ | ||||
| static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { | ||||
|   return (year - 1980) << 9 | month << 5 | day; | ||||
| } | ||||
| /** year part of FAT directory date field */ | ||||
| static inline uint16_t FAT_YEAR(uint16_t fatDate) { | ||||
|   return 1980 + (fatDate >> 9); | ||||
| } | ||||
| /** month part of FAT directory date field */ | ||||
| static inline uint8_t FAT_MONTH(uint16_t fatDate) { | ||||
|   return (fatDate >> 5) & 0XF; | ||||
| } | ||||
| /** day part of FAT directory date field */ | ||||
| static inline uint8_t FAT_DAY(uint16_t fatDate) { | ||||
|   return fatDate & 0X1F; | ||||
| } | ||||
| /** time field for FAT directory entry */ | ||||
| static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { | ||||
|   return hour << 11 | minute << 5 | second >> 1; | ||||
| } | ||||
| /** hour part of FAT directory time field */ | ||||
| static inline uint8_t FAT_HOUR(uint16_t fatTime) { | ||||
|   return fatTime >> 11; | ||||
| } | ||||
| /** minute part of FAT directory time field */ | ||||
| static inline uint8_t FAT_MINUTE(uint16_t fatTime) { | ||||
|   return(fatTime >> 5) & 0X3F; | ||||
| } | ||||
| /** second part of FAT directory time field */ | ||||
| static inline uint8_t FAT_SECOND(uint16_t fatTime) { | ||||
|   return 2*(fatTime & 0X1F); | ||||
| } | ||||
| /** Default date for file timestamps is 1 Jan 2000 */ | ||||
| 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); | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * \class SdFile | ||||
|  * \brief Access FAT16 and FAT32 files on SD and SDHC cards. | ||||
|  */ | ||||
| class SdFile : public Print { | ||||
| class SdFat { | ||||
|  public: | ||||
|   /** Create an instance of SdFile. */ | ||||
|   SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {} | ||||
|   /** | ||||
|    * 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; | ||||
|   /** | ||||
|    * Cancel unbuffered reads for this file. | ||||
|    * See setUnbufferedRead() | ||||
|    */ | ||||
|   void clearUnbufferedRead(void) { | ||||
|     flags_ &= ~F_FILE_UNBUFFERED_READ; | ||||
|   } | ||||
|   uint8_t close(void); | ||||
|   uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); | ||||
|   uint8_t createContiguous(SdFile* dirFile, | ||||
|           const char* fileName, uint32_t size); | ||||
|   /** \return The current cluster number for a file or directory. */ | ||||
|   uint32_t curCluster(void) const {return curCluster_;} | ||||
|   /** \return The current position for a file or directory. */ | ||||
|   uint32_t curPosition(void) const {return curPosition_;} | ||||
|   /** | ||||
|    * 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)) { | ||||
|     dateTime_ = dateTime; | ||||
|   } | ||||
|   /** | ||||
|    * Cancel the date/time callback function. | ||||
|    */ | ||||
|   static void dateTimeCallbackCancel(void) { | ||||
|     // use explicit zero since NULL is not defined for Sanguino | ||||
|     dateTime_ = 0; | ||||
|   } | ||||
|   /** \return Address of the block that contains this file's directory. */ | ||||
|   uint32_t dirBlock(void) const {return dirBlock_;} | ||||
|   uint8_t dirEntry(dir_t* dir); | ||||
|   /** \return Index of this file's directory in the block dirBlock. */ | ||||
|   uint8_t dirIndex(void) const {return dirIndex_;} | ||||
|   static void dirName(const dir_t& dir, char* name); | ||||
|   /** \return The total number of bytes in a file or directory. */ | ||||
|   uint32_t fileSize(void) const {return fileSize_;} | ||||
|   /** \return The first cluster number for a file or directory. */ | ||||
|   uint32_t firstCluster(void) const {return firstCluster_;} | ||||
|   /** \return True if this is a SdFile for a directory else false. */ | ||||
|   uint8_t isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;} | ||||
|   /** \return True if this is a SdFile for a file else false. */ | ||||
|   uint8_t isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;} | ||||
|   /** \return True if this is a SdFile for an open file/directory else false. */ | ||||
|   uint8_t isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;} | ||||
|   /** \return True if this is a SdFile for a subdirectory else false. */ | ||||
|   uint8_t isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;} | ||||
|   /** \return True if this is a SdFile for the root directory. */ | ||||
|   uint8_t isRoot(void) const { | ||||
|     return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32; | ||||
|   } | ||||
|   void ls(uint8_t flags = 0, uint8_t indent = 0); | ||||
|   uint8_t makeDir(SdFile* dir, const char* dirName); | ||||
|   uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag); | ||||
|   uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag); | ||||
|  | ||||
|   uint8_t openRoot(SdVolume* vol); | ||||
|   static void printDirName(const dir_t& dir, uint8_t width); | ||||
|   static void printFatDate(uint16_t fatDate); | ||||
|   static void printFatTime(uint16_t fatTime); | ||||
|   static void printTwoDigits(uint8_t v); | ||||
|   /** | ||||
|    * 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. | ||||
|    */ | ||||
|   int16_t read(void) { | ||||
|     uint8_t b; | ||||
|     return read(&b, 1) == 1 ? b : -1; | ||||
|   } | ||||
|   int16_t read(void* buf, uint16_t nbyte); | ||||
|   int8_t readDir(dir_t* dir); | ||||
|   static uint8_t remove(SdFile* dirFile, const char* fileName); | ||||
|   uint8_t remove(void); | ||||
|   /** Set the file's current position to zero. */ | ||||
|   void rewind(void) { | ||||
|     curPosition_ = curCluster_ = 0; | ||||
|   } | ||||
|   uint8_t rmDir(void); | ||||
|   uint8_t rmRfStar(void); | ||||
|   /** Set the files position to current position + \a pos. See seekSet(). */ | ||||
|   uint8_t seekCur(uint32_t pos) { | ||||
|     return seekSet(curPosition_ + pos); | ||||
|   } | ||||
|   /** | ||||
|    *  Set the files current position to end of file.  Useful to position | ||||
|    *  a file for append. See seekSet(). | ||||
|    */ | ||||
|   uint8_t seekEnd(void) {return seekSet(fileSize_);} | ||||
|   uint8_t seekSet(uint32_t pos); | ||||
|   /** | ||||
|    * Use unbuffered reads to access this file.  Used with Wave | ||||
|    * Shield ISR.  Used with Sd2Card::partialBlockRead() in WaveRP. | ||||
|    * | ||||
|    * Not recommended for normal applications. | ||||
|    */ | ||||
|   void setUnbufferedRead(void) { | ||||
|     if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ; | ||||
|   } | ||||
|   uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day, | ||||
|           uint8_t hour, uint8_t minute, uint8_t second); | ||||
|   uint8_t sync(void); | ||||
|   /** Type of this SdFile.  You should use isFile() or isDir() instead of type() | ||||
|    * if possible. | ||||
|    * | ||||
|    * \return The file or directory type. | ||||
|    */ | ||||
|   uint8_t type(void) const {return type_;} | ||||
|   uint8_t truncate(uint32_t size); | ||||
|   /** \return Unbuffered read flag. */ | ||||
|   uint8_t unbufferedRead(void) const { | ||||
|     return flags_ & F_FILE_UNBUFFERED_READ; | ||||
|   } | ||||
|   /** \return SdVolume that contains this file. */ | ||||
|   SdVolume* volume(void) const {return vol_;} | ||||
|   void write(uint8_t b); | ||||
|   int16_t write(const void* buf, uint16_t nbyte); | ||||
|   void write(const char* str); | ||||
|   void write_P(PGM_P str); | ||||
|   void writeln_P(PGM_P str); | ||||
| //------------------------------------------------------------------------------ | ||||
| #if ALLOW_DEPRECATED_FUNCTIONS | ||||
| // Deprecated functions  - suppress cpplint warnings with NOLINT comment | ||||
|   /** \deprecated Use: | ||||
|    * uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); | ||||
|    */ | ||||
|   uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) {  // NOLINT | ||||
|     return contiguousRange(&bgnBlock, &endBlock); | ||||
|   } | ||||
|  /** \deprecated Use: | ||||
|    * uint8_t SdFile::createContiguous(SdFile* dirFile, | ||||
|    *   const char* fileName, uint32_t size) | ||||
|    */ | ||||
|   uint8_t createContiguous(SdFile& dirFile,  // NOLINT | ||||
|     const char* fileName, uint32_t size) { | ||||
|     return createContiguous(&dirFile, fileName, size); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * \deprecated Use: | ||||
|    * static void SdFile::dateTimeCallback( | ||||
|    *   void (*dateTime)(uint16_t* date, uint16_t* time)); | ||||
|    */ | ||||
|   static void dateTimeCallback( | ||||
|     void (*dateTime)(uint16_t& date, uint16_t& time)) {  // NOLINT | ||||
|     oldDateTime_ = dateTime; | ||||
|     dateTime_ = dateTime ? oldToNew : 0; | ||||
|   } | ||||
|   /** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */ | ||||
|   uint8_t dirEntry(dir_t& dir) {return dirEntry(&dir);}  // NOLINT | ||||
|   /** \deprecated Use: | ||||
|    * uint8_t SdFile::makeDir(SdFile* dir, const char* dirName); | ||||
|    */ | ||||
|   uint8_t makeDir(SdFile& dir, const char* dirName) {  // NOLINT | ||||
|     return makeDir(&dir, dirName); | ||||
|   } | ||||
|   /** \deprecated Use: | ||||
|    * uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag); | ||||
|    */ | ||||
|   uint8_t open(SdFile& dirFile, // NOLINT | ||||
|     const char* fileName, uint8_t oflag) { | ||||
|     return open(&dirFile, fileName, oflag); | ||||
|   } | ||||
|   /** \deprecated  Do not use in new apps */ | ||||
|   uint8_t open(SdFile& dirFile, const char* fileName) {  // NOLINT | ||||
|     return open(dirFile, fileName, O_RDWR); | ||||
|   } | ||||
|   /** \deprecated Use: | ||||
|    * uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag); | ||||
|    */ | ||||
|   uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) {  // NOLINT | ||||
|     return open(&dirFile, index, oflag); | ||||
|   } | ||||
|   /** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */ | ||||
|   uint8_t openRoot(SdVolume& vol) {return openRoot(&vol);}  // NOLINT | ||||
|  | ||||
|   /** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */ | ||||
|   int8_t readDir(dir_t& dir) {return readDir(&dir);}  // NOLINT | ||||
|   /** \deprecated Use: | ||||
|    * static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName); | ||||
|    */ | ||||
|   static uint8_t remove(SdFile& dirFile, const char* fileName) {  // NOLINT | ||||
|     return remove(&dirFile, fileName); | ||||
|   } | ||||
| //------------------------------------------------------------------------------ | ||||
| // rest are private | ||||
|   SdFat() {} | ||||
|   /** \return a pointer to the Sd2Card object. */ | ||||
|   Sd2Card* card() {return &card_;} | ||||
|   bool chdir(bool set_cwd = false); | ||||
|   bool chdir(const char* path, bool set_cwd = false); | ||||
|   void chvol(); | ||||
|   void errorHalt(); | ||||
|   void errorHalt_P(PGM_P msg); | ||||
|   void errorHalt(char const *msg); | ||||
|   void errorPrint(); | ||||
|   void errorPrint_P(PGM_P msg); | ||||
|   void errorPrint(char const *msg); | ||||
|   bool exists(const char* name); | ||||
|   bool init(uint8_t sckRateID = SPI_FULL_SPEED, | ||||
|     uint8_t chipSelectPin = SD_CHIP_SELECT_PIN); | ||||
|   void initErrorHalt(); | ||||
|   void initErrorHalt(char const *msg); | ||||
|   void initErrorHalt_P(PGM_P msg); | ||||
|   void initErrorPrint(); | ||||
|   void initErrorPrint(char const *msg); | ||||
|   void initErrorPrint_P(PGM_P msg); | ||||
|   void ls(uint8_t flags = 0); | ||||
|   void ls(Print* pr, 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 &vol_;} | ||||
|   /** \return a pointer to the volume working directory. */ | ||||
|   SdBaseFile* vwd() {return &vwd_;} | ||||
|  private: | ||||
|   static void (*oldDateTime_)(uint16_t& date, uint16_t& time);  // NOLINT | ||||
|   static void oldToNew(uint16_t* date, uint16_t* time) { | ||||
|     uint16_t d; | ||||
|     uint16_t t; | ||||
|     oldDateTime_(d, t); | ||||
|     *date = d; | ||||
|     *time = t; | ||||
|   } | ||||
| #endif  // ALLOW_DEPRECATED_FUNCTIONS | ||||
|  private: | ||||
|   // bits defined in flags_ | ||||
|   // should be 0XF | ||||
|   static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC); | ||||
|   // available bits | ||||
|   static uint8_t const F_UNUSED = 0X30; | ||||
|   // use unbuffered SD read | ||||
|   static uint8_t const F_FILE_UNBUFFERED_READ = 0X40; | ||||
|   // sync of directory entry required | ||||
|   static uint8_t const F_FILE_DIR_DIRTY = 0X80; | ||||
|  | ||||
| // make sure F_OFLAG is ok | ||||
| #if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG) | ||||
| #error flags_ bits conflict | ||||
| #endif  // flags_ bits | ||||
|  | ||||
|   // private data | ||||
|   uint8_t   flags_;         // See above for definition of flags_ bits | ||||
|   uint8_t   type_;          // type of file see above for values | ||||
|   uint32_t  curCluster_;    // cluster for current file position | ||||
|   uint32_t  curPosition_;   // current file position in bytes from beginning | ||||
|   uint32_t  dirBlock_;      // SD block that contains directory entry for file | ||||
|   uint8_t   dirIndex_;      // index of entry in dirBlock 0 <= dirIndex_ <= 0XF | ||||
|   uint32_t  fileSize_;      // file size in bytes | ||||
|   uint32_t  firstCluster_;  // first cluster of file | ||||
|   SdVolume* vol_;           // volume where file is located | ||||
|  | ||||
|   // private functions | ||||
|   uint8_t addCluster(void); | ||||
|   uint8_t addDirCluster(void); | ||||
|   dir_t* cacheDirEntry(uint8_t action); | ||||
|   static void (*dateTime_)(uint16_t* date, uint16_t* time); | ||||
|   static uint8_t make83Name(const char* str, uint8_t* name); | ||||
|   uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags); | ||||
|   dir_t* readDirCache(void); | ||||
| }; | ||||
| //============================================================================== | ||||
| // 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 MasterBoot Record. */ | ||||
|   mbr_t    mbr; | ||||
|            /** Used to access to a cached FAT boot sector. */ | ||||
|   fbs_t    fbs; | ||||
| }; | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * \class SdVolume | ||||
|  * \brief Access FAT16 and FAT32 volumes on SD and SDHC cards. | ||||
|  */ | ||||
| class SdVolume { | ||||
|  public: | ||||
|   /** Create an instance of SdVolume */ | ||||
|   SdVolume(void) :allocSearchStart_(2), 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. | ||||
|    */ | ||||
|   static uint8_t* cacheClear(void) { | ||||
|     cacheFlush(); | ||||
|     cacheBlockNumber_ = 0XFFFFFFFF; | ||||
|     return cacheBuffer_.data; | ||||
|   } | ||||
|   /** | ||||
|    * 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. | ||||
|    */ | ||||
|   uint8_t init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);} | ||||
|   uint8_t init(Sd2Card* dev, uint8_t part); | ||||
|  | ||||
|   // inline functions that return volume info | ||||
|   /** \return The volume's cluster size in blocks. */ | ||||
|   uint8_t blocksPerCluster(void) const {return blocksPerCluster_;} | ||||
|   /** \return The number of blocks in one FAT. */ | ||||
|   uint32_t blocksPerFat(void)  const {return blocksPerFat_;} | ||||
|   /** \return The total number of clusters in the volume. */ | ||||
|   uint32_t clusterCount(void) const {return clusterCount_;} | ||||
|   /** \return The shift count required to multiply by blocksPerCluster. */ | ||||
|   uint8_t clusterSizeShift(void) const {return clusterSizeShift_;} | ||||
|   /** \return The logical block number for the start of file data. */ | ||||
|   uint32_t dataStartBlock(void) const {return dataStartBlock_;} | ||||
|   /** \return The number of FAT structures on the volume. */ | ||||
|   uint8_t fatCount(void) const {return fatCount_;} | ||||
|   /** \return The logical block number for the start of the first FAT. */ | ||||
|   uint32_t fatStartBlock(void) const {return fatStartBlock_;} | ||||
|   /** \return The FAT type of the volume. Values are 12, 16 or 32. */ | ||||
|   uint8_t fatType(void) const {return fatType_;} | ||||
|   /** \return The number of entries in the root directory for FAT16 volumes. */ | ||||
|   uint32_t rootDirEntryCount(void) const {return 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(void) const {return rootDirStart_;} | ||||
|   /** return a pointer to the Sd2Card object for this volume */ | ||||
|   static Sd2Card* sdCard(void) {return sdCard_;} | ||||
| //------------------------------------------------------------------------------ | ||||
| #if ALLOW_DEPRECATED_FUNCTIONS | ||||
|   // Deprecated functions  - suppress cpplint warnings with NOLINT comment | ||||
|   /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */ | ||||
|   uint8_t init(Sd2Card& dev) {return init(&dev);}  // NOLINT | ||||
|  | ||||
|   /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */ | ||||
|   uint8_t init(Sd2Card& dev, uint8_t part) {  // NOLINT | ||||
|     return init(&dev, part); | ||||
|   } | ||||
| #endif  // ALLOW_DEPRECATED_FUNCTIONS | ||||
| //------------------------------------------------------------------------------ | ||||
|   private: | ||||
|   // Allow SdFile access to SdVolume private data. | ||||
|   friend class SdFile; | ||||
|  | ||||
|   // value for action argument in cacheRawBlock to indicate read from cache | ||||
|   static uint8_t const CACHE_FOR_READ = 0; | ||||
|   // value for action argument in cacheRawBlock to indicate cache dirty | ||||
|   static uint8_t const CACHE_FOR_WRITE = 1; | ||||
|  | ||||
|   static cache_t cacheBuffer_;        // 512 byte cache for device blocks | ||||
|   static uint32_t cacheBlockNumber_;  // Logical number of block in the cache | ||||
|   static Sd2Card* sdCard_;            // Sd2Card object for cache | ||||
|   static uint8_t cacheDirty_;         // cacheFlush() will write block if true | ||||
|   static uint32_t cacheMirrorBlock_;  // block number for mirror FAT | ||||
| // | ||||
|   uint32_t allocSearchStart_;   // start cluster for alloc search | ||||
|   uint8_t blocksPerCluster_;    // cluster size in blocks | ||||
|   uint32_t blocksPerFat_;       // FAT size in blocks | ||||
|   uint32_t clusterCount_;       // clusters in one FAT | ||||
|   uint8_t clusterSizeShift_;    // shift to convert cluster count to block count | ||||
|   uint32_t dataStartBlock_;     // first data block number | ||||
|   uint8_t fatCount_;            // number of FATs on volume | ||||
|   uint32_t fatStartBlock_;      // start block for first FAT | ||||
|   uint8_t fatType_;             // volume type (12, 16, OR 32) | ||||
|   uint16_t rootDirEntryCount_;  // number of entries in FAT16 root dir | ||||
|   uint32_t rootDirStart_;       // root start block for FAT16, cluster for FAT32 | ||||
|   //---------------------------------------------------------------------------- | ||||
|   uint8_t allocContiguous(uint32_t count, uint32_t* curCluster); | ||||
|   uint8_t blockOfCluster(uint32_t position) const { | ||||
|           return (position >> 9) & (blocksPerCluster_ - 1);} | ||||
|   uint32_t clusterStartBlock(uint32_t cluster) const { | ||||
|            return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);} | ||||
|   uint32_t blockNumber(uint32_t cluster, uint32_t position) const { | ||||
|            return clusterStartBlock(cluster) + blockOfCluster(position);} | ||||
|   static uint8_t cacheFlush(void); | ||||
|   static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action); | ||||
|   static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;} | ||||
|   static uint8_t cacheZeroBlock(uint32_t blockNumber); | ||||
|   uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const; | ||||
|   uint8_t fatGet(uint32_t cluster, uint32_t* value) const; | ||||
|   uint8_t fatPut(uint32_t cluster, uint32_t value); | ||||
|   uint8_t fatPutEOC(uint32_t cluster) { | ||||
|     return fatPut(cluster, 0x0FFFFFFF); | ||||
|   } | ||||
|   uint8_t freeChain(uint32_t cluster); | ||||
|   uint8_t isEOC(uint32_t cluster) const { | ||||
|     return  cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN); | ||||
|   } | ||||
|   uint8_t readBlock(uint32_t block, uint8_t* dst) { | ||||
|     return sdCard_->readBlock(block, dst);} | ||||
|   uint8_t readData(uint32_t block, uint16_t offset, | ||||
|     uint16_t count, uint8_t* dst) { | ||||
|       return sdCard_->readData(block, offset, count, dst); | ||||
|   } | ||||
|   uint8_t writeBlock(uint32_t block, const uint8_t* dst) { | ||||
|     return sdCard_->writeBlock(block, dst); | ||||
|   } | ||||
|   Sd2Card card_; | ||||
|   SdVolume vol_; | ||||
|   SdBaseFile vwd_; | ||||
| }; | ||||
| #endif  // SdFat_h | ||||
|   | ||||
							
								
								
									
										108
									
								
								Marlin/SdFatConfig.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								Marlin/SdFatConfig.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| /* Arduino SdFat Library | ||||
|  * Copyright (C) 2009 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/>. | ||||
|  */ | ||||
| /** | ||||
|  * \file | ||||
|  * \brief configuration definitions | ||||
|  */ | ||||
| #ifndef SdFatConfig_h | ||||
| #define SdFatConfig_h | ||||
| #include <stdint.h> | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * To use multiple SD cards set USE_MULTIPLE_CARDS nonzero. | ||||
|  * | ||||
|  * Using multiple cards costs 400 - 500  bytes of flash. | ||||
|  * | ||||
|  * Each card requires about 550 bytes of SRAM so use of a Mega is recommended. | ||||
|  */ | ||||
| #define USE_MULTIPLE_CARDS 0 | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Call flush for endl if ENDL_CALLS_FLUSH is nonzero | ||||
|  * | ||||
|  * 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 SD 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 use of deprecated functions if ALLOW_DEPRECATED_FUNCTIONS is nonzero | ||||
|  */ | ||||
| #define ALLOW_DEPRECATED_FUNCTIONS 1 | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Allow FAT12 volumes if FAT12_SUPPORT is nonzero. | ||||
|  * FAT12 has not been well tested. | ||||
|  */ | ||||
| #define FAT12_SUPPORT 0 | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * SPI init rate for SD initialization commands. Must be 5 (F_CPU/64) | ||||
|  * or 6 (F_CPU/128). | ||||
|  */ | ||||
| #define SPI_SD_INIT_RATE 5 | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Set the SS pin high for hardware SPI.  If SS is chip select for another SPI | ||||
|  * device this will disable that device during the SD init phase. | ||||
|  */ | ||||
| #define SET_SPI_SS_HIGH 1 | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Define MEGA_SOFT_SPI nonzero to use software SPI on Mega Arduinos. | ||||
|  * Pins used are SS 10, MOSI 11, MISO 12, and SCK 13. | ||||
|  * | ||||
|  * MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used | ||||
|  * on Mega Arduinos.  Software SPI works well with GPS Shield V1.1 | ||||
|  * but many SD cards will fail with GPS Shield V1.0. | ||||
|  */ | ||||
| #define MEGA_SOFT_SPI 0 | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Set USE_SOFTWARE_SPI nonzero to always use software SPI. | ||||
|  */ | ||||
| #define USE_SOFTWARE_SPI 0 | ||||
| // define software SPI pins so Mega can use unmodified 168/328 shields | ||||
| /** Software SPI chip select pin for the SD */ | ||||
| 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 */ | ||||
| uint8_t const SOFT_SPI_MISO_PIN = 12; | ||||
| /** Software SPI Clock pin */ | ||||
| uint8_t const SOFT_SPI_SCK_PIN = 13; | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * The __cxa_pure_virtual function is an error handler that is invoked when | ||||
|  * a pure virtual function is called. | ||||
|  */ | ||||
| #define USE_CXA_PURE_VIRTUAL 1 | ||||
| #endif  // SdFatConfig_h | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										74
									
								
								Marlin/SdFatUtil.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								Marlin/SdFatUtil.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| /* Arduino SdFat Library | ||||
|  * Copyright (C) 2008 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 "SdFatUtil.h" | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Amount of free RAM | ||||
|  * \return The number of free bytes. | ||||
|  */ | ||||
| int SdFatUtil::FreeRam() { | ||||
|   extern int  __bss_end; | ||||
|   extern int* __brkval; | ||||
|   int free_memory; | ||||
|   if (reinterpret_cast<int>(__brkval) == 0) { | ||||
|     // if no heap use from end of bss section | ||||
|     free_memory = reinterpret_cast<int>(&free_memory) | ||||
|                   - reinterpret_cast<int>(&__bss_end); | ||||
|   } else { | ||||
|     // use from top of stack to heap | ||||
|     free_memory = reinterpret_cast<int>(&free_memory) | ||||
|                   - reinterpret_cast<int>(__brkval); | ||||
|   } | ||||
|   return free_memory; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** %Print a string in flash memory. | ||||
|  * | ||||
|  * \param[in] pr Print object for output. | ||||
|  * \param[in] str Pointer to string stored in flash memory. | ||||
|  */ | ||||
| void SdFatUtil::print_P(Print* pr, PGM_P str) { | ||||
|   for (uint8_t c; (c = pgm_read_byte(str)); str++) pr->write(c); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** %Print a string in flash memory followed by a CR/LF. | ||||
|  * | ||||
|  * \param[in] pr Print object for output. | ||||
|  * \param[in] str Pointer to string stored in flash memory. | ||||
|  */ | ||||
| void SdFatUtil::println_P(Print* pr, PGM_P str) { | ||||
|   print_P(pr, str); | ||||
|   pr->println(); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** %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(&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. | ||||
|  */ | ||||
| void SdFatUtil::SerialPrintln_P(PGM_P str) { | ||||
|   println_P(&Serial, str); | ||||
| } | ||||
| @@ -21,50 +21,26 @@ | ||||
| #define SdFatUtil_h | ||||
| /** | ||||
|  * \file | ||||
|  * Useful utility functions. | ||||
|  * \brief Useful utility functions. | ||||
|  */ | ||||
| #include <WProgram.h> | ||||
| #include <avr/pgmspace.h> | ||||
| #if ARDUINO < 100 | ||||
| #include <WProgram.h> | ||||
| #else  // ARDUINO | ||||
| #include <Arduino.h> | ||||
| #endif  // ARDUINO | ||||
| /** 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.*/ | ||||
| #define PgmPrintln(x) SerialPrintln_P(PSTR(x)) | ||||
| /** Defined so doxygen works for function definitions. */ | ||||
| #define NOINLINE __attribute__((noinline)) | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Return the number of bytes currently free in RAM. */ | ||||
| static int FreeRam(void) { | ||||
|   extern int  __bss_end; | ||||
|   extern int* __brkval; | ||||
|   int free_memory; | ||||
|   if (reinterpret_cast<int>(__brkval) == 0) { | ||||
|     // if no heap use from end of bss section | ||||
|     free_memory = reinterpret_cast<int>(&free_memory) | ||||
|                   - reinterpret_cast<int>(&__bss_end); | ||||
|   } else { | ||||
|     // use from top of stack to heap | ||||
|     free_memory = reinterpret_cast<int>(&free_memory) | ||||
|                   - reinterpret_cast<int>(__brkval); | ||||
|   } | ||||
|   return free_memory; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * %Print a string in flash memory to the serial port. | ||||
|  * | ||||
|  * \param[in] str Pointer to string stored in flash memory. | ||||
|  */ | ||||
| static NOINLINE void SerialPrint_P(PGM_P str) { | ||||
|   for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.print(c); | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * %Print a string in flash memory followed by a CR/LF. | ||||
|  * | ||||
|  * \param[in] str Pointer to string stored in flash memory. | ||||
|  */ | ||||
| static NOINLINE void SerialPrintln_P(PGM_P str) { | ||||
|   SerialPrint_P(str); | ||||
|   Serial.println(); | ||||
|  | ||||
| namespace SdFatUtil { | ||||
|   int FreeRam(); | ||||
|   void print_P(Print* pr, PGM_P str); | ||||
|   void println_P(Print* pr, PGM_P str); | ||||
|   void SerialPrint_P(PGM_P str); | ||||
|   void SerialPrintln_P(PGM_P str); | ||||
| } | ||||
|  | ||||
| using namespace SdFatUtil;  // NOLINT | ||||
| #endif  // #define SdFatUtil_h | ||||
|   | ||||
| @@ -1,202 +0,0 @@ | ||||
| /* Arduino SdFat Library | ||||
|  * Copyright (C) 2009 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/>. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
| \mainpage Arduino SdFat Library | ||||
| <CENTER>Copyright © 2009 by William Greiman | ||||
| </CENTER> | ||||
|  | ||||
| \section Intro Introduction | ||||
| The Arduino SdFat Library is a minimal implementation of FAT16 and FAT32 | ||||
| file systems on SD flash memory cards.  Standard SD and high capacity | ||||
| SDHC cards are supported. | ||||
|  | ||||
| The SdFat only supports short 8.3 names. | ||||
|  | ||||
| The main classes in SdFat are Sd2Card, SdVolume, and SdFile. | ||||
|  | ||||
| The Sd2Card class supports access to standard SD cards and SDHC cards.  Most | ||||
| applications will only need to call the Sd2Card::init() member function. | ||||
|  | ||||
| The SdVolume class supports FAT16 and FAT32 partitions.  Most applications | ||||
| will only need to call the SdVolume::init() member function. | ||||
|  | ||||
| The SdFile class provides file access functions such as open(), read(), | ||||
| remove(), write(), close() and sync(). This class supports access to the root | ||||
| directory and subdirectories. | ||||
|  | ||||
| A number of example are provided in the SdFat/examples folder.  These were | ||||
| developed to test SdFat and illustrate its use. | ||||
|  | ||||
| SdFat was developed for high speed data recording.  SdFat was used to implement | ||||
| an audio record/play class, WaveRP, for the Adafruit Wave Shield.  This | ||||
| application uses special Sd2Card calls to write to contiguous files in raw mode. | ||||
| These functions reduce write latency so that audio can be recorded with the | ||||
| small amount of RAM in the Arduino. | ||||
|  | ||||
| \section SDcard SD\SDHC Cards | ||||
|  | ||||
| Arduinos access SD cards using the cards SPI protocol.  PCs, Macs, and | ||||
| most consumer devices use the 4-bit parallel SD protocol.  A card that | ||||
| functions well on A PC or Mac may not work well on the Arduino. | ||||
|  | ||||
| Most cards have good SPI read performance but cards vary widely in SPI | ||||
| write performance.  Write performance is limited by how efficiently the | ||||
| card manages internal erase/remapping operations.  The Arduino cannot | ||||
| optimize writes to reduce erase operations because of its limit RAM. | ||||
|  | ||||
| SanDisk cards generally have good write performance.  They seem to have | ||||
| more internal RAM buffering than other cards and therefore can limit | ||||
| the number of flash erase operations that the Arduino forces due to its | ||||
| limited RAM. | ||||
|  | ||||
| \section Hardware Hardware Configuration | ||||
|  | ||||
| SdFat was developed using an | ||||
| <A HREF = "http://www.adafruit.com/"> Adafruit Industries</A>  | ||||
| <A HREF = "http://www.ladyada.net/make/waveshield/"> Wave Shield</A>. | ||||
|  | ||||
| The hardware interface to the SD card should not use a resistor based level | ||||
| shifter.  SdFat sets the SPI bus frequency to 8 MHz which results in signal | ||||
| rise times that are too slow for the edge detectors in many newer SD card | ||||
| controllers when resistor voltage dividers are used. | ||||
|  | ||||
| The 5 to 3.3 V level shifter for 5 V Arduinos should be IC based like the | ||||
| 74HC4050N based circuit shown in the file SdLevel.png.  The Adafruit Wave Shield | ||||
| uses a 74AHC125N.  Gravitech sells SD and MicroSD Card Adapters based on the | ||||
| 74LCX245. | ||||
|  | ||||
| If you are using a resistor based level shifter and are having problems try | ||||
| setting the SPI bus frequency to 4 MHz.  This can be done by using  | ||||
| card.init(SPI_HALF_SPEED) to initialize the SD card. | ||||
|  | ||||
| \section comment Bugs and Comments | ||||
|  | ||||
| If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net. | ||||
|  | ||||
| \section SdFatClass SdFat Usage | ||||
|  | ||||
| SdFat uses a slightly restricted form of short names. | ||||
| Only printable ASCII characters are supported. No characters with code point | ||||
| values greater than 127 are allowed.  Space is not allowed even though space | ||||
| was allowed in the API of early versions of DOS. | ||||
|  | ||||
| Short names are limited to 8 characters followed by an optional period (.) | ||||
| and extension of up to 3 characters.  The characters may be any combination | ||||
| of letters and digits.  The following special characters are also allowed: | ||||
|  | ||||
| $ % ' - _ @ ~ ` ! ( ) { } ^ # & | ||||
|  | ||||
| Short names are always converted to upper case and their original case | ||||
| value is lost. | ||||
|  | ||||
| \note | ||||
|   The Arduino Print class uses character | ||||
| at a time writes so it was necessary to use a \link SdFile::sync() sync() \endlink | ||||
| function to control when data is written to the SD card. | ||||
|  | ||||
| \par | ||||
| An application which writes to a file using \link Print::print() print()\endlink, | ||||
| \link Print::println() println() \endlink | ||||
| or \link SdFile::write write() \endlink must call \link SdFile::sync() sync() \endlink | ||||
| at the appropriate time to force data and directory information to be written | ||||
| to the SD Card.  Data and directory information are also written to the SD card | ||||
| when \link SdFile::close() close() \endlink is called. | ||||
|  | ||||
| \par | ||||
| Applications must use care calling \link SdFile::sync() sync() \endlink | ||||
| since 2048 bytes of I/O is required to update file and | ||||
| directory information.  This includes writing the current data block, reading | ||||
| the block that contains the directory entry for update, writing the directory | ||||
| block back and reading back the current data block. | ||||
|  | ||||
| It is possible to open a file with two or more instances of SdFile.  A file may | ||||
| be corrupted if data is written to the file by more than one instance of SdFile. | ||||
|  | ||||
| \section HowTo How to format SD Cards as FAT Volumes | ||||
|  | ||||
| You should use a freshly formatted SD card for best performance.  FAT | ||||
| file systems become slower if many files have been created and deleted. | ||||
| This is because the directory entry for a deleted file is marked as deleted, | ||||
| but is not deleted.  When a new file is created, these entries must be scanned | ||||
| before creating the file, a flaw in the FAT design.  Also files can become | ||||
| fragmented which causes reads and writes to be slower. | ||||
|  | ||||
| Microsoft operating systems support removable media formatted with a | ||||
| Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector | ||||
| in block zero. | ||||
|  | ||||
| Microsoft operating systems expect MBR formatted removable media | ||||
| to have only one partition. The first partition should be used. | ||||
|  | ||||
| Microsoft operating systems do not support partitioning SD flash cards. | ||||
| If you erase an SD card with a program like KillDisk, Most versions of | ||||
| Windows will format the card as a super floppy. | ||||
|  | ||||
| The best way to restore an SD card's format is to use SDFormatter | ||||
| which can be downloaded from: | ||||
|  | ||||
| http://www.sdcard.org/consumers/formatter/ | ||||
|  | ||||
| SDFormatter aligns flash erase boundaries with file | ||||
| system structures which reduces write latency and file system overhead. | ||||
|  | ||||
| SDFormatter does not have an option for FAT type so it may format | ||||
| small cards as FAT12. | ||||
|  | ||||
| After the MBR is restored by SDFormatter you may need to reformat small | ||||
| cards that have been formatted FAT12 to force the volume type to be FAT16. | ||||
|  | ||||
| If you reformat the SD card with an OS utility, choose a cluster size that | ||||
| will result in: | ||||
|  | ||||
| 4084 < CountOfClusters && CountOfClusters < 65525 | ||||
|  | ||||
| The volume will then be FAT16. | ||||
|  | ||||
| If you are formatting an SD card on OS X or Linux, be sure to use the first | ||||
| partition. Format this partition with a cluster count in above range. | ||||
|  | ||||
| \section  References References | ||||
|  | ||||
| Adafruit Industries: | ||||
|  | ||||
| http://www.adafruit.com/ | ||||
|  | ||||
| http://www.ladyada.net/make/waveshield/ | ||||
|  | ||||
| The Arduino site: | ||||
|  | ||||
| http://www.arduino.cc/ | ||||
|  | ||||
| For more information about FAT file systems see: | ||||
|  | ||||
| http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx | ||||
|  | ||||
| For information about using SD cards as SPI devices see: | ||||
|  | ||||
| http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf | ||||
|  | ||||
| The ATmega328 datasheet: | ||||
|  | ||||
| http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf | ||||
|   | ||||
|  | ||||
|  */   | ||||
							
								
								
									
										1215
									
								
								Marlin/SdFile.cpp
									
									
									
									
									
								
							
							
						
						
									
										1215
									
								
								Marlin/SdFile.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										42
									
								
								Marlin/SdFile.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								Marlin/SdFile.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| /* Arduino SdFat Library | ||||
|  * Copyright (C) 2009 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/>. | ||||
|  */ | ||||
| /** | ||||
|  * \file | ||||
|  * \brief SdFile class | ||||
|  */ | ||||
| #include "SdBaseFile.h" | ||||
| #ifndef SdFile_h | ||||
| #define SdFile_h | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * \class SdFile | ||||
|  * \brief SdBaseFile with Print. | ||||
|  */ | ||||
| class SdFile : public SdBaseFile, public Print { | ||||
|  public: | ||||
|   SdFile() {} | ||||
|   SdFile(const char* name, uint8_t oflag); | ||||
|   void write(uint8_t b); | ||||
|   int16_t write(const void* buf, uint16_t nbyte); | ||||
|   void write(const char* str); | ||||
|   void write_P(PGM_P str); | ||||
|   void writeln_P(PGM_P str); | ||||
| }; | ||||
| #endif  // SdFile_h | ||||
							
								
								
									
										237
									
								
								Marlin/SdInfo.h
									
									
									
									
									
								
							
							
						
						
									
										237
									
								
								Marlin/SdInfo.h
									
									
									
									
									
								
							| @@ -26,10 +26,10 @@ | ||||
| // Part 1 | ||||
| // Physical Layer | ||||
| // Simplified Specification | ||||
| // Version 2.00 | ||||
| // September 25, 2006 | ||||
| // Version 3.01 | ||||
| // May 18, 2010 | ||||
| // | ||||
| // www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf | ||||
| // http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs | ||||
| //------------------------------------------------------------------------------ | ||||
| // SD card commands | ||||
| /** GO_IDLE_STATE - init card in spi mode if CS low */ | ||||
| @@ -40,10 +40,14 @@ uint8_t const CMD8 = 0X08; | ||||
| uint8_t const CMD9 = 0X09; | ||||
| /** SEND_CID - read the card identification information (CID register) */ | ||||
| uint8_t const CMD10 = 0X0A; | ||||
| /** STOP_TRANSMISSION - end multiple block read sequence */ | ||||
| uint8_t const CMD12 = 0X0C; | ||||
| /** SEND_STATUS - read the card status register */ | ||||
| uint8_t const CMD13 = 0X0D; | ||||
| /** READ_BLOCK - read a single data block from the card */ | ||||
| /** READ_SINGLE_BLOCK - read a single data block from the card */ | ||||
| uint8_t const CMD17 = 0X11; | ||||
| /** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */ | ||||
| uint8_t const CMD18 = 0X12; | ||||
| /** WRITE_BLOCK - write a single data block to the card */ | ||||
| uint8_t const CMD24 = 0X18; | ||||
| /** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */ | ||||
| @@ -83,148 +87,187 @@ uint8_t const DATA_RES_MASK = 0X1F; | ||||
| /** write data accepted token */ | ||||
| uint8_t const DATA_RES_ACCEPTED = 0X05; | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Card IDentification (CID) register */ | ||||
| typedef struct CID { | ||||
|   // byte 0 | ||||
|   uint8_t mid;  // Manufacturer ID | ||||
|   /** Manufacturer ID */ | ||||
|   unsigned char mid; | ||||
|   // byte 1-2 | ||||
|   char oid[2];  // OEM/Application ID | ||||
|   /** OEM/Application ID */ | ||||
|   char oid[2]; | ||||
|   // byte 3-7 | ||||
|   char pnm[5];  // Product name | ||||
|   /** Product name */ | ||||
|   char pnm[5]; | ||||
|   // byte 8 | ||||
|   unsigned prv_m : 4;  // Product revision n.m | ||||
|   unsigned prv_n : 4; | ||||
|   /** Product revision least significant digit */ | ||||
|   unsigned char prv_m : 4; | ||||
|   /** Product revision most significant digit */ | ||||
|   unsigned char prv_n : 4; | ||||
|   // byte 9-12 | ||||
|   uint32_t psn;  // Product serial number | ||||
|   /** Product serial number */ | ||||
|   uint32_t psn; | ||||
|   // byte 13 | ||||
|   unsigned mdt_year_high : 4;  // Manufacturing date | ||||
|   unsigned reserved : 4; | ||||
|   /** Manufacturing date year low digit */ | ||||
|   unsigned char mdt_year_high : 4; | ||||
|   /** not used */ | ||||
|   unsigned char reserved : 4; | ||||
|   // byte 14 | ||||
|   unsigned mdt_month : 4; | ||||
|   unsigned mdt_year_low :4; | ||||
|   /** Manufacturing date month */ | ||||
|   unsigned char mdt_month : 4; | ||||
|   /** Manufacturing date year low digit */ | ||||
|   unsigned char mdt_year_low :4; | ||||
|   // byte 15 | ||||
|   unsigned always1 : 1; | ||||
|   unsigned crc : 7; | ||||
|   /** not used always 1 */ | ||||
|   unsigned char always1 : 1; | ||||
|   /** CRC7 checksum */ | ||||
|   unsigned char crc : 7; | ||||
| }cid_t; | ||||
| //------------------------------------------------------------------------------ | ||||
| // CSD for version 1.00 cards | ||||
| /** CSD for version 1.00 cards */ | ||||
| typedef struct CSDV1 { | ||||
|   // byte 0 | ||||
|   unsigned reserved1 : 6; | ||||
|   unsigned csd_ver : 2; | ||||
|   unsigned char reserved1 : 6; | ||||
|   unsigned char csd_ver : 2; | ||||
|   // byte 1 | ||||
|   uint8_t taac; | ||||
|   unsigned char taac; | ||||
|   // byte 2 | ||||
|   uint8_t nsac; | ||||
|   unsigned char nsac; | ||||
|   // byte 3 | ||||
|   uint8_t tran_speed; | ||||
|   unsigned char tran_speed; | ||||
|   // byte 4 | ||||
|   uint8_t ccc_high; | ||||
|   unsigned char ccc_high; | ||||
|   // byte 5 | ||||
|   unsigned read_bl_len : 4; | ||||
|   unsigned ccc_low : 4; | ||||
|   unsigned char read_bl_len : 4; | ||||
|   unsigned char ccc_low : 4; | ||||
|   // byte 6 | ||||
|   unsigned c_size_high : 2; | ||||
|   unsigned reserved2 : 2; | ||||
|   unsigned dsr_imp : 1; | ||||
|   unsigned read_blk_misalign :1; | ||||
|   unsigned write_blk_misalign : 1; | ||||
|   unsigned read_bl_partial : 1; | ||||
|   unsigned char c_size_high : 2; | ||||
|   unsigned char reserved2 : 2; | ||||
|   unsigned char dsr_imp : 1; | ||||
|   unsigned char read_blk_misalign :1; | ||||
|   unsigned char write_blk_misalign : 1; | ||||
|   unsigned char read_bl_partial : 1; | ||||
|   // byte 7 | ||||
|   uint8_t c_size_mid; | ||||
|   unsigned char c_size_mid; | ||||
|   // byte 8 | ||||
|   unsigned vdd_r_curr_max : 3; | ||||
|   unsigned vdd_r_curr_min : 3; | ||||
|   unsigned c_size_low :2; | ||||
|   unsigned char vdd_r_curr_max : 3; | ||||
|   unsigned char vdd_r_curr_min : 3; | ||||
|   unsigned char c_size_low :2; | ||||
|   // byte 9 | ||||
|   unsigned c_size_mult_high : 2; | ||||
|   unsigned vdd_w_cur_max : 3; | ||||
|   unsigned vdd_w_curr_min : 3; | ||||
|   unsigned char c_size_mult_high : 2; | ||||
|   unsigned char vdd_w_cur_max : 3; | ||||
|   unsigned char vdd_w_curr_min : 3; | ||||
|   // byte 10 | ||||
|   unsigned sector_size_high : 6; | ||||
|   unsigned erase_blk_en : 1; | ||||
|   unsigned c_size_mult_low : 1; | ||||
|   unsigned char sector_size_high : 6; | ||||
|   unsigned char erase_blk_en : 1; | ||||
|   unsigned char c_size_mult_low : 1; | ||||
|   // byte 11 | ||||
|   unsigned wp_grp_size : 7; | ||||
|   unsigned sector_size_low : 1; | ||||
|   unsigned char wp_grp_size : 7; | ||||
|   unsigned char sector_size_low : 1; | ||||
|   // byte 12 | ||||
|   unsigned write_bl_len_high : 2; | ||||
|   unsigned r2w_factor : 3; | ||||
|   unsigned reserved3 : 2; | ||||
|   unsigned wp_grp_enable : 1; | ||||
|   unsigned char write_bl_len_high : 2; | ||||
|   unsigned char r2w_factor : 3; | ||||
|   unsigned char reserved3 : 2; | ||||
|   unsigned char wp_grp_enable : 1; | ||||
|   // byte 13 | ||||
|   unsigned reserved4 : 5; | ||||
|   unsigned write_partial : 1; | ||||
|   unsigned write_bl_len_low : 2; | ||||
|   unsigned char reserved4 : 5; | ||||
|   unsigned char write_partial : 1; | ||||
|   unsigned char write_bl_len_low : 2; | ||||
|   // byte 14 | ||||
|   unsigned reserved5: 2; | ||||
|   unsigned file_format : 2; | ||||
|   unsigned tmp_write_protect : 1; | ||||
|   unsigned perm_write_protect : 1; | ||||
|   unsigned copy : 1; | ||||
|   unsigned file_format_grp : 1; | ||||
|   unsigned char reserved5: 2; | ||||
|   unsigned char file_format : 2; | ||||
|   unsigned char tmp_write_protect : 1; | ||||
|   unsigned char perm_write_protect : 1; | ||||
|   unsigned char copy : 1; | ||||
|   /** Indicates the file format on the card */ | ||||
|   unsigned char file_format_grp : 1; | ||||
|   // byte 15 | ||||
|   unsigned always1 : 1; | ||||
|   unsigned crc : 7; | ||||
|   unsigned char always1 : 1; | ||||
|   unsigned char crc : 7; | ||||
| }csd1_t; | ||||
| //------------------------------------------------------------------------------ | ||||
| // CSD for version 2.00 cards | ||||
| /** CSD for version 2.00 cards */ | ||||
| typedef struct CSDV2 { | ||||
|   // byte 0 | ||||
|   unsigned reserved1 : 6; | ||||
|   unsigned csd_ver : 2; | ||||
|   unsigned char reserved1 : 6; | ||||
|   unsigned char csd_ver : 2; | ||||
|   // byte 1 | ||||
|   uint8_t taac; | ||||
|   /** fixed to 0X0E */ | ||||
|   unsigned char taac; | ||||
|   // byte 2 | ||||
|   uint8_t nsac; | ||||
|   /** fixed to 0 */ | ||||
|   unsigned char nsac; | ||||
|   // byte 3 | ||||
|   uint8_t tran_speed; | ||||
|   unsigned char tran_speed; | ||||
|   // byte 4 | ||||
|   uint8_t ccc_high; | ||||
|   unsigned char ccc_high; | ||||
|   // byte 5 | ||||
|   unsigned read_bl_len : 4; | ||||
|   unsigned ccc_low : 4; | ||||
|   /** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */ | ||||
|   unsigned char read_bl_len : 4; | ||||
|   unsigned char ccc_low : 4; | ||||
|   // byte 6 | ||||
|   unsigned reserved2 : 4; | ||||
|   unsigned dsr_imp : 1; | ||||
|   unsigned read_blk_misalign :1; | ||||
|   unsigned write_blk_misalign : 1; | ||||
|   unsigned read_bl_partial : 1; | ||||
|   /** not used */ | ||||
|   unsigned char reserved2 : 4; | ||||
|   unsigned char dsr_imp : 1; | ||||
|   /** fixed to 0 */ | ||||
|   unsigned char read_blk_misalign :1; | ||||
|   /** fixed to 0 */ | ||||
|   unsigned char write_blk_misalign : 1; | ||||
|   /** fixed to 0 - no partial read */ | ||||
|   unsigned char read_bl_partial : 1; | ||||
|   // byte 7 | ||||
|   unsigned reserved3 : 2; | ||||
|   unsigned c_size_high : 6; | ||||
|   /** not used */ | ||||
|   unsigned char reserved3 : 2; | ||||
|   /** high part of card size */ | ||||
|   unsigned char c_size_high : 6; | ||||
|   // byte 8 | ||||
|   uint8_t c_size_mid; | ||||
|   /** middle part of card size */ | ||||
|   unsigned char c_size_mid; | ||||
|   // byte 9 | ||||
|   uint8_t c_size_low; | ||||
|   /** low part of card size */ | ||||
|   unsigned char c_size_low; | ||||
|   // byte 10 | ||||
|   unsigned sector_size_high : 6; | ||||
|   unsigned erase_blk_en : 1; | ||||
|   unsigned reserved4 : 1; | ||||
|   /** sector size is fixed at 64 KB */ | ||||
|   unsigned char sector_size_high : 6; | ||||
|   /** fixed to 1 - erase single is supported */ | ||||
|   unsigned char erase_blk_en : 1; | ||||
|   /** not used */ | ||||
|   unsigned char reserved4 : 1; | ||||
|   // byte 11 | ||||
|   unsigned wp_grp_size : 7; | ||||
|   unsigned sector_size_low : 1; | ||||
|   unsigned char wp_grp_size : 7; | ||||
|   /** sector size is fixed at 64 KB */ | ||||
|   unsigned char sector_size_low : 1; | ||||
|   // byte 12 | ||||
|   unsigned write_bl_len_high : 2; | ||||
|   unsigned r2w_factor : 3; | ||||
|   unsigned reserved5 : 2; | ||||
|   unsigned wp_grp_enable : 1; | ||||
|   /** write_bl_len fixed for 512 byte blocks */ | ||||
|   unsigned char write_bl_len_high : 2; | ||||
|   /** fixed value of 2 */ | ||||
|   unsigned char r2w_factor : 3; | ||||
|   /** not used */ | ||||
|   unsigned char reserved5 : 2; | ||||
|   /** fixed value of 0 - no write protect groups */ | ||||
|   unsigned char wp_grp_enable : 1; | ||||
|   // byte 13 | ||||
|   unsigned reserved6 : 5; | ||||
|   unsigned write_partial : 1; | ||||
|   unsigned write_bl_len_low : 2; | ||||
|   unsigned char reserved6 : 5; | ||||
|   /** always zero - no partial block read*/ | ||||
|   unsigned char write_partial : 1; | ||||
|   /** write_bl_len fixed for 512 byte blocks */ | ||||
|   unsigned char write_bl_len_low : 2; | ||||
|   // byte 14 | ||||
|   unsigned reserved7: 2; | ||||
|   unsigned file_format : 2; | ||||
|   unsigned tmp_write_protect : 1; | ||||
|   unsigned perm_write_protect : 1; | ||||
|   unsigned copy : 1; | ||||
|   unsigned file_format_grp : 1; | ||||
|   unsigned char reserved7: 2; | ||||
|   /** Do not use always 0 */ | ||||
|   unsigned char file_format : 2; | ||||
|   unsigned char tmp_write_protect : 1; | ||||
|   unsigned char perm_write_protect : 1; | ||||
|   unsigned char copy : 1; | ||||
|   /** Do not use always 0 */ | ||||
|   unsigned char file_format_grp : 1; | ||||
|   // byte 15 | ||||
|   unsigned always1 : 1; | ||||
|   unsigned crc : 7; | ||||
|   /** not used always 1 */ | ||||
|   unsigned char always1 : 1; | ||||
|   /** checksum */ | ||||
|   unsigned char crc : 7; | ||||
| }csd2_t; | ||||
| //------------------------------------------------------------------------------ | ||||
| // union of old and new style CSD register | ||||
| /** union of old and new style CSD register */ | ||||
| union csd_t { | ||||
|   csd1_t v1; | ||||
|   csd2_t v2; | ||||
|   | ||||
| @@ -17,23 +17,28 @@ | ||||
|  * along with the Arduino SdFat Library.  If not, see | ||||
|  * <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| #include "SdFat.h" | ||||
| #include "SdVolume.h" | ||||
| //------------------------------------------------------------------------------ | ||||
| #if !USE_MULTIPLE_CARDS | ||||
| // raw block cache | ||||
| // init cacheBlockNumber_to invalid SD block number | ||||
| uint32_t SdVolume::cacheBlockNumber_ = 0XFFFFFFFF; | ||||
| cache_t  SdVolume::cacheBuffer_;     // 512 byte cache for Sd2Card | ||||
| Sd2Card* SdVolume::sdCard_;          // pointer to SD card object | ||||
| uint8_t  SdVolume::cacheDirty_ = 0;  // cacheFlush() will write block if true | ||||
| uint32_t SdVolume::cacheMirrorBlock_ = 0;  // mirror  block for second FAT | ||||
| uint32_t SdVolume::cacheBlockNumber_;  // current block number | ||||
| cache_t  SdVolume::cacheBuffer_;       // 512 byte cache for Sd2Card | ||||
| Sd2Card* SdVolume::sdCard_;            // pointer to SD card object | ||||
| bool     SdVolume::cacheDirty_;        // cacheFlush() will write block if true | ||||
| uint32_t SdVolume::cacheMirrorBlock_;  // mirror  block for second FAT | ||||
| #endif  // USE_MULTIPLE_CARDS | ||||
| //------------------------------------------------------------------------------ | ||||
| // find a contiguous group of clusters | ||||
| uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { | ||||
| 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 = clusterCount_ + 1; | ||||
|  | ||||
|   // flag to save place to start next search | ||||
|   uint8_t setStart; | ||||
|   bool setStart; | ||||
|  | ||||
|   // set search start cluster | ||||
|   if (*curCluster) { | ||||
| @@ -47,25 +52,22 @@ uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { | ||||
|     bgnCluster = allocSearchStart_; | ||||
|  | ||||
|     // save next search start if one cluster | ||||
|     setStart = 1 == count; | ||||
|     setStart = count == 1; | ||||
|   } | ||||
|   // end of group | ||||
|   uint32_t endCluster = bgnCluster; | ||||
|  | ||||
|   // last cluster of FAT | ||||
|   uint32_t fatEnd = clusterCount_ + 1; | ||||
|   endCluster = bgnCluster; | ||||
|  | ||||
|   // search the FAT for free clusters | ||||
|   for (uint32_t n = 0;; n++, endCluster++) { | ||||
|     // can't find space checked all clusters | ||||
|     if (n >= clusterCount_) return false; | ||||
|     if (n >= clusterCount_) goto fail; | ||||
|  | ||||
|     // past end - start from beginning of FAT | ||||
|     if (endCluster > fatEnd) { | ||||
|       bgnCluster = endCluster = 2; | ||||
|     } | ||||
|     uint32_t f; | ||||
|     if (!fatGet(endCluster, &f)) return false; | ||||
|     if (!fatGet(endCluster, &f)) goto fail; | ||||
|  | ||||
|     if (f != 0) { | ||||
|       // cluster in use try next cluster as bgnCluster | ||||
| @@ -76,16 +78,16 @@ uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { | ||||
|     } | ||||
|   } | ||||
|   // mark end of chain | ||||
|   if (!fatPutEOC(endCluster)) return false; | ||||
|   if (!fatPutEOC(endCluster)) goto fail; | ||||
|  | ||||
|   // link clusters | ||||
|   while (endCluster > bgnCluster) { | ||||
|     if (!fatPut(endCluster - 1, endCluster)) return false; | ||||
|     if (!fatPut(endCluster - 1, endCluster)) goto fail; | ||||
|     endCluster--; | ||||
|   } | ||||
|   if (*curCluster != 0) { | ||||
|     // connect chains | ||||
|     if (!fatPut(*curCluster, bgnCluster)) return false; | ||||
|     if (!fatPut(*curCluster, bgnCluster)) goto fail; | ||||
|   } | ||||
|   // return first cluster number to caller | ||||
|   *curCluster = bgnCluster; | ||||
| @@ -94,66 +96,87 @@ uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { | ||||
|   if (setStart) allocSearchStart_ = bgnCluster + 1; | ||||
|  | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| uint8_t SdVolume::cacheFlush(void) { | ||||
| bool SdVolume::cacheFlush() { | ||||
|   if (cacheDirty_) { | ||||
|     if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) { | ||||
|       return false; | ||||
|       goto fail; | ||||
|     } | ||||
|     // mirror FAT tables | ||||
|     if (cacheMirrorBlock_) { | ||||
|       if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) { | ||||
|         return false; | ||||
|         goto fail; | ||||
|       } | ||||
|       cacheMirrorBlock_ = 0; | ||||
|     } | ||||
|     cacheDirty_ = 0; | ||||
|   } | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) { | ||||
| bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) { | ||||
|   if (cacheBlockNumber_ != blockNumber) { | ||||
|     if (!cacheFlush()) return false; | ||||
|     if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false; | ||||
|     if (!cacheFlush()) goto fail; | ||||
|     if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail; | ||||
|     cacheBlockNumber_ = blockNumber; | ||||
|   } | ||||
|   cacheDirty_ |= action; | ||||
|   if (dirty) cacheDirty_ = true; | ||||
|   return true; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| // cache a zero block for blockNumber | ||||
| uint8_t SdVolume::cacheZeroBlock(uint32_t blockNumber) { | ||||
|   if (!cacheFlush()) return false; | ||||
|  | ||||
|   // loop take less flash than memset(cacheBuffer_.data, 0, 512); | ||||
|   for (uint16_t i = 0; i < 512; i++) { | ||||
|     cacheBuffer_.data[i] = 0; | ||||
|   } | ||||
|   cacheBlockNumber_ = blockNumber; | ||||
|   cacheSetDirty(); | ||||
|   return true; | ||||
|  fail: | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| // return the size in bytes of a cluster chain | ||||
| uint8_t SdVolume::chainSize(uint32_t cluster, uint32_t* size) const { | ||||
| bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) { | ||||
|   uint32_t s = 0; | ||||
|   do { | ||||
|     if (!fatGet(cluster, &cluster)) return false; | ||||
|     if (!fatGet(cluster, &cluster)) goto fail; | ||||
|     s += 512UL << clusterSizeShift_; | ||||
|   } while (!isEOC(cluster)); | ||||
|   *size = s; | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| // Fetch a FAT entry | ||||
| uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const { | ||||
|   if (cluster > (clusterCount_ + 1)) return false; | ||||
|   uint32_t lba = fatStartBlock_; | ||||
|   lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7; | ||||
| bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) { | ||||
|   uint32_t lba; | ||||
|   if (cluster > (clusterCount_ + 1)) goto fail; | ||||
|   if (FAT12_SUPPORT && fatType_ == 12) { | ||||
|     uint16_t index = cluster; | ||||
|     index += index >> 1; | ||||
|     lba = fatStartBlock_ + (index >> 9); | ||||
|     if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; | ||||
|     index &= 0X1FF; | ||||
|     uint16_t tmp = cacheBuffer_.data[index]; | ||||
|     index++; | ||||
|     if (index == 512) { | ||||
|       if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail; | ||||
|       index = 0; | ||||
|     } | ||||
|     tmp |= cacheBuffer_.data[index] << 8; | ||||
|     *value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF; | ||||
|     return true; | ||||
|   } | ||||
|   if (fatType_ == 16) { | ||||
|     lba = fatStartBlock_ + (cluster >> 8); | ||||
|   } else if (fatType_ == 32) { | ||||
|     lba = fatStartBlock_ + (cluster >> 7); | ||||
|   } else { | ||||
|     goto fail; | ||||
|   } | ||||
|   if (lba != cacheBlockNumber_) { | ||||
|     if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false; | ||||
|     if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; | ||||
|   } | ||||
|   if (fatType_ == 16) { | ||||
|     *value = cacheBuffer_.fat16[cluster & 0XFF]; | ||||
| @@ -161,56 +184,127 @@ uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const { | ||||
|     *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK; | ||||
|   } | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| // Store a FAT entry | ||||
| uint8_t SdVolume::fatPut(uint32_t cluster, uint32_t value) { | ||||
| bool SdVolume::fatPut(uint32_t cluster, uint32_t value) { | ||||
|   uint32_t lba; | ||||
|   // error if reserved cluster | ||||
|   if (cluster < 2) return false; | ||||
|   if (cluster < 2) goto fail; | ||||
|  | ||||
|   // error if not in FAT | ||||
|   if (cluster > (clusterCount_ + 1)) return false; | ||||
|   if (cluster > (clusterCount_ + 1)) goto fail; | ||||
|  | ||||
|   // calculate block address for entry | ||||
|   uint32_t lba = fatStartBlock_; | ||||
|   lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7; | ||||
|  | ||||
|   if (lba != cacheBlockNumber_) { | ||||
|     if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false; | ||||
|   if (FAT12_SUPPORT && fatType_ == 12) { | ||||
|     uint16_t index = cluster; | ||||
|     index += index >> 1; | ||||
|     lba = fatStartBlock_ + (index >> 9); | ||||
|     if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; | ||||
|     // mirror second FAT | ||||
|     if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; | ||||
|     index &= 0X1FF; | ||||
|     uint8_t tmp = value; | ||||
|     if (cluster & 1) { | ||||
|       tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4; | ||||
|     } | ||||
|     cacheBuffer_.data[index] = tmp; | ||||
|     index++; | ||||
|     if (index == 512) { | ||||
|       lba++; | ||||
|       index = 0; | ||||
|       if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; | ||||
|       // mirror second FAT | ||||
|       if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; | ||||
|     } | ||||
|     tmp = value >> 4; | ||||
|     if (!(cluster & 1)) { | ||||
|       tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4; | ||||
|     } | ||||
|     cacheBuffer_.data[index] = tmp; | ||||
|     return true; | ||||
|   } | ||||
|   if (fatType_ == 16) { | ||||
|     lba = fatStartBlock_ + (cluster >> 8); | ||||
|   } else if (fatType_ == 32) { | ||||
|     lba = fatStartBlock_ + (cluster >> 7); | ||||
|   } else { | ||||
|     goto fail; | ||||
|   } | ||||
|   if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; | ||||
|   // store entry | ||||
|   if (fatType_ == 16) { | ||||
|     cacheBuffer_.fat16[cluster & 0XFF] = value; | ||||
|   } else { | ||||
|     cacheBuffer_.fat32[cluster & 0X7F] = value; | ||||
|   } | ||||
|   cacheSetDirty(); | ||||
|  | ||||
|   // mirror second FAT | ||||
|   if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| // free a cluster chain | ||||
| uint8_t SdVolume::freeChain(uint32_t cluster) { | ||||
| bool SdVolume::freeChain(uint32_t cluster) { | ||||
|   uint32_t next; | ||||
|  | ||||
|   // clear free cluster location | ||||
|   allocSearchStart_ = 2; | ||||
|  | ||||
|   do { | ||||
|     uint32_t next; | ||||
|     if (!fatGet(cluster, &next)) return false; | ||||
|     if (!fatGet(cluster, &next)) goto fail; | ||||
|  | ||||
|     // free cluster | ||||
|     if (!fatPut(cluster, 0)) return false; | ||||
|     if (!fatPut(cluster, 0)) goto fail; | ||||
|  | ||||
|     cluster = next; | ||||
|   } while (!isEOC(cluster)); | ||||
|  | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   return false; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** | ||||
|  * Initialize a FAT volume. | ||||
| /** Volume free space in clusters. | ||||
|  * | ||||
|  * \return Count of free clusters for success or -1 if an error occurs. | ||||
|  */ | ||||
| int32_t SdVolume::freeClusterCount() { | ||||
|   uint32_t free = 0; | ||||
|   uint16_t n; | ||||
|   uint32_t todo = clusterCount_ + 2; | ||||
|  | ||||
|   if (fatType_ == 16) { | ||||
|     n = 256; | ||||
|   } else if (fatType_ == 32) { | ||||
|     n = 128; | ||||
|   } else { | ||||
|     // put FAT12 here | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) { | ||||
|     if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1; | ||||
|     if (todo < n) n = todo; | ||||
|     if (fatType_ == 16) { | ||||
|       for (uint16_t i = 0; i < n; i++) { | ||||
|         if (cacheBuffer_.fat16[i] == 0) free++; | ||||
|       } | ||||
|     } else { | ||||
|       for (uint16_t i = 0; i < n; i++) { | ||||
|         if (cacheBuffer_.fat32[i] == 0) free++; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return free; | ||||
| } | ||||
| //------------------------------------------------------------------------------ | ||||
| /** Initialize a FAT volume. | ||||
|  * | ||||
|  * \param[in] dev The SD card where the volume is located. | ||||
|  * | ||||
| @@ -224,58 +318,66 @@ uint8_t SdVolume::freeChain(uint32_t cluster) { | ||||
|  * failure include not finding a valid partition, not finding a valid | ||||
|  * FAT file system in the specified partition or an I/O error. | ||||
|  */ | ||||
| uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) { | ||||
| bool SdVolume::init(Sd2Card* dev, uint8_t part) { | ||||
|   uint32_t totalBlocks; | ||||
|   uint32_t volumeStartBlock = 0; | ||||
|   fat32_boot_t* fbs; | ||||
|  | ||||
|   sdCard_ = dev; | ||||
|   fatType_ = 0; | ||||
|   allocSearchStart_ = 2; | ||||
|   cacheDirty_ = 0;  // cacheFlush() will write block if true | ||||
|   cacheMirrorBlock_ = 0; | ||||
|   cacheBlockNumber_ = 0XFFFFFFFF; | ||||
|  | ||||
|   // if part == 0 assume super floppy with FAT boot sector in block zero | ||||
|   // if part > 0 assume mbr volume with partition table | ||||
|   if (part) { | ||||
|     if (part > 4)return false; | ||||
|     if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false; | ||||
|     if (part > 4)goto fail; | ||||
|     if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; | ||||
|     part_t* p = &cacheBuffer_.mbr.part[part-1]; | ||||
|     if ((p->boot & 0X7F) !=0  || | ||||
|       p->totalSectors < 100 || | ||||
|       p->firstSector == 0) { | ||||
|       // not a valid partition | ||||
|       return false; | ||||
|       goto fail; | ||||
|     } | ||||
|     volumeStartBlock = p->firstSector; | ||||
|   } | ||||
|   if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false; | ||||
|   bpb_t* bpb = &cacheBuffer_.fbs.bpb; | ||||
|   if (bpb->bytesPerSector != 512 || | ||||
|     bpb->fatCount == 0 || | ||||
|     bpb->reservedSectorCount == 0 || | ||||
|     bpb->sectorsPerCluster == 0) { | ||||
|   if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; | ||||
|   fbs = &cacheBuffer_.fbs32; | ||||
|   if (fbs->bytesPerSector != 512 || | ||||
|     fbs->fatCount == 0 || | ||||
|     fbs->reservedSectorCount == 0 || | ||||
|     fbs->sectorsPerCluster == 0) { | ||||
|        // not valid FAT volume | ||||
|       return false; | ||||
|       goto fail; | ||||
|   } | ||||
|   fatCount_ = bpb->fatCount; | ||||
|   blocksPerCluster_ = bpb->sectorsPerCluster; | ||||
|  | ||||
|   fatCount_ = fbs->fatCount; | ||||
|   blocksPerCluster_ = fbs->sectorsPerCluster; | ||||
|   // determine shift that is same as multiply by blocksPerCluster_ | ||||
|   clusterSizeShift_ = 0; | ||||
|   while (blocksPerCluster_ != (1 << clusterSizeShift_)) { | ||||
|     // error if not power of 2 | ||||
|     if (clusterSizeShift_++ > 7) return false; | ||||
|     if (clusterSizeShift_++ > 7) goto fail; | ||||
|   } | ||||
|   blocksPerFat_ = bpb->sectorsPerFat16 ? | ||||
|                     bpb->sectorsPerFat16 : bpb->sectorsPerFat32; | ||||
|   blocksPerFat_ = fbs->sectorsPerFat16 ? | ||||
|                     fbs->sectorsPerFat16 : fbs->sectorsPerFat32; | ||||
|  | ||||
|   fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount; | ||||
|   fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount; | ||||
|  | ||||
|   // count for FAT16 zero for FAT32 | ||||
|   rootDirEntryCount_ = bpb->rootDirEntryCount; | ||||
|   rootDirEntryCount_ = fbs->rootDirEntryCount; | ||||
|  | ||||
|   // directory start for FAT16 dataStart for FAT32 | ||||
|   rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_; | ||||
|   rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_; | ||||
|  | ||||
|   // data start for FAT16 and FAT32 | ||||
|   dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511)/512); | ||||
|   dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512); | ||||
|  | ||||
|   // total blocks for FAT16 or FAT32 | ||||
|   uint32_t totalBlocks = bpb->totalSectors16 ? | ||||
|                            bpb->totalSectors16 : bpb->totalSectors32; | ||||
|   totalBlocks = fbs->totalSectors16 ? | ||||
|                            fbs->totalSectors16 : fbs->totalSectors32; | ||||
|   // total data blocks | ||||
|   clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock); | ||||
|  | ||||
| @@ -285,11 +387,15 @@ uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) { | ||||
|   // FAT type is determined by cluster count | ||||
|   if (clusterCount_ < 4085) { | ||||
|     fatType_ = 12; | ||||
|     if (!FAT12_SUPPORT) goto fail; | ||||
|   } else if (clusterCount_ < 65525) { | ||||
|     fatType_ = 16; | ||||
|   } else { | ||||
|     rootDirStart_ = bpb->fat32RootCluster; | ||||
|     rootDirStart_ = fbs->fat32RootCluster; | ||||
|     fatType_ = 32; | ||||
|   } | ||||
|   return true; | ||||
|  | ||||
|  fail: | ||||
|   return false; | ||||
| } | ||||
|   | ||||
							
								
								
									
										211
									
								
								Marlin/SdVolume.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								Marlin/SdVolume.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,211 @@ | ||||
| /* Arduino SdFat Library | ||||
|  * Copyright (C) 2009 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 SdVolume_h | ||||
| #define SdVolume_h | ||||
| /** | ||||
|  * \file | ||||
|  * \brief SdVolume class | ||||
|  */ | ||||
| #include "SdFatConfig.h" | ||||
| #include "Sd2Card.h" | ||||
| #include "SdFatStructs.h" | ||||
|  | ||||
| //============================================================================== | ||||
| // 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. | ||||
|  */ | ||||
| class SdVolume { | ||||
|  public: | ||||
|   /** Create an instance of SdVolume */ | ||||
|   SdVolume() : 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 (!cacheFlush()) return 0; | ||||
|     cacheBlockNumber_ = 0XFFFFFFFF; | ||||
|     return &cacheBuffer_; | ||||
|   } | ||||
|   /** 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 blocksPerCluster_;} | ||||
|   /** \return The number of blocks in one FAT. */ | ||||
|   uint32_t blocksPerFat()  const {return blocksPerFat_;} | ||||
|   /** \return The total number of clusters in the volume. */ | ||||
|   uint32_t clusterCount() const {return clusterCount_;} | ||||
|   /** \return The shift count required to multiply by blocksPerCluster. */ | ||||
|   uint8_t clusterSizeShift() const {return clusterSizeShift_;} | ||||
|   /** \return The logical block number for the start of file data. */ | ||||
|   uint32_t dataStartBlock() const {return dataStartBlock_;} | ||||
|   /** \return The number of FAT structures on the volume. */ | ||||
|   uint8_t fatCount() const {return fatCount_;} | ||||
|   /** \return The logical block number for the start of the first FAT. */ | ||||
|   uint32_t fatStartBlock() const {return fatStartBlock_;} | ||||
|   /** \return The FAT type of the volume. Values are 12, 16 or 32. */ | ||||
|   uint8_t fatType() const {return fatType_;} | ||||
|   int32_t freeClusterCount(); | ||||
|   /** \return The number of entries in the root directory for FAT16 volumes. */ | ||||
|   uint32_t rootDirEntryCount() const {return 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 rootDirStart_;} | ||||
|   /** Sd2Card object for this volume | ||||
|    * \return pointer to Sd2Card object. | ||||
|    */ | ||||
|   Sd2Card* sdCard() {return sdCard_;} | ||||
|   /** 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 SdBaseFile access to SdVolume private data. | ||||
|   friend class SdBaseFile; | ||||
|  | ||||
|   // value for dirty argument in cacheRawBlock to indicate read from cache | ||||
|   static bool const CACHE_FOR_READ = false; | ||||
|   // value for dirty argument in cacheRawBlock to indicate write to cache | ||||
|   static bool const CACHE_FOR_WRITE = true; | ||||
|  | ||||
| #if USE_MULTIPLE_CARDS | ||||
|   cache_t cacheBuffer_;        // 512 byte cache for device blocks | ||||
|   uint32_t cacheBlockNumber_;  // Logical number of block in the cache | ||||
|   Sd2Card* sdCard_;            // Sd2Card object for cache | ||||
|   bool cacheDirty_;            // cacheFlush() will write block if true | ||||
|   uint32_t cacheMirrorBlock_;  // block number for mirror FAT | ||||
| #else  // USE_MULTIPLE_CARDS | ||||
|   static cache_t cacheBuffer_;        // 512 byte cache for device blocks | ||||
|   static uint32_t cacheBlockNumber_;  // Logical number of block in the cache | ||||
|   static Sd2Card* sdCard_;            // Sd2Card object for cache | ||||
|   static bool cacheDirty_;            // cacheFlush() will write block if true | ||||
|   static uint32_t cacheMirrorBlock_;  // block number for mirror FAT | ||||
| #endif  // USE_MULTIPLE_CARDS | ||||
|   uint32_t allocSearchStart_;   // start cluster for alloc search | ||||
|   uint8_t blocksPerCluster_;    // cluster size in blocks | ||||
|   uint32_t blocksPerFat_;       // FAT size in blocks | ||||
|   uint32_t clusterCount_;       // clusters in one FAT | ||||
|   uint8_t clusterSizeShift_;    // shift to convert cluster count to block count | ||||
|   uint32_t dataStartBlock_;     // first data block number | ||||
|   uint8_t fatCount_;            // number of FATs on volume | ||||
|   uint32_t fatStartBlock_;      // start block for first FAT | ||||
|   uint8_t fatType_;             // volume type (12, 16, OR 32) | ||||
|   uint16_t rootDirEntryCount_;  // number of entries in FAT16 root dir | ||||
|   uint32_t rootDirStart_;       // root start block for FAT16, cluster for FAT32 | ||||
|   //---------------------------------------------------------------------------- | ||||
|   bool allocContiguous(uint32_t count, uint32_t* curCluster); | ||||
|   uint8_t blockOfCluster(uint32_t position) const { | ||||
|           return (position >> 9) & (blocksPerCluster_ - 1);} | ||||
|   uint32_t clusterStartBlock(uint32_t cluster) const { | ||||
|            return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);} | ||||
|   uint32_t blockNumber(uint32_t cluster, uint32_t position) const { | ||||
|            return clusterStartBlock(cluster) + blockOfCluster(position);} | ||||
|   cache_t *cache() {return &cacheBuffer_;} | ||||
|   uint32_t cacheBlockNumber() {return cacheBlockNumber_;} | ||||
| #if USE_MULTIPLE_CARDS | ||||
|   bool cacheFlush(); | ||||
|   bool cacheRawBlock(uint32_t blockNumber, bool dirty); | ||||
| #else  // USE_MULTIPLE_CARDS | ||||
|   static bool cacheFlush(); | ||||
|   static bool cacheRawBlock(uint32_t blockNumber, bool dirty); | ||||
| #endif  // USE_MULTIPLE_CARDS | ||||
|   // used by SdBaseFile write to assign cache to SD location | ||||
|   void cacheSetBlockNumber(uint32_t blockNumber, bool dirty) { | ||||
|     cacheDirty_ = dirty; | ||||
|     cacheBlockNumber_  = blockNumber; | ||||
|   } | ||||
|   void cacheSetDirty() {cacheDirty_ |= CACHE_FOR_WRITE;} | ||||
|   bool chainSize(uint32_t beginCluster, uint32_t* size); | ||||
|   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 { | ||||
|     if (FAT12_SUPPORT && fatType_ == 12) return  cluster >= FAT12EOC_MIN; | ||||
|     if (fatType_ == 16) return cluster >= FAT16EOC_MIN; | ||||
|     return  cluster >= FAT32EOC_MIN; | ||||
|   } | ||||
|   bool readBlock(uint32_t block, uint8_t* dst) { | ||||
|     return sdCard_->readBlock(block, dst);} | ||||
|   bool writeBlock(uint32_t block, const uint8_t* dst) { | ||||
|     return sdCard_->writeBlock(block, dst); | ||||
|   } | ||||
| //------------------------------------------------------------------------------ | ||||
|   // Deprecated functions  - suppress cpplint warnings with NOLINT comment | ||||
| #if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN) | ||||
|  public: | ||||
|   /** \deprecated Use: bool SdVolume::init(Sd2Card* dev); | ||||
|    * \param[in] dev The SD card where the volume is located. | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   bool init(Sd2Card& dev) {return init(&dev);}  // NOLINT | ||||
|   /** \deprecated Use: bool SdVolume::init(Sd2Card* dev, uint8_t vol); | ||||
|    * \param[in] dev The SD card where the volume is located. | ||||
|    * \param[in] part The partition to be used. | ||||
|    * \return true for success or false for failure. | ||||
|    */ | ||||
|   bool init(Sd2Card& dev, uint8_t part) {  // NOLINT | ||||
|     return init(&dev, part); | ||||
|   } | ||||
| #endif  // ALLOW_DEPRECATED_FUNCTIONS | ||||
| }; | ||||
| #endif  // SdVolume | ||||
| @@ -3,6 +3,7 @@ | ||||
|  | ||||
| #ifdef SDSUPPORT | ||||
|   | ||||
|  | ||||
| #include "SdFat.h" | ||||
|  | ||||
| class CardReader | ||||
|   | ||||
		Reference in New Issue
	
	Block a user