Bring in SdFat lib, turn on sd config in GUI Slice
This commit is contained in:
parent
aabfb0bd6b
commit
450c4aeb9c
|
@ -15,7 +15,8 @@ A debug console and configuration shield for serial TTL muxers. See the ```muxer
|
||||||
|
|
||||||
These librarires are used by the project and contained in the ```src/``` folder local to the project.
|
These librarires are used by the project and contained in the ```src/``` folder local to the project.
|
||||||
|
|
||||||
- [GUIslice](https://github.com/ImpulseAdventure/GUIslice)
|
- [GUIslice 0.15](https://github.com/ImpulseAdventure/GUIslice)
|
||||||
|
- [SdFat 1.1.4](https://github.com/greiman/SdFat)
|
||||||
|
|
||||||
### External
|
### External
|
||||||
|
|
||||||
|
|
40
hardware/_controller/src/SdFat/BlockDriver.h
Normal file
40
hardware/_controller/src/SdFat/BlockDriver.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief Define block driver.
|
||||||
|
*/
|
||||||
|
#ifndef BlockDriver_h
|
||||||
|
#define BlockDriver_h
|
||||||
|
#include "FatLib/BaseBlockDriver.h"
|
||||||
|
#include "SdCard/SdSpiCard.h"
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** typedef for BlockDriver */
|
||||||
|
#if ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
|
||||||
|
typedef BaseBlockDriver BlockDriver;
|
||||||
|
#else // ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
|
||||||
|
typedef SdSpiCard BlockDriver;
|
||||||
|
#endif // ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
|
||||||
|
#endif // BlockDriver_h
|
249
hardware/_controller/src/SdFat/FatLib/ArduinoFiles.h
Normal file
249
hardware/_controller/src/SdFat/FatLib/ArduinoFiles.h
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief PrintFile class
|
||||||
|
*/
|
||||||
|
#ifndef ArduinoFiles_h
|
||||||
|
#define ArduinoFiles_h
|
||||||
|
#include "FatLibConfig.h"
|
||||||
|
#if ENABLE_ARDUINO_FEATURES
|
||||||
|
#include "FatFile.h"
|
||||||
|
#include <limits.h>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Arduino SD.h style flag for open for read. */
|
||||||
|
#define FILE_READ O_RDONLY
|
||||||
|
/** Arduino SD.h style flag for open at EOF for read/write with create. */
|
||||||
|
#define FILE_WRITE (O_RDWR | O_CREAT | O_AT_END)
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class PrintFile
|
||||||
|
* \brief FatFile with Print.
|
||||||
|
*/
|
||||||
|
class PrintFile : public FatFile, public Print {
|
||||||
|
public:
|
||||||
|
PrintFile() {}
|
||||||
|
/** Create a file object and open it in the current working directory.
|
||||||
|
*
|
||||||
|
* \param[in] path A path for a file to be opened.
|
||||||
|
*
|
||||||
|
* \param[in] oflag Values for \a oflag are constructed by a
|
||||||
|
* bitwise-inclusive OR of open flags. see
|
||||||
|
* FatFile::open(FatFile*, const char*, oflag_t).
|
||||||
|
*/
|
||||||
|
PrintFile(const char* path, oflag_t oflag) : FatFile(path, oflag) {}
|
||||||
|
#if DESTRUCTOR_CLOSES_FILE
|
||||||
|
~PrintFile() {}
|
||||||
|
#endif // DESTRUCTOR_CLOSES_FILE
|
||||||
|
using FatFile::clearWriteError;
|
||||||
|
using FatFile::getWriteError;
|
||||||
|
using FatFile::read;
|
||||||
|
using FatFile::write;
|
||||||
|
/** \return number of bytes available from the current position to EOF
|
||||||
|
* or INT_MAX if more than INT_MAX bytes are available.
|
||||||
|
*/
|
||||||
|
int available() {
|
||||||
|
uint32_t n = FatFile::available();
|
||||||
|
return n > INT_MAX ? INT_MAX : n;
|
||||||
|
}
|
||||||
|
/** Ensure that any bytes written to the file are saved to the SD card. */
|
||||||
|
void flush() {
|
||||||
|
FatFile::sync();
|
||||||
|
}
|
||||||
|
/** Return the next available byte without consuming it.
|
||||||
|
*
|
||||||
|
* \return The byte if no error and not at eof else -1;
|
||||||
|
*/
|
||||||
|
int peek() {
|
||||||
|
return FatFile::peek();
|
||||||
|
}
|
||||||
|
/** Read the next byte from a file.
|
||||||
|
*
|
||||||
|
* \return For success return the next byte in the file as an int.
|
||||||
|
* If an error occurs or end of file is reached return -1.
|
||||||
|
*/
|
||||||
|
// int read() {
|
||||||
|
// return FatFile::read();
|
||||||
|
// }
|
||||||
|
/** Write a byte to a file. Required by the Arduino Print class.
|
||||||
|
* \param[in] b the byte to be written.
|
||||||
|
* Use getWriteError to check for errors.
|
||||||
|
* \return 1 for success and 0 for failure.
|
||||||
|
*/
|
||||||
|
size_t write(uint8_t b) {
|
||||||
|
return FatFile::write(b);
|
||||||
|
}
|
||||||
|
/** Write data to an open file. Form required by Print.
|
||||||
|
*
|
||||||
|
* \note Data is moved to the cache but may not be written to the
|
||||||
|
* storage device until sync() is called.
|
||||||
|
*
|
||||||
|
* \param[in] buf Pointer to the location of the data to be written.
|
||||||
|
*
|
||||||
|
* \param[in] size Number of bytes to write.
|
||||||
|
*
|
||||||
|
* \return For success write() returns the number of bytes written, always
|
||||||
|
* \a nbyte. If an error occurs, write() returns -1. Possible errors
|
||||||
|
* include write() is called before a file has been opened, write is called
|
||||||
|
* for a read-only file, device is full, a corrupt file system or an
|
||||||
|
* I/O error.
|
||||||
|
*/
|
||||||
|
size_t write(const uint8_t *buf, size_t size) {
|
||||||
|
return FatFile::write(buf, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class File
|
||||||
|
* \brief Arduino SD.h style File API
|
||||||
|
*/
|
||||||
|
class File : public FatFile, public Stream {
|
||||||
|
public:
|
||||||
|
File() {}
|
||||||
|
/** Create a file object and open it in the current working directory.
|
||||||
|
*
|
||||||
|
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
|
||||||
|
*
|
||||||
|
* \param[in] oflag Values for \a oflag are constructed by a
|
||||||
|
* bitwise-inclusive OR of open flags. see
|
||||||
|
* FatFile::open(FatFile*, const char*, oflag_t).
|
||||||
|
*/
|
||||||
|
File(const char* path, oflag_t oflag) {
|
||||||
|
open(path, oflag);
|
||||||
|
}
|
||||||
|
using FatFile::clearWriteError;
|
||||||
|
using FatFile::getWriteError;
|
||||||
|
using FatFile::read;
|
||||||
|
using FatFile::write;
|
||||||
|
/** The parenthesis operator.
|
||||||
|
*
|
||||||
|
* \return true if a file is open.
|
||||||
|
*/
|
||||||
|
operator bool() {
|
||||||
|
return isOpen();
|
||||||
|
}
|
||||||
|
/** \return number of bytes available from the current position to EOF
|
||||||
|
* or INT_MAX if more than INT_MAX bytes are available.
|
||||||
|
*/
|
||||||
|
int available() {
|
||||||
|
uint32_t n = FatFile::available();
|
||||||
|
return n > INT_MAX ? INT_MAX : n;
|
||||||
|
}
|
||||||
|
/** Ensure that any bytes written to the file are saved to the SD card. */
|
||||||
|
void flush() {
|
||||||
|
FatFile::sync();
|
||||||
|
}
|
||||||
|
/** This function reports if the current file is a directory or not.
|
||||||
|
* \return true if the file is a directory.
|
||||||
|
*/
|
||||||
|
bool isDirectory() {
|
||||||
|
return isDir();
|
||||||
|
}
|
||||||
|
/** No longer implemented due to Long File Names.
|
||||||
|
*
|
||||||
|
* Use getName(char* name, size_t size).
|
||||||
|
* \return a pointer to replacement suggestion.
|
||||||
|
*/
|
||||||
|
const char* name() const {
|
||||||
|
return "use getName()";
|
||||||
|
}
|
||||||
|
/** Return the next available byte without consuming it.
|
||||||
|
*
|
||||||
|
* \return The byte if no error and not at eof else -1;
|
||||||
|
*/
|
||||||
|
int peek() {
|
||||||
|
return FatFile::peek();
|
||||||
|
}
|
||||||
|
/** \return the current file position. */
|
||||||
|
uint32_t position() {
|
||||||
|
return curPosition();
|
||||||
|
}
|
||||||
|
/** Opens the next file or folder in a directory.
|
||||||
|
*
|
||||||
|
* \param[in] oflag open oflag flags.
|
||||||
|
* \return a File object.
|
||||||
|
*/
|
||||||
|
File openNextFile(oflag_t oflag = O_RDONLY) {
|
||||||
|
File tmpFile;
|
||||||
|
tmpFile.openNext(this, oflag);
|
||||||
|
return tmpFile;
|
||||||
|
}
|
||||||
|
/** Read the next byte from a file.
|
||||||
|
*
|
||||||
|
* \return For success return the next byte in the file as an int.
|
||||||
|
* If an error occurs or end of file is reached return -1.
|
||||||
|
*/
|
||||||
|
int read() {
|
||||||
|
return FatFile::read();
|
||||||
|
}
|
||||||
|
/** Rewind a file if it is a directory */
|
||||||
|
void rewindDirectory() {
|
||||||
|
if (isDir()) {
|
||||||
|
rewind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Seek to a new position in the file, which must be between
|
||||||
|
* 0 and the size of the file (inclusive).
|
||||||
|
*
|
||||||
|
* \param[in] pos the new file position.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool seek(uint32_t pos) {
|
||||||
|
return seekSet(pos);
|
||||||
|
}
|
||||||
|
/** \return the file's size. */
|
||||||
|
uint32_t size() {
|
||||||
|
return fileSize();
|
||||||
|
}
|
||||||
|
/** Write a byte to a file. Required by the Arduino Print class.
|
||||||
|
* \param[in] b the byte to be written.
|
||||||
|
* Use getWriteError to check for errors.
|
||||||
|
* \return 1 for success and 0 for failure.
|
||||||
|
*/
|
||||||
|
size_t write(uint8_t b) {
|
||||||
|
return FatFile::write(b);
|
||||||
|
}
|
||||||
|
/** Write data to an open file. Form required by Print.
|
||||||
|
*
|
||||||
|
* \note Data is moved to the cache but may not be written to the
|
||||||
|
* storage device until sync() is called.
|
||||||
|
*
|
||||||
|
* \param[in] buf Pointer to the location of the data to be written.
|
||||||
|
*
|
||||||
|
* \param[in] size Number of bytes to write.
|
||||||
|
*
|
||||||
|
* \return For success write() returns the number of bytes written, always
|
||||||
|
* \a nbyte. If an error occurs, write() returns -1. Possible errors
|
||||||
|
* include write() is called before a file has been opened, write is called
|
||||||
|
* for a read-only file, device is full, a corrupt file system or an
|
||||||
|
* I/O error.
|
||||||
|
*/
|
||||||
|
size_t write(const uint8_t *buf, size_t size) {
|
||||||
|
return FatFile::write(buf, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // ENABLE_ARDUINO_FEATURES
|
||||||
|
#endif // ArduinoFiles_h
|
153
hardware/_controller/src/SdFat/FatLib/ArduinoStream.h
Normal file
153
hardware/_controller/src/SdFat/FatLib/ArduinoStream.h
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef ArduinoStream_h
|
||||||
|
#define ArduinoStream_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief ArduinoInStream and ArduinoOutStream classes
|
||||||
|
*/
|
||||||
|
#include "FatLibConfig.h"
|
||||||
|
#if ENABLE_ARDUINO_FEATURES
|
||||||
|
#include "bufstream.h"
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class ArduinoInStream
|
||||||
|
* \brief Input stream for Arduino Stream objects
|
||||||
|
*/
|
||||||
|
class ArduinoInStream : public ibufstream {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* \param[in] hws hardware stream
|
||||||
|
* \param[in] buf buffer for input line
|
||||||
|
* \param[in] size size of input buffer
|
||||||
|
*/
|
||||||
|
ArduinoInStream(Stream &hws, char* buf, size_t size) {
|
||||||
|
m_hw = &hws;
|
||||||
|
m_line = buf;
|
||||||
|
m_size = size;
|
||||||
|
}
|
||||||
|
/** read a line. */
|
||||||
|
void readline() {
|
||||||
|
size_t i = 0;
|
||||||
|
uint32_t t;
|
||||||
|
m_line[0] = '\0';
|
||||||
|
while (!m_hw->available()) {
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
t = millis();
|
||||||
|
while (!m_hw->available()) {
|
||||||
|
if ((millis() - t) > 10) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i >= (m_size - 1)) {
|
||||||
|
setstate(failbit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_line[i++] = m_hw->read();
|
||||||
|
m_line[i] = '\0';
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
init(m_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Internal - do not use.
|
||||||
|
* \param[in] off
|
||||||
|
* \param[in] way
|
||||||
|
* \return true/false.
|
||||||
|
*/
|
||||||
|
bool seekoff(off_type off, seekdir way) {
|
||||||
|
(void)off;
|
||||||
|
(void)way;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/** Internal - do not use.
|
||||||
|
* \param[in] pos
|
||||||
|
* \return true/false.
|
||||||
|
*/
|
||||||
|
bool seekpos(pos_type pos) {
|
||||||
|
(void)pos;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char *m_line;
|
||||||
|
size_t m_size;
|
||||||
|
Stream* m_hw;
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class ArduinoOutStream
|
||||||
|
* \brief Output stream for Arduino Print objects
|
||||||
|
*/
|
||||||
|
class ArduinoOutStream : public ostream {
|
||||||
|
public:
|
||||||
|
/** constructor
|
||||||
|
*
|
||||||
|
* \param[in] pr Print object for this ArduinoOutStream.
|
||||||
|
*/
|
||||||
|
explicit ArduinoOutStream(Print& pr) : m_pr(&pr) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @cond SHOW_PROTECTED
|
||||||
|
/**
|
||||||
|
* Internal do not use
|
||||||
|
* \param[in] c
|
||||||
|
*/
|
||||||
|
void putch(char c) {
|
||||||
|
if (c == '\n') {
|
||||||
|
m_pr->write('\r');
|
||||||
|
}
|
||||||
|
m_pr->write(c);
|
||||||
|
}
|
||||||
|
void putstr(const char* str) {
|
||||||
|
m_pr->write(str);
|
||||||
|
}
|
||||||
|
bool seekoff(off_type off, seekdir way) {
|
||||||
|
(void)off;
|
||||||
|
(void)way;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool seekpos(pos_type pos) {
|
||||||
|
(void)pos;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool sync() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pos_type tellpos() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
private:
|
||||||
|
ArduinoOutStream() {}
|
||||||
|
Print* m_pr;
|
||||||
|
};
|
||||||
|
#endif // ENABLE_ARDUINO_FEATURES
|
||||||
|
#endif // ArduinoStream_h
|
80
hardware/_controller/src/SdFat/FatLib/BaseBlockDriver.h
Normal file
80
hardware/_controller/src/SdFat/FatLib/BaseBlockDriver.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef BaseBlockDriver_h
|
||||||
|
#define BaseBlockDriver_h
|
||||||
|
#include "FatLibConfig.h"
|
||||||
|
/**
|
||||||
|
* \class BaseBlockDriver
|
||||||
|
* \brief Base block driver.
|
||||||
|
*/
|
||||||
|
class BaseBlockDriver {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Read a 512 byte block from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
virtual bool readBlock(uint32_t block, uint8_t* dst) = 0;
|
||||||
|
/** End multi-block transfer and go to idle state.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
virtual bool syncBlocks() = 0;
|
||||||
|
/**
|
||||||
|
* Writes a 512 byte block to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
virtual bool writeBlock(uint32_t block, const uint8_t* src) = 0;
|
||||||
|
#if USE_MULTI_BLOCK_IO
|
||||||
|
/**
|
||||||
|
* Read multiple 512 byte blocks from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be read.
|
||||||
|
* \param[in] nb Number of blocks to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
virtual bool readBlocks(uint32_t block, uint8_t* dst, size_t nb) = 0;
|
||||||
|
/**
|
||||||
|
* Write multiple 512 byte blocks to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be written.
|
||||||
|
* \param[in] nb Number of blocks to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
virtual bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb) = 0;
|
||||||
|
#endif // USE_MULTI_BLOCK_IO
|
||||||
|
};
|
||||||
|
#endif // BaseBlockDriver_h
|
87
hardware/_controller/src/SdFat/FatLib/FatApiConstants.h
Normal file
87
hardware/_controller/src/SdFat/FatLib/FatApiConstants.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef FatApiConstants_h
|
||||||
|
#define FatApiConstants_h
|
||||||
|
#include "../SdFatConfig.h"
|
||||||
|
|
||||||
|
#if USE_FCNTL_H
|
||||||
|
#include <fcntl.h>
|
||||||
|
/* values for GNU Arm Embedded Toolchain.
|
||||||
|
* O_RDONLY: 0x0
|
||||||
|
* O_WRONLY: 0x1
|
||||||
|
* O_RDWR: 0x2
|
||||||
|
* O_ACCMODE: 0x3
|
||||||
|
* O_APPEND: 0x8
|
||||||
|
* O_CREAT: 0x200
|
||||||
|
* O_TRUNC: 0x400
|
||||||
|
* O_EXCL: 0x800
|
||||||
|
* O_SYNC: 0x2000
|
||||||
|
* O_NONBLOCK: 0x4000
|
||||||
|
*/
|
||||||
|
/** Use O_NONBLOCK for open at EOF */
|
||||||
|
#define O_AT_END O_NONBLOCK ///< Open at EOF.
|
||||||
|
typedef int oflag_t;
|
||||||
|
#else // USE_FCNTL_H
|
||||||
|
#define O_RDONLY 0X00 ///< Open for reading only.
|
||||||
|
#define O_WRONLY 0X01 ///< Open for writing only.
|
||||||
|
#define O_RDWR 0X02 ///< Open for reading and writing.
|
||||||
|
#define O_AT_END 0X04 ///< Open at EOF.
|
||||||
|
#define O_APPEND 0X08 ///< Set append mode.
|
||||||
|
#define O_CREAT 0x10 ///< Create file if it does not exist.
|
||||||
|
#define O_TRUNC 0x20 ///< Truncate file to zero length.
|
||||||
|
#define O_EXCL 0x40 ///< Fail if the file exists.
|
||||||
|
#define O_SYNC 0x80 ///< Synchronized write I/O operations.
|
||||||
|
|
||||||
|
#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) ///< Mask for access mode.
|
||||||
|
typedef uint8_t oflag_t;
|
||||||
|
#endif // USE_FCNTL_H
|
||||||
|
|
||||||
|
#define O_READ O_RDONLY
|
||||||
|
#define O_WRITE O_WRONLY
|
||||||
|
|
||||||
|
inline bool isWriteMode(oflag_t oflag) {
|
||||||
|
oflag &= O_ACCMODE;
|
||||||
|
return oflag == O_WRONLY || oflag == O_RDWR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FatFile class static and const definitions
|
||||||
|
// flags for ls()
|
||||||
|
/** ls() flag for list all files including hidden. */
|
||||||
|
#define LS_A 1
|
||||||
|
/** ls() flag to print modify. date */
|
||||||
|
#define LS_DATE 2
|
||||||
|
/** ls() flag to print file size. */
|
||||||
|
#define LS_SIZE 4
|
||||||
|
/** ls() flag for recursive list of subdirectories */
|
||||||
|
#define LS_R 8
|
||||||
|
|
||||||
|
// flags for timestamp
|
||||||
|
/** set the file's last access date */
|
||||||
|
#define T_ACCESS 1
|
||||||
|
/** set the file's creation date and time */
|
||||||
|
#define T_CREATE 2
|
||||||
|
/** Set the file's write date and time */
|
||||||
|
#define T_WRITE 4
|
||||||
|
#endif // FatApiConstants_h
|
1531
hardware/_controller/src/SdFat/FatLib/FatFile.cpp
Normal file
1531
hardware/_controller/src/SdFat/FatLib/FatFile.cpp
Normal file
File diff suppressed because it is too large
Load diff
1032
hardware/_controller/src/SdFat/FatLib/FatFile.h
Normal file
1032
hardware/_controller/src/SdFat/FatLib/FatFile.h
Normal file
File diff suppressed because it is too large
Load diff
685
hardware/_controller/src/SdFat/FatLib/FatFileLFN.cpp
Normal file
685
hardware/_controller/src/SdFat/FatLib/FatFileLFN.cpp
Normal file
|
@ -0,0 +1,685 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "FatFile.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
uint8_t FatFile::lfnChecksum(uint8_t* name) {
|
||||||
|
uint8_t sum = 0;
|
||||||
|
for (uint8_t i = 0; i < 11; i++) {
|
||||||
|
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + name[i];
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
#if USE_LONG_FILE_NAMES
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Saves about 90 bytes of flash on 328 over tolower().
|
||||||
|
inline char lfnToLower(char c) {
|
||||||
|
return 'A' <= c && c <= 'Z' ? c + 'a' - 'A' : c;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Daniel Bernstein University of Illinois at Chicago.
|
||||||
|
// Original had + instead of ^
|
||||||
|
static uint16_t Bernstein(uint16_t hash, const char *str, size_t len) {
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
// hash = hash * 33 ^ str[i];
|
||||||
|
hash = ((hash << 5) + hash) ^ str[i];
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Fetch a 16-bit long file name character.
|
||||||
|
*
|
||||||
|
* \param[in] ldir Pointer to long file name directory entry.
|
||||||
|
* \param[in] i Index of character.
|
||||||
|
* \return The 16-bit character.
|
||||||
|
*/
|
||||||
|
static uint16_t lfnGetChar(ldir_t *ldir, uint8_t i) {
|
||||||
|
if (i < LDIR_NAME1_DIM) {
|
||||||
|
return ldir->name1[i];
|
||||||
|
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM)) {
|
||||||
|
return ldir->name2[i - LDIR_NAME1_DIM];
|
||||||
|
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM + LDIR_NAME2_DIM)) {
|
||||||
|
return ldir->name3[i - LDIR_NAME1_DIM - LDIR_NAME2_DIM];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static bool lfnGetName(ldir_t *ldir, char* name, size_t n) {
|
||||||
|
uint8_t i;
|
||||||
|
size_t k = 13*((ldir->ord & 0X1F) - 1);
|
||||||
|
for (i = 0; i < 13; i++) {
|
||||||
|
uint16_t c = lfnGetChar(ldir, i);
|
||||||
|
if (c == 0 || k >= n) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
name[k++] = c >= 0X7F ? '?' : c;
|
||||||
|
}
|
||||||
|
// Terminate with zero byte if name fits.
|
||||||
|
if (k < n && (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY)) {
|
||||||
|
name[k] = 0;
|
||||||
|
}
|
||||||
|
// Truncate if name is too long.
|
||||||
|
name[n - 1] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline bool lfnLegalChar(char c) {
|
||||||
|
if (c == '/' || c == '\\' || c == '"' || c == '*' ||
|
||||||
|
c == ':' || c == '<' || c == '>' || c == '?' || c == '|') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return 0X1F < c && c < 0X7F;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Store a 16-bit long file name character.
|
||||||
|
*
|
||||||
|
* \param[in] ldir Pointer to long file name directory entry.
|
||||||
|
* \param[in] i Index of character.
|
||||||
|
* \param[in] c The 16-bit character.
|
||||||
|
*/
|
||||||
|
static void lfnPutChar(ldir_t *ldir, uint8_t i, uint16_t c) {
|
||||||
|
if (i < LDIR_NAME1_DIM) {
|
||||||
|
ldir->name1[i] = c;
|
||||||
|
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM)) {
|
||||||
|
ldir->name2[i - LDIR_NAME1_DIM] = c;
|
||||||
|
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM + LDIR_NAME2_DIM)) {
|
||||||
|
ldir->name3[i - LDIR_NAME1_DIM - LDIR_NAME2_DIM] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void lfnPutName(ldir_t *ldir, const char* name, size_t n) {
|
||||||
|
size_t k = 13*((ldir->ord & 0X1F) - 1);
|
||||||
|
for (uint8_t i = 0; i < 13; i++, k++) {
|
||||||
|
uint16_t c = k < n ? name[k] : k == n ? 0 : 0XFFFF;
|
||||||
|
lfnPutChar(ldir, i, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//==============================================================================
|
||||||
|
bool FatFile::getName(char* name, size_t size) {
|
||||||
|
FatFile dirFile;
|
||||||
|
ldir_t* ldir;
|
||||||
|
if (!isOpen() || size < 13) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!isLFN()) {
|
||||||
|
return getSFN(name);
|
||||||
|
}
|
||||||
|
if (!dirFile.openCluster(this)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
for (uint8_t ord = 1; ord <= m_lfnOrd; ord++) {
|
||||||
|
if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
|
||||||
|
if (!ldir) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (ldir->attr != DIR_ATT_LONG_NAME) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (ord != (ldir->ord & 0X1F)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!lfnGetName(ldir, name, size)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fall into fail.
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
name[0] = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::openCluster(FatFile* file) {
|
||||||
|
if (file->m_dirCluster == 0) {
|
||||||
|
return openRoot(file->m_vol);
|
||||||
|
}
|
||||||
|
memset(this, 0, sizeof(FatFile));
|
||||||
|
m_attr = FILE_ATTR_SUBDIR;
|
||||||
|
m_flags = F_READ;
|
||||||
|
m_vol = file->m_vol;
|
||||||
|
m_firstCluster = file->m_dirCluster;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::parsePathName(const char* path,
|
||||||
|
fname_t* fname, const char** ptr) {
|
||||||
|
char c;
|
||||||
|
bool is83;
|
||||||
|
uint8_t bit = DIR_NT_LC_BASE;
|
||||||
|
uint8_t lc = 0;
|
||||||
|
uint8_t uc = 0;
|
||||||
|
uint8_t i = 0;
|
||||||
|
uint8_t in = 7;
|
||||||
|
int end;
|
||||||
|
int len = 0;
|
||||||
|
int si;
|
||||||
|
int dot;
|
||||||
|
|
||||||
|
// Skip leading spaces.
|
||||||
|
while (*path == ' ') {
|
||||||
|
path++;
|
||||||
|
}
|
||||||
|
fname->lfn = path;
|
||||||
|
|
||||||
|
for (len = 0; ; len++) {
|
||||||
|
c = path[len];
|
||||||
|
if (c == 0 || isDirSeparator(c)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!lfnLegalChar(c)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Advance to next path component.
|
||||||
|
for (end = len; path[end] == ' ' || isDirSeparator(path[end]); end++) {}
|
||||||
|
*ptr = &path[end];
|
||||||
|
|
||||||
|
// Back over spaces and dots.
|
||||||
|
while (len) {
|
||||||
|
c = path[len - 1];
|
||||||
|
if (c != '.' && c != ' ') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
// Max length of LFN is 255.
|
||||||
|
if (len > 255) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fname->len = len;
|
||||||
|
// Blank file short name.
|
||||||
|
for (uint8_t k = 0; k < 11; k++) {
|
||||||
|
fname->sfn[k] = ' ';
|
||||||
|
}
|
||||||
|
// skip leading spaces and dots.
|
||||||
|
for (si = 0; path[si] == '.' || path[si] == ' '; si++) {}
|
||||||
|
// Not 8.3 if leading dot or space.
|
||||||
|
is83 = !si;
|
||||||
|
|
||||||
|
// find last dot.
|
||||||
|
for (dot = len - 1; dot >= 0 && path[dot] != '.'; dot--) {}
|
||||||
|
for (; si < len; si++) {
|
||||||
|
c = path[si];
|
||||||
|
if (c == ' ' || (c == '.' && dot != si)) {
|
||||||
|
is83 = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!legal83Char(c) && si != dot) {
|
||||||
|
is83 = false;
|
||||||
|
c = '_';
|
||||||
|
}
|
||||||
|
if (si == dot || i > in) {
|
||||||
|
if (in == 10) {
|
||||||
|
// Done - extension longer than three characters.
|
||||||
|
is83 = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (si != dot) {
|
||||||
|
is83 = false;
|
||||||
|
}
|
||||||
|
// Break if no dot and base-name is longer than eight characters.
|
||||||
|
if (si > dot) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
si = dot;
|
||||||
|
in = 10; // Max index for full 8.3 name.
|
||||||
|
i = 8; // Place for extension.
|
||||||
|
bit = DIR_NT_LC_EXT; // bit for extension.
|
||||||
|
} else {
|
||||||
|
if ('a' <= c && c <= 'z') {
|
||||||
|
c += 'A' - 'a';
|
||||||
|
lc |= bit;
|
||||||
|
} else if ('A' <= c && c <= 'Z') {
|
||||||
|
uc |= bit;
|
||||||
|
}
|
||||||
|
fname->sfn[i++] = c;
|
||||||
|
if (i < 7) {
|
||||||
|
fname->seqPos = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fname->sfn[0] == ' ') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is83) {
|
||||||
|
fname->flags = lc & uc ? FNAME_FLAG_MIXED_CASE : lc;
|
||||||
|
} else {
|
||||||
|
fname->flags = FNAME_FLAG_LOST_CHARS;
|
||||||
|
fname->sfn[fname->seqPos] = '~';
|
||||||
|
fname->sfn[fname->seqPos + 1] = '1';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) {
|
||||||
|
bool fnameFound = false;
|
||||||
|
uint8_t lfnOrd = 0;
|
||||||
|
uint8_t freeNeed;
|
||||||
|
uint8_t freeFound = 0;
|
||||||
|
uint8_t ord = 0;
|
||||||
|
uint8_t chksum = 0;
|
||||||
|
uint16_t freeIndex = 0;
|
||||||
|
uint16_t curIndex;
|
||||||
|
dir_t* dir;
|
||||||
|
ldir_t* ldir;
|
||||||
|
size_t len = fname->len;
|
||||||
|
|
||||||
|
if (!dirFile || !dirFile->isDir() || isOpen()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// Number of directory entries needed.
|
||||||
|
freeNeed = fname->flags & FNAME_FLAG_NEED_LFN ? 1 + (len + 12)/13 : 1;
|
||||||
|
|
||||||
|
dirFile->rewind();
|
||||||
|
while (1) {
|
||||||
|
curIndex = dirFile->m_curPosition/32;
|
||||||
|
dir = dirFile->readDirCache(true);
|
||||||
|
if (!dir) {
|
||||||
|
if (dirFile->getError()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// At EOF
|
||||||
|
goto create;
|
||||||
|
}
|
||||||
|
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == DIR_NAME_FREE) {
|
||||||
|
if (freeFound == 0) {
|
||||||
|
freeIndex = curIndex;
|
||||||
|
}
|
||||||
|
if (freeFound < freeNeed) {
|
||||||
|
freeFound++;
|
||||||
|
}
|
||||||
|
if (dir->name[0] == DIR_NAME_FREE) {
|
||||||
|
goto create;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (freeFound < freeNeed) {
|
||||||
|
freeFound = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// skip empty slot or '.' or '..'
|
||||||
|
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') {
|
||||||
|
lfnOrd = 0;
|
||||||
|
} else if (DIR_IS_LONG_NAME(dir)) {
|
||||||
|
ldir_t *ldir = reinterpret_cast<ldir_t*>(dir);
|
||||||
|
if (!lfnOrd) {
|
||||||
|
if ((ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lfnOrd = ord = ldir->ord & 0X1F;
|
||||||
|
chksum = ldir->chksum;
|
||||||
|
} else if (ldir->ord != --ord || chksum != ldir->chksum) {
|
||||||
|
lfnOrd = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
size_t k = 13*(ord - 1);
|
||||||
|
if (k >= len) {
|
||||||
|
// Not found.
|
||||||
|
lfnOrd = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < 13; i++) {
|
||||||
|
uint16_t u = lfnGetChar(ldir, i);
|
||||||
|
if (k == len) {
|
||||||
|
if (u != 0) {
|
||||||
|
// Not found.
|
||||||
|
lfnOrd = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (u > 255 || lfnToLower(u) != lfnToLower(fname->lfn[k++])) {
|
||||||
|
// Not found.
|
||||||
|
lfnOrd = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
|
||||||
|
if (lfnOrd) {
|
||||||
|
if (1 == ord && lfnChecksum(dir->name) == chksum) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!memcmp(dir->name, fname->sfn, sizeof(fname->sfn))) {
|
||||||
|
if (!(fname->flags & FNAME_FLAG_LOST_CHARS)) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
fnameFound = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lfnOrd = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
|
// Don't open if create only.
|
||||||
|
if (oflag & O_EXCL) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
goto open;
|
||||||
|
|
||||||
|
create:
|
||||||
|
// don't create unless O_CREAT and write mode.
|
||||||
|
if (!(oflag & O_CREAT) || !isWriteMode(oflag)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// If at EOF start in next cluster.
|
||||||
|
if (freeFound == 0) {
|
||||||
|
freeIndex = curIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (freeFound < freeNeed) {
|
||||||
|
dir = dirFile->readDirCache();
|
||||||
|
if (!dir) {
|
||||||
|
if (dirFile->getError()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// EOF if no error.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
freeFound++;
|
||||||
|
}
|
||||||
|
while (freeFound < freeNeed) {
|
||||||
|
// Will fail if FAT16 root.
|
||||||
|
if (!dirFile->addDirCluster()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// Done if more than one block per cluster. Max freeNeed is 21.
|
||||||
|
if (dirFile->m_vol->blocksPerCluster() > 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
freeFound += 16;
|
||||||
|
}
|
||||||
|
if (fnameFound) {
|
||||||
|
if (!dirFile->lfnUniqueSfn(fname)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dirFile->seekSet(32UL*freeIndex)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
lfnOrd = freeNeed - 1;
|
||||||
|
for (uint8_t ord = lfnOrd ; ord ; ord--) {
|
||||||
|
ldir = reinterpret_cast<ldir_t*>(dirFile->readDirCache());
|
||||||
|
if (!ldir) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
dirFile->m_vol->cacheDirty();
|
||||||
|
ldir->ord = ord == lfnOrd ? LDIR_ORD_LAST_LONG_ENTRY | ord : ord;
|
||||||
|
ldir->attr = DIR_ATT_LONG_NAME;
|
||||||
|
ldir->type = 0;
|
||||||
|
ldir->chksum = lfnChecksum(fname->sfn);
|
||||||
|
ldir->mustBeZero = 0;
|
||||||
|
lfnPutName(ldir, fname->lfn, len);
|
||||||
|
}
|
||||||
|
curIndex = dirFile->m_curPosition/32;
|
||||||
|
dir = dirFile->readDirCache();
|
||||||
|
if (!dir) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// initialize as empty file
|
||||||
|
memset(dir, 0, sizeof(dir_t));
|
||||||
|
memcpy(dir->name, fname->sfn, 11);
|
||||||
|
|
||||||
|
// Set base-name and extension lower case bits.
|
||||||
|
dir->reservedNT = (DIR_NT_LC_BASE | DIR_NT_LC_EXT) & fname->flags;
|
||||||
|
|
||||||
|
// set timestamps
|
||||||
|
if (m_dateTime) {
|
||||||
|
// call user date/time function
|
||||||
|
m_dateTime(&dir->creationDate, &dir->creationTime);
|
||||||
|
} else {
|
||||||
|
// use default date/time
|
||||||
|
dir->creationDate = FAT_DEFAULT_DATE;
|
||||||
|
dir->creationTime = FAT_DEFAULT_TIME;
|
||||||
|
}
|
||||||
|
dir->lastAccessDate = dir->creationDate;
|
||||||
|
dir->lastWriteDate = dir->creationDate;
|
||||||
|
dir->lastWriteTime = dir->creationTime;
|
||||||
|
|
||||||
|
// Force write of entry to device.
|
||||||
|
dirFile->m_vol->cacheDirty();
|
||||||
|
|
||||||
|
open:
|
||||||
|
// open entry in cache.
|
||||||
|
if (!openCachedEntry(dirFile, curIndex, oflag, lfnOrd)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
size_t FatFile::printName(print_t* pr) {
|
||||||
|
FatFile dirFile;
|
||||||
|
ldir_t* ldir;
|
||||||
|
size_t n = 0;
|
||||||
|
uint16_t u;
|
||||||
|
uint8_t buf[13];
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
if (!isLFN()) {
|
||||||
|
return printSFN(pr);
|
||||||
|
}
|
||||||
|
if (!dirFile.openCluster(this)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
for (uint8_t ord = 1; ord <= m_lfnOrd; ord++) {
|
||||||
|
if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
|
||||||
|
if (!ldir) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ldir->attr != DIR_ATT_LONG_NAME ||
|
||||||
|
ord != (ldir->ord & 0X1F)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 13; i++) {
|
||||||
|
u = lfnGetChar(ldir, i);
|
||||||
|
if (u == 0) {
|
||||||
|
// End of name.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[i] = u < 0X7F ? u : '?';
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
pr->write(buf, i);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::remove() {
|
||||||
|
bool last;
|
||||||
|
uint8_t chksum;
|
||||||
|
uint8_t ord;
|
||||||
|
FatFile dirFile;
|
||||||
|
dir_t* dir;
|
||||||
|
ldir_t* ldir;
|
||||||
|
|
||||||
|
// Cant' remove not open for write.
|
||||||
|
if (!isFile() || !(m_flags & F_WRITE)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// Free any clusters.
|
||||||
|
if (m_firstCluster && !m_vol->freeChain(m_firstCluster)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// Cache directory entry.
|
||||||
|
dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
|
||||||
|
if (!dir) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
chksum = lfnChecksum(dir->name);
|
||||||
|
|
||||||
|
// Mark entry deleted.
|
||||||
|
dir->name[0] = DIR_NAME_DELETED;
|
||||||
|
|
||||||
|
// Set this file closed.
|
||||||
|
m_attr = FILE_ATTR_CLOSED;
|
||||||
|
|
||||||
|
// Write entry to device.
|
||||||
|
if (!m_vol->cacheSync()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!isLFN()) {
|
||||||
|
// Done, no LFN entries.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!dirFile.openCluster(this)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
for (ord = 1; ord <= m_lfnOrd; ord++) {
|
||||||
|
if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
|
||||||
|
if (!ldir) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (ldir->attr != DIR_ATT_LONG_NAME ||
|
||||||
|
ord != (ldir->ord & 0X1F) ||
|
||||||
|
chksum != ldir->chksum) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
last = ldir->ord & LDIR_ORD_LAST_LONG_ENTRY;
|
||||||
|
ldir->ord = DIR_NAME_DELETED;
|
||||||
|
m_vol->cacheDirty();
|
||||||
|
if (last) {
|
||||||
|
if (!m_vol->cacheSync()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fall into fail.
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::lfnUniqueSfn(fname_t* fname) {
|
||||||
|
const uint8_t FIRST_HASH_SEQ = 2; // min value is 2
|
||||||
|
uint8_t pos = fname->seqPos;;
|
||||||
|
dir_t *dir;
|
||||||
|
uint16_t hex;
|
||||||
|
|
||||||
|
DBG_HALT_IF(!(fname->flags & FNAME_FLAG_LOST_CHARS));
|
||||||
|
DBG_HALT_IF(fname->sfn[pos] != '~' && fname->sfn[pos + 1] != '1');
|
||||||
|
|
||||||
|
for (uint8_t seq = 2; seq < 100; seq++) {
|
||||||
|
if (seq < FIRST_HASH_SEQ) {
|
||||||
|
fname->sfn[pos + 1] = '0' + seq;
|
||||||
|
} else {
|
||||||
|
DBG_PRINT_IF(seq > FIRST_HASH_SEQ);
|
||||||
|
hex = Bernstein(seq + fname->len, fname->lfn, fname->len);
|
||||||
|
if (pos > 3) {
|
||||||
|
// Make space in name for ~HHHH.
|
||||||
|
pos = 3;
|
||||||
|
}
|
||||||
|
for (uint8_t i = pos + 4 ; i > pos; i--) {
|
||||||
|
uint8_t h = hex & 0XF;
|
||||||
|
fname->sfn[i] = h < 10 ? h + '0' : h + 'A' - 10;
|
||||||
|
hex >>= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fname->sfn[pos] = '~';
|
||||||
|
rewind();
|
||||||
|
while (1) {
|
||||||
|
dir = readDirCache(true);
|
||||||
|
if (!dir) {
|
||||||
|
if (!getError()) {
|
||||||
|
// At EOF and name not found if no error.
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (dir->name[0] == DIR_NAME_FREE) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (DIR_IS_FILE_OR_SUBDIR(dir) && !memcmp(fname->sfn, dir->name, 11)) {
|
||||||
|
// Name found - try another.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fall inti fail - too many tries.
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif // #if USE_LONG_FILE_NAMES
|
267
hardware/_controller/src/SdFat/FatLib/FatFilePrint.cpp
Normal file
267
hardware/_controller/src/SdFat/FatLib/FatFilePrint.cpp
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <math.h>
|
||||||
|
#include "FatFile.h"
|
||||||
|
#include "FmtNumber.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// print uint8_t with width 2
|
||||||
|
static void print2u(print_t* pr, uint8_t v) {
|
||||||
|
char c0 = '?';
|
||||||
|
char c1 = '?';
|
||||||
|
if (v < 100) {
|
||||||
|
c1 = v/10;
|
||||||
|
c0 = v - 10*c1 + '0';
|
||||||
|
c1 += '0';
|
||||||
|
}
|
||||||
|
pr->write(c1);
|
||||||
|
pr->write(c0);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void printU32(print_t* pr, uint32_t v) {
|
||||||
|
char buf[11];
|
||||||
|
char* ptr = buf + sizeof(buf);
|
||||||
|
*--ptr = 0;
|
||||||
|
pr->write(fmtDec(v, ptr));
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void printHex(print_t* pr, uint8_t w, uint16_t h) {
|
||||||
|
char buf[5];
|
||||||
|
char* ptr = buf + sizeof(buf);
|
||||||
|
*--ptr = 0;
|
||||||
|
for (uint8_t i = 0; i < w; i++) {
|
||||||
|
char c = h & 0XF;
|
||||||
|
*--ptr = c < 10 ? c + '0' : c + 'A' - 10;
|
||||||
|
h >>= 4;
|
||||||
|
}
|
||||||
|
pr->write(ptr);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void FatFile::dmpFile(print_t* pr, uint32_t pos, size_t n) {
|
||||||
|
char text[17];
|
||||||
|
text[16] = 0;
|
||||||
|
if (n >= 0XFFF0) {
|
||||||
|
n = 0XFFF0;
|
||||||
|
}
|
||||||
|
if (!seekSet(pos)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i <= n; i++) {
|
||||||
|
if ((i & 15) == 0) {
|
||||||
|
if (i) {
|
||||||
|
pr->write(' ');
|
||||||
|
pr->write(text);
|
||||||
|
if (i == n) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pr->write('\r');
|
||||||
|
pr->write('\n');
|
||||||
|
if (i >= n) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printHex(pr, 4, i);
|
||||||
|
pr->write(' ');
|
||||||
|
}
|
||||||
|
int16_t h = read();
|
||||||
|
if (h < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pr->write(' ');
|
||||||
|
printHex(pr, 2, h);
|
||||||
|
text[i&15] = ' ' <= h && h < 0X7F ? h : '.';
|
||||||
|
}
|
||||||
|
pr->write('\r');
|
||||||
|
pr->write('\n');
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) {
|
||||||
|
FatFile file;
|
||||||
|
if (!isDir() || getError()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
rewind();
|
||||||
|
while (file.openNext(this, O_RDONLY)) {
|
||||||
|
if (!file.isHidden() || (flags & LS_A)) {
|
||||||
|
// indent for dir level
|
||||||
|
for (uint8_t i = 0; i < indent; i++) {
|
||||||
|
pr->write(' ');
|
||||||
|
}
|
||||||
|
if (flags & LS_DATE) {
|
||||||
|
file.printModifyDateTime(pr);
|
||||||
|
pr->write(' ');
|
||||||
|
}
|
||||||
|
if (flags & LS_SIZE) {
|
||||||
|
file.printFileSize(pr);
|
||||||
|
pr->write(' ');
|
||||||
|
}
|
||||||
|
file.printName(pr);
|
||||||
|
if (file.isDir()) {
|
||||||
|
pr->write('/');
|
||||||
|
}
|
||||||
|
pr->write('\r');
|
||||||
|
pr->write('\n');
|
||||||
|
if ((flags & LS_R) && file.isDir()) {
|
||||||
|
if (!file.ls(pr, flags, indent + 2)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
if (getError()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::printCreateDateTime(print_t* pr) {
|
||||||
|
dir_t dir;
|
||||||
|
if (!dirEntry(&dir)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
printFatDate(pr, dir.creationDate);
|
||||||
|
pr->write(' ');
|
||||||
|
printFatTime(pr, dir.creationTime);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void FatFile::printFatDate(print_t* pr, uint16_t fatDate) {
|
||||||
|
printU32(pr, FAT_YEAR(fatDate));
|
||||||
|
pr->write('-');
|
||||||
|
print2u(pr, FAT_MONTH(fatDate));
|
||||||
|
pr->write('-');
|
||||||
|
print2u(pr, FAT_DAY(fatDate));
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void FatFile::printFatTime(print_t* pr, uint16_t fatTime) {
|
||||||
|
print2u(pr, FAT_HOUR(fatTime));
|
||||||
|
pr->write(':');
|
||||||
|
print2u(pr, FAT_MINUTE(fatTime));
|
||||||
|
pr->write(':');
|
||||||
|
print2u(pr, FAT_SECOND(fatTime));
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Template for FatFile::printField() */
|
||||||
|
template <typename Type>
|
||||||
|
static int printFieldT(FatFile* file, char sign, Type value, char term) {
|
||||||
|
char buf[3*sizeof(Type) + 3];
|
||||||
|
char* str = &buf[sizeof(buf)];
|
||||||
|
|
||||||
|
if (term) {
|
||||||
|
*--str = term;
|
||||||
|
if (term == '\n') {
|
||||||
|
*--str = '\r';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef OLD_FMT
|
||||||
|
do {
|
||||||
|
Type m = value;
|
||||||
|
value /= 10;
|
||||||
|
*--str = '0' + m - 10*value;
|
||||||
|
} while (value);
|
||||||
|
#else // OLD_FMT
|
||||||
|
str = fmtDec(value, str);
|
||||||
|
#endif // OLD_FMT
|
||||||
|
if (sign) {
|
||||||
|
*--str = sign;
|
||||||
|
}
|
||||||
|
return file->write(str, &buf[sizeof(buf)] - str);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int FatFile::printField(float value, char term, uint8_t prec) {
|
||||||
|
char buf[24];
|
||||||
|
char* str = &buf[sizeof(buf)];
|
||||||
|
if (term) {
|
||||||
|
*--str = term;
|
||||||
|
if (term == '\n') {
|
||||||
|
*--str = '\r';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str = fmtFloat(value, str, prec);
|
||||||
|
return write(str, buf + sizeof(buf) - str);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int FatFile::printField(uint16_t value, char term) {
|
||||||
|
return printFieldT(this, 0, value, term);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int FatFile::printField(int16_t value, char term) {
|
||||||
|
char sign = 0;
|
||||||
|
if (value < 0) {
|
||||||
|
sign = '-';
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
return printFieldT(this, sign, (uint16_t)value, term);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int FatFile::printField(uint32_t value, char term) {
|
||||||
|
return printFieldT(this, 0, value, term);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int FatFile::printField(int32_t value, char term) {
|
||||||
|
char sign = 0;
|
||||||
|
if (value < 0) {
|
||||||
|
sign = '-';
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
return printFieldT(this, sign, (uint32_t)value, term);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::printModifyDateTime(print_t* pr) {
|
||||||
|
dir_t dir;
|
||||||
|
if (!dirEntry(&dir)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
printFatDate(pr, dir.lastWriteDate);
|
||||||
|
pr->write(' ');
|
||||||
|
printFatTime(pr, dir.lastWriteTime);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
size_t FatFile::printFileSize(print_t* pr) {
|
||||||
|
char buf[11];
|
||||||
|
char *ptr = buf + sizeof(buf);
|
||||||
|
*--ptr = 0;
|
||||||
|
ptr = fmtDec(fileSize(), ptr);
|
||||||
|
while (ptr > buf) {
|
||||||
|
*--ptr = ' ';
|
||||||
|
}
|
||||||
|
return pr->write(buf);
|
||||||
|
}
|
278
hardware/_controller/src/SdFat/FatLib/FatFileSFN.cpp
Normal file
278
hardware/_controller/src/SdFat/FatLib/FatFileSFN.cpp
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "FatFile.h"
|
||||||
|
#include "FatFileSystem.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::getSFN(char* name) {
|
||||||
|
dir_t* dir;
|
||||||
|
if (!isOpen()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (isRoot()) {
|
||||||
|
name[0] = '/';
|
||||||
|
name[1] = '\0';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// cache entry
|
||||||
|
dir = cacheDirEntry(FatCache::CACHE_FOR_READ);
|
||||||
|
if (!dir) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// format name
|
||||||
|
dirName(dir, name);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
size_t FatFile::printSFN(print_t* pr) {
|
||||||
|
char name[13];
|
||||||
|
if (!getSFN(name)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return pr->write(name);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#if !USE_LONG_FILE_NAMES
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::getName(char* name, size_t size) {
|
||||||
|
return size < 13 ? 0 : getSFN(name);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// format directory name field from a 8.3 name string
|
||||||
|
bool FatFile::parsePathName(const char* path, fname_t* fname,
|
||||||
|
const char** ptr) {
|
||||||
|
uint8_t uc = 0;
|
||||||
|
uint8_t lc = 0;
|
||||||
|
uint8_t bit = FNAME_FLAG_LC_BASE;
|
||||||
|
// blank fill name and extension
|
||||||
|
for (uint8_t i = 0; i < 11; i++) {
|
||||||
|
fname->sfn[i] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0, n = 7;; path++) {
|
||||||
|
uint8_t c = *path;
|
||||||
|
if (c == 0 || isDirSeparator(c)) {
|
||||||
|
// Done.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == '.' && n == 7) {
|
||||||
|
n = 10; // max index for full 8.3 name
|
||||||
|
i = 8; // place for extension
|
||||||
|
|
||||||
|
// bit for extension.
|
||||||
|
bit = FNAME_FLAG_LC_EXT;
|
||||||
|
} else {
|
||||||
|
if (!legal83Char(c) || i > n) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ('a' <= c && c <= 'z') {
|
||||||
|
c += 'A' - 'a';
|
||||||
|
lc |= bit;
|
||||||
|
} else if ('A' <= c && c <= 'Z') {
|
||||||
|
uc |= bit;
|
||||||
|
}
|
||||||
|
fname->sfn[i++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// must have a file name, extension is optional
|
||||||
|
if (fname->sfn[0] == ' ') {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// Set base-name and extension bits.
|
||||||
|
fname->flags = lc & uc ? 0 : lc;
|
||||||
|
while (isDirSeparator(*path)) {
|
||||||
|
path++;
|
||||||
|
}
|
||||||
|
*ptr = path;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// open with filename in fname
|
||||||
|
#define SFN_OPEN_USES_CHKSUM 0
|
||||||
|
bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) {
|
||||||
|
bool emptyFound = false;
|
||||||
|
#if SFN_OPEN_USES_CHKSUM
|
||||||
|
uint8_t chksum;
|
||||||
|
#endif
|
||||||
|
uint8_t lfnOrd = 0;
|
||||||
|
uint16_t emptyIndex;
|
||||||
|
uint16_t index = 0;
|
||||||
|
dir_t* dir;
|
||||||
|
ldir_t* ldir;
|
||||||
|
|
||||||
|
dirFile->rewind();
|
||||||
|
while (1) {
|
||||||
|
if (!emptyFound) {
|
||||||
|
emptyIndex = index;
|
||||||
|
}
|
||||||
|
dir = dirFile->readDirCache(true);
|
||||||
|
if (!dir) {
|
||||||
|
if (dirFile->getError()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// At EOF if no error.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dir->name[0] == DIR_NAME_FREE) {
|
||||||
|
emptyFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dir->name[0] == DIR_NAME_DELETED) {
|
||||||
|
lfnOrd = 0;
|
||||||
|
emptyFound = true;
|
||||||
|
} else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
|
||||||
|
if (!memcmp(fname->sfn, dir->name, 11)) {
|
||||||
|
// don't open existing file if O_EXCL
|
||||||
|
if (oflag & O_EXCL) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#if SFN_OPEN_USES_CHKSUM
|
||||||
|
if (lfnOrd && chksum != lfnChecksum(dir->name)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif // SFN_OPEN_USES_CHKSUM
|
||||||
|
if (!openCachedEntry(dirFile, index, oflag, lfnOrd)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
lfnOrd = 0;
|
||||||
|
}
|
||||||
|
} else if (DIR_IS_LONG_NAME(dir)) {
|
||||||
|
ldir = reinterpret_cast<ldir_t*>(dir);
|
||||||
|
if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) {
|
||||||
|
lfnOrd = ldir->ord & 0X1F;
|
||||||
|
#if SFN_OPEN_USES_CHKSUM
|
||||||
|
chksum = ldir->chksum;
|
||||||
|
#endif // SFN_OPEN_USES_CHKSUM
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lfnOrd = 0;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
// don't create unless O_CREAT and write mode
|
||||||
|
if (!(oflag & O_CREAT) || !isWriteMode(oflag)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (emptyFound) {
|
||||||
|
index = emptyIndex;
|
||||||
|
} else {
|
||||||
|
if (!dirFile->addDirCluster()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dirFile->seekSet(32UL*index)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
dir = dirFile->readDirCache();
|
||||||
|
if (!dir) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// initialize as empty file
|
||||||
|
memset(dir, 0, sizeof(dir_t));
|
||||||
|
memcpy(dir->name, fname->sfn, 11);
|
||||||
|
|
||||||
|
// Set base-name and extension lower case bits.
|
||||||
|
dir->reservedNT = (DIR_NT_LC_BASE | DIR_NT_LC_EXT) & fname->flags;
|
||||||
|
|
||||||
|
// set timestamps
|
||||||
|
if (m_dateTime) {
|
||||||
|
// call user date/time function
|
||||||
|
m_dateTime(&dir->creationDate, &dir->creationTime);
|
||||||
|
} else {
|
||||||
|
// use default date/time
|
||||||
|
dir->creationDate = FAT_DEFAULT_DATE;
|
||||||
|
dir->creationTime = FAT_DEFAULT_TIME;
|
||||||
|
}
|
||||||
|
dir->lastAccessDate = dir->creationDate;
|
||||||
|
dir->lastWriteDate = dir->creationDate;
|
||||||
|
dir->lastWriteTime = dir->creationTime;
|
||||||
|
|
||||||
|
// Force write of entry to device.
|
||||||
|
dirFile->m_vol->cacheDirty();
|
||||||
|
|
||||||
|
// open entry in cache.
|
||||||
|
return openCachedEntry(dirFile, index, oflag, 0);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
size_t FatFile::printName(print_t* pr) {
|
||||||
|
return printSFN(pr);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatFile::remove() {
|
||||||
|
dir_t* dir;
|
||||||
|
// Can't remove if LFN or not open for write.
|
||||||
|
if (!isFile() || isLFN() || !(m_flags & F_WRITE)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// Free any clusters.
|
||||||
|
if (m_firstCluster && !m_vol->freeChain(m_firstCluster)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// Cache directory entry.
|
||||||
|
dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
|
||||||
|
if (!dir) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// Mark entry deleted.
|
||||||
|
dir->name[0] = DIR_NAME_DELETED;
|
||||||
|
|
||||||
|
// Set this file closed.
|
||||||
|
m_attr = FILE_ATTR_CLOSED;
|
||||||
|
|
||||||
|
// Write entry to device.
|
||||||
|
return m_vol->cacheSync();
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif // !USE_LONG_FILE_NAMES
|
332
hardware/_controller/src/SdFat/FatLib/FatFileSystem.h
Normal file
332
hardware/_controller/src/SdFat/FatLib/FatFileSystem.h
Normal file
|
@ -0,0 +1,332 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef FatFileSystem_h
|
||||||
|
#define FatFileSystem_h
|
||||||
|
#include "FatVolume.h"
|
||||||
|
#include "FatFile.h"
|
||||||
|
#include "ArduinoFiles.h"
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief FatFileSystem class
|
||||||
|
*/
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \class FatFileSystem
|
||||||
|
* \brief Integration class for the FatLib library.
|
||||||
|
*/
|
||||||
|
class FatFileSystem : public FatVolume {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Initialize an FatFileSystem object.
|
||||||
|
* \param[in] blockDev Device block driver.
|
||||||
|
* \param[in] part partition to initialize.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool begin(BlockDriver* blockDev, uint8_t part = 0) {
|
||||||
|
m_blockDev = blockDev;
|
||||||
|
vwd()->close();
|
||||||
|
return (part ? init(part) : init(1) || init(0))
|
||||||
|
&& vwd()->openRoot(this) && FatFile::setCwd(vwd());
|
||||||
|
}
|
||||||
|
#if ENABLE_ARDUINO_FEATURES
|
||||||
|
/** 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.
|
||||||
|
*
|
||||||
|
* \return true for success or false if an error occurred.
|
||||||
|
*/
|
||||||
|
bool ls(uint8_t flags = 0) {
|
||||||
|
return ls(&Serial, flags);
|
||||||
|
}
|
||||||
|
/** List the directory contents of a directory to Serial.
|
||||||
|
*
|
||||||
|
* \param[in] path directory to list.
|
||||||
|
*
|
||||||
|
* \param[in] flags The inclusive OR of
|
||||||
|
*
|
||||||
|
* LS_DATE - %Print file modification date
|
||||||
|
*
|
||||||
|
* LS_SIZE - %Print file size.
|
||||||
|
*
|
||||||
|
* LS_R - Recursive list of subdirectories.
|
||||||
|
*
|
||||||
|
* \return true for success or false if an error occurred.
|
||||||
|
*/
|
||||||
|
bool ls(const char* path, uint8_t flags = 0) {
|
||||||
|
return ls(&Serial, path, flags);
|
||||||
|
}
|
||||||
|
/** open a file
|
||||||
|
*
|
||||||
|
* \param[in] path location of file to be opened.
|
||||||
|
* \param[in] oflag open flags.
|
||||||
|
* \return a File object.
|
||||||
|
*/
|
||||||
|
File open(const char *path, oflag_t oflag = FILE_READ) {
|
||||||
|
File tmpFile;
|
||||||
|
tmpFile.open(vwd(), path, oflag);
|
||||||
|
return tmpFile;
|
||||||
|
}
|
||||||
|
/** open a file
|
||||||
|
*
|
||||||
|
* \param[in] path location of file to be opened.
|
||||||
|
* \param[in] oflag open flags.
|
||||||
|
* \return a File object.
|
||||||
|
*/
|
||||||
|
File open(const String &path, oflag_t oflag = FILE_READ) {
|
||||||
|
return open(path.c_str(), oflag );
|
||||||
|
}
|
||||||
|
#endif // ENABLE_ARDUINO_FEATURES
|
||||||
|
/** 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 true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool chdir(bool set_cwd = false) {
|
||||||
|
vwd()->close();
|
||||||
|
return vwd()->openRoot(this) && (set_cwd ? FatFile::setCwd(vwd()) : true);
|
||||||
|
}
|
||||||
|
/** Change a volume's working directory
|
||||||
|
*
|
||||||
|
* Changes the volume working directory to the \a path subdirectory.
|
||||||
|
* Optionally set the current working directory to the volume's
|
||||||
|
* working directory.
|
||||||
|
*
|
||||||
|
* Example: If the volume's working directory is "/DIR", chdir("SUB")
|
||||||
|
* will change the volume's working directory from "/DIR" to "/DIR/SUB".
|
||||||
|
*
|
||||||
|
* If path is "/", the volume's working directory will be changed to the
|
||||||
|
* root directory
|
||||||
|
*
|
||||||
|
* \param[in] path The name of the subdirectory.
|
||||||
|
*
|
||||||
|
* \param[in] set_cwd Set the current working directory to this volume's
|
||||||
|
* working directory if true.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool chdir(const char *path, bool set_cwd = false) {
|
||||||
|
FatFile dir;
|
||||||
|
if (path[0] == '/' && path[1] == '\0') {
|
||||||
|
return chdir(set_cwd);
|
||||||
|
}
|
||||||
|
if (!dir.open(vwd(), path, O_RDONLY)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!dir.isDir()) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
m_vwd = dir;
|
||||||
|
if (set_cwd) {
|
||||||
|
FatFile::setCwd(vwd());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Set the current working directory to a volume's working directory.
|
||||||
|
*
|
||||||
|
* This is useful with multiple SD cards.
|
||||||
|
*
|
||||||
|
* The current working directory is changed to this
|
||||||
|
* volume's working directory.
|
||||||
|
*
|
||||||
|
* This is like the Windows/DOS \<drive letter>: command.
|
||||||
|
*/
|
||||||
|
void chvol() {
|
||||||
|
FatFile::setCwd(vwd());
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Test for the existence of a file.
|
||||||
|
*
|
||||||
|
* \param[in] path Path of the file to be tested for.
|
||||||
|
*
|
||||||
|
* \return true if the file exists else false.
|
||||||
|
*/
|
||||||
|
bool exists(const char* path) {
|
||||||
|
return vwd()->exists(path);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** List the directory contents of the volume working directory.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print stream for list.
|
||||||
|
*
|
||||||
|
* \param[in] flags The inclusive OR of
|
||||||
|
*
|
||||||
|
* LS_DATE - %Print file modification date
|
||||||
|
*
|
||||||
|
* LS_SIZE - %Print file size.
|
||||||
|
*
|
||||||
|
* LS_R - Recursive list of subdirectories.
|
||||||
|
*
|
||||||
|
* \return true for success or false if an error occurred.
|
||||||
|
*/
|
||||||
|
bool ls(print_t* pr, uint8_t flags = 0) {
|
||||||
|
return vwd()->ls(pr, flags);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** List the directory contents of a directory.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print stream for list.
|
||||||
|
*
|
||||||
|
* \param[in] path directory to list.
|
||||||
|
*
|
||||||
|
* \param[in] flags The inclusive OR of
|
||||||
|
*
|
||||||
|
* LS_DATE - %Print file modification date
|
||||||
|
*
|
||||||
|
* LS_SIZE - %Print file size.
|
||||||
|
*
|
||||||
|
* LS_R - Recursive list of subdirectories.
|
||||||
|
*
|
||||||
|
* \return true for success or false if an error occurred.
|
||||||
|
*/
|
||||||
|
bool ls(print_t* pr, const char* path, uint8_t flags) {
|
||||||
|
FatFile dir;
|
||||||
|
return dir.open(vwd(), path, O_RDONLY) && dir.ls(pr, flags);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Make a subdirectory in the volume working directory.
|
||||||
|
*
|
||||||
|
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
|
||||||
|
*
|
||||||
|
* \param[in] pFlag Create missing parent directories if true.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool mkdir(const char* path, bool pFlag = true) {
|
||||||
|
FatFile sub;
|
||||||
|
return sub.mkdir(vwd(), path, pFlag);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Remove a file from the volume working directory.
|
||||||
|
*
|
||||||
|
* \param[in] path A path with a valid 8.3 DOS name for the file.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool remove(const char* path) {
|
||||||
|
return FatFile::remove(vwd(), path);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Rename a file or subdirectory.
|
||||||
|
*
|
||||||
|
* \param[in] oldPath Path name to the file or subdirectory to be renamed.
|
||||||
|
*
|
||||||
|
* \param[in] newPath New path name of the file or subdirectory.
|
||||||
|
*
|
||||||
|
* The \a newPath object must not exist before the rename call.
|
||||||
|
*
|
||||||
|
* The file to be renamed must not be open. The directory entry may be
|
||||||
|
* moved and file system corruption could occur if the file is accessed by
|
||||||
|
* a file object that was opened before the rename() call.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool rename(const char *oldPath, const char *newPath) {
|
||||||
|
FatFile file;
|
||||||
|
if (!file.open(vwd(), oldPath, O_RDONLY)) {
|
||||||
|
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 true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool rmdir(const char* path) {
|
||||||
|
FatFile sub;
|
||||||
|
if (!sub.open(vwd(), path, O_RDONLY)) {
|
||||||
|
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 true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool truncate(const char* path, uint32_t length) {
|
||||||
|
FatFile file;
|
||||||
|
if (!file.open(vwd(), path, O_WRONLY)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return file.truncate(length);
|
||||||
|
}
|
||||||
|
/** \return a pointer to the FatVolume object. */
|
||||||
|
FatVolume* vol() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/** \return a pointer to the volume working directory. */
|
||||||
|
FatFile* vwd() {
|
||||||
|
return &m_vwd;
|
||||||
|
}
|
||||||
|
/** Wipe all data from the volume. You must reinitialize the volume before
|
||||||
|
* accessing it again.
|
||||||
|
* \param[in] pr print stream for status dots.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool wipe(print_t* pr = 0) {
|
||||||
|
vwd()->close();
|
||||||
|
return FatVolume::wipe(pr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FatFile m_vwd;
|
||||||
|
};
|
||||||
|
#endif // FatFileSystem_h
|
36
hardware/_controller/src/SdFat/FatLib/FatLib.h
Normal file
36
hardware/_controller/src/SdFat/FatLib/FatLib.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef FatLib_h
|
||||||
|
#define FatLib_h
|
||||||
|
#include "ArduinoFiles.h"
|
||||||
|
#include "FatFileSystem.h"
|
||||||
|
#include "FatLibConfig.h"
|
||||||
|
#include "FatVolume.h"
|
||||||
|
#include "FatFile.h"
|
||||||
|
#include "StdioStream.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** FatFileSystem version YYYYMMDD */
|
||||||
|
#define FAT_LIB_VERSION 20150131
|
||||||
|
#endif // FatLib_h
|
146
hardware/_controller/src/SdFat/FatLib/FatLibConfig.h
Normal file
146
hardware/_controller/src/SdFat/FatLib/FatLibConfig.h
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief configuration definitions
|
||||||
|
*/
|
||||||
|
#ifndef FatLibConfig_h
|
||||||
|
#define FatLibConfig_h
|
||||||
|
#include <stdint.h>
|
||||||
|
// Allow this file to override defaults.
|
||||||
|
#include "../SdFatConfig.h"
|
||||||
|
|
||||||
|
#ifdef __AVR__
|
||||||
|
#include <avr/io.h>
|
||||||
|
#endif // __AVR__
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set USE_LONG_FILE_NAMES nonzero to use long file names (LFN).
|
||||||
|
* Long File Name are limited to a maximum length of 255 characters.
|
||||||
|
*
|
||||||
|
* This implementation allows 7-bit characters in the range
|
||||||
|
* 0X20 to 0X7E. The following characters are not allowed:
|
||||||
|
*
|
||||||
|
* < (less than)
|
||||||
|
* > (greater than)
|
||||||
|
* : (colon)
|
||||||
|
* " (double quote)
|
||||||
|
* / (forward slash)
|
||||||
|
* \ (backslash)
|
||||||
|
* | (vertical bar or pipe)
|
||||||
|
* ? (question mark)
|
||||||
|
* * (asterisk)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef USE_LONG_FILE_NAMES
|
||||||
|
#define USE_LONG_FILE_NAMES 1
|
||||||
|
#endif // USE_LONG_FILE_NAMES
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set USE_SEPARATE_FAT_CACHE non-zero to use a second 512 byte cache
|
||||||
|
* for FAT table entries. Improves performance for large writes that
|
||||||
|
* are not a multiple of 512 bytes.
|
||||||
|
*/
|
||||||
|
#ifndef USE_SEPARATE_FAT_CACHE
|
||||||
|
#ifdef __arm__
|
||||||
|
#define USE_SEPARATE_FAT_CACHE 1
|
||||||
|
#else // __arm__
|
||||||
|
#define USE_SEPARATE_FAT_CACHE 0
|
||||||
|
#endif // __arm__
|
||||||
|
#endif // USE_SEPARATE_FAT_CACHE
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set USE_MULTI_BLOCK_IO non-zero to use multi-block SD read/write.
|
||||||
|
*
|
||||||
|
* Don't use mult-block read/write on small AVR boards.
|
||||||
|
*/
|
||||||
|
#ifndef USE_MULTI_BLOCK_IO
|
||||||
|
#if defined(RAMEND) && RAMEND < 3000
|
||||||
|
#define USE_MULTI_BLOCK_IO 0
|
||||||
|
#else // RAMEND
|
||||||
|
#define USE_MULTI_BLOCK_IO 1
|
||||||
|
#endif // RAMEND
|
||||||
|
#endif // USE_MULTI_BLOCK_IO
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters
|
||||||
|
* updated. This will increase the speed of the freeClusterCount() call
|
||||||
|
* after the first call. Extra flash will be required.
|
||||||
|
*/
|
||||||
|
#ifndef MAINTAIN_FREE_CLUSTER_COUNT
|
||||||
|
#define MAINTAIN_FREE_CLUSTER_COUNT 0
|
||||||
|
#endif // MAINTAIN_FREE_CLUSTER_COUNT
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set DESTRUCTOR_CLOSES_FILE non-zero to close a file in its destructor.
|
||||||
|
*
|
||||||
|
* Causes use of lots of heap in ARM.
|
||||||
|
*/
|
||||||
|
#ifndef DESTRUCTOR_CLOSES_FILE
|
||||||
|
#define DESTRUCTOR_CLOSES_FILE 0
|
||||||
|
#endif // DESTRUCTOR_CLOSES_FILE
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Call flush for endl if ENDL_CALLS_FLUSH is non-zero
|
||||||
|
*
|
||||||
|
* The standard for iostreams is to call flush. This is very costly for
|
||||||
|
* SdFat. Each call to flush causes 2048 bytes of I/O to the SD.
|
||||||
|
*
|
||||||
|
* SdFat has a single 512 byte buffer for I/O so it must write the current
|
||||||
|
* data block to the SD, read the directory block from the SD, update the
|
||||||
|
* directory entry, write the directory block to the SD and read the data
|
||||||
|
* block back into the buffer.
|
||||||
|
*
|
||||||
|
* The SD flash memory controller is not designed for this many rewrites
|
||||||
|
* so performance may be reduced by more than a factor of 100.
|
||||||
|
*
|
||||||
|
* If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force
|
||||||
|
* all data to be written to the SD.
|
||||||
|
*/
|
||||||
|
#ifndef ENDL_CALLS_FLUSH
|
||||||
|
#define ENDL_CALLS_FLUSH 0
|
||||||
|
#endif // ENDL_CALLS_FLUSH
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Allow FAT12 volumes if FAT12_SUPPORT is non-zero.
|
||||||
|
* FAT12 has not been well tested.
|
||||||
|
*/
|
||||||
|
#ifndef FAT12_SUPPORT
|
||||||
|
#define FAT12_SUPPORT 0
|
||||||
|
#endif // FAT12_SUPPORT
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Enable Extra features for Arduino.
|
||||||
|
*/
|
||||||
|
// #define ENABLE_ARDUINO_FEATURES 0 ////////////////////////FIX THIS /////////////////
|
||||||
|
#ifndef ENABLE_ARDUINO_FEATURES
|
||||||
|
#include <Arduino.h>
|
||||||
|
#if defined(ARDUINO) || defined(PLATFORM_ID) || defined(DOXYGEN)
|
||||||
|
#define ENABLE_ARDUINO_FEATURES 1
|
||||||
|
#else // #if defined(ARDUINO) || defined(DOXYGEN)
|
||||||
|
#define ENABLE_ARDUINO_FEATURES 0
|
||||||
|
#endif // defined(ARDUINO) || defined(DOXYGEN)
|
||||||
|
#endif // ENABLE_ARDUINO_FEATURES
|
||||||
|
#endif // FatLibConfig_h
|
882
hardware/_controller/src/SdFat/FatLib/FatStructs.h
Normal file
882
hardware/_controller/src/SdFat/FatLib/FatStructs.h
Normal file
|
@ -0,0 +1,882 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef FatStructs_h
|
||||||
|
#define FatStructs_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief FAT file structures
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* mostly from Microsoft document fatgen103.doc
|
||||||
|
* http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||||
|
*/
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Value for byte 510 of boot block or MBR */
|
||||||
|
const uint8_t BOOTSIG0 = 0X55;
|
||||||
|
/** Value for byte 511 of boot block or MBR */
|
||||||
|
const uint8_t BOOTSIG1 = 0XAA;
|
||||||
|
/** Value for bootSignature field int FAT/FAT32 boot sector */
|
||||||
|
const uint8_t EXTENDED_BOOT_SIG = 0X29;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct partitionTable
|
||||||
|
* \brief MBR partition table entry
|
||||||
|
*
|
||||||
|
* A partition table entry for a MBR formatted storage device.
|
||||||
|
* The MBR partition table has four entries.
|
||||||
|
*/
|
||||||
|
struct partitionTable {
|
||||||
|
/**
|
||||||
|
* Boot Indicator . Indicates whether the volume is the active
|
||||||
|
* partition. Legal values include: 0X00. Do not use for booting.
|
||||||
|
* 0X80 Active partition.
|
||||||
|
*/
|
||||||
|
uint8_t boot;
|
||||||
|
/**
|
||||||
|
* Head part of Cylinder-head-sector address of the first block in
|
||||||
|
* the partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t beginHead;
|
||||||
|
/**
|
||||||
|
* Sector part of Cylinder-head-sector address of the first block in
|
||||||
|
* the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
unsigned beginSector : 6;
|
||||||
|
/** High bits cylinder for first block in partition. */
|
||||||
|
unsigned beginCylinderHigh : 2;
|
||||||
|
/**
|
||||||
|
* Combine beginCylinderLow with beginCylinderHigh. Legal values
|
||||||
|
* are 0-1023. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t beginCylinderLow;
|
||||||
|
/**
|
||||||
|
* Partition type. See defines that begin with PART_TYPE_ for
|
||||||
|
* some Microsoft partition types.
|
||||||
|
*/
|
||||||
|
uint8_t type;
|
||||||
|
/**
|
||||||
|
* head part of cylinder-head-sector address of the last sector in the
|
||||||
|
* partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t endHead;
|
||||||
|
/**
|
||||||
|
* Sector part of cylinder-head-sector address of the last sector in
|
||||||
|
* the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
unsigned endSector : 6;
|
||||||
|
/** High bits of end cylinder */
|
||||||
|
unsigned endCylinderHigh : 2;
|
||||||
|
/**
|
||||||
|
* Combine endCylinderLow with endCylinderHigh. Legal values
|
||||||
|
* are 0-1023. Only used in old PC BIOS.
|
||||||
|
*/
|
||||||
|
uint8_t endCylinderLow;
|
||||||
|
/** Logical block address of the first block in the partition. */
|
||||||
|
uint32_t firstSector;
|
||||||
|
/** Length of the partition, in blocks. */
|
||||||
|
uint32_t totalSectors;
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for partitionTable */
|
||||||
|
typedef struct partitionTable part_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct masterBootRecord
|
||||||
|
*
|
||||||
|
* \brief Master Boot Record
|
||||||
|
*
|
||||||
|
* The first block of a storage device that is formatted with a MBR.
|
||||||
|
*/
|
||||||
|
struct masterBootRecord {
|
||||||
|
/** Code Area for master boot program. */
|
||||||
|
uint8_t codeArea[440];
|
||||||
|
/** Optional Windows NT disk signature. May contain boot code. */
|
||||||
|
uint32_t diskSignature;
|
||||||
|
/** Usually zero but may be more boot code. */
|
||||||
|
uint16_t usuallyZero;
|
||||||
|
/** Partition tables. */
|
||||||
|
part_t part[4];
|
||||||
|
/** First MBR signature byte. Must be 0X55 */
|
||||||
|
uint8_t mbrSig0;
|
||||||
|
/** Second MBR signature byte. Must be 0XAA */
|
||||||
|
uint8_t mbrSig1;
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for masterBootRecord */
|
||||||
|
typedef struct masterBootRecord mbr_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct biosParmBlock
|
||||||
|
*
|
||||||
|
* \brief BIOS parameter block
|
||||||
|
*
|
||||||
|
* The BIOS parameter block describes the physical layout of a FAT volume.
|
||||||
|
*/
|
||||||
|
struct biosParmBlock {
|
||||||
|
/**
|
||||||
|
* Count of bytes per sector. This value may take on only the
|
||||||
|
* following values: 512, 1024, 2048 or 4096
|
||||||
|
*/
|
||||||
|
uint16_t bytesPerSector;
|
||||||
|
/**
|
||||||
|
* Number of sectors per allocation unit. This value must be a
|
||||||
|
* power of 2 that is greater than 0. The legal values are
|
||||||
|
* 1, 2, 4, 8, 16, 32, 64, and 128.
|
||||||
|
*/
|
||||||
|
uint8_t sectorsPerCluster;
|
||||||
|
/**
|
||||||
|
* Number of sectors before the first FAT.
|
||||||
|
* This value must not be zero.
|
||||||
|
*/
|
||||||
|
uint16_t reservedSectorCount;
|
||||||
|
/** The count of FAT data structures on the volume. This field should
|
||||||
|
* always contain the value 2 for any FAT volume of any type.
|
||||||
|
*/
|
||||||
|
uint8_t fatCount;
|
||||||
|
/**
|
||||||
|
* For FAT12 and FAT16 volumes, this field contains the count of
|
||||||
|
* 32-byte directory entries in the root directory. For FAT32 volumes,
|
||||||
|
* this field must be set to 0. For FAT12 and FAT16 volumes, this
|
||||||
|
* value should always specify a count that when multiplied by 32
|
||||||
|
* results in a multiple of bytesPerSector. FAT16 volumes should
|
||||||
|
* use the value 512.
|
||||||
|
*/
|
||||||
|
uint16_t rootDirEntryCount;
|
||||||
|
/**
|
||||||
|
* This field is the old 16-bit total count of sectors on the volume.
|
||||||
|
* This count includes the count of all sectors in all four regions
|
||||||
|
* of the volume. This field can be 0; if it is 0, then totalSectors32
|
||||||
|
* must be nonzero. For FAT32 volumes, this field must be 0. For
|
||||||
|
* FAT12 and FAT16 volumes, this field contains the sector count, and
|
||||||
|
* totalSectors32 is 0 if the total sector count fits
|
||||||
|
* (is less than 0x10000).
|
||||||
|
*/
|
||||||
|
uint16_t totalSectors16;
|
||||||
|
/**
|
||||||
|
* This dates back to the old MS-DOS 1.x media determination and is
|
||||||
|
* no longer usually used for anything. 0xF8 is the standard value
|
||||||
|
* for fixed (nonremovable) media. For removable media, 0xF0 is
|
||||||
|
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||||
|
*/
|
||||||
|
uint8_t mediaType;
|
||||||
|
/**
|
||||||
|
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
|
||||||
|
* On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||||
|
* contains the FAT size count.
|
||||||
|
*/
|
||||||
|
uint16_t sectorsPerFat16;
|
||||||
|
/** Sectors per track for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t sectorsPerTrtack;
|
||||||
|
/** Number of heads for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t headCount;
|
||||||
|
/**
|
||||||
|
* Count of hidden sectors preceding the partition that contains this
|
||||||
|
* FAT volume. This field is generally only relevant for media
|
||||||
|
* visible on interrupt 0x13.
|
||||||
|
*/
|
||||||
|
uint32_t hidddenSectors;
|
||||||
|
/**
|
||||||
|
* This field is the new 32-bit total count of sectors on the volume.
|
||||||
|
* This count includes the count of all sectors in all four regions
|
||||||
|
* of the volume. This field can be 0; if it is 0, then
|
||||||
|
* totalSectors16 must be nonzero.
|
||||||
|
*/
|
||||||
|
uint32_t totalSectors32;
|
||||||
|
/**
|
||||||
|
* Count of sectors occupied by one FAT on FAT32 volumes.
|
||||||
|
*/
|
||||||
|
uint32_t sectorsPerFat32;
|
||||||
|
/**
|
||||||
|
* This field is only defined for FAT32 media and does not exist on
|
||||||
|
* FAT12 and FAT16 media.
|
||||||
|
* Bits 0-3 -- Zero-based number of active FAT.
|
||||||
|
* Only valid if mirroring is disabled.
|
||||||
|
* Bits 4-6 -- Reserved.
|
||||||
|
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
|
||||||
|
* -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
|
||||||
|
* Bits 8-15 -- Reserved.
|
||||||
|
*/
|
||||||
|
uint16_t fat32Flags;
|
||||||
|
/**
|
||||||
|
* FAT32 version. High byte is major revision number.
|
||||||
|
* Low byte is minor revision number. Only 0.0 define.
|
||||||
|
*/
|
||||||
|
uint16_t fat32Version;
|
||||||
|
/**
|
||||||
|
* Cluster number of the first cluster of the root directory for FAT32.
|
||||||
|
* This usually 2 but not required to be 2.
|
||||||
|
*/
|
||||||
|
uint32_t fat32RootCluster;
|
||||||
|
/**
|
||||||
|
* Sector number of FSINFO structure in the reserved area of the
|
||||||
|
* FAT32 volume. Usually 1.
|
||||||
|
*/
|
||||||
|
uint16_t fat32FSInfo;
|
||||||
|
/**
|
||||||
|
* If nonzero, indicates the sector number in the reserved area
|
||||||
|
* of the volume of a copy of the boot record. Usually 6.
|
||||||
|
* No value other than 6 is recommended.
|
||||||
|
*/
|
||||||
|
uint16_t fat32BackBootBlock;
|
||||||
|
/**
|
||||||
|
* Reserved for future expansion. Code that formats FAT32 volumes
|
||||||
|
* should always set all of the bytes of this field to 0.
|
||||||
|
*/
|
||||||
|
uint8_t fat32Reserved[12];
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for biosParmBlock */
|
||||||
|
typedef struct biosParmBlock bpb_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct fat_boot
|
||||||
|
*
|
||||||
|
* \brief Boot sector for a FAT12/FAT16 volume.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct fat_boot {
|
||||||
|
/**
|
||||||
|
* The first three bytes of the boot sector must be valid,
|
||||||
|
* executable x 86-based CPU instructions. This includes a
|
||||||
|
* jump instruction that skips the next non-executable bytes.
|
||||||
|
*/
|
||||||
|
uint8_t jump[3];
|
||||||
|
/**
|
||||||
|
* This is typically a string of characters that identifies
|
||||||
|
* the operating system that formatted the volume.
|
||||||
|
*/
|
||||||
|
char oemId[8];
|
||||||
|
/**
|
||||||
|
* The size of a hardware sector. Valid decimal values for this
|
||||||
|
* field are 512, 1024, 2048, and 4096. For most disks used in
|
||||||
|
* the United States, the value of this field is 512.
|
||||||
|
*/
|
||||||
|
uint16_t bytesPerSector;
|
||||||
|
/**
|
||||||
|
* Number of sectors per allocation unit. This value must be a
|
||||||
|
* power of 2 that is greater than 0. The legal values are
|
||||||
|
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
|
||||||
|
*/
|
||||||
|
uint8_t sectorsPerCluster;
|
||||||
|
/**
|
||||||
|
* The number of sectors preceding the start of the first FAT,
|
||||||
|
* including the boot sector. The value of this field is always 1.
|
||||||
|
*/
|
||||||
|
uint16_t reservedSectorCount;
|
||||||
|
/**
|
||||||
|
* The number of copies of the FAT on the volume.
|
||||||
|
* The value of this field is always 2.
|
||||||
|
*/
|
||||||
|
uint8_t fatCount;
|
||||||
|
/**
|
||||||
|
* For FAT12 and FAT16 volumes, this field contains the count of
|
||||||
|
* 32-byte directory entries in the root directory. For FAT32 volumes,
|
||||||
|
* this field must be set to 0. For FAT12 and FAT16 volumes, this
|
||||||
|
* value should always specify a count that when multiplied by 32
|
||||||
|
* results in a multiple of bytesPerSector. FAT16 volumes should
|
||||||
|
* use the value 512.
|
||||||
|
*/
|
||||||
|
uint16_t rootDirEntryCount;
|
||||||
|
/**
|
||||||
|
* This field is the old 16-bit total count of sectors on the volume.
|
||||||
|
* This count includes the count of all sectors in all four regions
|
||||||
|
* of the volume. This field can be 0; if it is 0, then totalSectors32
|
||||||
|
* must be non-zero. For FAT32 volumes, this field must be 0. For
|
||||||
|
* FAT12 and FAT16 volumes, this field contains the sector count, and
|
||||||
|
* totalSectors32 is 0 if the total sector count fits
|
||||||
|
* (is less than 0x10000).
|
||||||
|
*/
|
||||||
|
uint16_t totalSectors16;
|
||||||
|
/**
|
||||||
|
* This dates back to the old MS-DOS 1.x media determination and is
|
||||||
|
* no longer usually used for anything. 0xF8 is the standard value
|
||||||
|
* for fixed (non-removable) media. For removable media, 0xF0 is
|
||||||
|
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||||
|
*/
|
||||||
|
uint8_t mediaType;
|
||||||
|
/**
|
||||||
|
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
|
||||||
|
* On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||||
|
* contains the FAT size count.
|
||||||
|
*/
|
||||||
|
uint16_t sectorsPerFat16;
|
||||||
|
/** Sectors per track for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t sectorsPerTrack;
|
||||||
|
/** Number of heads for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t headCount;
|
||||||
|
/**
|
||||||
|
* Count of hidden sectors preceding the partition that contains this
|
||||||
|
* FAT volume. This field is generally only relevant for media
|
||||||
|
* visible on interrupt 0x13.
|
||||||
|
*/
|
||||||
|
uint32_t hidddenSectors;
|
||||||
|
/**
|
||||||
|
* This field is the new 32-bit total count of sectors on the volume.
|
||||||
|
* This count includes the count of all sectors in all four regions
|
||||||
|
* of the volume. This field can be 0; if it is 0, then
|
||||||
|
* totalSectors16 must be non-zero.
|
||||||
|
*/
|
||||||
|
uint32_t totalSectors32;
|
||||||
|
/**
|
||||||
|
* Related to the BIOS physical drive number. Floppy drives are
|
||||||
|
* identified as 0x00 and physical hard disks are identified as
|
||||||
|
* 0x80, regardless of the number of physical disk drives.
|
||||||
|
* Typically, this value is set prior to issuing an INT 13h BIOS
|
||||||
|
* call to specify the device to access. The value is only
|
||||||
|
* relevant if the device is a boot device.
|
||||||
|
*/
|
||||||
|
uint8_t driveNumber;
|
||||||
|
/** used by Windows NT - should be zero for FAT */
|
||||||
|
uint8_t reserved1;
|
||||||
|
/** 0X29 if next three fields are valid */
|
||||||
|
uint8_t bootSignature;
|
||||||
|
/**
|
||||||
|
* A random serial number created when formatting a disk,
|
||||||
|
* which helps to distinguish between disks.
|
||||||
|
* Usually generated by combining date and time.
|
||||||
|
*/
|
||||||
|
uint32_t volumeSerialNumber;
|
||||||
|
/**
|
||||||
|
* A field once used to store the volume label. The volume label
|
||||||
|
* is now stored as a special file in the root directory.
|
||||||
|
*/
|
||||||
|
char volumeLabel[11];
|
||||||
|
/**
|
||||||
|
* A field with a value of either FAT, FAT12 or FAT16,
|
||||||
|
* depending on the disk format.
|
||||||
|
*/
|
||||||
|
char fileSystemType[8];
|
||||||
|
/** X86 boot code */
|
||||||
|
uint8_t bootCode[448];
|
||||||
|
/** must be 0X55 */
|
||||||
|
uint8_t bootSectorSig0;
|
||||||
|
/** must be 0XAA */
|
||||||
|
uint8_t bootSectorSig1;
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for FAT Boot Sector */
|
||||||
|
typedef struct fat_boot fat_boot_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct fat32_boot
|
||||||
|
*
|
||||||
|
* \brief Boot sector for a FAT32 volume.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct fat32_boot {
|
||||||
|
/**
|
||||||
|
* The first three bytes of the boot sector must be valid,
|
||||||
|
* executable x 86-based CPU instructions. This includes a
|
||||||
|
* jump instruction that skips the next non-executable bytes.
|
||||||
|
*/
|
||||||
|
uint8_t jump[3];
|
||||||
|
/**
|
||||||
|
* This is typically a string of characters that identifies
|
||||||
|
* the operating system that formatted the volume.
|
||||||
|
*/
|
||||||
|
char oemId[8];
|
||||||
|
/**
|
||||||
|
* The size of a hardware sector. Valid decimal values for this
|
||||||
|
* field are 512, 1024, 2048, and 4096. For most disks used in
|
||||||
|
* the United States, the value of this field is 512.
|
||||||
|
*/
|
||||||
|
uint16_t bytesPerSector;
|
||||||
|
/**
|
||||||
|
* Number of sectors per allocation unit. This value must be a
|
||||||
|
* power of 2 that is greater than 0. The legal values are
|
||||||
|
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
|
||||||
|
*/
|
||||||
|
uint8_t sectorsPerCluster;
|
||||||
|
/**
|
||||||
|
* The number of sectors preceding the start of the first FAT,
|
||||||
|
* including the boot sector. Must not be zero
|
||||||
|
*/
|
||||||
|
uint16_t reservedSectorCount;
|
||||||
|
/**
|
||||||
|
* The number of copies of the FAT on the volume.
|
||||||
|
* The value of this field is always 2.
|
||||||
|
*/
|
||||||
|
uint8_t fatCount;
|
||||||
|
/**
|
||||||
|
* FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0.
|
||||||
|
*/
|
||||||
|
uint16_t rootDirEntryCount;
|
||||||
|
/**
|
||||||
|
* For FAT32 volumes, this field must be 0.
|
||||||
|
*/
|
||||||
|
uint16_t totalSectors16;
|
||||||
|
/**
|
||||||
|
* This dates back to the old MS-DOS 1.x media determination and is
|
||||||
|
* no longer usually used for anything. 0xF8 is the standard value
|
||||||
|
* for fixed (non-removable) media. For removable media, 0xF0 is
|
||||||
|
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||||
|
*/
|
||||||
|
uint8_t mediaType;
|
||||||
|
/**
|
||||||
|
* On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||||
|
* contains the FAT size count.
|
||||||
|
*/
|
||||||
|
uint16_t sectorsPerFat16;
|
||||||
|
/** Sectors per track for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t sectorsPerTrack;
|
||||||
|
/** Number of heads for interrupt 0x13. Not used otherwise. */
|
||||||
|
uint16_t headCount;
|
||||||
|
/**
|
||||||
|
* Count of hidden sectors preceding the partition that contains this
|
||||||
|
* FAT volume. This field is generally only relevant for media
|
||||||
|
* visible on interrupt 0x13.
|
||||||
|
*/
|
||||||
|
uint32_t hidddenSectors;
|
||||||
|
/**
|
||||||
|
* Contains the total number of sectors in the FAT32 volume.
|
||||||
|
*/
|
||||||
|
uint32_t totalSectors32;
|
||||||
|
/**
|
||||||
|
* Count of sectors occupied by one FAT on FAT32 volumes.
|
||||||
|
*/
|
||||||
|
uint32_t sectorsPerFat32;
|
||||||
|
/**
|
||||||
|
* This field is only defined for FAT32 media and does not exist on
|
||||||
|
* FAT12 and FAT16 media.
|
||||||
|
* Bits 0-3 -- Zero-based number of active FAT.
|
||||||
|
* Only valid if mirroring is disabled.
|
||||||
|
* Bits 4-6 -- Reserved.
|
||||||
|
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
|
||||||
|
* -- 1 means only one FAT is active; it is the one referenced
|
||||||
|
* in bits 0-3.
|
||||||
|
* Bits 8-15 -- Reserved.
|
||||||
|
*/
|
||||||
|
uint16_t fat32Flags;
|
||||||
|
/**
|
||||||
|
* FAT32 version. High byte is major revision number.
|
||||||
|
* Low byte is minor revision number. Only 0.0 define.
|
||||||
|
*/
|
||||||
|
uint16_t fat32Version;
|
||||||
|
/**
|
||||||
|
* Cluster number of the first cluster of the root directory for FAT32.
|
||||||
|
* This usually 2 but not required to be 2.
|
||||||
|
*/
|
||||||
|
uint32_t fat32RootCluster;
|
||||||
|
/**
|
||||||
|
* Sector number of FSINFO structure in the reserved area of the
|
||||||
|
* FAT32 volume. Usually 1.
|
||||||
|
*/
|
||||||
|
uint16_t fat32FSInfo;
|
||||||
|
/**
|
||||||
|
* If non-zero, indicates the sector number in the reserved area
|
||||||
|
* of the volume of a copy of the boot record. Usually 6.
|
||||||
|
* No value other than 6 is recommended.
|
||||||
|
*/
|
||||||
|
uint16_t fat32BackBootBlock;
|
||||||
|
/**
|
||||||
|
* Reserved for future expansion. Code that formats FAT32 volumes
|
||||||
|
* should always set all of the bytes of this field to 0.
|
||||||
|
*/
|
||||||
|
uint8_t fat32Reserved[12];
|
||||||
|
/**
|
||||||
|
* Related to the BIOS physical drive number. Floppy drives are
|
||||||
|
* identified as 0x00 and physical hard disks are identified as
|
||||||
|
* 0x80, regardless of the number of physical disk drives.
|
||||||
|
* Typically, this value is set prior to issuing an INT 13h BIOS
|
||||||
|
* call to specify the device to access. The value is only
|
||||||
|
* relevant if the device is a boot device.
|
||||||
|
*/
|
||||||
|
uint8_t driveNumber;
|
||||||
|
/** used by Windows NT - should be zero for FAT */
|
||||||
|
uint8_t reserved1;
|
||||||
|
/** 0X29 if next three fields are valid */
|
||||||
|
uint8_t bootSignature;
|
||||||
|
/**
|
||||||
|
* A random serial number created when formatting a disk,
|
||||||
|
* which helps to distinguish between disks.
|
||||||
|
* Usually generated by combining date and time.
|
||||||
|
*/
|
||||||
|
uint32_t volumeSerialNumber;
|
||||||
|
/**
|
||||||
|
* A field once used to store the volume label. The volume label
|
||||||
|
* is now stored as a special file in the root directory.
|
||||||
|
*/
|
||||||
|
char volumeLabel[11];
|
||||||
|
/**
|
||||||
|
* A text field with a value of FAT32.
|
||||||
|
*/
|
||||||
|
char fileSystemType[8];
|
||||||
|
/** X86 boot code */
|
||||||
|
uint8_t bootCode[420];
|
||||||
|
/** must be 0X55 */
|
||||||
|
uint8_t bootSectorSig0;
|
||||||
|
/** must be 0XAA */
|
||||||
|
uint8_t bootSectorSig1;
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for FAT32 Boot Sector */
|
||||||
|
typedef struct fat32_boot fat32_boot_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Lead signature for a FSINFO sector */
|
||||||
|
const uint32_t FSINFO_LEAD_SIG = 0x41615252;
|
||||||
|
/** Struct signature for a FSINFO sector */
|
||||||
|
const uint32_t FSINFO_STRUCT_SIG = 0x61417272;
|
||||||
|
/**
|
||||||
|
* \struct fat32_fsinfo
|
||||||
|
*
|
||||||
|
* \brief FSINFO sector for a FAT32 volume.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct fat32_fsinfo {
|
||||||
|
/** must be 0X52, 0X52, 0X61, 0X41 */
|
||||||
|
uint32_t leadSignature;
|
||||||
|
/** must be zero */
|
||||||
|
uint8_t reserved1[480];
|
||||||
|
/** must be 0X72, 0X72, 0X41, 0X61 */
|
||||||
|
uint32_t structSignature;
|
||||||
|
/**
|
||||||
|
* Contains the last known free cluster count on the volume.
|
||||||
|
* If the value is 0xFFFFFFFF, then the free count is unknown
|
||||||
|
* and must be computed. Any other value can be used, but is
|
||||||
|
* not necessarily correct. It should be range checked at least
|
||||||
|
* to make sure it is <= volume cluster count.
|
||||||
|
*/
|
||||||
|
uint32_t freeCount;
|
||||||
|
/**
|
||||||
|
* This is a hint for the FAT driver. It indicates the cluster
|
||||||
|
* number at which the driver should start looking for free clusters.
|
||||||
|
* If the value is 0xFFFFFFFF, then there is no hint and the driver
|
||||||
|
* should start looking at cluster 2.
|
||||||
|
*/
|
||||||
|
uint32_t nextFree;
|
||||||
|
/** must be zero */
|
||||||
|
uint8_t reserved2[12];
|
||||||
|
/** must be 0X00, 0X00, 0X55, 0XAA */
|
||||||
|
uint8_t tailSignature[4];
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for FAT32 FSINFO Sector */
|
||||||
|
typedef struct fat32_fsinfo fat32_fsinfo_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// End Of Chain values for FAT entries
|
||||||
|
/** FAT12 end of chain value used by Microsoft. */
|
||||||
|
const uint16_t FAT12EOC = 0XFFF;
|
||||||
|
/** Minimum value for FAT12 EOC. Use to test for EOC. */
|
||||||
|
const uint16_t FAT12EOC_MIN = 0XFF8;
|
||||||
|
/** FAT16 end of chain value used by Microsoft. */
|
||||||
|
const uint16_t FAT16EOC = 0XFFFF;
|
||||||
|
/** Minimum value for FAT16 EOC. Use to test for EOC. */
|
||||||
|
const uint16_t FAT16EOC_MIN = 0XFFF8;
|
||||||
|
/** FAT32 end of chain value used by Microsoft. */
|
||||||
|
const uint32_t FAT32EOC = 0X0FFFFFFF;
|
||||||
|
/** Minimum value for FAT32 EOC. Use to test for EOC. */
|
||||||
|
const uint32_t FAT32EOC_MIN = 0X0FFFFFF8;
|
||||||
|
/** Mask a for FAT32 entry. Entries are 28 bits. */
|
||||||
|
const uint32_t FAT32MASK = 0X0FFFFFFF;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \struct directoryEntry
|
||||||
|
* \brief FAT short directory entry
|
||||||
|
*
|
||||||
|
* Short means short 8.3 name, not the entry size.
|
||||||
|
*
|
||||||
|
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
|
||||||
|
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
|
||||||
|
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
|
||||||
|
* 16-bit word):
|
||||||
|
*
|
||||||
|
* Bits 9-15: Count of years from 1980, valid value range 0-127
|
||||||
|
* inclusive (1980-2107).
|
||||||
|
*
|
||||||
|
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
|
||||||
|
*
|
||||||
|
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
|
||||||
|
*
|
||||||
|
* Time Format. A FAT directory entry time stamp is a 16-bit field that has
|
||||||
|
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
|
||||||
|
* 16-bit word, bit 15 is the MSB of the 16-bit word).
|
||||||
|
*
|
||||||
|
* Bits 11-15: Hours, valid value range 0-23 inclusive.
|
||||||
|
*
|
||||||
|
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
|
||||||
|
*
|
||||||
|
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
|
||||||
|
*
|
||||||
|
* The valid time range is from Midnight 00:00:00 to 23:59:58.
|
||||||
|
*/
|
||||||
|
struct directoryEntry {
|
||||||
|
/** Short 8.3 name.
|
||||||
|
*
|
||||||
|
* The first eight bytes contain the file name with blank fill.
|
||||||
|
* The last three bytes contain the file extension with blank fill.
|
||||||
|
*/
|
||||||
|
uint8_t name[11];
|
||||||
|
/** Entry attributes.
|
||||||
|
*
|
||||||
|
* The upper two bits of the attribute byte are reserved and should
|
||||||
|
* always be set to 0 when a file is created and never modified or
|
||||||
|
* looked at after that. See defines that begin with DIR_ATT_.
|
||||||
|
*/
|
||||||
|
uint8_t attributes;
|
||||||
|
/**
|
||||||
|
* Reserved for use by Windows NT. Set value to 0 when a file is
|
||||||
|
* created and never modify or look at it after that.
|
||||||
|
*/
|
||||||
|
uint8_t reservedNT;
|
||||||
|
/**
|
||||||
|
* The granularity of the seconds part of creationTime is 2 seconds
|
||||||
|
* so this field is a count of tenths of a second and its valid
|
||||||
|
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
|
||||||
|
*/
|
||||||
|
uint8_t creationTimeTenths;
|
||||||
|
/** Time file was created. */
|
||||||
|
uint16_t creationTime;
|
||||||
|
/** Date file was created. */
|
||||||
|
uint16_t creationDate;
|
||||||
|
/**
|
||||||
|
* Last access date. Note that there is no last access time, only
|
||||||
|
* a date. This is the date of last read or write. In the case of
|
||||||
|
* a write, this should be set to the same date as lastWriteDate.
|
||||||
|
*/
|
||||||
|
uint16_t lastAccessDate;
|
||||||
|
/**
|
||||||
|
* High word of this entry's first cluster number (always 0 for a
|
||||||
|
* FAT12 or FAT16 volume).
|
||||||
|
*/
|
||||||
|
uint16_t firstClusterHigh;
|
||||||
|
/** Time of last write. File creation is considered a write. */
|
||||||
|
uint16_t lastWriteTime;
|
||||||
|
/** Date of last write. File creation is considered a write. */
|
||||||
|
uint16_t lastWriteDate;
|
||||||
|
/** Low word of this entry's first cluster number. */
|
||||||
|
uint16_t firstClusterLow;
|
||||||
|
/** 32-bit unsigned holding this file's size in bytes. */
|
||||||
|
uint32_t fileSize;
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for directoryEntry */
|
||||||
|
typedef struct directoryEntry dir_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Definitions for directory entries
|
||||||
|
//
|
||||||
|
/** escape for name[0] = 0XE5 */
|
||||||
|
const uint8_t DIR_NAME_0XE5 = 0X05;
|
||||||
|
/** name[0] value for entry that is free after being "deleted" */
|
||||||
|
const uint8_t DIR_NAME_DELETED = 0XE5;
|
||||||
|
/** name[0] value for entry that is free and no allocated entries follow */
|
||||||
|
const uint8_t DIR_NAME_FREE = 0X00;
|
||||||
|
/** file is read-only */
|
||||||
|
const uint8_t DIR_ATT_READ_ONLY = 0X01;
|
||||||
|
/** File should e hidden in directory listings */
|
||||||
|
const uint8_t DIR_ATT_HIDDEN = 0X02;
|
||||||
|
/** Entry is for a system file */
|
||||||
|
const uint8_t DIR_ATT_SYSTEM = 0X04;
|
||||||
|
/** Directory entry contains the volume label */
|
||||||
|
const uint8_t DIR_ATT_VOLUME_ID = 0X08;
|
||||||
|
/** Entry is for a directory */
|
||||||
|
const uint8_t DIR_ATT_DIRECTORY = 0X10;
|
||||||
|
/** Old DOS archive bit for backup support */
|
||||||
|
const uint8_t DIR_ATT_ARCHIVE = 0X20;
|
||||||
|
/** Test value for long name entry. Test is
|
||||||
|
(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
|
||||||
|
const uint8_t DIR_ATT_LONG_NAME = 0X0F;
|
||||||
|
/** Test mask for long name entry */
|
||||||
|
const uint8_t DIR_ATT_LONG_NAME_MASK = 0X3F;
|
||||||
|
/** defined attribute bits */
|
||||||
|
const uint8_t DIR_ATT_DEFINED_BITS = 0X3F;
|
||||||
|
|
||||||
|
/** Mask for file/subdirectory tests */
|
||||||
|
const uint8_t DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
|
||||||
|
|
||||||
|
/** Filename base-name is all lower case */
|
||||||
|
const uint8_t DIR_NT_LC_BASE = 0X08;
|
||||||
|
/** Filename extension is all lower case.*/
|
||||||
|
const uint8_t DIR_NT_LC_EXT = 0X10;
|
||||||
|
|
||||||
|
|
||||||
|
/** Directory entry is for a file
|
||||||
|
* \param[in] dir Pointer to a directory entry.
|
||||||
|
*
|
||||||
|
* \return true if the entry is for a normal file else false.
|
||||||
|
*/
|
||||||
|
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
|
||||||
|
}
|
||||||
|
/** Directory entry is for a file or subdirectory
|
||||||
|
* \param[in] dir Pointer to a directory entry.
|
||||||
|
*
|
||||||
|
* \return true if the entry is for a normal file or subdirectory else false.
|
||||||
|
*/
|
||||||
|
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
|
||||||
|
}
|
||||||
|
/** Directory entry is part of a long name
|
||||||
|
* \param[in] dir Pointer to a directory entry.
|
||||||
|
*
|
||||||
|
* \return true if the entry is for part of a long name else false.
|
||||||
|
*/
|
||||||
|
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
|
||||||
|
return dir->attributes == DIR_ATT_LONG_NAME;
|
||||||
|
}
|
||||||
|
/** Directory entry is hidden
|
||||||
|
* \param[in] dir Pointer to a directory entry.
|
||||||
|
*
|
||||||
|
* \return true if the entry is hidden else false.
|
||||||
|
*/
|
||||||
|
static inline uint8_t DIR_IS_HIDDEN(const dir_t* dir) {
|
||||||
|
return dir->attributes & DIR_ATT_HIDDEN;
|
||||||
|
}
|
||||||
|
/** Directory entry is for a subdirectory
|
||||||
|
* \param[in] dir Pointer to a directory entry.
|
||||||
|
*
|
||||||
|
* \return true if the entry is for a subdirectory else false.
|
||||||
|
*/
|
||||||
|
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
|
||||||
|
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
|
||||||
|
}
|
||||||
|
/** Directory entry is system type
|
||||||
|
* \param[in] dir Pointer to a directory entry.
|
||||||
|
*
|
||||||
|
* \return true if the entry is system else false.
|
||||||
|
*/
|
||||||
|
static inline uint8_t DIR_IS_SYSTEM(const dir_t* dir) {
|
||||||
|
return dir->attributes & DIR_ATT_SYSTEM;
|
||||||
|
}
|
||||||
|
/** date field for FAT directory entry
|
||||||
|
* \param[in] year [1980,2107]
|
||||||
|
* \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 */
|
||||||
|
const uint16_t FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
|
||||||
|
/** Default time for file timestamp is 1 am */
|
||||||
|
const uint16_t FAT_DEFAULT_TIME = (1 << 11);
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Dimension of first name field in long directory entry */
|
||||||
|
const uint8_t LDIR_NAME1_DIM = 5;
|
||||||
|
/** Dimension of first name field in long directory entry */
|
||||||
|
const uint8_t LDIR_NAME2_DIM = 6;
|
||||||
|
/** Dimension of first name field in long directory entry */
|
||||||
|
const uint8_t LDIR_NAME3_DIM = 2;
|
||||||
|
/**
|
||||||
|
* \struct longDirectoryEntry
|
||||||
|
* \brief FAT long directory entry
|
||||||
|
*/
|
||||||
|
struct longDirectoryEntry {
|
||||||
|
/**
|
||||||
|
* The order of this entry in the sequence of long dir entries
|
||||||
|
* associated with the short dir entry at the end of the long dir set.
|
||||||
|
*
|
||||||
|
* If masked with 0X40 (LAST_LONG_ENTRY), this indicates the
|
||||||
|
* entry is the last long dir entry in a set of long dir entries.
|
||||||
|
* All valid sets of long dir entries must begin with an entry having
|
||||||
|
* this mask.
|
||||||
|
*/
|
||||||
|
uint8_t ord;
|
||||||
|
/** Characters 1-5 of the long-name sub-component in this entry. */
|
||||||
|
uint16_t name1[LDIR_NAME1_DIM];
|
||||||
|
/** Attributes - must be ATTR_LONG_NAME */
|
||||||
|
uint8_t attr;
|
||||||
|
/**
|
||||||
|
* If zero, indicates a directory entry that is a sub-component of a
|
||||||
|
* long name. NOTE: Other values reserved for future extensions.
|
||||||
|
*
|
||||||
|
* Non-zero implies other directory entry types.
|
||||||
|
*/
|
||||||
|
uint8_t type;
|
||||||
|
/**
|
||||||
|
* Checksum of name in the short dir entry at the end of the
|
||||||
|
* long dir set.
|
||||||
|
*/
|
||||||
|
uint8_t chksum;
|
||||||
|
/** Characters 6-11 of the long-name sub-component in this entry. */
|
||||||
|
uint16_t name2[LDIR_NAME2_DIM];
|
||||||
|
/** Must be ZERO. This is an artifact of the FAT "first cluster" */
|
||||||
|
uint16_t mustBeZero;
|
||||||
|
/** Characters 12 and 13 of the long-name sub-component in this entry. */
|
||||||
|
uint16_t name3[LDIR_NAME3_DIM];
|
||||||
|
} __attribute__((packed));
|
||||||
|
/** Type name for longDirectoryEntry */
|
||||||
|
typedef struct longDirectoryEntry ldir_t;
|
||||||
|
/**
|
||||||
|
* Ord mast that indicates the entry is the last long dir entry in a
|
||||||
|
* set of long dir entries. All valid sets of long dir entries must
|
||||||
|
* begin with an entry having this mask.
|
||||||
|
*/
|
||||||
|
const uint8_t LDIR_ORD_LAST_LONG_ENTRY = 0X40;
|
||||||
|
#endif // FatStructs_h
|
625
hardware/_controller/src/SdFat/FatLib/FatVolume.cpp
Normal file
625
hardware/_controller/src/SdFat/FatLib/FatVolume.cpp
Normal file
|
@ -0,0 +1,625 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "FatVolume.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
cache_t* FatCache::read(uint32_t lbn, uint8_t option) {
|
||||||
|
if (m_lbn != lbn) {
|
||||||
|
if (!sync()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!(option & CACHE_OPTION_NO_READ)) {
|
||||||
|
if (!m_vol->readBlock(lbn, m_block.data)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_status = 0;
|
||||||
|
m_lbn = lbn;
|
||||||
|
}
|
||||||
|
m_status |= option & CACHE_STATUS_MASK;
|
||||||
|
return &m_block;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatCache::sync() {
|
||||||
|
if (m_status & CACHE_STATUS_DIRTY) {
|
||||||
|
if (!m_vol->writeBlock(m_lbn, m_block.data)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// mirror second FAT
|
||||||
|
if (m_status & CACHE_STATUS_MIRROR_FAT) {
|
||||||
|
uint32_t lbn = m_lbn + m_vol->blocksPerFat();
|
||||||
|
if (!m_vol->writeBlock(lbn, m_block.data)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_status &= ~CACHE_STATUS_DIRTY;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatVolume::allocateCluster(uint32_t current, uint32_t* next) {
|
||||||
|
uint32_t find;
|
||||||
|
bool setStart;
|
||||||
|
if (m_allocSearchStart < current) {
|
||||||
|
// Try to keep file contiguous. Start just after current cluster.
|
||||||
|
find = current;
|
||||||
|
setStart = false;
|
||||||
|
} else {
|
||||||
|
find = m_allocSearchStart;
|
||||||
|
setStart = true;
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
find++;
|
||||||
|
if (find > m_lastCluster) {
|
||||||
|
if (setStart) {
|
||||||
|
// Can't find space, checked all clusters.
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
find = m_allocSearchStart;
|
||||||
|
setStart = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (find == current) {
|
||||||
|
// Can't find space, already searched clusters after current.
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
uint32_t f;
|
||||||
|
int8_t fg = fatGet(find, &f);
|
||||||
|
if (fg < 0) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (fg && f == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (setStart) {
|
||||||
|
m_allocSearchStart = find;
|
||||||
|
}
|
||||||
|
// Mark end of chain.
|
||||||
|
if (!fatPutEOC(find)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (current) {
|
||||||
|
// Link clusters.
|
||||||
|
if (!fatPut(current, find)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateFreeClusterCount(-1);
|
||||||
|
*next = find;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// find a contiguous group of clusters
|
||||||
|
bool FatVolume::allocContiguous(uint32_t count,
|
||||||
|
uint32_t* firstCluster, uint32_t startCluster) {
|
||||||
|
// flag to save place to start next search
|
||||||
|
bool setStart;
|
||||||
|
// start of group
|
||||||
|
uint32_t bgnCluster;
|
||||||
|
// end of group
|
||||||
|
uint32_t endCluster;
|
||||||
|
if (startCluster != 0) {
|
||||||
|
bgnCluster = startCluster;
|
||||||
|
setStart = false;
|
||||||
|
} else {
|
||||||
|
// Start at cluster after last allocated cluster.
|
||||||
|
bgnCluster = m_allocSearchStart + 1;
|
||||||
|
setStart = true;
|
||||||
|
}
|
||||||
|
endCluster = bgnCluster;
|
||||||
|
// search the FAT for free clusters
|
||||||
|
while (1) {
|
||||||
|
if (endCluster > m_lastCluster) {
|
||||||
|
// Can't find space.
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
uint32_t f;
|
||||||
|
int8_t fg = fatGet(endCluster, &f);
|
||||||
|
if (fg < 0) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (f || fg == 0) {
|
||||||
|
if (startCluster) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// don't update search start if unallocated clusters before endCluster.
|
||||||
|
if (bgnCluster != endCluster) {
|
||||||
|
setStart = false;
|
||||||
|
}
|
||||||
|
// cluster in use try next cluster as bgnCluster
|
||||||
|
bgnCluster = endCluster + 1;
|
||||||
|
} else if ((endCluster - bgnCluster + 1) == count) {
|
||||||
|
// done - found space
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
endCluster++;
|
||||||
|
}
|
||||||
|
// Remember possible next free cluster.
|
||||||
|
if (setStart) {
|
||||||
|
m_allocSearchStart = endCluster;
|
||||||
|
}
|
||||||
|
// mark end of chain
|
||||||
|
if (!fatPutEOC(endCluster)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// link clusters
|
||||||
|
while (endCluster > bgnCluster) {
|
||||||
|
if (!fatPut(endCluster - 1, endCluster)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
endCluster--;
|
||||||
|
}
|
||||||
|
// Maintain count of free clusters.
|
||||||
|
updateFreeClusterCount(-count);
|
||||||
|
|
||||||
|
// return first cluster number to caller
|
||||||
|
*firstCluster = bgnCluster;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
uint32_t FatVolume::clusterFirstBlock(uint32_t cluster) const {
|
||||||
|
return m_dataStartBlock + ((cluster - 2) << m_clusterSizeShift);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Fetch a FAT entry - return -1 error, 0 EOC, else 1.
|
||||||
|
int8_t FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
|
||||||
|
uint32_t lba;
|
||||||
|
uint32_t next;
|
||||||
|
cache_t* pc;
|
||||||
|
|
||||||
|
// error if reserved cluster of beyond FAT
|
||||||
|
if (cluster < 2 || cluster > m_lastCluster) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fatType() == 32) {
|
||||||
|
lba = m_fatStartBlock + (cluster >> 7);
|
||||||
|
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
next = pc->fat32[cluster & 0X7F] & FAT32MASK;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (fatType() == 16) {
|
||||||
|
lba = m_fatStartBlock + ((cluster >> 8) & 0XFF);
|
||||||
|
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
next = pc->fat16[cluster & 0XFF];
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (FAT12_SUPPORT && fatType() == 12) {
|
||||||
|
uint16_t index = cluster;
|
||||||
|
index += index >> 1;
|
||||||
|
lba = m_fatStartBlock + (index >> 9);
|
||||||
|
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
index &= 0X1FF;
|
||||||
|
uint16_t tmp = pc->data[index];
|
||||||
|
index++;
|
||||||
|
if (index == 512) {
|
||||||
|
pc = cacheFetchFat(lba + 1, FatCache::CACHE_FOR_READ);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
tmp |= pc->data[index] << 8;
|
||||||
|
next = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
|
||||||
|
goto done;
|
||||||
|
} else {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
if (isEOC(next)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*value = next;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Store a FAT entry
|
||||||
|
bool FatVolume::fatPut(uint32_t cluster, uint32_t value) {
|
||||||
|
uint32_t lba;
|
||||||
|
cache_t* pc;
|
||||||
|
|
||||||
|
// error if reserved cluster of beyond FAT
|
||||||
|
if (cluster < 2 || cluster > m_lastCluster) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fatType() == 32) {
|
||||||
|
lba = m_fatStartBlock + (cluster >> 7);
|
||||||
|
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
pc->fat32[cluster & 0X7F] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fatType() == 16) {
|
||||||
|
lba = m_fatStartBlock + ((cluster >> 8) & 0XFF);
|
||||||
|
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
pc->fat16[cluster & 0XFF] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAT12_SUPPORT && fatType() == 12) {
|
||||||
|
uint16_t index = cluster;
|
||||||
|
index += index >> 1;
|
||||||
|
lba = m_fatStartBlock + (index >> 9);
|
||||||
|
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
index &= 0X1FF;
|
||||||
|
uint8_t tmp = value;
|
||||||
|
if (cluster & 1) {
|
||||||
|
tmp = (pc->data[index] & 0XF) | tmp << 4;
|
||||||
|
}
|
||||||
|
pc->data[index] = tmp;
|
||||||
|
|
||||||
|
index++;
|
||||||
|
if (index == 512) {
|
||||||
|
lba++;
|
||||||
|
index = 0;
|
||||||
|
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp = value >> 4;
|
||||||
|
if (!(cluster & 1)) {
|
||||||
|
tmp = ((pc->data[index] & 0XF0)) | tmp >> 4;
|
||||||
|
}
|
||||||
|
pc->data[index] = tmp;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// free a cluster chain
|
||||||
|
bool FatVolume::freeChain(uint32_t cluster) {
|
||||||
|
uint32_t next = 0;
|
||||||
|
int8_t fg;
|
||||||
|
do {
|
||||||
|
fg = fatGet(cluster, &next);
|
||||||
|
if (fg < 0) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// free cluster
|
||||||
|
if (!fatPut(cluster, 0)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// Add one to count of free clusters.
|
||||||
|
updateFreeClusterCount(1);
|
||||||
|
|
||||||
|
if (cluster <= m_allocSearchStart) {
|
||||||
|
m_allocSearchStart = cluster - 1;
|
||||||
|
}
|
||||||
|
cluster = next;
|
||||||
|
} while (fg);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int32_t FatVolume::freeClusterCount() {
|
||||||
|
#if MAINTAIN_FREE_CLUSTER_COUNT
|
||||||
|
if (m_freeClusterCount >= 0) {
|
||||||
|
return m_freeClusterCount;
|
||||||
|
}
|
||||||
|
#endif // MAINTAIN_FREE_CLUSTER_COUNT
|
||||||
|
uint32_t free = 0;
|
||||||
|
uint32_t lba;
|
||||||
|
uint32_t todo = m_lastCluster + 1;
|
||||||
|
uint16_t n;
|
||||||
|
|
||||||
|
if (FAT12_SUPPORT && fatType() == 12) {
|
||||||
|
for (unsigned i = 2; i < todo; i++) {
|
||||||
|
uint32_t c;
|
||||||
|
int8_t fg = fatGet(i, &c);
|
||||||
|
if (fg < 0) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (fg && c == 0) {
|
||||||
|
free++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (fatType() == 16 || fatType() == 32) {
|
||||||
|
lba = m_fatStartBlock;
|
||||||
|
while (todo) {
|
||||||
|
cache_t* pc = cacheFetchFat(lba++, FatCache::CACHE_FOR_READ);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
n = fatType() == 16 ? 256 : 128;
|
||||||
|
if (todo < n) {
|
||||||
|
n = todo;
|
||||||
|
}
|
||||||
|
if (fatType() == 16) {
|
||||||
|
for (uint16_t i = 0; i < n; i++) {
|
||||||
|
if (pc->fat16[i] == 0) {
|
||||||
|
free++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (uint16_t i = 0; i < n; i++) {
|
||||||
|
if (pc->fat32[i] == 0) {
|
||||||
|
free++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
todo -= n;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// invalid FAT type
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
setFreeClusterCount(free);
|
||||||
|
return free;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatVolume::init(uint8_t part) {
|
||||||
|
uint32_t clusterCount;
|
||||||
|
uint32_t totalBlocks;
|
||||||
|
uint32_t volumeStartBlock = 0;
|
||||||
|
fat32_boot_t* fbs;
|
||||||
|
cache_t* pc;
|
||||||
|
uint8_t tmp;
|
||||||
|
m_fatType = 0;
|
||||||
|
m_allocSearchStart = 1;
|
||||||
|
m_cache.init(this);
|
||||||
|
#if USE_SEPARATE_FAT_CACHE
|
||||||
|
m_fatCache.init(this);
|
||||||
|
#endif // USE_SEPARATE_FAT_CACHE
|
||||||
|
// if part == 0 assume super floppy with FAT boot sector in block zero
|
||||||
|
// if part > 0 assume mbr volume with partition table
|
||||||
|
if (part) {
|
||||||
|
if (part > 4) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
pc = cacheFetchData(0, FatCache::CACHE_FOR_READ);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
part_t* p = &pc->mbr.part[part - 1];
|
||||||
|
if ((p->boot & 0X7F) != 0 || p->firstSector == 0) {
|
||||||
|
// not a valid partition
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
volumeStartBlock = p->firstSector;
|
||||||
|
}
|
||||||
|
pc = cacheFetchData(volumeStartBlock, FatCache::CACHE_FOR_READ);
|
||||||
|
if (!pc) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
fbs = &(pc->fbs32);
|
||||||
|
if (fbs->bytesPerSector != 512 ||
|
||||||
|
fbs->fatCount != 2 ||
|
||||||
|
fbs->reservedSectorCount == 0) {
|
||||||
|
// not valid FAT volume
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
m_blocksPerCluster = fbs->sectorsPerCluster;
|
||||||
|
m_clusterBlockMask = m_blocksPerCluster - 1;
|
||||||
|
// determine shift that is same as multiply by m_blocksPerCluster
|
||||||
|
m_clusterSizeShift = 0;
|
||||||
|
for (tmp = 1; m_blocksPerCluster != tmp; tmp <<= 1, m_clusterSizeShift++) {
|
||||||
|
if (tmp == 0) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_blocksPerFat = fbs->sectorsPerFat16 ?
|
||||||
|
fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
|
||||||
|
|
||||||
|
m_fatStartBlock = volumeStartBlock + fbs->reservedSectorCount;
|
||||||
|
|
||||||
|
// count for FAT16 zero for FAT32
|
||||||
|
m_rootDirEntryCount = fbs->rootDirEntryCount;
|
||||||
|
|
||||||
|
// directory start for FAT16 dataStart for FAT32
|
||||||
|
m_rootDirStart = m_fatStartBlock + 2 * m_blocksPerFat;
|
||||||
|
// data start for FAT16 and FAT32
|
||||||
|
m_dataStartBlock = m_rootDirStart + ((32 * fbs->rootDirEntryCount + 511)/512);
|
||||||
|
|
||||||
|
// total blocks for FAT16 or FAT32
|
||||||
|
totalBlocks = fbs->totalSectors16 ?
|
||||||
|
fbs->totalSectors16 : fbs->totalSectors32;
|
||||||
|
// total data blocks
|
||||||
|
clusterCount = totalBlocks - (m_dataStartBlock - volumeStartBlock);
|
||||||
|
|
||||||
|
// divide by cluster size to get cluster count
|
||||||
|
clusterCount >>= m_clusterSizeShift;
|
||||||
|
m_lastCluster = clusterCount + 1;
|
||||||
|
|
||||||
|
// Indicate unknown number of free clusters.
|
||||||
|
setFreeClusterCount(-1);
|
||||||
|
// FAT type is determined by cluster count
|
||||||
|
if (clusterCount < 4085) {
|
||||||
|
m_fatType = 12;
|
||||||
|
if (!FAT12_SUPPORT) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else if (clusterCount < 65525) {
|
||||||
|
m_fatType = 16;
|
||||||
|
} else {
|
||||||
|
m_rootDirStart = fbs->fat32RootCluster;
|
||||||
|
m_fatType = 32;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool FatVolume::wipe(print_t* pr) {
|
||||||
|
cache_t* cache;
|
||||||
|
uint16_t count;
|
||||||
|
uint32_t lbn;
|
||||||
|
if (!fatType()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
cache = cacheClear();
|
||||||
|
if (!cache) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
memset(cache->data, 0, 512);
|
||||||
|
// Zero root.
|
||||||
|
if (fatType() == 32) {
|
||||||
|
lbn = clusterFirstBlock(m_rootDirStart);
|
||||||
|
count = m_blocksPerCluster;
|
||||||
|
} else {
|
||||||
|
lbn = m_rootDirStart;
|
||||||
|
count = m_rootDirEntryCount/16;
|
||||||
|
}
|
||||||
|
for (uint32_t n = 0; n < count; n++) {
|
||||||
|
if (!writeBlock(lbn + n, cache->data)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clear FATs.
|
||||||
|
count = 2*m_blocksPerFat;
|
||||||
|
lbn = m_fatStartBlock;
|
||||||
|
for (uint32_t nb = 0; nb < count; nb++) {
|
||||||
|
if (pr && (nb & 0XFF) == 0) {
|
||||||
|
pr->write('.');
|
||||||
|
}
|
||||||
|
if (!writeBlock(lbn + nb, cache->data)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Reserve first two clusters.
|
||||||
|
if (fatType() == 32) {
|
||||||
|
cache->fat32[0] = 0x0FFFFFF8;
|
||||||
|
cache->fat32[1] = 0x0FFFFFFF;
|
||||||
|
} else if (fatType() == 16) {
|
||||||
|
cache->fat16[0] = 0XFFF8;
|
||||||
|
cache->fat16[1] = 0XFFFF;
|
||||||
|
} else if (FAT12_SUPPORT && fatType() == 12) {
|
||||||
|
cache->fat32[0] = 0XFFFFF8;
|
||||||
|
} else {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!writeBlock(m_fatStartBlock, cache->data) ||
|
||||||
|
!writeBlock(m_fatStartBlock + m_blocksPerFat, cache->data)) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (fatType() == 32) {
|
||||||
|
// Reserve root cluster.
|
||||||
|
if (!fatPutEOC(m_rootDirStart) || !cacheSync()) {
|
||||||
|
DBG_FAIL_MACRO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pr) {
|
||||||
|
pr->write('\r');
|
||||||
|
pr->write('\n');
|
||||||
|
}
|
||||||
|
m_fatType = 0;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
m_fatType = 0;
|
||||||
|
return false;
|
||||||
|
}
|
396
hardware/_controller/src/SdFat/FatLib/FatVolume.h
Normal file
396
hardware/_controller/src/SdFat/FatLib/FatVolume.h
Normal file
|
@ -0,0 +1,396 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef FatVolume_h
|
||||||
|
#define FatVolume_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief FatVolume class
|
||||||
|
*/
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "FatLibConfig.h"
|
||||||
|
#include "FatStructs.h"
|
||||||
|
#include "../BlockDriver.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
/** Macro for debug. */
|
||||||
|
#define DEBUG_MODE 0
|
||||||
|
#if DEBUG_MODE
|
||||||
|
#define DBG_FAIL_MACRO Serial.print(F(__FILE__)); Serial.println(__LINE__);
|
||||||
|
#define DBG_PRINT_IF(b) if (b) {Serial.println(F(#b)); DBG_FAIL_MACRO;}
|
||||||
|
#define DBG_HALT_IF(b) if (b) {Serial.println(F(#b));\
|
||||||
|
DBG_FAIL_MACRO; while (1);}
|
||||||
|
#else // DEBUG_MODE
|
||||||
|
#define DBG_FAIL_MACRO
|
||||||
|
#define DBG_PRINT_IF(b)
|
||||||
|
#define DBG_HALT_IF(b)
|
||||||
|
#endif // DEBUG_MODE
|
||||||
|
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if ENABLE_ARDUINO_FEATURES
|
||||||
|
/** Use Print for Arduino */
|
||||||
|
typedef Print print_t;
|
||||||
|
#else // ENABLE_ARDUINO_FEATURES
|
||||||
|
/**
|
||||||
|
* \class CharWriter
|
||||||
|
* \brief Character output - often serial port.
|
||||||
|
*/
|
||||||
|
class CharWriter {
|
||||||
|
public:
|
||||||
|
virtual size_t write(char c) = 0;
|
||||||
|
virtual size_t write(const char* s) = 0;
|
||||||
|
};
|
||||||
|
typedef CharWriter print_t;
|
||||||
|
#endif // ENABLE_ARDUINO_FEATURES
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Forward declaration of FatVolume.
|
||||||
|
class FatVolume;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \brief Cache for an raw data block.
|
||||||
|
*/
|
||||||
|
union cache_t {
|
||||||
|
/** Used to access cached file data blocks. */
|
||||||
|
uint8_t data[512];
|
||||||
|
/** Used to access cached FAT16 entries. */
|
||||||
|
uint16_t fat16[256];
|
||||||
|
/** Used to access cached FAT32 entries. */
|
||||||
|
uint32_t fat32[128];
|
||||||
|
/** Used to access cached directory entries. */
|
||||||
|
dir_t dir[16];
|
||||||
|
/** Used to access a cached Master Boot Record. */
|
||||||
|
mbr_t mbr;
|
||||||
|
/** Used to access to a cached FAT boot sector. */
|
||||||
|
fat_boot_t fbs;
|
||||||
|
/** Used to access to a cached FAT32 boot sector. */
|
||||||
|
fat32_boot_t fbs32;
|
||||||
|
/** Used to access to a cached FAT32 FSINFO sector. */
|
||||||
|
fat32_fsinfo_t fsinfo;
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class FatCache
|
||||||
|
* \brief Block cache.
|
||||||
|
*/
|
||||||
|
class FatCache {
|
||||||
|
public:
|
||||||
|
/** Cached block is dirty */
|
||||||
|
static const uint8_t CACHE_STATUS_DIRTY = 1;
|
||||||
|
/** Cashed block is FAT entry and must be mirrored in second FAT. */
|
||||||
|
static const uint8_t CACHE_STATUS_MIRROR_FAT = 2;
|
||||||
|
/** Cache block status bits */
|
||||||
|
static const uint8_t CACHE_STATUS_MASK
|
||||||
|
= CACHE_STATUS_DIRTY | CACHE_STATUS_MIRROR_FAT;
|
||||||
|
/** Sync existing block but do not read new block. */
|
||||||
|
static const uint8_t CACHE_OPTION_NO_READ = 4;
|
||||||
|
/** Cache block for read. */
|
||||||
|
static const uint8_t CACHE_FOR_READ = 0;
|
||||||
|
/** Cache block for write. */
|
||||||
|
static const uint8_t CACHE_FOR_WRITE = CACHE_STATUS_DIRTY;
|
||||||
|
/** Reserve cache block for write - do not read from block device. */
|
||||||
|
static const uint8_t CACHE_RESERVE_FOR_WRITE
|
||||||
|
= CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ;
|
||||||
|
/** \return Cache block address. */
|
||||||
|
cache_t* block() {
|
||||||
|
return &m_block;
|
||||||
|
}
|
||||||
|
/** Set current block dirty. */
|
||||||
|
void dirty() {
|
||||||
|
m_status |= CACHE_STATUS_DIRTY;
|
||||||
|
}
|
||||||
|
/** Initialize the cache.
|
||||||
|
* \param[in] vol FatVolume that owns this FatCache.
|
||||||
|
*/
|
||||||
|
void init(FatVolume *vol) {
|
||||||
|
m_vol = vol;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
/** Invalidate current cache block. */
|
||||||
|
void invalidate() {
|
||||||
|
m_status = 0;
|
||||||
|
m_lbn = 0XFFFFFFFF;
|
||||||
|
}
|
||||||
|
/** \return dirty status */
|
||||||
|
bool isDirty() {
|
||||||
|
return m_status & CACHE_STATUS_DIRTY;
|
||||||
|
}
|
||||||
|
/** \return Logical block number for cached block. */
|
||||||
|
uint32_t lbn() {
|
||||||
|
return m_lbn;
|
||||||
|
}
|
||||||
|
/** Read a block into the cache.
|
||||||
|
* \param[in] lbn Block to read.
|
||||||
|
* \param[in] option mode for cached block.
|
||||||
|
* \return Address of cached block. */
|
||||||
|
cache_t* read(uint32_t lbn, uint8_t option);
|
||||||
|
/** Write current block if dirty.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool sync();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t m_status;
|
||||||
|
FatVolume* m_vol;
|
||||||
|
uint32_t m_lbn;
|
||||||
|
cache_t m_block;
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class FatVolume
|
||||||
|
* \brief Access FAT16 and FAT32 volumes on raw file devices.
|
||||||
|
*/
|
||||||
|
class FatVolume {
|
||||||
|
public:
|
||||||
|
/** Create an instance of FatVolume
|
||||||
|
*/
|
||||||
|
FatVolume() : m_fatType(0) {}
|
||||||
|
|
||||||
|
/** \return The volume's cluster size in blocks. */
|
||||||
|
uint8_t blocksPerCluster() const {
|
||||||
|
return m_blocksPerCluster;
|
||||||
|
}
|
||||||
|
/** \return The number of blocks in one FAT. */
|
||||||
|
uint32_t blocksPerFat() const {
|
||||||
|
return m_blocksPerFat;
|
||||||
|
}
|
||||||
|
/** Clear the cache and returns a pointer to the cache. Not for normal apps.
|
||||||
|
* \return A pointer to the cache buffer or zero if an error occurs.
|
||||||
|
*/
|
||||||
|
cache_t* cacheClear() {
|
||||||
|
if (!cacheSync()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
m_cache.invalidate();
|
||||||
|
return m_cache.block();
|
||||||
|
}
|
||||||
|
/** \return The total number of clusters in the volume. */
|
||||||
|
uint32_t clusterCount() const {
|
||||||
|
return m_lastCluster - 1;
|
||||||
|
}
|
||||||
|
/** \return The shift count required to multiply by blocksPerCluster. */
|
||||||
|
uint8_t clusterSizeShift() const {
|
||||||
|
return m_clusterSizeShift;
|
||||||
|
}
|
||||||
|
/** \return The logical block number for the start of file data. */
|
||||||
|
uint32_t dataStartBlock() const {
|
||||||
|
return m_dataStartBlock;
|
||||||
|
}
|
||||||
|
/** \return The sector number for the start of file data. */
|
||||||
|
uint32_t dataStartSector() const {
|
||||||
|
return m_dataStartBlock;
|
||||||
|
}
|
||||||
|
/** \return The number of File Allocation Tables. */
|
||||||
|
uint8_t fatCount() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
/** \return The logical block number for the start of the first FAT. */
|
||||||
|
uint32_t fatStartBlock() const {
|
||||||
|
return m_fatStartBlock;
|
||||||
|
}
|
||||||
|
/** \return The sector number for the start of the first FAT. */
|
||||||
|
uint32_t fatStartSector() const {
|
||||||
|
return m_fatStartBlock;
|
||||||
|
}
|
||||||
|
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
|
||||||
|
uint8_t fatType() const {
|
||||||
|
return m_fatType;
|
||||||
|
}
|
||||||
|
/** Volume free space in clusters.
|
||||||
|
*
|
||||||
|
* \return Count of free clusters for success or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int32_t freeClusterCount();
|
||||||
|
/** Initialize a FAT volume. Try partition one first then try super
|
||||||
|
* floppy format.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool init() {
|
||||||
|
return init(1) || init(0);
|
||||||
|
}
|
||||||
|
/** Initialize a FAT volume.
|
||||||
|
|
||||||
|
* \param[in] part The partition to be used. Legal values for \a part are
|
||||||
|
* 1-4 to use the corresponding partition on a device formatted with
|
||||||
|
* a MBR, Master Boot Record, or zero if the device is formatted as
|
||||||
|
* a super floppy with the FAT boot sector in block zero.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool init(uint8_t part);
|
||||||
|
/** \return The cluster number of last cluster in the volume. */
|
||||||
|
uint32_t lastCluster() const {
|
||||||
|
return m_lastCluster;
|
||||||
|
}
|
||||||
|
/** \return The number of entries in the root directory for FAT16 volumes. */
|
||||||
|
uint16_t rootDirEntryCount() const {
|
||||||
|
return m_rootDirEntryCount;
|
||||||
|
}
|
||||||
|
/** \return The logical block number for the start of the root directory
|
||||||
|
on FAT16 volumes or the first cluster number on FAT32 volumes. */
|
||||||
|
uint32_t rootDirStart() const {
|
||||||
|
return m_rootDirStart;
|
||||||
|
}
|
||||||
|
/** \return The volume's cluster size in sectors. */
|
||||||
|
uint8_t sectorsPerCluster() const {
|
||||||
|
return m_blocksPerCluster;
|
||||||
|
}
|
||||||
|
/** \return The number of blocks in the volume */
|
||||||
|
uint32_t volumeBlockCount() const {
|
||||||
|
return blocksPerCluster()*clusterCount();
|
||||||
|
}
|
||||||
|
/** \return The number of sectors in the volume */
|
||||||
|
uint32_t volumeSectorCount() const {
|
||||||
|
return sectorsPerCluster()*clusterCount();
|
||||||
|
}
|
||||||
|
/** Wipe all data from the volume.
|
||||||
|
* \param[in] pr print stream for status dots.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool wipe(print_t* pr = 0);
|
||||||
|
/** Debug access to FAT table
|
||||||
|
*
|
||||||
|
* \param[in] n cluster number.
|
||||||
|
* \param[out] v value of entry
|
||||||
|
* \return -1 error, 0 EOC, else 1.
|
||||||
|
*/
|
||||||
|
int8_t dbgFat(uint32_t n, uint32_t* v) {
|
||||||
|
return fatGet(n, v);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
private:
|
||||||
|
// Allow FatFile and FatCache access to FatVolume private functions.
|
||||||
|
friend class FatCache; ///< Allow access to FatVolume.
|
||||||
|
friend class FatFile; ///< Allow access to FatVolume.
|
||||||
|
friend class FatFileSystem; ///< Allow access to FatVolume.
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
BlockDriver* m_blockDev; // block device
|
||||||
|
uint8_t m_blocksPerCluster; // Cluster size in blocks.
|
||||||
|
uint8_t m_clusterBlockMask; // Mask to extract block of cluster.
|
||||||
|
uint8_t m_clusterSizeShift; // Cluster count to block count shift.
|
||||||
|
uint8_t m_fatType; // Volume type (12, 16, OR 32).
|
||||||
|
uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
|
||||||
|
uint32_t m_allocSearchStart; // Start cluster for alloc search.
|
||||||
|
uint32_t m_blocksPerFat; // FAT size in blocks
|
||||||
|
uint32_t m_dataStartBlock; // First data block number.
|
||||||
|
uint32_t m_fatStartBlock; // Start block for first FAT.
|
||||||
|
uint32_t m_lastCluster; // Last cluster number in FAT.
|
||||||
|
uint32_t m_rootDirStart; // Start block for FAT16, cluster for FAT32.
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// block I/O functions.
|
||||||
|
bool readBlock(uint32_t block, uint8_t* dst) {
|
||||||
|
return m_blockDev->readBlock(block, dst);
|
||||||
|
}
|
||||||
|
bool syncBlocks() {
|
||||||
|
return m_blockDev->syncBlocks();
|
||||||
|
}
|
||||||
|
bool writeBlock(uint32_t block, const uint8_t* src) {
|
||||||
|
return m_blockDev->writeBlock(block, src);
|
||||||
|
}
|
||||||
|
#if USE_MULTI_BLOCK_IO
|
||||||
|
bool readBlocks(uint32_t block, uint8_t* dst, size_t nb) {
|
||||||
|
return m_blockDev->readBlocks(block, dst, nb);
|
||||||
|
}
|
||||||
|
bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb) {
|
||||||
|
return m_blockDev->writeBlocks(block, src, nb);
|
||||||
|
}
|
||||||
|
#endif // USE_MULTI_BLOCK_IO
|
||||||
|
#if MAINTAIN_FREE_CLUSTER_COUNT
|
||||||
|
int32_t m_freeClusterCount; // Count of free clusters in volume.
|
||||||
|
void setFreeClusterCount(int32_t value) {
|
||||||
|
m_freeClusterCount = value;
|
||||||
|
}
|
||||||
|
void updateFreeClusterCount(int32_t change) {
|
||||||
|
if (m_freeClusterCount >= 0) {
|
||||||
|
m_freeClusterCount += change;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else // MAINTAIN_FREE_CLUSTER_COUNT
|
||||||
|
void setFreeClusterCount(int32_t value) {
|
||||||
|
(void)value;
|
||||||
|
}
|
||||||
|
void updateFreeClusterCount(int32_t change) {
|
||||||
|
(void)change;
|
||||||
|
}
|
||||||
|
#endif // MAINTAIN_FREE_CLUSTER_COUNT
|
||||||
|
|
||||||
|
// block caches
|
||||||
|
FatCache m_cache;
|
||||||
|
#if USE_SEPARATE_FAT_CACHE
|
||||||
|
FatCache m_fatCache;
|
||||||
|
cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options) {
|
||||||
|
return m_fatCache.read(blockNumber,
|
||||||
|
options | FatCache::CACHE_STATUS_MIRROR_FAT);
|
||||||
|
}
|
||||||
|
bool cacheSync() {
|
||||||
|
return m_cache.sync() && m_fatCache.sync() && syncBlocks();
|
||||||
|
}
|
||||||
|
#else //
|
||||||
|
cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options) {
|
||||||
|
return cacheFetchData(blockNumber,
|
||||||
|
options | FatCache::CACHE_STATUS_MIRROR_FAT);
|
||||||
|
}
|
||||||
|
bool cacheSync() {
|
||||||
|
return m_cache.sync() && syncBlocks();
|
||||||
|
}
|
||||||
|
#endif // USE_SEPARATE_FAT_CACHE
|
||||||
|
cache_t* cacheFetchData(uint32_t blockNumber, uint8_t options) {
|
||||||
|
return m_cache.read(blockNumber, options);
|
||||||
|
}
|
||||||
|
void cacheInvalidate() {
|
||||||
|
m_cache.invalidate();
|
||||||
|
}
|
||||||
|
bool cacheSyncData() {
|
||||||
|
return m_cache.sync();
|
||||||
|
}
|
||||||
|
cache_t *cacheAddress() {
|
||||||
|
return m_cache.block();
|
||||||
|
}
|
||||||
|
uint32_t cacheBlockNumber() {
|
||||||
|
return m_cache.lbn();
|
||||||
|
}
|
||||||
|
void cacheDirty() {
|
||||||
|
m_cache.dirty();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool allocateCluster(uint32_t current, uint32_t* next);
|
||||||
|
bool allocContiguous(uint32_t count,
|
||||||
|
uint32_t* firstCluster, uint32_t startCluster = 0);
|
||||||
|
uint8_t blockOfCluster(uint32_t position) const {
|
||||||
|
return (position >> 9) & m_clusterBlockMask;
|
||||||
|
}
|
||||||
|
uint32_t clusterFirstBlock(uint32_t cluster) const;
|
||||||
|
int8_t fatGet(uint32_t cluster, uint32_t* value);
|
||||||
|
bool fatPut(uint32_t cluster, uint32_t value);
|
||||||
|
bool fatPutEOC(uint32_t cluster) {
|
||||||
|
return fatPut(cluster, 0x0FFFFFFF);
|
||||||
|
}
|
||||||
|
bool freeChain(uint32_t cluster);
|
||||||
|
bool isEOC(uint32_t cluster) const {
|
||||||
|
return cluster > m_lastCluster;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // FatVolume
|
460
hardware/_controller/src/SdFat/FatLib/FmtNumber.cpp
Normal file
460
hardware/_controller/src/SdFat/FatLib/FmtNumber.cpp
Normal file
|
@ -0,0 +1,460 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "FmtNumber.h"
|
||||||
|
// Use Stimmer div/mod 10 on avr
|
||||||
|
#ifdef __AVR__
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#define USE_STIMMER
|
||||||
|
#endif // __AVR__
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Stimmer div/mod 10 for AVR
|
||||||
|
// this code fragment works out i/10 and i%10 by calculating
|
||||||
|
// i*(51/256)*(256/255)/2 == i*51/510 == i/10
|
||||||
|
// by "j.k" I mean 32.8 fixed point, j is integer part, k is fractional part
|
||||||
|
// j.k = ((j+1.0)*51.0)/256.0
|
||||||
|
// (we add 1 because we will be using the floor of the result later)
|
||||||
|
// divmod10_asm16 and divmod10_asm32 are public domain code by Stimmer.
|
||||||
|
// http://forum.arduino.cc/index.php?topic=167414.msg1293679#msg1293679
|
||||||
|
#define divmod10_asm16(in32, mod8, tmp8) \
|
||||||
|
asm volatile( \
|
||||||
|
" ldi %2,51 \n\t" \
|
||||||
|
" mul %A0,%2 \n\t" \
|
||||||
|
" clr %A0 \n\t" \
|
||||||
|
" add r0,%2 \n\t" \
|
||||||
|
" adc %A0,r1 \n\t" \
|
||||||
|
" mov %1,r0 \n\t" \
|
||||||
|
" mul %B0,%2 \n\t" \
|
||||||
|
" clr %B0 \n\t" \
|
||||||
|
" add %A0,r0 \n\t" \
|
||||||
|
" adc %B0,r1 \n\t" \
|
||||||
|
" clr r1 \n\t" \
|
||||||
|
" add %1,%A0 \n\t" \
|
||||||
|
" adc %A0,%B0 \n\t" \
|
||||||
|
" adc %B0,r1 \n\t" \
|
||||||
|
" add %1,%B0 \n\t" \
|
||||||
|
" adc %A0,r1 \n\t" \
|
||||||
|
" adc %B0,r1 \n\t" \
|
||||||
|
" lsr %B0 \n\t" \
|
||||||
|
" ror %A0 \n\t" \
|
||||||
|
" ror %1 \n\t" \
|
||||||
|
" ldi %2,10 \n\t" \
|
||||||
|
" mul %1,%2 \n\t" \
|
||||||
|
" mov %1,r1 \n\t" \
|
||||||
|
" clr r1 \n\t" \
|
||||||
|
:"+r"(in32), "=d"(mod8), "=d"(tmp8) : : "r0")
|
||||||
|
|
||||||
|
#define divmod10_asm32(in32, mod8, tmp8) \
|
||||||
|
asm volatile( \
|
||||||
|
" ldi %2,51 \n\t" \
|
||||||
|
" mul %A0,%2 \n\t" \
|
||||||
|
" clr %A0 \n\t" \
|
||||||
|
" add r0,%2 \n\t" \
|
||||||
|
" adc %A0,r1 \n\t" \
|
||||||
|
" mov %1,r0 \n\t" \
|
||||||
|
" mul %B0,%2 \n\t" \
|
||||||
|
" clr %B0 \n\t" \
|
||||||
|
" add %A0,r0 \n\t" \
|
||||||
|
" adc %B0,r1 \n\t" \
|
||||||
|
" mul %C0,%2 \n\t" \
|
||||||
|
" clr %C0 \n\t" \
|
||||||
|
" add %B0,r0 \n\t" \
|
||||||
|
" adc %C0,r1 \n\t" \
|
||||||
|
" mul %D0,%2 \n\t" \
|
||||||
|
" clr %D0 \n\t" \
|
||||||
|
" add %C0,r0 \n\t" \
|
||||||
|
" adc %D0,r1 \n\t" \
|
||||||
|
" clr r1 \n\t" \
|
||||||
|
" add %1,%A0 \n\t" \
|
||||||
|
" adc %A0,%B0 \n\t" \
|
||||||
|
" adc %B0,%C0 \n\t" \
|
||||||
|
" adc %C0,%D0 \n\t" \
|
||||||
|
" adc %D0,r1 \n\t" \
|
||||||
|
" add %1,%B0 \n\t" \
|
||||||
|
" adc %A0,%C0 \n\t" \
|
||||||
|
" adc %B0,%D0 \n\t" \
|
||||||
|
" adc %C0,r1 \n\t" \
|
||||||
|
" adc %D0,r1 \n\t" \
|
||||||
|
" add %1,%D0 \n\t" \
|
||||||
|
" adc %A0,r1 \n\t" \
|
||||||
|
" adc %B0,r1 \n\t" \
|
||||||
|
" adc %C0,r1 \n\t" \
|
||||||
|
" adc %D0,r1 \n\t" \
|
||||||
|
" lsr %D0 \n\t" \
|
||||||
|
" ror %C0 \n\t" \
|
||||||
|
" ror %B0 \n\t" \
|
||||||
|
" ror %A0 \n\t" \
|
||||||
|
" ror %1 \n\t" \
|
||||||
|
" ldi %2,10 \n\t" \
|
||||||
|
" mul %1,%2 \n\t" \
|
||||||
|
" mov %1,r1 \n\t" \
|
||||||
|
" clr r1 \n\t" \
|
||||||
|
:"+r"(in32), "=d"(mod8), "=d"(tmp8) : : "r0")
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
// C++ code is based on this version of divmod10 by robtillaart.
|
||||||
|
// http://forum.arduino.cc/index.php?topic=167414.msg1246851#msg1246851
|
||||||
|
// from robtillaart post:
|
||||||
|
// The code is based upon the divu10() code from the book Hackers Delight1.
|
||||||
|
// My insight was that the error formula in divu10() was in fact modulo 10
|
||||||
|
// but not always. Sometimes it was 10 more.
|
||||||
|
void divmod10(uint32_t in, uint32_t &div, uint32_t &mod)
|
||||||
|
{
|
||||||
|
// q = in * 0.8;
|
||||||
|
uint32_t q = (in >> 1) + (in >> 2);
|
||||||
|
q = q + (q >> 4);
|
||||||
|
q = q + (q >> 8);
|
||||||
|
q = q + (q >> 16); // not needed for 16 bit version
|
||||||
|
|
||||||
|
// q = q / 8; ==> q = in *0.1;
|
||||||
|
q = q >> 3;
|
||||||
|
|
||||||
|
// determine error
|
||||||
|
uint32_t r = in - ((q << 3) + (q << 1)); // r = in - q*10;
|
||||||
|
div = q + (r > 9);
|
||||||
|
if (r > 9) mod = r - 10;
|
||||||
|
else mod = r;
|
||||||
|
}
|
||||||
|
// Hackers delight function is here:
|
||||||
|
// http://www.hackersdelight.org/hdcodetxt/divuc.c.txt
|
||||||
|
// Code below uses 8/10 = 0.1100 1100 1100 1100 1100 1100 1100 1100.
|
||||||
|
// 15 ops including the multiply, or 17 elementary ops.
|
||||||
|
unsigned divu10(unsigned n) {
|
||||||
|
unsigned q, r;
|
||||||
|
|
||||||
|
q = (n >> 1) + (n >> 2);
|
||||||
|
q = q + (q >> 4);
|
||||||
|
q = q + (q >> 8);
|
||||||
|
q = q + (q >> 16);
|
||||||
|
q = q >> 3;
|
||||||
|
r = n - q*10;
|
||||||
|
return q + ((r + 6) >> 4);
|
||||||
|
// return q + (r > 9);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
#ifdef __AVR__
|
||||||
|
static const float m[] PROGMEM = {1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32};
|
||||||
|
static const float p[] PROGMEM = {1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32};
|
||||||
|
#else // __AVR__
|
||||||
|
static const float m[] = {1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32};
|
||||||
|
static const float p[] = {1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32};
|
||||||
|
#endif // __AVR__
|
||||||
|
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
// scale float v by power of ten. return v*10^n
|
||||||
|
float scale10(float v, int8_t n) {
|
||||||
|
const float *s;
|
||||||
|
if (n < 0) {
|
||||||
|
n = -n;
|
||||||
|
s = m;
|
||||||
|
} else {
|
||||||
|
s = p;
|
||||||
|
}
|
||||||
|
n &= 63;
|
||||||
|
for (uint8_t i = 0; n; n >>= 1, i++) {
|
||||||
|
#ifdef __AVR__
|
||||||
|
if (n & 1) {
|
||||||
|
v *= pgm_read_float(&s[i]);
|
||||||
|
}
|
||||||
|
#else // __AVR__
|
||||||
|
if (n & 1) {
|
||||||
|
v *= s[i];
|
||||||
|
}
|
||||||
|
#endif // __AVR__
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Format 16-bit unsigned
|
||||||
|
char* fmtDec(uint16_t n, char* p) {
|
||||||
|
while (n > 9) {
|
||||||
|
#ifdef USE_STIMMER
|
||||||
|
uint8_t tmp8, r;
|
||||||
|
divmod10_asm16(n, r, tmp8);
|
||||||
|
#else // USE_STIMMER
|
||||||
|
uint16_t t = n;
|
||||||
|
n = (n >> 1) + (n >> 2);
|
||||||
|
n = n + (n >> 4);
|
||||||
|
n = n + (n >> 8);
|
||||||
|
// n = n + (n >> 16); // no code for 16-bit n
|
||||||
|
n = n >> 3;
|
||||||
|
uint8_t r = t - (((n << 2) + n) << 1);
|
||||||
|
if (r > 9) {
|
||||||
|
n++;
|
||||||
|
r -= 10;
|
||||||
|
}
|
||||||
|
#endif // USE_STIMMER
|
||||||
|
*--p = r + '0';
|
||||||
|
}
|
||||||
|
*--p = n + '0';
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// format 32-bit unsigned
|
||||||
|
char* fmtDec(uint32_t n, char* p) {
|
||||||
|
while (n >> 16) {
|
||||||
|
#ifdef USE_STIMMER
|
||||||
|
uint8_t tmp8, r;
|
||||||
|
divmod10_asm32(n, r, tmp8);
|
||||||
|
#else // USE_STIMMER
|
||||||
|
uint32_t t = n;
|
||||||
|
n = (n >> 1) + (n >> 2);
|
||||||
|
n = n + (n >> 4);
|
||||||
|
n = n + (n >> 8);
|
||||||
|
n = n + (n >> 16);
|
||||||
|
n = n >> 3;
|
||||||
|
uint8_t r = t - (((n << 2) + n) << 1);
|
||||||
|
if (r > 9) {
|
||||||
|
n++;
|
||||||
|
r -= 10;
|
||||||
|
}
|
||||||
|
#endif // USE_STIMMER
|
||||||
|
*--p = r + '0';
|
||||||
|
}
|
||||||
|
return fmtDec((uint16_t)n, p);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
char* fmtFloat(float value, char* p, uint8_t prec) {
|
||||||
|
char sign = value < 0 ? '-' : 0;
|
||||||
|
if (sign) {
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isnan(value)) {
|
||||||
|
*--p = 'n';
|
||||||
|
*--p = 'a';
|
||||||
|
*--p = 'n';
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (isinf(value)) {
|
||||||
|
*--p = 'f';
|
||||||
|
*--p = 'n';
|
||||||
|
*--p = 'i';
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (value > 4294967040.0) {
|
||||||
|
*--p = 'f';
|
||||||
|
*--p = 'v';
|
||||||
|
*--p = 'o';
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (prec > 9) {
|
||||||
|
prec = 9;
|
||||||
|
}
|
||||||
|
value += scale10(0.5, -prec);
|
||||||
|
|
||||||
|
uint32_t whole = value;
|
||||||
|
if (prec) {
|
||||||
|
char* tmp = p - prec;
|
||||||
|
uint32_t fraction = scale10(value - whole, prec);
|
||||||
|
p = fmtDec(fraction, p);
|
||||||
|
while (p > tmp) {
|
||||||
|
*--p = '0';
|
||||||
|
}
|
||||||
|
*--p = '.';
|
||||||
|
}
|
||||||
|
p = fmtDec(whole, p);
|
||||||
|
if (sign) {
|
||||||
|
*--p = sign;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Print a number followed by a field terminator.
|
||||||
|
* \param[in] value The number to be printed.
|
||||||
|
* \param[in] ptr Pointer to last char in buffer.
|
||||||
|
* \param[in] prec Number of digits after decimal point.
|
||||||
|
* \param[in] expChar Use exp format if non zero.
|
||||||
|
* \return Pointer to first character of result.
|
||||||
|
*/
|
||||||
|
char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar) {
|
||||||
|
bool neg = value < 0;
|
||||||
|
if (neg) {
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for nan inf ovf
|
||||||
|
if (isnan(value)) {
|
||||||
|
*--ptr = 'n';
|
||||||
|
*--ptr = 'a';
|
||||||
|
*--ptr = 'n';
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
if (isinf(value)) {
|
||||||
|
*--ptr = 'f';
|
||||||
|
*--ptr = 'n';
|
||||||
|
*--ptr = 'i';
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
if (!expChar && value > 4294967040.0) {
|
||||||
|
*--ptr = 'f';
|
||||||
|
*--ptr = 'v';
|
||||||
|
*--ptr = 'o';
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
if (prec > 9) {
|
||||||
|
prec = 9;
|
||||||
|
}
|
||||||
|
float round = scale10(0.5, -prec);
|
||||||
|
if (expChar) {
|
||||||
|
int8_t exp = 0;
|
||||||
|
bool expNeg = false;
|
||||||
|
if (value) {
|
||||||
|
while (value > 10.0) {
|
||||||
|
value *= 0.1;
|
||||||
|
exp++;
|
||||||
|
}
|
||||||
|
while (value < 1.0) {
|
||||||
|
value *= 10.0;
|
||||||
|
exp--;
|
||||||
|
}
|
||||||
|
value += round;
|
||||||
|
if (value > 10.0) {
|
||||||
|
value *= 0.1;
|
||||||
|
exp++;
|
||||||
|
}
|
||||||
|
expNeg = exp < 0;
|
||||||
|
if (expNeg) {
|
||||||
|
exp = -exp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr = fmtDec((uint16_t)exp, ptr);
|
||||||
|
if (exp < 10) {
|
||||||
|
*--ptr = '0';
|
||||||
|
}
|
||||||
|
*--ptr = expNeg ? '-' : '+';
|
||||||
|
*--ptr = expChar;
|
||||||
|
} else {
|
||||||
|
// round value
|
||||||
|
value += round;
|
||||||
|
}
|
||||||
|
uint32_t whole = value;
|
||||||
|
if (prec) {
|
||||||
|
char* tmp = ptr - prec;
|
||||||
|
uint32_t fraction = scale10(value - whole, prec);
|
||||||
|
ptr = fmtDec(fraction, ptr);
|
||||||
|
while (ptr > tmp) {
|
||||||
|
*--ptr = '0';
|
||||||
|
}
|
||||||
|
*--ptr = '.';
|
||||||
|
}
|
||||||
|
ptr = fmtDec(whole, ptr);
|
||||||
|
if (neg) {
|
||||||
|
*--ptr = '-';
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
char* fmtHex(uint32_t n, char* p) {
|
||||||
|
do {
|
||||||
|
uint8_t h = n & 0XF;
|
||||||
|
*--p = h + (h < 10 ? '0' : 'A' - 10);
|
||||||
|
n >>= 4;
|
||||||
|
} while (n);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
float scanFloat(const char* str, char** ptr) {
|
||||||
|
int16_t const EXP_LIMIT = 100;
|
||||||
|
bool digit = false;
|
||||||
|
bool dot = false;
|
||||||
|
uint32_t fract = 0;
|
||||||
|
int fracExp = 0;
|
||||||
|
uint8_t nd = 0;
|
||||||
|
bool neg;
|
||||||
|
int c;
|
||||||
|
float v;
|
||||||
|
const char* successPtr = str;
|
||||||
|
|
||||||
|
if (ptr) {
|
||||||
|
*ptr = const_cast<char*>(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (isSpace((c = *str++))) {}
|
||||||
|
neg = c == '-';
|
||||||
|
if (c == '-' || c == '+') {
|
||||||
|
c = *str++;
|
||||||
|
}
|
||||||
|
// Skip leading zeros
|
||||||
|
while (c == '0') {
|
||||||
|
c = *str++;
|
||||||
|
digit = true;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
if (isDigit(c)) {
|
||||||
|
digit = true;
|
||||||
|
if (nd < 9) {
|
||||||
|
fract = 10*fract + c - '0';
|
||||||
|
nd++;
|
||||||
|
if (dot) {
|
||||||
|
fracExp--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!dot) {
|
||||||
|
fracExp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (c == '.') {
|
||||||
|
if (dot) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
dot = true;
|
||||||
|
} else {
|
||||||
|
if (!digit) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
successPtr = str;
|
||||||
|
c = *str++;
|
||||||
|
}
|
||||||
|
if (c == 'e' || c == 'E') {
|
||||||
|
int exp = 0;
|
||||||
|
c = *str++;
|
||||||
|
bool expNeg = c == '-';
|
||||||
|
if (c == '-' || c == '+') {
|
||||||
|
c = *str++;
|
||||||
|
}
|
||||||
|
while (isDigit(c)) {
|
||||||
|
if (exp > EXP_LIMIT) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
exp = 10*exp + c - '0';
|
||||||
|
successPtr = str;
|
||||||
|
c = *str++;
|
||||||
|
}
|
||||||
|
fracExp += expNeg ? -exp : exp;
|
||||||
|
}
|
||||||
|
if (ptr) {
|
||||||
|
*ptr = const_cast<char*>(successPtr);
|
||||||
|
}
|
||||||
|
v = scale10(static_cast<float>(fract), fracExp);
|
||||||
|
return neg ? -v : v;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
43
hardware/_controller/src/SdFat/FatLib/FmtNumber.h
Normal file
43
hardware/_controller/src/SdFat/FatLib/FmtNumber.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef FmtNumber_h
|
||||||
|
#define FmtNumber_h
|
||||||
|
// #include <ctype.h>
|
||||||
|
inline bool isDigit(char c) {
|
||||||
|
return '0' <= c && c <= '9';
|
||||||
|
}
|
||||||
|
inline bool isSpace(char c) {
|
||||||
|
return c == ' ' || (0X9 <= c && c <= 0XD);
|
||||||
|
}
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
char* fmtDec(uint16_t n, char* p);
|
||||||
|
char* fmtDec(uint32_t n, char* p);
|
||||||
|
char* fmtFloat(float value, char* p, uint8_t prec);
|
||||||
|
char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar);
|
||||||
|
char* fmtHex(uint32_t n, char* p);
|
||||||
|
float scale10(float v, int8_t n);
|
||||||
|
float scanFloat(const char* str, char** ptr);
|
||||||
|
#endif // FmtNumber_h
|
508
hardware/_controller/src/SdFat/FatLib/StdioStream.cpp
Normal file
508
hardware/_controller/src/SdFat/FatLib/StdioStream.cpp
Normal file
|
@ -0,0 +1,508 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "StdioStream.h"
|
||||||
|
#include "FmtNumber.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::fclose() {
|
||||||
|
int rtn = 0;
|
||||||
|
if (!m_status) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
if (m_status & S_SWR) {
|
||||||
|
if (!flushBuf()) {
|
||||||
|
rtn = EOF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!FatFile::close()) {
|
||||||
|
rtn = EOF;
|
||||||
|
}
|
||||||
|
m_r = 0;
|
||||||
|
m_w = 0;
|
||||||
|
m_status = 0;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::fflush() {
|
||||||
|
if ((m_status & (S_SWR | S_SRW)) && !(m_status & S_SRD)) {
|
||||||
|
if (flushBuf() && FatFile::sync()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
char* StdioStream::fgets(char* str, size_t num, size_t* len) {
|
||||||
|
char* s = str;
|
||||||
|
size_t n;
|
||||||
|
if (num-- == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (num) {
|
||||||
|
if ((n = m_r) == 0) {
|
||||||
|
if (!fillBuf()) {
|
||||||
|
if (s == str) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n = m_r;
|
||||||
|
}
|
||||||
|
if (n > num) {
|
||||||
|
n = num;
|
||||||
|
}
|
||||||
|
uint8_t* end = reinterpret_cast<uint8_t*>(memchr(m_p, '\n', n));
|
||||||
|
if (end != 0) {
|
||||||
|
n = ++end - m_p;
|
||||||
|
memcpy(s, m_p, n);
|
||||||
|
m_r -= n;
|
||||||
|
m_p = end;
|
||||||
|
s += n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(s, m_p, n);
|
||||||
|
m_r -= n;
|
||||||
|
m_p += n;
|
||||||
|
s += n;
|
||||||
|
num -= n;
|
||||||
|
}
|
||||||
|
*s = 0;
|
||||||
|
if (len) {
|
||||||
|
*len = s - str;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool StdioStream::fopen(const char* path, const char* mode) {
|
||||||
|
oflag_t oflag;
|
||||||
|
uint8_t m;
|
||||||
|
switch (*mode++) {
|
||||||
|
case 'a':
|
||||||
|
m = O_WRONLY;
|
||||||
|
oflag = O_CREAT | O_APPEND;
|
||||||
|
m_status = S_SWR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
m = O_RDONLY;
|
||||||
|
oflag = 0;
|
||||||
|
m_status = S_SRD;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'w':
|
||||||
|
m = O_WRONLY;
|
||||||
|
oflag = O_CREAT | O_TRUNC;
|
||||||
|
m_status = S_SWR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
while (*mode) {
|
||||||
|
switch (*mode++) {
|
||||||
|
case '+':
|
||||||
|
m_status = S_SRW;
|
||||||
|
m = O_RDWR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
oflag |= O_EXCL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oflag |= m;
|
||||||
|
|
||||||
|
if (!FatFile::open(path, oflag)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
m_r = 0;
|
||||||
|
m_w = 0;
|
||||||
|
m_p = m_buf;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
m_status = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::fputs(const char* str) {
|
||||||
|
size_t len = strlen(str);
|
||||||
|
return fwrite(str, 1, len) == len ? len : EOF;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
size_t StdioStream::fread(void* ptr, size_t size, size_t count) {
|
||||||
|
uint8_t* dst = reinterpret_cast<uint8_t*>(ptr);
|
||||||
|
size_t total = size*count;
|
||||||
|
if (total == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t need = total;
|
||||||
|
while (need > m_r) {
|
||||||
|
memcpy(dst, m_p, m_r);
|
||||||
|
dst += m_r;
|
||||||
|
m_p += m_r;
|
||||||
|
need -= m_r;
|
||||||
|
if (!fillBuf()) {
|
||||||
|
return (total - need)/size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(dst, m_p, need);
|
||||||
|
m_r -= need;
|
||||||
|
m_p += need;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::fseek(int32_t offset, int origin) {
|
||||||
|
int32_t pos;
|
||||||
|
if (m_status & S_SWR) {
|
||||||
|
if (!flushBuf()) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (origin) {
|
||||||
|
case SEEK_CUR:
|
||||||
|
pos = ftell();
|
||||||
|
if (pos < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
pos += offset;
|
||||||
|
if (!FatFile::seekCur(pos)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_SET:
|
||||||
|
if (!FatFile::seekSet(offset)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_END:
|
||||||
|
if (!FatFile::seekEnd(offset)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
m_r = 0;
|
||||||
|
m_p = m_buf;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int32_t StdioStream::ftell() {
|
||||||
|
uint32_t pos = FatFile::curPosition();
|
||||||
|
if (m_status & S_SRD) {
|
||||||
|
if (m_r > pos) {
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
pos -= m_r;
|
||||||
|
} else if (m_status & S_SWR) {
|
||||||
|
pos += m_p - m_buf;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
size_t StdioStream::fwrite(const void* ptr, size_t size, size_t count) {
|
||||||
|
return write(ptr, count*size) < 0 ? EOF : count;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::write(const void* buf, size_t count) {
|
||||||
|
const uint8_t* src = static_cast<const uint8_t*>(buf);
|
||||||
|
size_t todo = count;
|
||||||
|
|
||||||
|
while (todo > m_w) {
|
||||||
|
memcpy(m_p, src, m_w);
|
||||||
|
m_p += m_w;
|
||||||
|
src += m_w;
|
||||||
|
todo -= m_w;
|
||||||
|
if (!flushBuf()) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(m_p, src, todo);
|
||||||
|
m_p += todo;
|
||||||
|
m_w -= todo;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
|
||||||
|
size_t StdioStream::print(const __FlashStringHelper *str) {
|
||||||
|
const char *p = (const char*)str;
|
||||||
|
uint8_t c;
|
||||||
|
while ((c = pgm_read_byte(p))) {
|
||||||
|
if (putc(c) < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return p - (const char*)str;
|
||||||
|
}
|
||||||
|
#endif // (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::printDec(float value, uint8_t prec) {
|
||||||
|
char buf[24];
|
||||||
|
char *ptr = fmtFloat(value, buf + sizeof(buf), prec);
|
||||||
|
return write(ptr, buf + sizeof(buf) - ptr);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::printDec(signed char n) {
|
||||||
|
if (n < 0) {
|
||||||
|
if (fputc('-') < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = -n;
|
||||||
|
}
|
||||||
|
return printDec((unsigned char)n);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::printDec(int16_t n) {
|
||||||
|
int s;
|
||||||
|
uint8_t rtn = 0;
|
||||||
|
if (n < 0) {
|
||||||
|
if (fputc('-') < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = -n;
|
||||||
|
rtn++;
|
||||||
|
}
|
||||||
|
if ((s = printDec((uint16_t)n)) < 0) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::printDec(uint16_t n) {
|
||||||
|
#define NEW_WAY
|
||||||
|
#ifdef NEW_WAY
|
||||||
|
char buf[5];
|
||||||
|
char *ptr = fmtDec(n, buf + sizeof(buf));
|
||||||
|
uint8_t len = buf + sizeof(buf) - ptr;
|
||||||
|
return write(ptr, len);
|
||||||
|
#else
|
||||||
|
uint8_t len;
|
||||||
|
if (n < 100) {
|
||||||
|
len = n < 10 ? 1 : 2;
|
||||||
|
} else {
|
||||||
|
len = n < 1000 ? 3 : n < 10000 ? 4 : 5;
|
||||||
|
}
|
||||||
|
char* str = fmtSpace(len);
|
||||||
|
if (!str) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fmtDec(n, str);
|
||||||
|
return len;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::printDec(int32_t n) {
|
||||||
|
uint8_t s = 0;
|
||||||
|
if (n < 0) {
|
||||||
|
if (fputc('-') < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = -n;
|
||||||
|
s = 1;
|
||||||
|
}
|
||||||
|
int rtn = printDec((uint32_t)n);
|
||||||
|
return rtn > 0 ? rtn + s : -1;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::printDec(uint32_t n) {
|
||||||
|
#ifdef NEW_WAY
|
||||||
|
char buf[10];
|
||||||
|
char *ptr = fmtDec(n, buf + sizeof(buf));
|
||||||
|
uint8_t len = buf + sizeof(buf) - ptr;
|
||||||
|
return write(ptr, len);
|
||||||
|
#else
|
||||||
|
uint8_t len;
|
||||||
|
if (n < 0X10000) {
|
||||||
|
return printDec((uint16_t)n);
|
||||||
|
}
|
||||||
|
if (n < 10000000) {
|
||||||
|
len = n < 100000 ? 5 : n < 1000000 ? 6 : 7;
|
||||||
|
} else {
|
||||||
|
len = n < 100000000 ? 8 : n < 1000000000 ? 9 : 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* str = fmtSpace(len);
|
||||||
|
if (!str) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fmtDec(n, str);
|
||||||
|
return len;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::printHex(uint32_t n) {
|
||||||
|
#ifdef NEW_WAY
|
||||||
|
char buf[8];
|
||||||
|
char *ptr = fmtHex(n, buf + sizeof(buf));
|
||||||
|
uint8_t len = buf + sizeof(buf) - ptr;
|
||||||
|
return write(ptr, len);
|
||||||
|
#else
|
||||||
|
size_t len;
|
||||||
|
if (n < 0X10000) {
|
||||||
|
len = n < 0X10 ? 1 : n < 0X100 ? 2 : n < 0X1000 ? 3 : 4;
|
||||||
|
} else {
|
||||||
|
len = n < 0X100000 ? 5 : n < 0X1000000 ? 6 : n < 0X10000000 ? 7 : 8;
|
||||||
|
}
|
||||||
|
char* str = fmtSpace(len);
|
||||||
|
if (!str) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint8_t h = n & 0XF;
|
||||||
|
*str-- = h + (h < 10 ? '0' : 'A' - 10);
|
||||||
|
n >>= 4;
|
||||||
|
} while (n);
|
||||||
|
return len;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool StdioStream::rewind() {
|
||||||
|
if (m_status & S_SWR) {
|
||||||
|
if (!flushBuf()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FatFile::seekSet(0);
|
||||||
|
m_r = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::ungetc(int c) {
|
||||||
|
// error if EOF.
|
||||||
|
if (c == EOF) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
// error if not reading.
|
||||||
|
if ((m_status & S_SRD) == 0) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
// error if no space.
|
||||||
|
if (m_p == m_buf) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
m_r++;
|
||||||
|
m_status &= ~S_EOF;
|
||||||
|
return *--m_p = (uint8_t)c;
|
||||||
|
}
|
||||||
|
//==============================================================================
|
||||||
|
// private
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::fillGet() {
|
||||||
|
if (!fillBuf()) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
m_r--;
|
||||||
|
return *m_p++;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// private
|
||||||
|
bool StdioStream::fillBuf() {
|
||||||
|
if (!(m_status &
|
||||||
|
S_SRD)) { // check for S_ERR and S_EOF ??/////////////////
|
||||||
|
if (!(m_status & S_SRW)) {
|
||||||
|
m_status |= S_ERR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (m_status & S_SWR) {
|
||||||
|
if (!flushBuf()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_status &= ~S_SWR;
|
||||||
|
m_status |= S_SRD;
|
||||||
|
m_w = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_p = m_buf + UNGETC_BUF_SIZE;
|
||||||
|
int nr = FatFile::read(m_p, sizeof(m_buf) - UNGETC_BUF_SIZE);
|
||||||
|
if (nr <= 0) {
|
||||||
|
m_status |= nr < 0 ? S_ERR : S_EOF;
|
||||||
|
m_r = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_r = nr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// private
|
||||||
|
bool StdioStream::flushBuf() {
|
||||||
|
if (!(m_status &
|
||||||
|
S_SWR)) { // check for S_ERR ??////////////////////////
|
||||||
|
if (!(m_status & S_SRW)) {
|
||||||
|
m_status |= S_ERR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_status &= ~S_SRD;
|
||||||
|
m_status |= S_SWR;
|
||||||
|
m_r = 0;
|
||||||
|
m_w = sizeof(m_buf);
|
||||||
|
m_p = m_buf;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
uint8_t n = m_p - m_buf;
|
||||||
|
m_p = m_buf;
|
||||||
|
m_w = sizeof(m_buf);
|
||||||
|
if (FatFile::write(m_buf, n) == n) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
m_status |= S_ERR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int StdioStream::flushPut(uint8_t c) {
|
||||||
|
if (!flushBuf()) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
m_w--;
|
||||||
|
return *m_p++ = c;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
char* StdioStream::fmtSpace(uint8_t len) {
|
||||||
|
if (m_w < len) {
|
||||||
|
if (!flushBuf() || m_w < len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len > m_w) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
m_p += len;
|
||||||
|
m_w -= len;
|
||||||
|
return reinterpret_cast<char*>(m_p);
|
||||||
|
}
|
||||||
|
|
667
hardware/_controller/src/SdFat/FatLib/StdioStream.h
Normal file
667
hardware/_controller/src/SdFat/FatLib/StdioStream.h
Normal file
|
@ -0,0 +1,667 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef StdioStream_h
|
||||||
|
#define StdioStream_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief StdioStream class
|
||||||
|
*/
|
||||||
|
#include <limits.h>
|
||||||
|
#include "FatFile.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Total size of stream buffer. The entire buffer is used for output.
|
||||||
|
* During input UNGETC_BUF_SIZE of this space is reserved for ungetc.
|
||||||
|
*/
|
||||||
|
const uint8_t STREAM_BUF_SIZE = 64;
|
||||||
|
/** Amount of buffer allocated for ungetc during input. */
|
||||||
|
const uint8_t UNGETC_BUF_SIZE = 2;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Get rid of any macros defined in <stdio.h>.
|
||||||
|
#include <stdio.h>
|
||||||
|
#undef clearerr
|
||||||
|
#undef fclose
|
||||||
|
#undef feof
|
||||||
|
#undef ferror
|
||||||
|
#undef fflush
|
||||||
|
#undef fgetc
|
||||||
|
#undef fgetpos
|
||||||
|
#undef fgets
|
||||||
|
#undef fopen
|
||||||
|
#undef fprintf
|
||||||
|
#undef fputc
|
||||||
|
#undef fputs
|
||||||
|
#undef fread
|
||||||
|
#undef freopen
|
||||||
|
#undef fscanf
|
||||||
|
#undef fseek
|
||||||
|
#undef fsetpos
|
||||||
|
#undef ftell
|
||||||
|
#undef fwrite
|
||||||
|
#undef getc
|
||||||
|
#undef getchar
|
||||||
|
#undef gets
|
||||||
|
#undef perror
|
||||||
|
//#undef printf // NOLINT
|
||||||
|
#undef putc
|
||||||
|
#undef putchar
|
||||||
|
#undef puts
|
||||||
|
#undef remove
|
||||||
|
#undef rename
|
||||||
|
#undef rewind
|
||||||
|
#undef scanf
|
||||||
|
#undef setbuf
|
||||||
|
#undef setvbuf
|
||||||
|
//#undef sprintf // NOLINT
|
||||||
|
#undef sscanf
|
||||||
|
#undef tmpfile
|
||||||
|
#undef tmpnam
|
||||||
|
#undef ungetc
|
||||||
|
#undef vfprintf
|
||||||
|
#undef vprintf
|
||||||
|
#undef vsprintf
|
||||||
|
|
||||||
|
// make sure needed macros are defined
|
||||||
|
#ifndef EOF
|
||||||
|
/** End-of-file return value. */
|
||||||
|
#define EOF (-1)
|
||||||
|
#endif // EOF
|
||||||
|
#ifndef NULL
|
||||||
|
/** Null pointer */
|
||||||
|
#define NULL 0
|
||||||
|
#endif // NULL
|
||||||
|
#ifndef SEEK_CUR
|
||||||
|
/** Seek relative to current position. */
|
||||||
|
#define SEEK_CUR 1
|
||||||
|
#endif // SEEK_CUR
|
||||||
|
#ifndef SEEK_END
|
||||||
|
/** Seek relative to end-of-file. */
|
||||||
|
#define SEEK_END 2
|
||||||
|
#endif // SEEK_END
|
||||||
|
#ifndef SEEK_SET
|
||||||
|
/** Seek relative to start-of-file. */
|
||||||
|
#define SEEK_SET 0
|
||||||
|
#endif // SEEK_SET
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \class StdioStream
|
||||||
|
* \brief StdioStream implements a minimal stdio stream.
|
||||||
|
*
|
||||||
|
* StdioStream does not support subdirectories or long file names.
|
||||||
|
*/
|
||||||
|
class StdioStream : private FatFile {
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
StdioStream() {
|
||||||
|
m_w = m_r = 0;
|
||||||
|
m_p = m_buf;
|
||||||
|
m_status = 0;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Clear the stream's end-of-file and error indicators. */
|
||||||
|
void clearerr() {
|
||||||
|
m_status &= ~(S_ERR | S_EOF);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Close a stream.
|
||||||
|
*
|
||||||
|
* A successful call to the fclose function causes the stream to be
|
||||||
|
* flushed and the associated file to be closed. Any unwritten buffered
|
||||||
|
* data is written to the file; any unread buffered data is discarded.
|
||||||
|
* Whether or not the call succeeds, the stream is disassociated from
|
||||||
|
* the file.
|
||||||
|
*
|
||||||
|
* \return zero if the stream was successfully closed, or EOF if any any
|
||||||
|
* errors are detected.
|
||||||
|
*/
|
||||||
|
int fclose();
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Test the stream's end-of-file indicator.
|
||||||
|
* \return non-zero if and only if the end-of-file indicator is set.
|
||||||
|
*/
|
||||||
|
int feof() {
|
||||||
|
return (m_status & S_EOF) != 0;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Test the stream's error indicator.
|
||||||
|
* \return return non-zero if and only if the error indicator is set.
|
||||||
|
*/
|
||||||
|
int ferror() {
|
||||||
|
return (m_status & S_ERR) != 0;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Flush the stream.
|
||||||
|
*
|
||||||
|
* If stream is an output stream or an update stream in which the most
|
||||||
|
* recent operation was not input, any unwritten data is written to the
|
||||||
|
* file; otherwise the call is an error since any buffered input data
|
||||||
|
* would be lost.
|
||||||
|
*
|
||||||
|
* \return sets the error indicator for the stream and returns EOF if an
|
||||||
|
* error occurs, otherwise it returns zero.
|
||||||
|
*/
|
||||||
|
int fflush();
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Get a byte from the stream.
|
||||||
|
*
|
||||||
|
* \return If the end-of-file indicator for the stream is set, or if the
|
||||||
|
* stream is at end-of-file, the end-of-file indicator for the stream is
|
||||||
|
* set and the fgetc function returns EOF. Otherwise, the fgetc function
|
||||||
|
* returns the next character from the input stream.
|
||||||
|
*/
|
||||||
|
int fgetc() {
|
||||||
|
return m_r-- == 0 ? fillGet() : *m_p++;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Get a string from a stream.
|
||||||
|
*
|
||||||
|
* The fgets function reads at most one less than the number of
|
||||||
|
* characters specified by num from the stream into the array pointed
|
||||||
|
* to by str. No additional characters are read after a new-line
|
||||||
|
* character (which is retained) or after end-of-file. A null character
|
||||||
|
* is written immediately after the last character read into the array.
|
||||||
|
*
|
||||||
|
* \param[out] str Pointer to an array of where the string is copied.
|
||||||
|
*
|
||||||
|
* \param[in] num Maximum number of characters including the null
|
||||||
|
* character.
|
||||||
|
*
|
||||||
|
* \param[out] len If len is not null and fgets is successful, the
|
||||||
|
* length of the string is returned.
|
||||||
|
*
|
||||||
|
* \return str if successful. If end-of-file is encountered and no
|
||||||
|
* characters have been read into the array, the contents of the array
|
||||||
|
* remain unchanged and a null pointer is returned. If a read error
|
||||||
|
* occurs during the operation, the array contents are indeterminate
|
||||||
|
* and a null pointer is returned.
|
||||||
|
*/
|
||||||
|
char* fgets(char* str, size_t num, size_t* len = 0);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Open a stream.
|
||||||
|
*
|
||||||
|
* Open a file and associates the stream with it.
|
||||||
|
*
|
||||||
|
* \param[in] path file to be opened.
|
||||||
|
*
|
||||||
|
* \param[in] mode a string that indicates the open mode.
|
||||||
|
*
|
||||||
|
* <table>
|
||||||
|
* <tr>
|
||||||
|
* <td>"r" or "rb"</td>
|
||||||
|
* <td>Open a file for reading. The file must exist.</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>"w" or "wb"</td>
|
||||||
|
* <td>Truncate an existing to zero length or create an empty file
|
||||||
|
* for writing.</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>"wx" or "wbx"</td>
|
||||||
|
* <td>Create a file for writing. Fails if the file already exists.</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>"a" or "ab"</td>
|
||||||
|
* <td>Append; open or create file for writing at end-of-file.</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>"r+" or "rb+" or "r+b"</td>
|
||||||
|
* <td>Open a file for update (reading and writing).</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>"w+" or "w+b" or "wb+"</td>
|
||||||
|
* <td>Truncate an existing to zero length or create a file for update.</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>"w+x" or "w+bx" or "wb+x"</td>
|
||||||
|
* <td>Create a file for update. Fails if the file already exists.</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>"a+" or "a+b" or "ab+"</td>
|
||||||
|
* <td>Append; open or create a file for update, writing at end-of-file.</td>
|
||||||
|
* </tr>
|
||||||
|
* </table>
|
||||||
|
* The character 'b' shall have no effect, but is allowed for ISO C
|
||||||
|
* standard conformance.
|
||||||
|
*
|
||||||
|
* Opening a file with append mode causes all subsequent writes to the
|
||||||
|
* file to be forced to the then current end-of-file, regardless of
|
||||||
|
* intervening calls to the fseek function.
|
||||||
|
*
|
||||||
|
* When a file is opened with update mode, both input and output may be
|
||||||
|
* performed on the associated stream. However, output shall not be
|
||||||
|
* directly followed by input without an intervening call to the fflush
|
||||||
|
* function or to a file positioning function (fseek, or rewind), and
|
||||||
|
* input shall not be directly followed by output without an intervening
|
||||||
|
* call to a file positioning function, unless the input operation
|
||||||
|
* encounters end-of-file.
|
||||||
|
*
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool fopen(const char* path, const char * mode);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Write a byte to a stream.
|
||||||
|
*
|
||||||
|
* \param[in] c the byte to be written (converted to an unsigned char).
|
||||||
|
*
|
||||||
|
* \return Upon successful completion, fputc() returns the value it
|
||||||
|
* has written. Otherwise, it returns EOF and sets the error indicator for
|
||||||
|
* the stream.
|
||||||
|
*/
|
||||||
|
int fputc(int c) {
|
||||||
|
return m_w-- == 0 ? flushPut(c) : *m_p++ = c;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Write a string to a stream.
|
||||||
|
*
|
||||||
|
* \param[in] str a pointer to the string to be written.
|
||||||
|
*
|
||||||
|
* \return for success, fputs() returns a non-negative
|
||||||
|
* number. Otherwise, it returns EOF and sets the error indicator for
|
||||||
|
* the stream.
|
||||||
|
*/
|
||||||
|
int fputs(const char* str);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Binary input.
|
||||||
|
*
|
||||||
|
* Reads an array of up to count elements, each one with a size of size
|
||||||
|
* bytes.
|
||||||
|
* \param[out] ptr pointer to area of at least (size*count) bytes where
|
||||||
|
* the data will be stored.
|
||||||
|
*
|
||||||
|
* \param[in] size the size, in bytes, of each element to be read.
|
||||||
|
*
|
||||||
|
* \param[in] count the number of elements to be read.
|
||||||
|
*
|
||||||
|
* \return number of elements successfully read, which may be less than
|
||||||
|
* count if a read error or end-of-file is encountered. If size or count
|
||||||
|
* is zero, fread returns zero and the contents of the array and the
|
||||||
|
* state of the stream remain unchanged.
|
||||||
|
*/
|
||||||
|
size_t fread(void* ptr, size_t size, size_t count);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Set the file position for the stream.
|
||||||
|
*
|
||||||
|
* \param[in] offset number of offset from the origin.
|
||||||
|
*
|
||||||
|
* \param[in] origin position used as reference for the offset. It is
|
||||||
|
* specified by one of the following constants.
|
||||||
|
*
|
||||||
|
* SEEK_SET - Beginning of file.
|
||||||
|
*
|
||||||
|
* SEEK_CUR - Current position of the file pointer.
|
||||||
|
*
|
||||||
|
* SEEK_END - End of file.
|
||||||
|
*
|
||||||
|
* \return zero for success. Otherwise, it returns non-zero and sets the
|
||||||
|
* error indicator for the stream.
|
||||||
|
*/
|
||||||
|
int fseek(int32_t offset, int origin);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Get the current position in a stream.
|
||||||
|
*
|
||||||
|
* \return If successful, ftell return the current value of the position
|
||||||
|
* indicator. On failure, ftell returns −1L.
|
||||||
|
*/
|
||||||
|
int32_t ftell();
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Binary output.
|
||||||
|
*
|
||||||
|
* Writes an array of up to count elements, each one with a size of size
|
||||||
|
* bytes.
|
||||||
|
* \param[in] ptr pointer to (size*count) bytes of data to be written.
|
||||||
|
*
|
||||||
|
* \param[in] size the size, in bytes, of each element to be written.
|
||||||
|
*
|
||||||
|
* \param[in] count the number of elements to be written.
|
||||||
|
*
|
||||||
|
* \return number of elements successfully written. if this number is
|
||||||
|
* less than count, an error has occurred. If size or count is zero,
|
||||||
|
* fwrite returns zero.
|
||||||
|
*/
|
||||||
|
size_t fwrite(const void * ptr, size_t size, size_t count);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Get a byte from the stream.
|
||||||
|
*
|
||||||
|
* getc and fgetc are equivalent but getc is in-line so it is faster but
|
||||||
|
* require more flash memory.
|
||||||
|
*
|
||||||
|
* \return If the end-of-file indicator for the stream is set, or if the
|
||||||
|
* stream is at end-of-file, the end-of-file indicator for the stream is
|
||||||
|
* set and the fgetc function returns EOF. Otherwise, the fgetc function
|
||||||
|
* returns the next character from the input stream.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
int getc() {
|
||||||
|
return m_r-- == 0 ? fillGet() : *m_p++;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Write a byte to a stream.
|
||||||
|
*
|
||||||
|
* putc and fputc are equivalent but putc is in-line so it is faster but
|
||||||
|
* require more flash memory.
|
||||||
|
*
|
||||||
|
* \param[in] c the byte to be written (converted to an unsigned char).
|
||||||
|
*
|
||||||
|
* \return Upon successful completion, fputc() returns the value it
|
||||||
|
* has written. Otherwise, it returns EOF and sets the error indicator for
|
||||||
|
* the stream.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
int putc(int c) {
|
||||||
|
return m_w-- == 0 ? flushPut(c) : *m_p++ = c;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Write a CR/LF.
|
||||||
|
*
|
||||||
|
* \return two, the number of bytes written, for success or -1 for failure.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
int putCRLF() {
|
||||||
|
if (m_w < 2) {
|
||||||
|
if (!flushBuf()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*m_p++ = '\r';
|
||||||
|
*m_p++ = '\n';
|
||||||
|
m_w -= 2;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Write a character.
|
||||||
|
* \param[in] c the character to write.
|
||||||
|
* \return the number of bytes written.
|
||||||
|
*/
|
||||||
|
size_t print(char c) {
|
||||||
|
return putc(c) < 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Write a string.
|
||||||
|
*
|
||||||
|
* \param[in] str the string to be written.
|
||||||
|
*
|
||||||
|
* \return the number of bytes written.
|
||||||
|
*/
|
||||||
|
size_t print(const char* str) {
|
||||||
|
int n = fputs(str);
|
||||||
|
return n < 0 ? 0 : n;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
#if (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
|
||||||
|
/** Print a string stored in flash memory.
|
||||||
|
*
|
||||||
|
* \param[in] str the string to print.
|
||||||
|
*
|
||||||
|
* \return the number of bytes written.
|
||||||
|
*/
|
||||||
|
size_t print(const __FlashStringHelper *str);
|
||||||
|
#endif // (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a floating point number.
|
||||||
|
*
|
||||||
|
* \param[in] prec Number of digits after decimal point.
|
||||||
|
*
|
||||||
|
* \param[in] val the number to be printed.
|
||||||
|
*
|
||||||
|
* \return the number of bytes written.
|
||||||
|
*/
|
||||||
|
size_t print(double val, uint8_t prec = 2) {
|
||||||
|
return print(static_cast<float>(val), prec);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a floating point number.
|
||||||
|
*
|
||||||
|
* \param[in] prec Number of digits after decimal point.
|
||||||
|
*
|
||||||
|
* \param[in] val the number to be printed.
|
||||||
|
*
|
||||||
|
* \return the number of bytes written.
|
||||||
|
*/
|
||||||
|
size_t print(float val, uint8_t prec = 2) {
|
||||||
|
int n = printDec(val, prec);
|
||||||
|
return n > 0 ? n : 0;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a number.
|
||||||
|
*
|
||||||
|
* \param[in] val the number to be printed.
|
||||||
|
*
|
||||||
|
* \return the number of bytes written.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
size_t print(T val) {
|
||||||
|
int n = printDec(val);
|
||||||
|
return n > 0 ? n : 0;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Write a CR/LF.
|
||||||
|
*
|
||||||
|
* \return two, the number of bytes written, for success or zero for failure.
|
||||||
|
*/
|
||||||
|
size_t println() {
|
||||||
|
return putCRLF() > 0 ? 2 : 0;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a floating point number followed by CR/LF.
|
||||||
|
*
|
||||||
|
* \param[in] val the number to be printed.
|
||||||
|
*
|
||||||
|
* \param[in] prec Number of digits after decimal point.
|
||||||
|
*
|
||||||
|
* \return the number of bytes written.
|
||||||
|
*/
|
||||||
|
size_t println(double val, uint8_t prec = 2) {
|
||||||
|
return println(static_cast<float>(val), prec);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a floating point number followed by CR/LF.
|
||||||
|
*
|
||||||
|
* \param[in] val the number to be printed.
|
||||||
|
*
|
||||||
|
* \param[in] prec Number of digits after decimal point.
|
||||||
|
*
|
||||||
|
* \return the number of bytes written.
|
||||||
|
*/
|
||||||
|
size_t println(float val, uint8_t prec = 2) {
|
||||||
|
int n = printDec(val, prec);
|
||||||
|
return n > 0 && putCRLF() > 0 ? n + 2 : 0;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print an item followed by CR/LF
|
||||||
|
*
|
||||||
|
* \param[in] val the item to be printed.
|
||||||
|
*
|
||||||
|
* \return the number of bytes written.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
size_t println(T val) {
|
||||||
|
int n = print(val);
|
||||||
|
return putCRLF() > 0 ? n + 2 : 0;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a char as a number.
|
||||||
|
* \param[in] n number to be printed.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printDec(char n) {
|
||||||
|
if (CHAR_MIN == 0) {
|
||||||
|
return printDec((unsigned char)n);
|
||||||
|
} else {
|
||||||
|
return printDec((signed char)n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** print a signed 8-bit integer
|
||||||
|
* \param[in] n number to be printed.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printDec(signed char n);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print an unsigned 8-bit number.
|
||||||
|
* \param[in] n number to be print.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printDec(unsigned char n) {
|
||||||
|
return printDec((uint16_t)n);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a int16_t
|
||||||
|
* \param[in] n number to be printed.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printDec(int16_t n);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** print a uint16_t.
|
||||||
|
* \param[in] n number to be printed.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printDec(uint16_t n);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a signed 32-bit integer.
|
||||||
|
* \param[in] n number to be printed.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printDec(int32_t n);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Write an unsigned 32-bit number.
|
||||||
|
* \param[in] n number to be printed.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printDec(uint32_t n);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a double.
|
||||||
|
* \param[in] value The number to be printed.
|
||||||
|
* \param[in] prec Number of digits after decimal point.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printDec(double value, uint8_t prec) {
|
||||||
|
return printDec(static_cast<float>(value), prec);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a float.
|
||||||
|
* \param[in] value The number to be printed.
|
||||||
|
* \param[in] prec Number of digits after decimal point.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printDec(float value, uint8_t prec);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a number followed by a field terminator.
|
||||||
|
* \param[in] value The number to be printed.
|
||||||
|
* \param[in] term The field terminator.
|
||||||
|
* \param[in] prec Number of digits after decimal point.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printField(double value, char term, uint8_t prec = 2) {
|
||||||
|
return printField(static_cast<float>(value), term, prec) > 0;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a number followed by a field terminator.
|
||||||
|
* \param[in] value The number to be printed.
|
||||||
|
* \param[in] term The field terminator.
|
||||||
|
* \param[in] prec Number of digits after decimal point.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printField(float value, char term, uint8_t prec = 2) {
|
||||||
|
int rtn = printDec(value, prec);
|
||||||
|
return rtn < 0 || putc(term) < 0 ? -1 : rtn + 1;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print a number followed by a field terminator.
|
||||||
|
* \param[in] value The number to be printed.
|
||||||
|
* \param[in] term The field terminator.
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
int printField(T value, char term) {
|
||||||
|
int rtn = printDec(value);
|
||||||
|
return rtn < 0 || putc(term) < 0 ? -1 : rtn + 1;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print HEX
|
||||||
|
* \param[in] n number to be printed as HEX.
|
||||||
|
*
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printHex(uint32_t n);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Print HEX with CRLF
|
||||||
|
* \param[in] n number to be printed as HEX.
|
||||||
|
*
|
||||||
|
* \return The number of bytes written or -1 if an error occurs.
|
||||||
|
*/
|
||||||
|
int printHexln(uint32_t n) {
|
||||||
|
int rtn = printHex(n);
|
||||||
|
return rtn < 0 || putCRLF() != 2 ? -1 : rtn + 2;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Set position of a stream to the beginning.
|
||||||
|
*
|
||||||
|
* The rewind function sets the file position to the beginning of the
|
||||||
|
* file. It is equivalent to fseek(0L, SEEK_SET) except that the error
|
||||||
|
* indicator for the stream is also cleared.
|
||||||
|
*
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool rewind();
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Push a byte back into an input stream.
|
||||||
|
*
|
||||||
|
* \param[in] c the byte (converted to an unsigned char) to be pushed back.
|
||||||
|
*
|
||||||
|
* One character of push-back is guaranteed. If the ungetc function is
|
||||||
|
* called too many times without an intervening read or file positioning
|
||||||
|
* operation on that stream, the operation may fail.
|
||||||
|
*
|
||||||
|
* A successful intervening call to a file positioning function (fseek,
|
||||||
|
* fsetpos, or rewind) discards any pushed-back characters for the stream.
|
||||||
|
*
|
||||||
|
* \return Upon successful completion, ungetc() returns the byte pushed
|
||||||
|
* back after conversion. Otherwise it returns EOF.
|
||||||
|
*/
|
||||||
|
int ungetc(int c);
|
||||||
|
//============================================================================
|
||||||
|
private:
|
||||||
|
bool fillBuf();
|
||||||
|
int fillGet();
|
||||||
|
bool flushBuf();
|
||||||
|
int flushPut(uint8_t c);
|
||||||
|
char* fmtSpace(uint8_t len);
|
||||||
|
int write(const void* buf, size_t count);
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// S_SRD and S_WR are never simultaneously asserted
|
||||||
|
static const uint8_t S_SRD = 0x01; // OK to read
|
||||||
|
static const uint8_t S_SWR = 0x02; // OK to write
|
||||||
|
static const uint8_t S_SRW = 0x04; // open for reading & writing
|
||||||
|
static const uint8_t S_EOF = 0x10; // found EOF
|
||||||
|
static const uint8_t S_ERR = 0x20; // found error
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
uint8_t m_status;
|
||||||
|
uint8_t* m_p;
|
||||||
|
uint8_t m_r;
|
||||||
|
uint8_t m_w;
|
||||||
|
uint8_t m_buf[STREAM_BUF_SIZE];
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#endif // StdioStream_h
|
172
hardware/_controller/src/SdFat/FatLib/bufstream.h
Normal file
172
hardware/_controller/src/SdFat/FatLib/bufstream.h
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef bufstream_h
|
||||||
|
#define bufstream_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief \ref ibufstream and \ref obufstream classes
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "iostream.h"
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class ibufstream
|
||||||
|
* \brief parse a char string
|
||||||
|
*/
|
||||||
|
class ibufstream : public istream {
|
||||||
|
public:
|
||||||
|
/** Constructor */
|
||||||
|
ibufstream() : m_buf(0), m_len(0) {}
|
||||||
|
/** Constructor
|
||||||
|
* \param[in] str pointer to string to be parsed
|
||||||
|
* Warning: The string will not be copied so must stay in scope.
|
||||||
|
*/
|
||||||
|
explicit ibufstream(const char* str) {
|
||||||
|
init(str);
|
||||||
|
}
|
||||||
|
/** Initialize an ibufstream
|
||||||
|
* \param[in] str pointer to string to be parsed
|
||||||
|
* Warning: The string will not be copied so must stay in scope.
|
||||||
|
*/
|
||||||
|
void init(const char* str) {
|
||||||
|
m_buf = str;
|
||||||
|
m_len = strlen(m_buf);
|
||||||
|
m_pos = 0;
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @cond SHOW_PROTECTED
|
||||||
|
int16_t getch() {
|
||||||
|
if (m_pos < m_len) {
|
||||||
|
return m_buf[m_pos++];
|
||||||
|
}
|
||||||
|
setstate(eofbit);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
void getpos(FatPos_t *pos) {
|
||||||
|
pos->position = m_pos;
|
||||||
|
}
|
||||||
|
bool seekoff(off_type off, seekdir way) {
|
||||||
|
(void)off;
|
||||||
|
(void)way;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool seekpos(pos_type pos) {
|
||||||
|
if (pos < m_len) {
|
||||||
|
m_pos = pos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void setpos(FatPos_t *pos) {
|
||||||
|
m_pos = pos->position;
|
||||||
|
}
|
||||||
|
pos_type tellpos() {
|
||||||
|
return m_pos;
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
private:
|
||||||
|
const char* m_buf;
|
||||||
|
size_t m_len;
|
||||||
|
size_t m_pos;
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class obufstream
|
||||||
|
* \brief format a char string
|
||||||
|
*/
|
||||||
|
class obufstream : public ostream {
|
||||||
|
public:
|
||||||
|
/** constructor */
|
||||||
|
obufstream() : m_in(0) {}
|
||||||
|
/** Constructor
|
||||||
|
* \param[in] buf buffer for formatted string
|
||||||
|
* \param[in] size buffer size
|
||||||
|
*/
|
||||||
|
obufstream(char *buf, size_t size) {
|
||||||
|
init(buf, size);
|
||||||
|
}
|
||||||
|
/** Initialize an obufstream
|
||||||
|
* \param[in] buf buffer for formatted string
|
||||||
|
* \param[in] size buffer size
|
||||||
|
*/
|
||||||
|
void init(char *buf, size_t size) {
|
||||||
|
m_buf = buf;
|
||||||
|
buf[0] = '\0';
|
||||||
|
m_size = size;
|
||||||
|
m_in = 0;
|
||||||
|
}
|
||||||
|
/** \return a pointer to the buffer */
|
||||||
|
char* buf() {
|
||||||
|
return m_buf;
|
||||||
|
}
|
||||||
|
/** \return the length of the formatted string */
|
||||||
|
size_t length() {
|
||||||
|
return m_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @cond SHOW_PROTECTED
|
||||||
|
void putch(char c) {
|
||||||
|
if (m_in >= (m_size - 1)) {
|
||||||
|
setstate(badbit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_buf[m_in++] = c;
|
||||||
|
m_buf[m_in] = '\0';
|
||||||
|
}
|
||||||
|
void putstr(const char *str) {
|
||||||
|
while (*str) {
|
||||||
|
putch(*str++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool seekoff(off_type off, seekdir way) {
|
||||||
|
(void)off;
|
||||||
|
(void)way;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool seekpos(pos_type pos) {
|
||||||
|
if (pos > m_in) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_in = pos;
|
||||||
|
m_buf[m_in] = '\0';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool sync() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos_type tellpos() {
|
||||||
|
return m_in;
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
private:
|
||||||
|
char *m_buf;
|
||||||
|
size_t m_size;
|
||||||
|
size_t m_in;
|
||||||
|
};
|
||||||
|
#endif // bufstream_h
|
172
hardware/_controller/src/SdFat/FatLib/fstream.cpp
Normal file
172
hardware/_controller/src/SdFat/FatLib/fstream.cpp
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "fstream.h"
|
||||||
|
//==============================================================================
|
||||||
|
/// @cond SHOW_PROTECTED
|
||||||
|
int16_t FatStreamBase::getch() {
|
||||||
|
uint8_t c;
|
||||||
|
int8_t s = read(&c, 1);
|
||||||
|
if (s != 1) {
|
||||||
|
if (s < 0) {
|
||||||
|
setstate(badbit);
|
||||||
|
} else {
|
||||||
|
setstate(eofbit);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (c != '\r' || (getmode() & ios::binary)) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
s = read(&c, 1);
|
||||||
|
if (s == 1 && c == '\n') {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
if (s == 1) {
|
||||||
|
seekCur(-1);
|
||||||
|
}
|
||||||
|
return '\r';
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void FatStreamBase::open(const char* path, ios::openmode mode) {
|
||||||
|
oflag_t oflag;
|
||||||
|
switch (mode & (app | in | out | trunc)) {
|
||||||
|
case app | in:
|
||||||
|
case app | in | out:
|
||||||
|
oflag = O_RDWR | O_APPEND | O_CREAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case app:
|
||||||
|
case app | out:
|
||||||
|
oflag = O_WRONLY | O_APPEND | O_CREAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case in:
|
||||||
|
oflag = O_RDONLY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case in | out:
|
||||||
|
oflag = O_RDWR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case in | out | trunc:
|
||||||
|
oflag = O_RDWR | O_TRUNC | O_CREAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case out:
|
||||||
|
case out | trunc:
|
||||||
|
oflag = O_WRONLY | O_TRUNC | O_CREAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (mode & ios::ate) {
|
||||||
|
oflag |= O_AT_END;
|
||||||
|
}
|
||||||
|
if (!FatFile::open(path, oflag)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
setmode(mode);
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
FatFile::close();
|
||||||
|
setstate(failbit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void FatStreamBase::putch(char c) {
|
||||||
|
if (c == '\n' && !(getmode() & ios::binary)) {
|
||||||
|
write('\r');
|
||||||
|
}
|
||||||
|
write(c);
|
||||||
|
if (getWriteError()) {
|
||||||
|
setstate(badbit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void FatStreamBase::putstr(const char* str) {
|
||||||
|
size_t n = 0;
|
||||||
|
while (1) {
|
||||||
|
char c = str[n];
|
||||||
|
if (c == '\0' || (c == '\n' && !(getmode() & ios::binary))) {
|
||||||
|
if (n > 0) {
|
||||||
|
write(str, n);
|
||||||
|
}
|
||||||
|
if (c == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
write('\r');
|
||||||
|
str += n;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
if (getWriteError()) {
|
||||||
|
setstate(badbit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Internal do not use
|
||||||
|
* \param[in] off
|
||||||
|
* \param[in] way
|
||||||
|
*/
|
||||||
|
bool FatStreamBase::seekoff(off_type off, seekdir way) {
|
||||||
|
pos_type pos;
|
||||||
|
switch (way) {
|
||||||
|
case beg:
|
||||||
|
pos = off;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case cur:
|
||||||
|
pos = curPosition() + off;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case end:
|
||||||
|
pos = fileSize() + off;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return seekpos(pos);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Internal do not use
|
||||||
|
* \param[in] pos
|
||||||
|
*/
|
||||||
|
bool FatStreamBase::seekpos(pos_type pos) {
|
||||||
|
return seekSet(pos);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int FatStreamBase::write(const void* buf, size_t n) {
|
||||||
|
return FatFile::write(buf, n);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void FatStreamBase::write(char c) {
|
||||||
|
write(&c, 1);
|
||||||
|
}
|
||||||
|
/// @endcond
|
320
hardware/_controller/src/SdFat/FatLib/fstream.h
Normal file
320
hardware/_controller/src/SdFat/FatLib/fstream.h
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef fstream_h
|
||||||
|
#define fstream_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief \ref fstream, \ref ifstream, and \ref ofstream classes
|
||||||
|
*/
|
||||||
|
#include "FatFile.h"
|
||||||
|
#include "iostream.h"
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class FatStreamBase
|
||||||
|
* \brief Base class for C++ style streams
|
||||||
|
*/
|
||||||
|
class FatStreamBase : protected FatFile, virtual public ios {
|
||||||
|
protected:
|
||||||
|
/// @cond SHOW_PROTECTED
|
||||||
|
int16_t getch();
|
||||||
|
void putch(char c);
|
||||||
|
void putstr(const char *str);
|
||||||
|
void open(const char* path, ios::openmode mode);
|
||||||
|
/** Internal do not use
|
||||||
|
* \return mode
|
||||||
|
*/
|
||||||
|
ios::openmode getmode() {
|
||||||
|
return m_mode;
|
||||||
|
}
|
||||||
|
/** Internal do not use
|
||||||
|
* \param[in] mode
|
||||||
|
*/
|
||||||
|
void setmode(ios::openmode mode) {
|
||||||
|
m_mode = mode;
|
||||||
|
}
|
||||||
|
bool seekoff(off_type off, seekdir way);
|
||||||
|
bool seekpos(pos_type pos);
|
||||||
|
int write(const void* buf, size_t n);
|
||||||
|
void write(char c);
|
||||||
|
/// @endcond
|
||||||
|
private:
|
||||||
|
ios::openmode m_mode;
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class fstream
|
||||||
|
* \brief file input/output stream.
|
||||||
|
*/
|
||||||
|
class fstream : public iostream, FatStreamBase {
|
||||||
|
public:
|
||||||
|
using iostream::peek;
|
||||||
|
fstream() {}
|
||||||
|
/** Constructor with open
|
||||||
|
*
|
||||||
|
* \param[in] path path to open
|
||||||
|
* \param[in] mode open mode
|
||||||
|
*/
|
||||||
|
explicit fstream(const char* path, openmode mode = in | out) {
|
||||||
|
open(path, mode);
|
||||||
|
}
|
||||||
|
#if DESTRUCTOR_CLOSES_FILE
|
||||||
|
~fstream() {}
|
||||||
|
#endif // DESTRUCTOR_CLOSES_FILE
|
||||||
|
/** Clear state and writeError
|
||||||
|
* \param[in] state new state for stream
|
||||||
|
*/
|
||||||
|
void clear(iostate state = goodbit) {
|
||||||
|
ios::clear(state);
|
||||||
|
FatFile::clearWriteError();
|
||||||
|
}
|
||||||
|
/** Close a file and force cached data and directory information
|
||||||
|
* to be written to the storage device.
|
||||||
|
*/
|
||||||
|
void close() {
|
||||||
|
FatFile::close();
|
||||||
|
}
|
||||||
|
/** Open a fstream
|
||||||
|
* \param[in] path file to open
|
||||||
|
* \param[in] mode open mode
|
||||||
|
*
|
||||||
|
* Valid open modes are (at end, ios::ate, and/or ios::binary may be added):
|
||||||
|
*
|
||||||
|
* ios::in - Open file for reading.
|
||||||
|
*
|
||||||
|
* ios::out or ios::out | ios::trunc - Truncate to 0 length, if existent,
|
||||||
|
* or create a file for writing only.
|
||||||
|
*
|
||||||
|
* ios::app or ios::out | ios::app - Append; open or create file for
|
||||||
|
* writing at end-of-file.
|
||||||
|
*
|
||||||
|
* ios::in | ios::out - Open file for update (reading and writing).
|
||||||
|
*
|
||||||
|
* ios::in | ios::out | ios::trunc - Truncate to zero length, if existent,
|
||||||
|
* or create file for update.
|
||||||
|
*
|
||||||
|
* ios::in | ios::app or ios::in | ios::out | ios::app - Append; open or
|
||||||
|
* create text file for update, writing at end of file.
|
||||||
|
*/
|
||||||
|
void open(const char* path, openmode mode = in | out) {
|
||||||
|
FatStreamBase::open(path, mode);
|
||||||
|
}
|
||||||
|
/** \return True if stream is open else false. */
|
||||||
|
bool is_open() {
|
||||||
|
return FatFile::isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @cond SHOW_PROTECTED
|
||||||
|
/** Internal - do not use
|
||||||
|
* \return
|
||||||
|
*/
|
||||||
|
int16_t getch() {
|
||||||
|
return FatStreamBase::getch();
|
||||||
|
}
|
||||||
|
/** Internal - do not use
|
||||||
|
* \param[out] pos
|
||||||
|
*/
|
||||||
|
void getpos(FatPos_t* pos) {
|
||||||
|
FatFile::getpos(pos);
|
||||||
|
}
|
||||||
|
/** Internal - do not use
|
||||||
|
* \param[in] c
|
||||||
|
*/
|
||||||
|
void putch(char c) {
|
||||||
|
FatStreamBase::putch(c);
|
||||||
|
}
|
||||||
|
/** Internal - do not use
|
||||||
|
* \param[in] str
|
||||||
|
*/
|
||||||
|
void putstr(const char *str) {
|
||||||
|
FatStreamBase::putstr(str);
|
||||||
|
}
|
||||||
|
/** Internal - do not use
|
||||||
|
* \param[in] pos
|
||||||
|
*/
|
||||||
|
bool seekoff(off_type off, seekdir way) {
|
||||||
|
return FatStreamBase::seekoff(off, way);
|
||||||
|
}
|
||||||
|
bool seekpos(pos_type pos) {
|
||||||
|
return FatStreamBase::seekpos(pos);
|
||||||
|
}
|
||||||
|
void setpos(FatPos_t* pos) {
|
||||||
|
FatFile::setpos(pos);
|
||||||
|
}
|
||||||
|
bool sync() {
|
||||||
|
return FatStreamBase::sync();
|
||||||
|
}
|
||||||
|
pos_type tellpos() {
|
||||||
|
return FatStreamBase::curPosition();
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class ifstream
|
||||||
|
* \brief file input stream.
|
||||||
|
*/
|
||||||
|
class ifstream : public istream, FatStreamBase {
|
||||||
|
public:
|
||||||
|
using istream::peek;
|
||||||
|
ifstream() {}
|
||||||
|
/** Constructor with open
|
||||||
|
* \param[in] path file to open
|
||||||
|
* \param[in] mode open mode
|
||||||
|
*/
|
||||||
|
explicit ifstream(const char* path, openmode mode = in) {
|
||||||
|
open(path, mode);
|
||||||
|
}
|
||||||
|
#if DESTRUCTOR_CLOSES_FILE
|
||||||
|
~ifstream() {}
|
||||||
|
#endif // DESTRUCTOR_CLOSES_FILE
|
||||||
|
/** Close a file and force cached data and directory information
|
||||||
|
* to be written to the storage device.
|
||||||
|
*/
|
||||||
|
void close() {
|
||||||
|
FatFile::close();
|
||||||
|
}
|
||||||
|
/** \return True if stream is open else false. */
|
||||||
|
bool is_open() {
|
||||||
|
return FatFile::isOpen();
|
||||||
|
}
|
||||||
|
/** Open an ifstream
|
||||||
|
* \param[in] path file to open
|
||||||
|
* \param[in] mode open mode
|
||||||
|
*
|
||||||
|
* \a mode See fstream::open() for valid modes.
|
||||||
|
*/
|
||||||
|
void open(const char* path, openmode mode = in) {
|
||||||
|
FatStreamBase::open(path, mode | in);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @cond SHOW_PROTECTED
|
||||||
|
/** Internal - do not use
|
||||||
|
* \return
|
||||||
|
*/
|
||||||
|
int16_t getch() {
|
||||||
|
return FatStreamBase::getch();
|
||||||
|
}
|
||||||
|
/** Internal - do not use
|
||||||
|
* \param[out] pos
|
||||||
|
*/
|
||||||
|
void getpos(FatPos_t* pos) {
|
||||||
|
FatFile::getpos(pos);
|
||||||
|
}
|
||||||
|
/** Internal - do not use
|
||||||
|
* \param[in] pos
|
||||||
|
*/
|
||||||
|
bool seekoff(off_type off, seekdir way) {
|
||||||
|
return FatStreamBase::seekoff(off, way);
|
||||||
|
}
|
||||||
|
bool seekpos(pos_type pos) {
|
||||||
|
return FatStreamBase::seekpos(pos);
|
||||||
|
}
|
||||||
|
void setpos(FatPos_t* pos) {
|
||||||
|
FatFile::setpos(pos);
|
||||||
|
}
|
||||||
|
pos_type tellpos() {
|
||||||
|
return FatStreamBase::curPosition();
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class ofstream
|
||||||
|
* \brief file output stream.
|
||||||
|
*/
|
||||||
|
class ofstream : public ostream, FatStreamBase {
|
||||||
|
public:
|
||||||
|
ofstream() {}
|
||||||
|
/** Constructor with open
|
||||||
|
* \param[in] path file to open
|
||||||
|
* \param[in] mode open mode
|
||||||
|
*/
|
||||||
|
explicit ofstream(const char* path, ios::openmode mode = out) {
|
||||||
|
open(path, mode);
|
||||||
|
}
|
||||||
|
#if DESTRUCTOR_CLOSES_FILE
|
||||||
|
~ofstream() {}
|
||||||
|
#endif // DESTRUCTOR_CLOSES_FILE
|
||||||
|
/** Clear state and writeError
|
||||||
|
* \param[in] state new state for stream
|
||||||
|
*/
|
||||||
|
void clear(iostate state = goodbit) {
|
||||||
|
ios::clear(state);
|
||||||
|
FatFile::clearWriteError();
|
||||||
|
}
|
||||||
|
/** Close a file and force cached data and directory information
|
||||||
|
* to be written to the storage device.
|
||||||
|
*/
|
||||||
|
void close() {
|
||||||
|
FatFile::close();
|
||||||
|
}
|
||||||
|
/** Open an ofstream
|
||||||
|
* \param[in] path file to open
|
||||||
|
* \param[in] mode open mode
|
||||||
|
*
|
||||||
|
* \a mode See fstream::open() for valid modes.
|
||||||
|
*/
|
||||||
|
void open(const char* path, openmode mode = out) {
|
||||||
|
FatStreamBase::open(path, mode | out);
|
||||||
|
}
|
||||||
|
/** \return True if stream is open else false. */
|
||||||
|
bool is_open() {
|
||||||
|
return FatFile::isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @cond SHOW_PROTECTED
|
||||||
|
/**
|
||||||
|
* Internal do not use
|
||||||
|
* \param[in] c
|
||||||
|
*/
|
||||||
|
void putch(char c) {
|
||||||
|
FatStreamBase::putch(c);
|
||||||
|
}
|
||||||
|
void putstr(const char* str) {
|
||||||
|
FatStreamBase::putstr(str);
|
||||||
|
}
|
||||||
|
bool seekoff(off_type off, seekdir way) {
|
||||||
|
return FatStreamBase::seekoff(off, way);
|
||||||
|
}
|
||||||
|
bool seekpos(pos_type pos) {
|
||||||
|
return FatStreamBase::seekpos(pos);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Internal do not use
|
||||||
|
* \param[in] b
|
||||||
|
*/
|
||||||
|
bool sync() {
|
||||||
|
return FatStreamBase::sync();
|
||||||
|
}
|
||||||
|
pos_type tellpos() {
|
||||||
|
return FatStreamBase::curPosition();
|
||||||
|
}
|
||||||
|
/// @endcond
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#endif // fstream_h
|
423
hardware/_controller/src/SdFat/FatLib/ios.h
Normal file
423
hardware/_controller/src/SdFat/FatLib/ios.h
Normal file
|
@ -0,0 +1,423 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef ios_h
|
||||||
|
#define ios_h
|
||||||
|
#include "FatFile.h"
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief \ref ios_base and \ref ios classes
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class ios_base
|
||||||
|
* \brief Base class for all streams
|
||||||
|
*/
|
||||||
|
class ios_base {
|
||||||
|
public:
|
||||||
|
/** typedef for iostate bitmask */
|
||||||
|
typedef unsigned char iostate;
|
||||||
|
// State flags.
|
||||||
|
/** iostate for no flags */
|
||||||
|
static const iostate goodbit = 0x00;
|
||||||
|
/** iostate bad bit for a nonrecoverable error. */
|
||||||
|
static const iostate badbit = 0X01;
|
||||||
|
/** iostate bit for end of file reached */
|
||||||
|
static const iostate eofbit = 0x02;
|
||||||
|
/** iostate fail bit for nonfatal error */
|
||||||
|
static const iostate failbit = 0X04;
|
||||||
|
/**
|
||||||
|
* unsigned size that can represent maximum file size.
|
||||||
|
* (violates spec - should be signed)
|
||||||
|
*/
|
||||||
|
typedef uint32_t streamsize;
|
||||||
|
/** type for absolute seek position */
|
||||||
|
typedef uint32_t pos_type;
|
||||||
|
/** type for relative seek offset */
|
||||||
|
typedef int32_t off_type;
|
||||||
|
|
||||||
|
/** enumerated type for the direction of relative seeks */
|
||||||
|
enum seekdir {
|
||||||
|
/** seek relative to the beginning of the stream */
|
||||||
|
beg,
|
||||||
|
/** seek relative to the current stream position */
|
||||||
|
cur,
|
||||||
|
/** seek relative to the end of the stream */
|
||||||
|
end
|
||||||
|
};
|
||||||
|
/** type for format flags */
|
||||||
|
typedef unsigned int fmtflags;
|
||||||
|
/** left adjust fields */
|
||||||
|
static const fmtflags left = 0x0001;
|
||||||
|
/** right adjust fields */
|
||||||
|
static const fmtflags right = 0x0002;
|
||||||
|
/** fill between sign/base prefix and number */
|
||||||
|
static const fmtflags internal = 0x0004;
|
||||||
|
/** base 10 flag*/
|
||||||
|
static const fmtflags dec = 0x0008;
|
||||||
|
/** base 16 flag */
|
||||||
|
static const fmtflags hex = 0x0010;
|
||||||
|
/** base 8 flag */
|
||||||
|
static const fmtflags oct = 0x0020;
|
||||||
|
// static const fmtflags fixed = 0x0040;
|
||||||
|
// static const fmtflags scientific = 0x0080;
|
||||||
|
/** use strings true/false for bool */
|
||||||
|
static const fmtflags boolalpha = 0x0100;
|
||||||
|
/** use prefix 0X for hex and 0 for oct */
|
||||||
|
static const fmtflags showbase = 0x0200;
|
||||||
|
/** always show '.' for floating numbers */
|
||||||
|
static const fmtflags showpoint = 0x0400;
|
||||||
|
/** show + sign for nonnegative numbers */
|
||||||
|
static const fmtflags showpos = 0x0800;
|
||||||
|
/** skip initial white space */
|
||||||
|
static const fmtflags skipws = 0x1000;
|
||||||
|
// static const fmtflags unitbuf = 0x2000;
|
||||||
|
/** use uppercase letters in number representations */
|
||||||
|
static const fmtflags uppercase = 0x4000;
|
||||||
|
/** mask for adjustfield */
|
||||||
|
static const fmtflags adjustfield = left | right | internal;
|
||||||
|
/** mask for basefield */
|
||||||
|
static const fmtflags basefield = dec | hex | oct;
|
||||||
|
// static const fmtflags floatfield = scientific | fixed;
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** typedef for iostream open mode */
|
||||||
|
typedef uint8_t openmode;
|
||||||
|
|
||||||
|
// Openmode flags.
|
||||||
|
/** seek to end before each write */
|
||||||
|
static const openmode app = 0X4;
|
||||||
|
/** open and seek to end immediately after opening */
|
||||||
|
static const openmode ate = 0X8;
|
||||||
|
/** perform input and output in binary mode (as opposed to text mode) */
|
||||||
|
static const openmode binary = 0X10;
|
||||||
|
/** open for input */
|
||||||
|
static const openmode in = 0X20;
|
||||||
|
/** open for output */
|
||||||
|
static const openmode out = 0X40;
|
||||||
|
/** truncate an existing stream when opening */
|
||||||
|
static const openmode trunc = 0X80;
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
ios_base() : m_fill(' '), m_fmtflags(dec | right | skipws)
|
||||||
|
, m_precision(2), m_width(0) {}
|
||||||
|
/** \return fill character */
|
||||||
|
char fill() {
|
||||||
|
return m_fill;
|
||||||
|
}
|
||||||
|
/** Set fill character
|
||||||
|
* \param[in] c new fill character
|
||||||
|
* \return old fill character
|
||||||
|
*/
|
||||||
|
char fill(char c) {
|
||||||
|
char r = m_fill;
|
||||||
|
m_fill = c;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
/** \return format flags */
|
||||||
|
fmtflags flags() const {
|
||||||
|
return m_fmtflags;
|
||||||
|
}
|
||||||
|
/** set format flags
|
||||||
|
* \param[in] fl new flag
|
||||||
|
* \return old flags
|
||||||
|
*/
|
||||||
|
fmtflags flags(fmtflags fl) {
|
||||||
|
fmtflags tmp = m_fmtflags;
|
||||||
|
m_fmtflags = fl;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
/** \return precision */
|
||||||
|
int precision() const {
|
||||||
|
return m_precision;
|
||||||
|
}
|
||||||
|
/** set precision
|
||||||
|
* \param[in] n new precision
|
||||||
|
* \return old precision
|
||||||
|
*/
|
||||||
|
int precision(unsigned int n) {
|
||||||
|
int r = m_precision;
|
||||||
|
m_precision = n;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
/** set format flags
|
||||||
|
* \param[in] fl new flags to be or'ed in
|
||||||
|
* \return old flags
|
||||||
|
*/
|
||||||
|
fmtflags setf(fmtflags fl) {
|
||||||
|
fmtflags r = m_fmtflags;
|
||||||
|
m_fmtflags |= fl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
/** modify format flags
|
||||||
|
* \param[in] mask flags to be removed
|
||||||
|
* \param[in] fl flags to be set after mask bits have been cleared
|
||||||
|
* \return old flags
|
||||||
|
*/
|
||||||
|
fmtflags setf(fmtflags fl, fmtflags mask) {
|
||||||
|
fmtflags r = m_fmtflags;
|
||||||
|
m_fmtflags &= ~mask;
|
||||||
|
m_fmtflags |= fl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
/** clear format flags
|
||||||
|
* \param[in] fl flags to be cleared
|
||||||
|
* \return old flags
|
||||||
|
*/
|
||||||
|
void unsetf(fmtflags fl) {
|
||||||
|
m_fmtflags &= ~fl;
|
||||||
|
}
|
||||||
|
/** \return width */
|
||||||
|
unsigned width() {
|
||||||
|
return m_width;
|
||||||
|
}
|
||||||
|
/** set width
|
||||||
|
* \param[in] n new width
|
||||||
|
* \return old width
|
||||||
|
*/
|
||||||
|
unsigned width(unsigned n) {
|
||||||
|
unsigned r = m_width;
|
||||||
|
m_width = n;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** \return current number base */
|
||||||
|
uint8_t flagsToBase() {
|
||||||
|
uint8_t f = flags() & basefield;
|
||||||
|
return f == oct ? 8 : f != hex ? 10 : 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char m_fill;
|
||||||
|
fmtflags m_fmtflags;
|
||||||
|
unsigned char m_precision;
|
||||||
|
unsigned int m_width;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** function for boolalpha manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& boolalpha(ios_base& str) {
|
||||||
|
str.setf(ios_base::boolalpha);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for dec manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& dec(ios_base& str) {
|
||||||
|
str.setf(ios_base::dec, ios_base::basefield);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for hex manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& hex(ios_base& str) {
|
||||||
|
str.setf(ios_base::hex, ios_base::basefield);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for internal manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& internal(ios_base& str) {
|
||||||
|
str.setf(ios_base::internal, ios_base::adjustfield);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for left manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& left(ios_base& str) {
|
||||||
|
str.setf(ios_base::left, ios_base::adjustfield);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for noboolalpha manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& noboolalpha(ios_base& str) {
|
||||||
|
str.unsetf(ios_base::boolalpha);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for noshowbase manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& noshowbase(ios_base& str) {
|
||||||
|
str.unsetf(ios_base::showbase);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for noshowpoint manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& noshowpoint(ios_base& str) {
|
||||||
|
str.unsetf(ios_base::showpoint);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for noshowpos manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& noshowpos(ios_base& str) {
|
||||||
|
str.unsetf(ios_base::showpos);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for noskipws manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& noskipws(ios_base& str) {
|
||||||
|
str.unsetf(ios_base::skipws);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for nouppercase manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& nouppercase(ios_base& str) {
|
||||||
|
str.unsetf(ios_base::uppercase);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for oct manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& oct(ios_base& str) {
|
||||||
|
str.setf(ios_base::oct, ios_base::basefield);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for right manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& right(ios_base& str) {
|
||||||
|
str.setf(ios_base::right, ios_base::adjustfield);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for showbase manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& showbase(ios_base& str) {
|
||||||
|
str.setf(ios_base::showbase);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for showpos manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& showpos(ios_base& str) {
|
||||||
|
str.setf(ios_base::showpos);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for showpoint manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& showpoint(ios_base& str) {
|
||||||
|
str.setf(ios_base::showpoint);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for skipws manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& skipws(ios_base& str) {
|
||||||
|
str.setf(ios_base::skipws);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
/** function for uppercase manipulator
|
||||||
|
* \param[in] str The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ios_base& uppercase(ios_base& str) {
|
||||||
|
str.setf(ios_base::uppercase);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class ios
|
||||||
|
* \brief Error and state information for all streams
|
||||||
|
*/
|
||||||
|
class ios : public ios_base {
|
||||||
|
public:
|
||||||
|
/** Create ios with no error flags set */
|
||||||
|
ios() : m_iostate(0) {}
|
||||||
|
|
||||||
|
/** \return null pointer if fail() is true. */
|
||||||
|
operator const void*() const {
|
||||||
|
return !fail() ? reinterpret_cast<const void*>(this) : 0;
|
||||||
|
}
|
||||||
|
/** \return true if fail() else false. */
|
||||||
|
bool operator!() const {
|
||||||
|
return fail();
|
||||||
|
}
|
||||||
|
/** \return The iostate flags for this file. */
|
||||||
|
iostate rdstate() const {
|
||||||
|
return m_iostate;
|
||||||
|
}
|
||||||
|
/** \return True if no iostate flags are set else false. */
|
||||||
|
bool good() const {
|
||||||
|
return m_iostate == goodbit;
|
||||||
|
}
|
||||||
|
/** \return true if end of file has been reached else false.
|
||||||
|
*
|
||||||
|
* Warning: An empty file returns false before the first read.
|
||||||
|
*
|
||||||
|
* Moral: eof() is only useful in combination with fail(), to find out
|
||||||
|
* whether EOF was the cause for failure
|
||||||
|
*/
|
||||||
|
bool eof() const {
|
||||||
|
return m_iostate & eofbit;
|
||||||
|
}
|
||||||
|
/** \return true if any iostate bit other than eof are set else false. */
|
||||||
|
bool fail() const {
|
||||||
|
return m_iostate & (failbit | badbit);
|
||||||
|
}
|
||||||
|
/** \return true if bad bit is set else false. */
|
||||||
|
bool bad() const {
|
||||||
|
return m_iostate & badbit;
|
||||||
|
}
|
||||||
|
/** Clear iostate bits.
|
||||||
|
*
|
||||||
|
* \param[in] state The flags you want to set after clearing all flags.
|
||||||
|
**/
|
||||||
|
void clear(iostate state = goodbit) {
|
||||||
|
m_iostate = state;
|
||||||
|
}
|
||||||
|
/** Set iostate bits.
|
||||||
|
*
|
||||||
|
* \param[in] state Bitts to set.
|
||||||
|
**/
|
||||||
|
void setstate(iostate state) {
|
||||||
|
m_iostate |= state;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
iostate m_iostate;
|
||||||
|
};
|
||||||
|
#endif // ios_h
|
158
hardware/_controller/src/SdFat/FatLib/iostream.h
Normal file
158
hardware/_controller/src/SdFat/FatLib/iostream.h
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef iostream_h
|
||||||
|
#define iostream_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief \ref iostream class
|
||||||
|
*/
|
||||||
|
#include "istream.h"
|
||||||
|
#include "ostream.h"
|
||||||
|
/** Skip white space
|
||||||
|
* \param[in] is the Stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline istream& ws(istream& is) {
|
||||||
|
is.skipWhite();
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
/** insert endline
|
||||||
|
* \param[in] os The Stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ostream& endl(ostream& os) {
|
||||||
|
os.put('\n');
|
||||||
|
#if ENDL_CALLS_FLUSH
|
||||||
|
os.flush();
|
||||||
|
#endif // ENDL_CALLS_FLUSH
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
/** flush manipulator
|
||||||
|
* \param[in] os The stream
|
||||||
|
* \return The stream
|
||||||
|
*/
|
||||||
|
inline ostream& flush(ostream& os) {
|
||||||
|
os.flush();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \struct setfill
|
||||||
|
* \brief type for setfill manipulator
|
||||||
|
*/
|
||||||
|
struct setfill {
|
||||||
|
/** fill character */
|
||||||
|
char c;
|
||||||
|
/** constructor
|
||||||
|
*
|
||||||
|
* \param[in] arg new fill character
|
||||||
|
*/
|
||||||
|
explicit setfill(char arg) : c(arg) {}
|
||||||
|
};
|
||||||
|
/** setfill manipulator
|
||||||
|
* \param[in] os the stream
|
||||||
|
* \param[in] arg set setfill object
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
inline ostream &operator<< (ostream &os, const setfill &arg) {
|
||||||
|
os.fill(arg.c);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
/** setfill manipulator
|
||||||
|
* \param[in] obj the stream
|
||||||
|
* \param[in] arg set setfill object
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
inline istream &operator>>(istream &obj, const setfill &arg) {
|
||||||
|
obj.fill(arg.c);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \struct setprecision
|
||||||
|
* \brief type for setprecision manipulator
|
||||||
|
*/
|
||||||
|
struct setprecision {
|
||||||
|
/** precision */
|
||||||
|
unsigned int p;
|
||||||
|
/** constructor
|
||||||
|
* \param[in] arg new precision
|
||||||
|
*/
|
||||||
|
explicit setprecision(unsigned int arg) : p(arg) {}
|
||||||
|
};
|
||||||
|
/** setprecision manipulator
|
||||||
|
* \param[in] os the stream
|
||||||
|
* \param[in] arg set setprecision object
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
inline ostream &operator<< (ostream &os, const setprecision &arg) {
|
||||||
|
os.precision(arg.p);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
/** setprecision manipulator
|
||||||
|
* \param[in] is the stream
|
||||||
|
* \param[in] arg set setprecision object
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
inline istream &operator>>(istream &is, const setprecision &arg) {
|
||||||
|
is.precision(arg.p);
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \struct setw
|
||||||
|
* \brief type for setw manipulator
|
||||||
|
*/
|
||||||
|
struct setw {
|
||||||
|
/** width */
|
||||||
|
unsigned w;
|
||||||
|
/** constructor
|
||||||
|
* \param[in] arg new width
|
||||||
|
*/
|
||||||
|
explicit setw(unsigned arg) : w(arg) {}
|
||||||
|
};
|
||||||
|
/** setw manipulator
|
||||||
|
* \param[in] os the stream
|
||||||
|
* \param[in] arg set setw object
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
inline ostream &operator<< (ostream &os, const setw &arg) {
|
||||||
|
os.width(arg.w);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
/** setw manipulator
|
||||||
|
* \param[in] is the stream
|
||||||
|
* \param[in] arg set setw object
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
inline istream &operator>>(istream &is, const setw &arg) {
|
||||||
|
is.width(arg.w);
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class iostream
|
||||||
|
* \brief Input/Output stream
|
||||||
|
*/
|
||||||
|
class iostream : public istream, public ostream {
|
||||||
|
};
|
||||||
|
#endif // iostream_h
|
396
hardware/_controller/src/SdFat/FatLib/istream.cpp
Normal file
396
hardware/_controller/src/SdFat/FatLib/istream.cpp
Normal file
|
@ -0,0 +1,396 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
// #include <ctype.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "istream.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int istream::get() {
|
||||||
|
int c;
|
||||||
|
m_gcount = 0;
|
||||||
|
c = getch();
|
||||||
|
if (c < 0) {
|
||||||
|
setstate(failbit);
|
||||||
|
} else {
|
||||||
|
m_gcount = 1;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
istream& istream::get(char& c) {
|
||||||
|
int tmp = get();
|
||||||
|
if (tmp >= 0) {
|
||||||
|
c = tmp;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
istream& istream::get(char *str, streamsize n, char delim) {
|
||||||
|
int c;
|
||||||
|
FatPos_t pos;
|
||||||
|
m_gcount = 0;
|
||||||
|
while ((m_gcount + 1) < n) {
|
||||||
|
c = getch(&pos);
|
||||||
|
if (c < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == delim) {
|
||||||
|
setpos(&pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str[m_gcount++] = c;
|
||||||
|
}
|
||||||
|
if (n > 0) {
|
||||||
|
str[m_gcount] = '\0';
|
||||||
|
}
|
||||||
|
if (m_gcount == 0) {
|
||||||
|
setstate(failbit);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void istream::getBool(bool *b) {
|
||||||
|
if ((flags() & boolalpha) == 0) {
|
||||||
|
getNumber(b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifdef __AVR__
|
||||||
|
PGM_P truePtr = PSTR("true");
|
||||||
|
PGM_P falsePtr = PSTR("false");
|
||||||
|
#else // __AVR__
|
||||||
|
const char* truePtr = "true";
|
||||||
|
const char* falsePtr = "false";
|
||||||
|
#endif // __AVR
|
||||||
|
const uint8_t true_len = 4;
|
||||||
|
const uint8_t false_len = 5;
|
||||||
|
bool trueOk = true;
|
||||||
|
bool falseOk = true;
|
||||||
|
uint8_t i = 0;
|
||||||
|
int c = readSkip();
|
||||||
|
while (1) {
|
||||||
|
#ifdef __AVR__
|
||||||
|
falseOk = falseOk && c == pgm_read_byte(falsePtr + i);
|
||||||
|
trueOk = trueOk && c == pgm_read_byte(truePtr + i);
|
||||||
|
#else // __AVR__
|
||||||
|
falseOk = falseOk && c == falsePtr[i];
|
||||||
|
trueOk = trueOk && c == truePtr[i];
|
||||||
|
#endif // __AVR__
|
||||||
|
if (trueOk == false && falseOk == false) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
if (trueOk && i == true_len) {
|
||||||
|
*b = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (falseOk && i == false_len) {
|
||||||
|
*b = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
c = getch();
|
||||||
|
}
|
||||||
|
setstate(failbit);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void istream::getChar(char* ch) {
|
||||||
|
int16_t c = readSkip();
|
||||||
|
if (c < 0) {
|
||||||
|
setstate(failbit);
|
||||||
|
} else {
|
||||||
|
*ch = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// http://www.exploringbinary.com/category/numbers-in-computers/
|
||||||
|
//
|
||||||
|
int16_t const EXP_LIMIT = 100;
|
||||||
|
static const uint32_t uint32_max = (uint32_t)-1;
|
||||||
|
bool istream::getDouble(double* value) {
|
||||||
|
bool got_digit = false;
|
||||||
|
bool got_dot = false;
|
||||||
|
bool neg;
|
||||||
|
int16_t c;
|
||||||
|
bool expNeg = false;
|
||||||
|
int16_t exp = 0;
|
||||||
|
int16_t fracExp = 0;
|
||||||
|
uint32_t frac = 0;
|
||||||
|
FatPos_t endPos;
|
||||||
|
double pow10;
|
||||||
|
double v;
|
||||||
|
|
||||||
|
getpos(&endPos);
|
||||||
|
c = readSkip();
|
||||||
|
neg = c == '-';
|
||||||
|
if (c == '-' || c == '+') {
|
||||||
|
c = getch();
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
if (isdigit(c)) {
|
||||||
|
got_digit = true;
|
||||||
|
if (frac < uint32_max/10) {
|
||||||
|
frac = frac * 10 + (c - '0');
|
||||||
|
if (got_dot) {
|
||||||
|
fracExp--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!got_dot) {
|
||||||
|
fracExp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!got_dot && c == '.') {
|
||||||
|
got_dot = true;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fracExp < -EXP_LIMIT || fracExp > EXP_LIMIT) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
c = getch(&endPos);
|
||||||
|
}
|
||||||
|
if (!got_digit) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (c == 'e' || c == 'E') {
|
||||||
|
c = getch();
|
||||||
|
expNeg = c == '-';
|
||||||
|
if (c == '-' || c == '+') {
|
||||||
|
c = getch();
|
||||||
|
}
|
||||||
|
while (isdigit(c)) {
|
||||||
|
if (exp > EXP_LIMIT) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
exp = exp * 10 + (c - '0');
|
||||||
|
c = getch(&endPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = static_cast<double>(frac);
|
||||||
|
exp = expNeg ? fracExp - exp : fracExp + exp;
|
||||||
|
expNeg = exp < 0;
|
||||||
|
if (expNeg) {
|
||||||
|
exp = -exp;
|
||||||
|
}
|
||||||
|
pow10 = 10.0;
|
||||||
|
while (exp) {
|
||||||
|
if (exp & 1) {
|
||||||
|
if (expNeg) {
|
||||||
|
// check for underflow
|
||||||
|
if (v < FLT_MIN * pow10 && frac != 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
v /= pow10;
|
||||||
|
} else {
|
||||||
|
// check for overflow
|
||||||
|
if (v > FLT_MAX / pow10) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
v *= pow10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pow10 *= pow10;
|
||||||
|
exp >>= 1;
|
||||||
|
}
|
||||||
|
setpos(&endPos);
|
||||||
|
*value = neg ? -v : v;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
// error restore position to last good place
|
||||||
|
setpos(&endPos);
|
||||||
|
setstate(failbit);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
istream& istream::getline(char *str, streamsize n, char delim) {
|
||||||
|
FatPos_t pos;
|
||||||
|
int c;
|
||||||
|
m_gcount = 0;
|
||||||
|
if (n > 0) {
|
||||||
|
str[0] = '\0';
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
c = getch(&pos);
|
||||||
|
if (c < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == delim) {
|
||||||
|
m_gcount++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((m_gcount + 1) >= n) {
|
||||||
|
setpos(&pos);
|
||||||
|
setstate(failbit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str[m_gcount++] = c;
|
||||||
|
str[m_gcount] = '\0';
|
||||||
|
}
|
||||||
|
if (m_gcount == 0) {
|
||||||
|
setstate(failbit);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool istream::getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num) {
|
||||||
|
int16_t c;
|
||||||
|
int8_t any = 0;
|
||||||
|
int8_t have_zero = 0;
|
||||||
|
uint8_t neg;
|
||||||
|
uint32_t val = 0;
|
||||||
|
uint32_t cutoff;
|
||||||
|
uint8_t cutlim;
|
||||||
|
FatPos_t endPos;
|
||||||
|
uint8_t f = flags() & basefield;
|
||||||
|
uint8_t base = f == oct ? 8 : f != hex ? 10 : 16;
|
||||||
|
getpos(&endPos);
|
||||||
|
c = readSkip();
|
||||||
|
|
||||||
|
neg = c == '-' ? 1 : 0;
|
||||||
|
if (c == '-' || c == '+') {
|
||||||
|
c = getch();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base == 16 && c == '0') { // TESTSUITE
|
||||||
|
c = getch(&endPos);
|
||||||
|
if (c == 'X' || c == 'x') {
|
||||||
|
c = getch();
|
||||||
|
// remember zero in case no hex digits follow x/X
|
||||||
|
have_zero = 1;
|
||||||
|
} else {
|
||||||
|
any = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// set values for overflow test
|
||||||
|
cutoff = neg ? negMax : posMax;
|
||||||
|
cutlim = cutoff % base;
|
||||||
|
cutoff /= base;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (isdigit(c)) {
|
||||||
|
c -= '0';
|
||||||
|
} else if (isalpha(c)) {
|
||||||
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c >= base) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (val > cutoff || (val == cutoff && c > cutlim)) {
|
||||||
|
// indicate overflow error
|
||||||
|
any = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
val = val * base + c;
|
||||||
|
c = getch(&endPos);
|
||||||
|
any = 1;
|
||||||
|
}
|
||||||
|
setpos(&endPos);
|
||||||
|
if (any > 0 || (have_zero && any >= 0)) {
|
||||||
|
*num = neg ? -val : val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
setstate(failbit);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void istream::getStr(char *str) {
|
||||||
|
FatPos_t pos;
|
||||||
|
uint16_t i = 0;
|
||||||
|
uint16_t m = width() ? width() - 1 : 0XFFFE;
|
||||||
|
if (m != 0) {
|
||||||
|
getpos(&pos);
|
||||||
|
int c = readSkip();
|
||||||
|
|
||||||
|
while (i < m) {
|
||||||
|
if (c < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isspace(c)) {
|
||||||
|
setpos(&pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str[i++] = c;
|
||||||
|
c = getch(&pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str[i] = '\0';
|
||||||
|
if (i == 0) {
|
||||||
|
setstate(failbit);
|
||||||
|
}
|
||||||
|
width(0);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
istream& istream::ignore(streamsize n, int delim) {
|
||||||
|
int c;
|
||||||
|
m_gcount = 0;
|
||||||
|
while (m_gcount < n) {
|
||||||
|
c = getch();
|
||||||
|
if (c < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_gcount++;
|
||||||
|
if (c == delim) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int istream::peek() {
|
||||||
|
int16_t c;
|
||||||
|
FatPos_t pos;
|
||||||
|
m_gcount = 0;
|
||||||
|
getpos(&pos);
|
||||||
|
c = getch();
|
||||||
|
if (c < 0) {
|
||||||
|
if (!bad()) {
|
||||||
|
setstate(eofbit);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setpos(&pos);
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int16_t istream::readSkip() {
|
||||||
|
int16_t c;
|
||||||
|
do {
|
||||||
|
c = getch();
|
||||||
|
} while (isspace(c) && (flags() & skipws));
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** used to implement ws() */
|
||||||
|
void istream::skipWhite() {
|
||||||
|
int c;
|
||||||
|
FatPos_t pos;
|
||||||
|
do {
|
||||||
|
c = getch(&pos);
|
||||||
|
} while (isspace(c));
|
||||||
|
setpos(&pos);
|
||||||
|
}
|
384
hardware/_controller/src/SdFat/FatLib/istream.h
Normal file
384
hardware/_controller/src/SdFat/FatLib/istream.h
Normal file
|
@ -0,0 +1,384 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef istream_h
|
||||||
|
#define istream_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief \ref istream class
|
||||||
|
*/
|
||||||
|
#include "ios.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class istream
|
||||||
|
* \brief Input Stream
|
||||||
|
*/
|
||||||
|
class istream : public virtual ios {
|
||||||
|
public:
|
||||||
|
istream() {}
|
||||||
|
/** call manipulator
|
||||||
|
* \param[in] pf function to call
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
istream& operator>>(istream& (*pf)(istream& str)) {
|
||||||
|
return pf(*this);
|
||||||
|
}
|
||||||
|
/** call manipulator
|
||||||
|
* \param[in] pf function to call
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
istream& operator>>(ios_base& (*pf)(ios_base& str)) {
|
||||||
|
pf(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** call manipulator
|
||||||
|
* \param[in] pf function to call
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
istream& operator>>(ios& (*pf)(ios& str)) {
|
||||||
|
pf(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a character string
|
||||||
|
* \param[out] str location to store the string.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream& operator>>(char *str) {
|
||||||
|
getStr(str);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a character
|
||||||
|
* \param[out] ch location to store the character.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream& operator>>(char& ch) {
|
||||||
|
getChar(&ch);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a character string
|
||||||
|
* \param[out] str location to store the string.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream& operator>>(signed char *str) {
|
||||||
|
getStr(reinterpret_cast<char*>(str));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a character
|
||||||
|
* \param[out] ch location to store the character.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream& operator>>(signed char& ch) {
|
||||||
|
getChar(reinterpret_cast<char*>(&ch));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a character string
|
||||||
|
* \param[out] str location to store the string.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream& operator>>(unsigned char *str) {
|
||||||
|
getStr(reinterpret_cast<char*>(str));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a character
|
||||||
|
* \param[out] ch location to store the character.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream& operator>>(unsigned char& ch) {
|
||||||
|
getChar(reinterpret_cast<char*>(&ch));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a value of type bool.
|
||||||
|
* \param[out] arg location to store the value.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream& operator>>(bool& arg) {
|
||||||
|
getBool(&arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a value of type short.
|
||||||
|
* \param[out] arg location to store the value.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream &operator>>(short& arg) { // NOLINT
|
||||||
|
getNumber(&arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a value of type unsigned short.
|
||||||
|
* \param[out] arg location to store the value.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream &operator>>(unsigned short& arg) { // NOLINT
|
||||||
|
getNumber(&arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a value of type int.
|
||||||
|
* \param[out] arg location to store the value.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream &operator>>(int& arg) {
|
||||||
|
getNumber(&arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a value of type unsigned int.
|
||||||
|
* \param[out] arg location to store the value.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream &operator>>(unsigned int& arg) {
|
||||||
|
getNumber(&arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a value of type long.
|
||||||
|
* \param[out] arg location to store the value.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream &operator>>(long& arg) { // NOLINT
|
||||||
|
getNumber(&arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a value of type unsigned long.
|
||||||
|
* \param[out] arg location to store the value.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream &operator>>(unsigned long& arg) { // NOLINT
|
||||||
|
getNumber(&arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a value of type double.
|
||||||
|
* \param[out] arg location to store the value.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream &operator>> (double& arg) {
|
||||||
|
getDouble(&arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a value of type float.
|
||||||
|
* \param[out] arg location to store the value.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream &operator>> (float& arg) {
|
||||||
|
double v;
|
||||||
|
getDouble(&v);
|
||||||
|
arg = v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a value of type void*.
|
||||||
|
* \param[out] arg location to store the value.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream& operator>> (void*& arg) {
|
||||||
|
uint32_t val;
|
||||||
|
getNumber(&val);
|
||||||
|
arg = reinterpret_cast<void*>(val);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \return The number of characters extracted by the last unformatted
|
||||||
|
* input function.
|
||||||
|
*/
|
||||||
|
streamsize gcount() const {
|
||||||
|
return m_gcount;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Extract a character if one is available.
|
||||||
|
*
|
||||||
|
* \return The character or -1 if a failure occurs. A failure is indicated
|
||||||
|
* by the stream state.
|
||||||
|
*/
|
||||||
|
int get();
|
||||||
|
/**
|
||||||
|
* Extract a character if one is available.
|
||||||
|
*
|
||||||
|
* \param[out] ch location to receive the extracted character.
|
||||||
|
*
|
||||||
|
* \return always returns *this. A failure is indicated by the stream state.
|
||||||
|
*/
|
||||||
|
istream& get(char& ch);
|
||||||
|
/**
|
||||||
|
* Extract characters.
|
||||||
|
*
|
||||||
|
* \param[out] str Location to receive extracted characters.
|
||||||
|
* \param[in] n Size of str.
|
||||||
|
* \param[in] delim Delimiter
|
||||||
|
*
|
||||||
|
* Characters are extracted until extraction fails, n is less than 1,
|
||||||
|
* n-1 characters are extracted, or the next character equals
|
||||||
|
* \a delim (delim is not extracted). If no characters are extracted
|
||||||
|
* failbit is set. If end-of-file occurs the eofbit is set.
|
||||||
|
*
|
||||||
|
* \return always returns *this. A failure is indicated by the stream state.
|
||||||
|
*/
|
||||||
|
istream& get(char *str, streamsize n, char delim = '\n');
|
||||||
|
/**
|
||||||
|
* Extract characters
|
||||||
|
*
|
||||||
|
* \param[out] str Location to receive extracted characters.
|
||||||
|
* \param[in] n Size of str.
|
||||||
|
* \param[in] delim Delimiter
|
||||||
|
*
|
||||||
|
* Characters are extracted until extraction fails,
|
||||||
|
* the next character equals \a delim (delim is extracted), or n-1
|
||||||
|
* characters are extracted.
|
||||||
|
*
|
||||||
|
* The failbit is set if no characters are extracted or n-1 characters
|
||||||
|
* are extracted. If end-of-file occurs the eofbit is set.
|
||||||
|
*
|
||||||
|
* \return always returns *this. A failure is indicated by the stream state.
|
||||||
|
*/
|
||||||
|
istream& getline(char *str, streamsize n, char delim = '\n');
|
||||||
|
/**
|
||||||
|
* Extract characters and discard them.
|
||||||
|
*
|
||||||
|
* \param[in] n maximum number of characters to ignore.
|
||||||
|
* \param[in] delim Delimiter.
|
||||||
|
*
|
||||||
|
* Characters are extracted until extraction fails, \a n characters
|
||||||
|
* are extracted, or the next input character equals \a delim
|
||||||
|
* (the delimiter is extracted). If end-of-file occurs the eofbit is set.
|
||||||
|
*
|
||||||
|
* Failures are indicated by the state of the stream.
|
||||||
|
*
|
||||||
|
* \return *this
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
istream& ignore(streamsize n = 1, int delim = -1);
|
||||||
|
/**
|
||||||
|
* Return the next available character without consuming it.
|
||||||
|
*
|
||||||
|
* \return The character if the stream state is good else -1;
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int peek();
|
||||||
|
// istream& read(char *str, streamsize count);
|
||||||
|
// streamsize readsome(char *str, streamsize count);
|
||||||
|
/**
|
||||||
|
* \return the stream position
|
||||||
|
*/
|
||||||
|
pos_type tellg() {
|
||||||
|
return tellpos();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the stream position
|
||||||
|
* \param[in] pos The absolute position in which to move the read pointer.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream& seekg(pos_type pos) {
|
||||||
|
if (!seekpos(pos)) {
|
||||||
|
setstate(failbit);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the stream position.
|
||||||
|
*
|
||||||
|
* \param[in] off An offset to move the read pointer relative to way.
|
||||||
|
* \a off is a signed 32-bit int so the offset is limited to +- 2GB.
|
||||||
|
* \param[in] way One of ios::beg, ios::cur, or ios::end.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
istream& seekg(off_type off, seekdir way) {
|
||||||
|
if (!seekoff(off, way)) {
|
||||||
|
setstate(failbit);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
void skipWhite();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @cond SHOW_PROTECTED
|
||||||
|
/**
|
||||||
|
* Internal - do not use
|
||||||
|
* \return
|
||||||
|
*/
|
||||||
|
virtual int16_t getch() = 0;
|
||||||
|
/**
|
||||||
|
* Internal - do not use
|
||||||
|
* \param[out] pos
|
||||||
|
* \return
|
||||||
|
*/
|
||||||
|
int16_t getch(FatPos_t* pos) {
|
||||||
|
getpos(pos);
|
||||||
|
return getch();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Internal - do not use
|
||||||
|
* \param[out] pos
|
||||||
|
*/
|
||||||
|
virtual void getpos(FatPos_t* pos) = 0;
|
||||||
|
/**
|
||||||
|
* Internal - do not use
|
||||||
|
* \param[in] pos
|
||||||
|
*/
|
||||||
|
virtual bool seekoff(off_type off, seekdir way) = 0;
|
||||||
|
virtual bool seekpos(pos_type pos) = 0;
|
||||||
|
virtual void setpos(FatPos_t* pos) = 0;
|
||||||
|
virtual pos_type tellpos() = 0;
|
||||||
|
|
||||||
|
/// @endcond
|
||||||
|
private:
|
||||||
|
void getBool(bool *b);
|
||||||
|
void getChar(char* ch);
|
||||||
|
bool getDouble(double* value);
|
||||||
|
template <typename T> void getNumber(T* value);
|
||||||
|
bool getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num);
|
||||||
|
void getStr(char *str);
|
||||||
|
int16_t readSkip();
|
||||||
|
|
||||||
|
size_t m_gcount;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
void istream::getNumber(T* value) {
|
||||||
|
uint32_t tmp;
|
||||||
|
if ((T)-1 < 0) {
|
||||||
|
// number is signed, max positive value
|
||||||
|
uint32_t const m = ((uint32_t)-1) >> (33 - sizeof(T) * 8);
|
||||||
|
// max absolute value of negative number is m + 1.
|
||||||
|
if (getNumber(m, m + 1, &tmp)) {
|
||||||
|
*value = (T)tmp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// max unsigned value for T
|
||||||
|
uint32_t const m = (T)-1;
|
||||||
|
if (getNumber(m, m, &tmp)) {
|
||||||
|
*value = (T)tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // istream_h
|
196
hardware/_controller/src/SdFat/FatLib/ostream.cpp
Normal file
196
hardware/_controller/src/SdFat/FatLib/ostream.cpp
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "ostream.h"
|
||||||
|
#ifndef PSTR
|
||||||
|
#define PSTR(x) x
|
||||||
|
#endif
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void ostream::do_fill(unsigned len) {
|
||||||
|
for (; len < width(); len++) {
|
||||||
|
putch(fill());
|
||||||
|
}
|
||||||
|
width(0);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void ostream::fill_not_left(unsigned len) {
|
||||||
|
if ((flags() & adjustfield) != left) {
|
||||||
|
do_fill(len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
char* ostream::fmtNum(uint32_t n, char *ptr, uint8_t base) {
|
||||||
|
char a = flags() & uppercase ? 'A' - 10 : 'a' - 10;
|
||||||
|
do {
|
||||||
|
uint32_t m = n;
|
||||||
|
n /= base;
|
||||||
|
char c = m - base * n;
|
||||||
|
*--ptr = c < 10 ? c + '0' : c + a;
|
||||||
|
} while (n);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void ostream::putBool(bool b) {
|
||||||
|
if (flags() & boolalpha) {
|
||||||
|
if (b) {
|
||||||
|
putPgm(PSTR("true"));
|
||||||
|
} else {
|
||||||
|
putPgm(PSTR("false"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
putChar(b ? '1' : '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void ostream::putChar(char c) {
|
||||||
|
fill_not_left(1);
|
||||||
|
putch(c);
|
||||||
|
do_fill(1);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void ostream::putDouble(double n) {
|
||||||
|
uint8_t nd = precision();
|
||||||
|
double round = 0.5;
|
||||||
|
char sign;
|
||||||
|
char buf[13]; // room for sign, 10 digits, '.', and zero byte
|
||||||
|
char *end = buf + sizeof(buf) - 1;
|
||||||
|
char *str = end;
|
||||||
|
// terminate string
|
||||||
|
*end = '\0';
|
||||||
|
|
||||||
|
// get sign and make nonnegative
|
||||||
|
if (n < 0.0) {
|
||||||
|
sign = '-';
|
||||||
|
n = -n;
|
||||||
|
} else {
|
||||||
|
sign = flags() & showpos ? '+' : '\0';
|
||||||
|
}
|
||||||
|
// check for larger than uint32_t
|
||||||
|
if (n > 4.0E9) {
|
||||||
|
putPgm(PSTR("BIG FLT"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// round up and separate int and fraction parts
|
||||||
|
for (uint8_t i = 0; i < nd; ++i) {
|
||||||
|
round *= 0.1;
|
||||||
|
}
|
||||||
|
n += round;
|
||||||
|
uint32_t intPart = n;
|
||||||
|
double fractionPart = n - intPart;
|
||||||
|
|
||||||
|
// format intPart and decimal point
|
||||||
|
if (nd || (flags() & showpoint)) {
|
||||||
|
*--str = '.';
|
||||||
|
}
|
||||||
|
str = fmtNum(intPart, str, 10);
|
||||||
|
|
||||||
|
// calculate length for fill
|
||||||
|
uint8_t len = sign ? 1 : 0;
|
||||||
|
len += nd + end - str;
|
||||||
|
|
||||||
|
// extract adjust field
|
||||||
|
fmtflags adj = flags() & adjustfield;
|
||||||
|
if (adj == internal) {
|
||||||
|
if (sign) {
|
||||||
|
putch(sign);
|
||||||
|
}
|
||||||
|
do_fill(len);
|
||||||
|
} else {
|
||||||
|
// do fill for internal or right
|
||||||
|
fill_not_left(len);
|
||||||
|
if (sign) {
|
||||||
|
*--str = sign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putstr(str);
|
||||||
|
// output fraction
|
||||||
|
while (nd-- > 0) {
|
||||||
|
fractionPart *= 10.0;
|
||||||
|
int digit = static_cast<int>(fractionPart);
|
||||||
|
putch(digit + '0');
|
||||||
|
fractionPart -= digit;
|
||||||
|
}
|
||||||
|
// do fill if not done above
|
||||||
|
do_fill(len);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void ostream::putNum(int32_t n) {
|
||||||
|
bool neg = n < 0 && flagsToBase() == 10;
|
||||||
|
if (neg) {
|
||||||
|
n = -n;
|
||||||
|
}
|
||||||
|
putNum(n, neg);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void ostream::putNum(uint32_t n, bool neg) {
|
||||||
|
char buf[13];
|
||||||
|
char* end = buf + sizeof(buf) - 1;
|
||||||
|
char* num;
|
||||||
|
char* str;
|
||||||
|
uint8_t base = flagsToBase();
|
||||||
|
*end = '\0';
|
||||||
|
str = num = fmtNum(n, end, base);
|
||||||
|
if (base == 10) {
|
||||||
|
if (neg) {
|
||||||
|
*--str = '-';
|
||||||
|
} else if (flags() & showpos) {
|
||||||
|
*--str = '+';
|
||||||
|
}
|
||||||
|
} else if (flags() & showbase) {
|
||||||
|
if (flags() & hex) {
|
||||||
|
*--str = flags() & uppercase ? 'X' : 'x';
|
||||||
|
}
|
||||||
|
*--str = '0';
|
||||||
|
}
|
||||||
|
uint8_t len = end - str;
|
||||||
|
fmtflags adj = flags() & adjustfield;
|
||||||
|
if (adj == internal) {
|
||||||
|
while (str < num) {
|
||||||
|
putch(*str++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (adj != left) {
|
||||||
|
do_fill(len);
|
||||||
|
}
|
||||||
|
putstr(str);
|
||||||
|
do_fill(len);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void ostream::putPgm(const char* str) {
|
||||||
|
int n;
|
||||||
|
for (n = 0; pgm_read_byte(&str[n]); n++) {}
|
||||||
|
fill_not_left(n);
|
||||||
|
for (uint8_t c; (c = pgm_read_byte(str)); str++) {
|
||||||
|
putch(c);
|
||||||
|
}
|
||||||
|
do_fill(n);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void ostream::putStr(const char *str) {
|
||||||
|
unsigned n = strlen(str);
|
||||||
|
fill_not_left(n);
|
||||||
|
putstr(str);
|
||||||
|
do_fill(n);
|
||||||
|
}
|
276
hardware/_controller/src/SdFat/FatLib/ostream.h
Normal file
276
hardware/_controller/src/SdFat/FatLib/ostream.h
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef ostream_h
|
||||||
|
#define ostream_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief \ref ostream class
|
||||||
|
*/
|
||||||
|
#include "ios.h"
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class ostream
|
||||||
|
* \brief Output Stream
|
||||||
|
*/
|
||||||
|
class ostream : public virtual ios {
|
||||||
|
public:
|
||||||
|
ostream() {}
|
||||||
|
|
||||||
|
/** call manipulator
|
||||||
|
* \param[in] pf function to call
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream& operator<< (ostream& (*pf)(ostream& str)) {
|
||||||
|
return pf(*this);
|
||||||
|
}
|
||||||
|
/** call manipulator
|
||||||
|
* \param[in] pf function to call
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream& operator<< (ios_base& (*pf)(ios_base& str)) {
|
||||||
|
pf(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output bool
|
||||||
|
* \param[in] arg value to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (bool arg) {
|
||||||
|
putBool(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output string
|
||||||
|
* \param[in] arg string to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (const char *arg) {
|
||||||
|
putStr(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output string
|
||||||
|
* \param[in] arg string to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (const signed char *arg) {
|
||||||
|
putStr((const char*)arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output string
|
||||||
|
* \param[in] arg string to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (const unsigned char *arg) {
|
||||||
|
putStr((const char*)arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output character
|
||||||
|
* \param[in] arg character to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (char arg) {
|
||||||
|
putChar(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output character
|
||||||
|
* \param[in] arg character to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (signed char arg) {
|
||||||
|
putChar(static_cast<char>(arg));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output character
|
||||||
|
* \param[in] arg character to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (unsigned char arg) {
|
||||||
|
putChar(static_cast<char>(arg));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output double
|
||||||
|
* \param[in] arg value to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (double arg) {
|
||||||
|
putDouble(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output float
|
||||||
|
* \param[in] arg value to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (float arg) {
|
||||||
|
putDouble(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output signed short
|
||||||
|
* \param[in] arg value to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (short arg) { // NOLINT
|
||||||
|
putNum((int32_t)arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output unsigned short
|
||||||
|
* \param[in] arg value to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (unsigned short arg) { // NOLINT
|
||||||
|
putNum((uint32_t)arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output signed int
|
||||||
|
* \param[in] arg value to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (int arg) {
|
||||||
|
putNum((int32_t)arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output unsigned int
|
||||||
|
* \param[in] arg value to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (unsigned int arg) {
|
||||||
|
putNum((uint32_t)arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output signed long
|
||||||
|
* \param[in] arg value to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (long arg) { // NOLINT
|
||||||
|
putNum((int32_t)arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output unsigned long
|
||||||
|
* \param[in] arg value to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (unsigned long arg) { // NOLINT
|
||||||
|
putNum((uint32_t)arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/** Output pointer
|
||||||
|
* \param[in] arg value to output
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream& operator<< (const void* arg) {
|
||||||
|
putNum(reinterpret_cast<uint32_t>(arg));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#if (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
|
||||||
|
/** Output a string from flash using the Arduino F() macro.
|
||||||
|
* \param[in] arg pointing to flash string
|
||||||
|
* \return the stream
|
||||||
|
*/
|
||||||
|
ostream &operator<< (const __FlashStringHelper *arg) {
|
||||||
|
putPgm(reinterpret_cast<const char*>(arg));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif // (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
|
||||||
|
/**
|
||||||
|
* Puts a character in a stream.
|
||||||
|
*
|
||||||
|
* The unformatted output function inserts the element \a ch.
|
||||||
|
* It returns *this.
|
||||||
|
*
|
||||||
|
* \param[in] ch The character
|
||||||
|
* \return A reference to the ostream object.
|
||||||
|
*/
|
||||||
|
ostream& put(char ch) {
|
||||||
|
putch(ch);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
// ostream& write(char *str, streamsize count);
|
||||||
|
/**
|
||||||
|
* Flushes the buffer associated with this stream. The flush function
|
||||||
|
* calls the sync function of the associated file.
|
||||||
|
* \return A reference to the ostream object.
|
||||||
|
*/
|
||||||
|
ostream& flush() {
|
||||||
|
if (!sync()) {
|
||||||
|
setstate(badbit);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \return the stream position
|
||||||
|
*/
|
||||||
|
pos_type tellp() {
|
||||||
|
return tellpos();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the stream position
|
||||||
|
* \param[in] pos The absolute position in which to move the write pointer.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
ostream& seekp(pos_type pos) {
|
||||||
|
if (!seekpos(pos)) {
|
||||||
|
setstate(failbit);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the stream position.
|
||||||
|
*
|
||||||
|
* \param[in] off An offset to move the write pointer relative to way.
|
||||||
|
* \a off is a signed 32-bit int so the offset is limited to +- 2GB.
|
||||||
|
* \param[in] way One of ios::beg, ios::cur, or ios::end.
|
||||||
|
* \return Is always *this. Failure is indicated by the state of *this.
|
||||||
|
*/
|
||||||
|
ostream& seekp(off_type off, seekdir way) {
|
||||||
|
if (!seekoff(off, way)) {
|
||||||
|
setstate(failbit);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @cond SHOW_PROTECTED
|
||||||
|
/** Put character with binary/text conversion
|
||||||
|
* \param[in] ch character to write
|
||||||
|
*/
|
||||||
|
virtual void putch(char ch) = 0;
|
||||||
|
virtual void putstr(const char *str) = 0;
|
||||||
|
virtual bool seekoff(off_type pos, seekdir way) = 0;
|
||||||
|
virtual bool seekpos(pos_type pos) = 0;
|
||||||
|
virtual bool sync() = 0;
|
||||||
|
|
||||||
|
virtual pos_type tellpos() = 0;
|
||||||
|
/// @endcond
|
||||||
|
private:
|
||||||
|
void do_fill(unsigned len);
|
||||||
|
void fill_not_left(unsigned len);
|
||||||
|
char* fmtNum(uint32_t n, char *ptr, uint8_t base);
|
||||||
|
void putBool(bool b);
|
||||||
|
void putChar(char c);
|
||||||
|
void putDouble(double n);
|
||||||
|
void putNum(uint32_t n, bool neg = false);
|
||||||
|
void putNum(int32_t n);
|
||||||
|
void putPgm(const char* str);
|
||||||
|
void putStr(const char* str);
|
||||||
|
};
|
||||||
|
#endif // ostream_h
|
61
hardware/_controller/src/SdFat/FreeStack.h
Normal file
61
hardware/_controller/src/SdFat/FreeStack.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef FreeStack_h
|
||||||
|
#define FreeStack_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief FreeStack() function.
|
||||||
|
*/
|
||||||
|
#if defined(__AVR__) || defined(DOXYGEN)
|
||||||
|
/** boundary between stack and heap. */
|
||||||
|
extern char *__brkval;
|
||||||
|
/** End of bss section.*/
|
||||||
|
extern char __bss_end;
|
||||||
|
/** Amount of free stack space.
|
||||||
|
* \return The number of free bytes.
|
||||||
|
*/
|
||||||
|
static int FreeStack() {
|
||||||
|
char* sp = reinterpret_cast<char*>(SP);
|
||||||
|
return __brkval ? sp - __brkval : sp - &__bss_end;
|
||||||
|
// char top;
|
||||||
|
// return __brkval ? &top - __brkval : &top - &__bss_end;
|
||||||
|
}
|
||||||
|
#elif defined(PLATFORM_ID) // Particle board
|
||||||
|
static int FreeStack() {
|
||||||
|
return System.freeMemory();
|
||||||
|
}
|
||||||
|
#elif defined(__arm__)
|
||||||
|
extern "C" char* sbrk(int incr);
|
||||||
|
static int FreeStack() {
|
||||||
|
char top = 't';
|
||||||
|
return &top - reinterpret_cast<char*>(sbrk(0));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#warning FreeStack is not defined for this system.
|
||||||
|
static int FreeStack() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif // FreeStack_h
|
71
hardware/_controller/src/SdFat/MinimumSerial.cpp
Normal file
71
hardware/_controller/src/SdFat/MinimumSerial.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "SysCall.h"
|
||||||
|
#if defined(UDR0) || defined(DOXYGEN)
|
||||||
|
#include "MinimumSerial.h"
|
||||||
|
const uint16_t MIN_2X_BAUD = F_CPU/(4*(2*0XFFF + 1)) + 1;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int MinimumSerial::available() {
|
||||||
|
return UCSR0A & (1 << RXC0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MinimumSerial::begin(uint32_t baud) {
|
||||||
|
uint16_t baud_setting;
|
||||||
|
// don't worry, the compiler will squeeze out F_CPU != 16000000UL
|
||||||
|
if ((F_CPU != 16000000UL || baud != 57600) && baud > MIN_2X_BAUD) {
|
||||||
|
// Double the USART Transmission Speed
|
||||||
|
UCSR0A = 1 << U2X0;
|
||||||
|
baud_setting = (F_CPU / 4 / baud - 1) / 2;
|
||||||
|
} else {
|
||||||
|
// hardcoded exception for compatibility with the bootloader shipped
|
||||||
|
// with the Duemilanove and previous boards and the firmware on the 8U2
|
||||||
|
// on the Uno and Mega 2560.
|
||||||
|
UCSR0A = 0;
|
||||||
|
baud_setting = (F_CPU / 8 / baud - 1) / 2;
|
||||||
|
}
|
||||||
|
// assign the baud_setting
|
||||||
|
UBRR0H = baud_setting >> 8;
|
||||||
|
UBRR0L = baud_setting;
|
||||||
|
// enable transmit and receive
|
||||||
|
UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void MinimumSerial::flush() {
|
||||||
|
while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
int MinimumSerial::read() {
|
||||||
|
if (UCSR0A & (1 << RXC0)) {
|
||||||
|
return UDR0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
size_t MinimumSerial::write(uint8_t b) {
|
||||||
|
while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {}
|
||||||
|
UDR0 = b;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif // defined(UDR0) || defined(DOXYGEN)
|
67
hardware/_controller/src/SdFat/MinimumSerial.h
Normal file
67
hardware/_controller/src/SdFat/MinimumSerial.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief Minimal AVR Serial driver.
|
||||||
|
*/
|
||||||
|
#ifndef MinimumSerial_h
|
||||||
|
#define MinimumSerial_h
|
||||||
|
#include "SysCall.h"
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class MinimumSerial
|
||||||
|
* \brief mini serial class for the %SdFat library.
|
||||||
|
*/
|
||||||
|
class MinimumSerial : public Print {
|
||||||
|
public:
|
||||||
|
/** \return true for hardware serial */
|
||||||
|
operator bool() { return true; }
|
||||||
|
/**
|
||||||
|
* \return one if data is available.
|
||||||
|
*/
|
||||||
|
int available();
|
||||||
|
/**
|
||||||
|
* Set baud rate for serial port zero and enable in non interrupt mode.
|
||||||
|
* Do not call this function if you use another serial library.
|
||||||
|
* \param[in] baud rate
|
||||||
|
*/
|
||||||
|
void begin(uint32_t baud);
|
||||||
|
/** Wait for write done. */
|
||||||
|
void flush();
|
||||||
|
/**
|
||||||
|
* Unbuffered read
|
||||||
|
* \return -1 if no character is available or an available character.
|
||||||
|
*/
|
||||||
|
int read();
|
||||||
|
/**
|
||||||
|
* Unbuffered write
|
||||||
|
*
|
||||||
|
* \param[in] b byte to write.
|
||||||
|
* \return 1
|
||||||
|
*/
|
||||||
|
size_t write(uint8_t b);
|
||||||
|
using Print::write;
|
||||||
|
};
|
||||||
|
#endif // MinimumSerial_h
|
485
hardware/_controller/src/SdFat/SdCard/SdInfo.h
Normal file
485
hardware/_controller/src/SdFat/SdCard/SdInfo.h
Normal file
|
@ -0,0 +1,485 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SdInfo_h
|
||||||
|
#define SdInfo_h
|
||||||
|
#include <stdint.h>
|
||||||
|
// Based on the document:
|
||||||
|
//
|
||||||
|
// SD Specifications
|
||||||
|
// Part 1
|
||||||
|
// Physical Layer
|
||||||
|
// Simplified Specification
|
||||||
|
// Version 5.00
|
||||||
|
// Aug 10, 2016
|
||||||
|
//
|
||||||
|
// https://www.sdcard.org/downloads/pls/
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// SD card errors
|
||||||
|
// See the SD Specification for command info.
|
||||||
|
typedef enum {
|
||||||
|
SD_CARD_ERROR_NONE = 0,
|
||||||
|
|
||||||
|
// Basic commands and switch command.
|
||||||
|
SD_CARD_ERROR_CMD0 = 0X20,
|
||||||
|
SD_CARD_ERROR_CMD2,
|
||||||
|
SD_CARD_ERROR_CMD3,
|
||||||
|
SD_CARD_ERROR_CMD6,
|
||||||
|
SD_CARD_ERROR_CMD7,
|
||||||
|
SD_CARD_ERROR_CMD8,
|
||||||
|
SD_CARD_ERROR_CMD9,
|
||||||
|
SD_CARD_ERROR_CMD10,
|
||||||
|
SD_CARD_ERROR_CMD12,
|
||||||
|
SD_CARD_ERROR_CMD13,
|
||||||
|
|
||||||
|
// Read, write, erase, and extension commands.
|
||||||
|
SD_CARD_ERROR_CMD17 = 0X30,
|
||||||
|
SD_CARD_ERROR_CMD18,
|
||||||
|
SD_CARD_ERROR_CMD24,
|
||||||
|
SD_CARD_ERROR_CMD25,
|
||||||
|
SD_CARD_ERROR_CMD32,
|
||||||
|
SD_CARD_ERROR_CMD33,
|
||||||
|
SD_CARD_ERROR_CMD38,
|
||||||
|
SD_CARD_ERROR_CMD58,
|
||||||
|
SD_CARD_ERROR_CMD59,
|
||||||
|
|
||||||
|
// Application specific commands.
|
||||||
|
SD_CARD_ERROR_ACMD6 = 0X40,
|
||||||
|
SD_CARD_ERROR_ACMD13,
|
||||||
|
SD_CARD_ERROR_ACMD23,
|
||||||
|
SD_CARD_ERROR_ACMD41,
|
||||||
|
|
||||||
|
// Read/write errors
|
||||||
|
SD_CARD_ERROR_READ = 0X50,
|
||||||
|
SD_CARD_ERROR_READ_CRC,
|
||||||
|
SD_CARD_ERROR_READ_FIFO,
|
||||||
|
SD_CARD_ERROR_READ_REG,
|
||||||
|
SD_CARD_ERROR_READ_START,
|
||||||
|
SD_CARD_ERROR_READ_TIMEOUT,
|
||||||
|
SD_CARD_ERROR_STOP_TRAN,
|
||||||
|
SD_CARD_ERROR_WRITE,
|
||||||
|
SD_CARD_ERROR_WRITE_FIFO,
|
||||||
|
SD_CARD_ERROR_WRITE_START,
|
||||||
|
SD_CARD_ERROR_FLASH_PROGRAMMING,
|
||||||
|
SD_CARD_ERROR_WRITE_TIMEOUT,
|
||||||
|
|
||||||
|
// Misc errors.
|
||||||
|
SD_CARD_ERROR_DMA = 0X60,
|
||||||
|
SD_CARD_ERROR_ERASE,
|
||||||
|
SD_CARD_ERROR_ERASE_SINGLE_BLOCK,
|
||||||
|
SD_CARD_ERROR_ERASE_TIMEOUT,
|
||||||
|
SD_CARD_ERROR_INIT_NOT_CALLED,
|
||||||
|
SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED
|
||||||
|
} sd_error_code_t;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// card types
|
||||||
|
/** Standard capacity V1 SD card */
|
||||||
|
const uint8_t SD_CARD_TYPE_SD1 = 1;
|
||||||
|
/** Standard capacity V2 SD card */
|
||||||
|
const uint8_t SD_CARD_TYPE_SD2 = 2;
|
||||||
|
/** High Capacity SD card */
|
||||||
|
const uint8_t SD_CARD_TYPE_SDHC = 3;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#define SD_SCK_HZ(maxSpeed) SPISettings(maxSpeed, MSBFIRST, SPI_MODE0)
|
||||||
|
#define SD_SCK_MHZ(maxMhz) SPISettings(1000000UL*maxMhz, MSBFIRST, SPI_MODE0)
|
||||||
|
// SPI divisor constants
|
||||||
|
/** Set SCK to max rate of F_CPU/2. */
|
||||||
|
#define SPI_FULL_SPEED SD_SCK_MHZ(50)
|
||||||
|
/** Set SCK rate to F_CPU/3 for Due */
|
||||||
|
#define SPI_DIV3_SPEED SD_SCK_HZ(F_CPU/3)
|
||||||
|
/** Set SCK rate to F_CPU/4. */
|
||||||
|
#define SPI_HALF_SPEED SD_SCK_HZ(F_CPU/4)
|
||||||
|
/** Set SCK rate to F_CPU/6 for Due */
|
||||||
|
#define SPI_DIV6_SPEED SD_SCK_HZ(F_CPU/6)
|
||||||
|
/** Set SCK rate to F_CPU/8. */
|
||||||
|
#define SPI_QUARTER_SPEED SD_SCK_HZ(F_CPU/8)
|
||||||
|
/** Set SCK rate to F_CPU/16. */
|
||||||
|
#define SPI_EIGHTH_SPEED SD_SCK_HZ(F_CPU/16)
|
||||||
|
/** Set SCK rate to F_CPU/32. */
|
||||||
|
#define SPI_SIXTEENTH_SPEED SD_SCK_HZ(F_CPU/32)
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// SD operation timeouts
|
||||||
|
/** CMD0 retry count */
|
||||||
|
const uint8_t SD_CMD0_RETRY = 10;
|
||||||
|
/** command timeout ms */
|
||||||
|
const uint16_t SD_CMD_TIMEOUT = 300;
|
||||||
|
/** init timeout ms */
|
||||||
|
const uint16_t SD_INIT_TIMEOUT = 2000;
|
||||||
|
/** erase timeout ms */
|
||||||
|
const uint16_t SD_ERASE_TIMEOUT = 10000;
|
||||||
|
/** read timeout ms */
|
||||||
|
const uint16_t SD_READ_TIMEOUT = 1000;
|
||||||
|
/** write time out ms */
|
||||||
|
const uint16_t SD_WRITE_TIMEOUT = 2000;
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// SD card commands
|
||||||
|
/** GO_IDLE_STATE - init card in spi mode if CS low */
|
||||||
|
const uint8_t CMD0 = 0X00;
|
||||||
|
/** ALL_SEND_CID - Asks any card to send the CID. */
|
||||||
|
const uint8_t CMD2 = 0X02;
|
||||||
|
/** SEND_RELATIVE_ADDR - Ask the card to publish a new RCA. */
|
||||||
|
const uint8_t CMD3 = 0X03;
|
||||||
|
/** SWITCH_FUNC - Switch Function Command */
|
||||||
|
const uint8_t CMD6 = 0X06;
|
||||||
|
/** SELECT/DESELECT_CARD - toggles between the stand-by and transfer states. */
|
||||||
|
const uint8_t CMD7 = 0X07;
|
||||||
|
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
|
||||||
|
const uint8_t CMD8 = 0X08;
|
||||||
|
/** SEND_CSD - read the Card Specific Data (CSD register) */
|
||||||
|
const uint8_t CMD9 = 0X09;
|
||||||
|
/** SEND_CID - read the card identification information (CID register) */
|
||||||
|
const uint8_t CMD10 = 0X0A;
|
||||||
|
/** STOP_TRANSMISSION - end multiple block read sequence */
|
||||||
|
const uint8_t CMD12 = 0X0C;
|
||||||
|
/** SEND_STATUS - read the card status register */
|
||||||
|
const uint8_t CMD13 = 0X0D;
|
||||||
|
/** READ_SINGLE_BLOCK - read a single data block from the card */
|
||||||
|
const uint8_t CMD17 = 0X11;
|
||||||
|
/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */
|
||||||
|
const uint8_t CMD18 = 0X12;
|
||||||
|
/** WRITE_BLOCK - write a single data block to the card */
|
||||||
|
const uint8_t CMD24 = 0X18;
|
||||||
|
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
|
||||||
|
const uint8_t CMD25 = 0X19;
|
||||||
|
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
|
||||||
|
const uint8_t CMD32 = 0X20;
|
||||||
|
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
|
||||||
|
range to be erased*/
|
||||||
|
const uint8_t CMD33 = 0X21;
|
||||||
|
/** ERASE - erase all previously selected blocks */
|
||||||
|
const uint8_t CMD38 = 0X26;
|
||||||
|
/** APP_CMD - escape for application specific command */
|
||||||
|
const uint8_t CMD55 = 0X37;
|
||||||
|
/** READ_OCR - read the OCR register of a card */
|
||||||
|
const uint8_t CMD58 = 0X3A;
|
||||||
|
/** CRC_ON_OFF - enable or disable CRC checking */
|
||||||
|
const uint8_t CMD59 = 0X3B;
|
||||||
|
/** SET_BUS_WIDTH - Defines the data bus width for data transfer. */
|
||||||
|
const uint8_t ACMD6 = 0X06;
|
||||||
|
/** SD_STATUS - Send the SD Status. */
|
||||||
|
const uint8_t ACMD13 = 0X0D;
|
||||||
|
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
|
||||||
|
pre-erased before writing */
|
||||||
|
const uint8_t ACMD23 = 0X17;
|
||||||
|
/** SD_SEND_OP_COMD - Sends host capacity support information and
|
||||||
|
activates the card's initialization process */
|
||||||
|
const uint8_t ACMD41 = 0X29;
|
||||||
|
//==============================================================================
|
||||||
|
// CARD_STATUS
|
||||||
|
/** The command's argument was out of the allowed range for this card. */
|
||||||
|
const uint32_t CARD_STATUS_OUT_OF_RANGE = 1UL << 31;
|
||||||
|
/** A misaligned address which did not match the block length. */
|
||||||
|
const uint32_t CARD_STATUS_ADDRESS_ERROR = 1UL << 30;
|
||||||
|
/** The transferred block length is not allowed for this card. */
|
||||||
|
const uint32_t CARD_STATUS_BLOCK_LEN_ERROR = 1UL << 29;
|
||||||
|
/** An error in the sequence of erase commands occurred. */
|
||||||
|
const uint32_t CARD_STATUS_ERASE_SEQ_ERROR = 1UL <<28;
|
||||||
|
/** An invalid selection of write-blocks for erase occurred. */
|
||||||
|
const uint32_t CARD_STATUS_ERASE_PARAM = 1UL << 27;
|
||||||
|
/** Set when the host attempts to write to a protected block. */
|
||||||
|
const uint32_t CARD_STATUS_WP_VIOLATION = 1UL << 26;
|
||||||
|
/** When set, signals that the card is locked by the host. */
|
||||||
|
const uint32_t CARD_STATUS_CARD_IS_LOCKED = 1UL << 25;
|
||||||
|
/** Set when a sequence or password error has been detected. */
|
||||||
|
const uint32_t CARD_STATUS_LOCK_UNLOCK_FAILED = 1UL << 24;
|
||||||
|
/** The CRC check of the previous command failed. */
|
||||||
|
const uint32_t CARD_STATUS_COM_CRC_ERROR = 1UL << 23;
|
||||||
|
/** Command not legal for the card state. */
|
||||||
|
const uint32_t CARD_STATUS_ILLEGAL_COMMAND = 1UL << 22;
|
||||||
|
/** Card internal ECC was applied but failed to correct the data. */
|
||||||
|
const uint32_t CARD_STATUS_CARD_ECC_FAILED = 1UL << 21;
|
||||||
|
/** Internal card controller error */
|
||||||
|
const uint32_t CARD_STATUS_CC_ERROR = 1UL << 20;
|
||||||
|
/** A general or an unknown error occurred during the operation. */
|
||||||
|
const uint32_t CARD_STATUS_ERROR = 1UL << 19;
|
||||||
|
// bits 19, 18, and 17 reserved.
|
||||||
|
/** Permanent WP set or attempt to change read only values of CSD. */
|
||||||
|
const uint32_t CARD_STATUS_CSD_OVERWRITE = 1UL <<16;
|
||||||
|
/** partial address space was erased due to write protect. */
|
||||||
|
const uint32_t CARD_STATUS_WP_ERASE_SKIP = 1UL << 15;
|
||||||
|
/** The command has been executed without using the internal ECC. */
|
||||||
|
const uint32_t CARD_STATUS_CARD_ECC_DISABLED = 1UL << 14;
|
||||||
|
/** out of erase sequence command was received. */
|
||||||
|
const uint32_t CARD_STATUS_ERASE_RESET = 1UL << 13;
|
||||||
|
/** The state of the card when receiving the command.
|
||||||
|
* 0 = idle
|
||||||
|
* 1 = ready
|
||||||
|
* 2 = ident
|
||||||
|
* 3 = stby
|
||||||
|
* 4 = tran
|
||||||
|
* 5 = data
|
||||||
|
* 6 = rcv
|
||||||
|
* 7 = prg
|
||||||
|
* 8 = dis
|
||||||
|
* 9-14 = reserved
|
||||||
|
* 15 = reserved for I/O mode
|
||||||
|
*/
|
||||||
|
const uint32_t CARD_STATUS_CURRENT_STATE = 0XF << 9;
|
||||||
|
/** Shift for current state. */
|
||||||
|
const uint32_t CARD_STATUS_CURRENT_STATE_SHIFT = 9;
|
||||||
|
/** Corresponds to buffer empty signaling on the bus. */
|
||||||
|
const uint32_t CARD_STATUS_READY_FOR_DATA = 1UL << 8;
|
||||||
|
// bit 7 reserved.
|
||||||
|
/** Extension Functions may set this bit to get host to deal with events. */
|
||||||
|
const uint32_t CARD_STATUS_FX_EVENT = 1UL << 6;
|
||||||
|
/** The card will expect ACMD, or the command has been interpreted as ACMD */
|
||||||
|
const uint32_t CARD_STATUS_APP_CMD = 1UL << 5;
|
||||||
|
// bit 4 reserved.
|
||||||
|
/** Error in the sequence of the authentication process. */
|
||||||
|
const uint32_t CARD_STATUS_AKE_SEQ_ERROR = 1UL << 3;
|
||||||
|
// bits 2,1, and 0 reserved for manufacturer test mode.
|
||||||
|
//==============================================================================
|
||||||
|
/** status for card in the ready state */
|
||||||
|
const uint8_t R1_READY_STATE = 0X00;
|
||||||
|
/** status for card in the idle state */
|
||||||
|
const uint8_t R1_IDLE_STATE = 0X01;
|
||||||
|
/** status bit for illegal command */
|
||||||
|
const uint8_t R1_ILLEGAL_COMMAND = 0X04;
|
||||||
|
/** start data token for read or write single block*/
|
||||||
|
const uint8_t DATA_START_BLOCK = 0XFE;
|
||||||
|
/** stop token for write multiple blocks*/
|
||||||
|
const uint8_t STOP_TRAN_TOKEN = 0XFD;
|
||||||
|
/** start data token for write multiple blocks*/
|
||||||
|
const uint8_t WRITE_MULTIPLE_TOKEN = 0XFC;
|
||||||
|
/** mask for data response tokens after a write block operation */
|
||||||
|
const uint8_t DATA_RES_MASK = 0X1F;
|
||||||
|
/** write data accepted token */
|
||||||
|
const uint8_t DATA_RES_ACCEPTED = 0X05;
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class CID
|
||||||
|
* \brief Card IDentification (CID) register.
|
||||||
|
*/
|
||||||
|
typedef struct CID {
|
||||||
|
// byte 0
|
||||||
|
/** Manufacturer ID */
|
||||||
|
unsigned char mid;
|
||||||
|
// byte 1-2
|
||||||
|
/** OEM/Application ID */
|
||||||
|
char oid[2];
|
||||||
|
// byte 3-7
|
||||||
|
/** Product name */
|
||||||
|
char pnm[5];
|
||||||
|
// byte 8
|
||||||
|
/** Product revision least significant digit */
|
||||||
|
unsigned char prv_m : 4;
|
||||||
|
/** Product revision most significant digit */
|
||||||
|
unsigned char prv_n : 4;
|
||||||
|
// byte 9-12
|
||||||
|
/** Product serial number */
|
||||||
|
uint32_t psn;
|
||||||
|
// byte 13
|
||||||
|
/** Manufacturing date year low digit */
|
||||||
|
unsigned char mdt_year_high : 4;
|
||||||
|
/** not used */
|
||||||
|
unsigned char reserved : 4;
|
||||||
|
// byte 14
|
||||||
|
/** Manufacturing date month */
|
||||||
|
unsigned char mdt_month : 4;
|
||||||
|
/** Manufacturing date year low digit */
|
||||||
|
unsigned char mdt_year_low : 4;
|
||||||
|
// byte 15
|
||||||
|
/** not used always 1 */
|
||||||
|
unsigned char always1 : 1;
|
||||||
|
/** CRC7 checksum */
|
||||||
|
unsigned char crc : 7;
|
||||||
|
} __attribute__((packed)) cid_t;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class CSDV1
|
||||||
|
* \brief CSD register for version 1.00 cards .
|
||||||
|
*/
|
||||||
|
typedef struct CSDV1 {
|
||||||
|
// byte 0
|
||||||
|
unsigned char reserved1 : 6;
|
||||||
|
unsigned char csd_ver : 2;
|
||||||
|
// byte 1
|
||||||
|
unsigned char taac;
|
||||||
|
// byte 2
|
||||||
|
unsigned char nsac;
|
||||||
|
// byte 3
|
||||||
|
unsigned char tran_speed;
|
||||||
|
// byte 4
|
||||||
|
unsigned char ccc_high;
|
||||||
|
// byte 5
|
||||||
|
unsigned char read_bl_len : 4;
|
||||||
|
unsigned char ccc_low : 4;
|
||||||
|
// byte 6
|
||||||
|
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
|
||||||
|
unsigned char c_size_mid;
|
||||||
|
// byte 8
|
||||||
|
unsigned char vdd_r_curr_max : 3;
|
||||||
|
unsigned char vdd_r_curr_min : 3;
|
||||||
|
unsigned char c_size_low : 2;
|
||||||
|
// byte 9
|
||||||
|
unsigned char c_size_mult_high : 2;
|
||||||
|
unsigned char vdd_w_cur_max : 3;
|
||||||
|
unsigned char vdd_w_curr_min : 3;
|
||||||
|
// byte 10
|
||||||
|
unsigned char sector_size_high : 6;
|
||||||
|
unsigned char erase_blk_en : 1;
|
||||||
|
unsigned char c_size_mult_low : 1;
|
||||||
|
// byte 11
|
||||||
|
unsigned char wp_grp_size : 7;
|
||||||
|
unsigned char sector_size_low : 1;
|
||||||
|
// byte 12
|
||||||
|
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 char reserved4 : 5;
|
||||||
|
unsigned char write_partial : 1;
|
||||||
|
unsigned char write_bl_len_low : 2;
|
||||||
|
// byte 14
|
||||||
|
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 char always1 : 1;
|
||||||
|
unsigned char crc : 7;
|
||||||
|
} __attribute__((packed)) csd1_t;
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class CSDV2
|
||||||
|
* \brief CSD register for version 2.00 cards.
|
||||||
|
*/
|
||||||
|
typedef struct CSDV2 {
|
||||||
|
// byte 0
|
||||||
|
unsigned char reserved1 : 6;
|
||||||
|
unsigned char csd_ver : 2;
|
||||||
|
// byte 1
|
||||||
|
/** fixed to 0X0E */
|
||||||
|
unsigned char taac;
|
||||||
|
// byte 2
|
||||||
|
/** fixed to 0 */
|
||||||
|
unsigned char nsac;
|
||||||
|
// byte 3
|
||||||
|
unsigned char tran_speed;
|
||||||
|
// byte 4
|
||||||
|
unsigned char ccc_high;
|
||||||
|
// byte 5
|
||||||
|
/** 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
|
||||||
|
/** 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
|
||||||
|
/** high part of card size */
|
||||||
|
unsigned char c_size_high : 6;
|
||||||
|
/** not used */
|
||||||
|
unsigned char reserved3 : 2;
|
||||||
|
// byte 8
|
||||||
|
/** middle part of card size */
|
||||||
|
unsigned char c_size_mid;
|
||||||
|
// byte 9
|
||||||
|
/** low part of card size */
|
||||||
|
unsigned char c_size_low;
|
||||||
|
// byte 10
|
||||||
|
/** 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 char wp_grp_size : 7;
|
||||||
|
/** sector size is fixed at 64 KB */
|
||||||
|
unsigned char sector_size_low : 1;
|
||||||
|
// byte 12
|
||||||
|
/** 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 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 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
|
||||||
|
/** not used always 1 */
|
||||||
|
unsigned char always1 : 1;
|
||||||
|
/** checksum */
|
||||||
|
unsigned char crc : 7;
|
||||||
|
} __attribute__((packed)) csd2_t;
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class csd_t
|
||||||
|
* \brief Union of old and new style CSD register.
|
||||||
|
*/
|
||||||
|
union csd_t {
|
||||||
|
csd1_t v1;
|
||||||
|
csd2_t v2;
|
||||||
|
};
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
inline uint32_t sdCardCapacity(csd_t* csd) {
|
||||||
|
if (csd->v1.csd_ver == 0) {
|
||||||
|
uint8_t read_bl_len = csd->v1.read_bl_len;
|
||||||
|
uint16_t c_size = (csd->v1.c_size_high << 10)
|
||||||
|
| (csd->v1.c_size_mid << 2) | csd->v1.c_size_low;
|
||||||
|
uint8_t c_size_mult = (csd->v1.c_size_mult_high << 1)
|
||||||
|
| csd->v1.c_size_mult_low;
|
||||||
|
return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
|
||||||
|
} else if (csd->v2.csd_ver == 1) {
|
||||||
|
uint32_t c_size = 0X10000L * csd->v2.c_size_high + 0X100L
|
||||||
|
* (uint32_t)csd->v2.c_size_mid + csd->v2.c_size_low;
|
||||||
|
return (c_size + 1) << 10;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // SdInfo_h
|
802
hardware/_controller/src/SdFat/SdCard/SdSpiCard.cpp
Normal file
802
hardware/_controller/src/SdFat/SdCard/SdSpiCard.cpp
Normal file
|
@ -0,0 +1,802 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "SdSpiCard.h"
|
||||||
|
//==============================================================================
|
||||||
|
// debug trace macro
|
||||||
|
#define SD_TRACE(m, b)
|
||||||
|
// #define SD_TRACE(m, b) Serial.print(m);Serial.println(b);
|
||||||
|
#define SD_CS_DBG(m)
|
||||||
|
// #define SD_CS_DBG(m) Serial.println(F(m));
|
||||||
|
|
||||||
|
#define DBG_PROFILE_STATS 0
|
||||||
|
#if DBG_PROFILE_STATS
|
||||||
|
|
||||||
|
#define DBG_TAG_LIST\
|
||||||
|
DBG_TAG(DBG_CMD0_TIME, "CMD0 time")\
|
||||||
|
DBG_TAG(DBG_ACMD41_TIME, "ACMD41 time")\
|
||||||
|
DBG_TAG(DBG_CMD_BUSY, "cmd busy")\
|
||||||
|
DBG_TAG(DBG_ERASE_BUSY, "erase busy")\
|
||||||
|
DBG_TAG(DBG_WAIT_READ, "wait read")\
|
||||||
|
DBG_TAG(DBG_WRITE_FLASH, "write flash")\
|
||||||
|
DBG_TAG(DBG_WRITE_BUSY, "write busy")\
|
||||||
|
DBG_TAG(DBG_WRITE_STOP, "write stop")\
|
||||||
|
DBG_TAG(DBG_ACMD41_COUNT, "ACMD41 count")\
|
||||||
|
DBG_TAG(DBG_CMD0_COUNT, "CMD0 count")
|
||||||
|
|
||||||
|
#define DBG_TIME_DIM DBG_ACMD41_COUNT
|
||||||
|
|
||||||
|
enum DbgTag {
|
||||||
|
#define DBG_TAG(tag, str) tag,
|
||||||
|
DBG_TAG_LIST
|
||||||
|
DBG_COUNT_DIM
|
||||||
|
#undef DBG_TAG
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t dbgCount[DBG_COUNT_DIM];
|
||||||
|
static uint32_t dbgBgnTime[DBG_TIME_DIM];
|
||||||
|
static uint32_t dbgMaxTime[DBG_TIME_DIM];
|
||||||
|
static uint32_t dbgMinTime[DBG_TIME_DIM];
|
||||||
|
static uint32_t dbgTotalTime[DBG_TIME_DIM];
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void dbgBeginTime(DbgTag tag) {
|
||||||
|
dbgBgnTime[tag] = micros();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void dbgClearStats() {
|
||||||
|
for (int i = 0; i < DBG_COUNT_DIM; i++) {
|
||||||
|
dbgCount[i] = 0;
|
||||||
|
if (i < DBG_TIME_DIM) {
|
||||||
|
dbgMaxTime[i] = 0;
|
||||||
|
dbgMinTime[i] = 9999999;
|
||||||
|
dbgTotalTime[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void dbgEndTime(DbgTag tag) {
|
||||||
|
uint32_t m = micros() - dbgBgnTime[tag];
|
||||||
|
dbgTotalTime[tag] += m;
|
||||||
|
if (m > dbgMaxTime[tag]) {
|
||||||
|
dbgMaxTime[tag] = m;
|
||||||
|
}
|
||||||
|
if (m < dbgMinTime[tag]) {
|
||||||
|
dbgMinTime[tag] = m;
|
||||||
|
}
|
||||||
|
dbgCount[tag]++;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void dbgEventCount(DbgTag tag) {
|
||||||
|
dbgCount[tag]++;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void dbgPrintTagText(uint8_t tag) {
|
||||||
|
#define DBG_TAG(e, m) case e: Serial.print(F(m)); break;
|
||||||
|
switch (tag) {
|
||||||
|
DBG_TAG_LIST
|
||||||
|
}
|
||||||
|
#undef DBG_TAG
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void dbgPrintStats() {
|
||||||
|
Serial.println();
|
||||||
|
Serial.println(F("======================="));
|
||||||
|
Serial.println(F("item,event,min,max,avg"));
|
||||||
|
Serial.println(F("tag,count,usec,usec,usec"));
|
||||||
|
for (int i = 0; i < DBG_COUNT_DIM; i++) {
|
||||||
|
if (dbgCount[i]) {
|
||||||
|
dbgPrintTagText(i);
|
||||||
|
Serial.print(',');
|
||||||
|
Serial.print(dbgCount[i]);
|
||||||
|
if (i < DBG_TIME_DIM) {
|
||||||
|
Serial.print(',');
|
||||||
|
Serial.print(dbgMinTime[i]);
|
||||||
|
Serial.print(',');
|
||||||
|
Serial.print(dbgMaxTime[i]);
|
||||||
|
Serial.print(',');
|
||||||
|
Serial.print(dbgTotalTime[i]/dbgCount[i]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.println(F("======================="));
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
#undef DBG_TAG_LIST
|
||||||
|
#define DBG_BEGIN_TIME(tag) dbgBeginTime(tag)
|
||||||
|
#define DBG_END_TIME(tag) dbgEndTime(tag)
|
||||||
|
#define DBG_EVENT_COUNT(tag) dbgEventCount(tag)
|
||||||
|
#else // DBG_PROFILE_STATS
|
||||||
|
#define DBG_BEGIN_TIME(tag)
|
||||||
|
#define DBG_END_TIME(tag)
|
||||||
|
#define DBG_EVENT_COUNT(tag)
|
||||||
|
static void dbgClearStats() {}
|
||||||
|
static void dbgPrintStats() {}
|
||||||
|
#endif // DBG_PROFILE_STATS
|
||||||
|
//==============================================================================
|
||||||
|
#if USE_SD_CRC
|
||||||
|
// CRC functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static uint8_t CRC7(const uint8_t* data, uint8_t n) {
|
||||||
|
uint8_t crc = 0;
|
||||||
|
for (uint8_t i = 0; i < n; i++) {
|
||||||
|
uint8_t d = data[i];
|
||||||
|
for (uint8_t j = 0; j < 8; j++) {
|
||||||
|
crc <<= 1;
|
||||||
|
if ((d & 0x80) ^ (crc & 0x80)) {
|
||||||
|
crc ^= 0x09;
|
||||||
|
}
|
||||||
|
d <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (crc << 1) | 1;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if USE_SD_CRC == 1
|
||||||
|
// Shift based CRC-CCITT
|
||||||
|
// uses the x^16,x^12,x^5,x^1 polynomial.
|
||||||
|
static uint16_t CRC_CCITT(const uint8_t *data, size_t n) {
|
||||||
|
uint16_t crc = 0;
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
crc = (uint8_t)(crc >> 8) | (crc << 8);
|
||||||
|
crc ^= data[i];
|
||||||
|
crc ^= (uint8_t)(crc & 0xff) >> 4;
|
||||||
|
crc ^= crc << 12;
|
||||||
|
crc ^= (crc & 0xff) << 5;
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
#elif USE_SD_CRC > 1 // CRC_CCITT
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Table based CRC-CCITT
|
||||||
|
// uses the x^16,x^12,x^5,x^1 polynomial.
|
||||||
|
#ifdef __AVR__
|
||||||
|
static const uint16_t crctab[] PROGMEM = {
|
||||||
|
#else // __AVR__
|
||||||
|
static const uint16_t crctab[] = {
|
||||||
|
#endif // __AVR__
|
||||||
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||||
|
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||||
|
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||||
|
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
|
||||||
|
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
|
||||||
|
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
|
||||||
|
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
|
||||||
|
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
|
||||||
|
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||||
|
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
|
||||||
|
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
|
||||||
|
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
|
||||||
|
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
||||||
|
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
|
||||||
|
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
|
||||||
|
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
|
||||||
|
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
|
||||||
|
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||||
|
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
|
||||||
|
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||||
|
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
|
||||||
|
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||||
|
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
|
||||||
|
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||||
|
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
|
||||||
|
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
||||||
|
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||||
|
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
|
||||||
|
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
|
||||||
|
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
|
||||||
|
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||||
|
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||||
|
};
|
||||||
|
static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
|
||||||
|
uint16_t crc = 0;
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
#ifdef __AVR__
|
||||||
|
crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8);
|
||||||
|
#else // __AVR__
|
||||||
|
crc = crctab[(crc >> 8 ^ data[i]) & 0XFF] ^ (crc << 8);
|
||||||
|
#endif // __AVR__
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
#endif // CRC_CCITT
|
||||||
|
#endif // USE_SD_CRC
|
||||||
|
//==============================================================================
|
||||||
|
// SdSpiCard member functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::begin(SdSpiDriver* spi, uint8_t csPin, SPISettings settings) {
|
||||||
|
m_spiActive = false;
|
||||||
|
m_errorCode = SD_CARD_ERROR_NONE;
|
||||||
|
m_type = 0;
|
||||||
|
m_spiDriver = spi;
|
||||||
|
uint16_t t0 = curTimeMS();
|
||||||
|
uint32_t arg;
|
||||||
|
|
||||||
|
m_spiDriver->begin(csPin);
|
||||||
|
m_spiDriver->setSpiSettings(SD_SCK_HZ(250000));
|
||||||
|
spiStart();
|
||||||
|
|
||||||
|
// must supply min of 74 clock cycles with CS high.
|
||||||
|
spiUnselect();
|
||||||
|
for (uint8_t i = 0; i < 10; i++) {
|
||||||
|
spiSend(0XFF);
|
||||||
|
}
|
||||||
|
spiSelect();
|
||||||
|
|
||||||
|
DBG_BEGIN_TIME(DBG_CMD0_TIME);
|
||||||
|
// command to go idle in SPI mode
|
||||||
|
for (uint8_t i = 1;; i++) {
|
||||||
|
DBG_EVENT_COUNT(DBG_CMD0_COUNT);
|
||||||
|
if (cardCommand(CMD0, 0) == R1_IDLE_STATE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == SD_CMD0_RETRY) {
|
||||||
|
error(SD_CARD_ERROR_CMD0);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// stop multi-block write
|
||||||
|
spiSend(STOP_TRAN_TOKEN);
|
||||||
|
// finish block transfer
|
||||||
|
for (int i = 0; i < 520; i++) {
|
||||||
|
spiReceive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG_END_TIME(DBG_CMD0_TIME);
|
||||||
|
#if USE_SD_CRC
|
||||||
|
if (cardCommand(CMD59, 1) != R1_IDLE_STATE) {
|
||||||
|
error(SD_CARD_ERROR_CMD59);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif // USE_SD_CRC
|
||||||
|
// check SD version
|
||||||
|
if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) {
|
||||||
|
type(SD_CARD_TYPE_SD1);
|
||||||
|
} else {
|
||||||
|
for (uint8_t i = 0; i < 4; i++) {
|
||||||
|
m_status = spiReceive();
|
||||||
|
}
|
||||||
|
if (m_status == 0XAA) {
|
||||||
|
type(SD_CARD_TYPE_SD2);
|
||||||
|
} else {
|
||||||
|
error(SD_CARD_ERROR_CMD8);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// initialize card and send host supports SDHC if SD2
|
||||||
|
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
|
||||||
|
DBG_BEGIN_TIME(DBG_ACMD41_TIME);
|
||||||
|
while (cardAcmd(ACMD41, arg) != R1_READY_STATE) {
|
||||||
|
DBG_EVENT_COUNT(DBG_ACMD41_COUNT);
|
||||||
|
// check for timeout
|
||||||
|
if (isTimedOut(t0, SD_INIT_TIMEOUT)) {
|
||||||
|
error(SD_CARD_ERROR_ACMD41);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG_END_TIME(DBG_ACMD41_TIME);
|
||||||
|
// if SD2 read OCR register to check for SDHC card
|
||||||
|
if (type() == SD_CARD_TYPE_SD2) {
|
||||||
|
if (cardCommand(CMD58, 0)) {
|
||||||
|
error(SD_CARD_ERROR_CMD58);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((spiReceive() & 0XC0) == 0XC0) {
|
||||||
|
type(SD_CARD_TYPE_SDHC);
|
||||||
|
}
|
||||||
|
// Discard rest of ocr - contains allowed voltage range.
|
||||||
|
for (uint8_t i = 0; i < 3; i++) {
|
||||||
|
spiReceive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spiStop();
|
||||||
|
m_spiDriver->setSpiSettings(settings);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// send command and return error code. Return zero for OK
|
||||||
|
uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
|
||||||
|
// select card
|
||||||
|
if (!m_spiActive) {
|
||||||
|
spiStart();
|
||||||
|
}
|
||||||
|
// wait if busy unless CMD0
|
||||||
|
if (cmd != CMD0) {
|
||||||
|
DBG_BEGIN_TIME(DBG_CMD_BUSY);
|
||||||
|
waitNotBusy(SD_CMD_TIMEOUT);
|
||||||
|
DBG_END_TIME(DBG_CMD_BUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_SD_CRC
|
||||||
|
// form message
|
||||||
|
uint8_t buf[6];
|
||||||
|
buf[0] = (uint8_t)0x40U | cmd;
|
||||||
|
buf[1] = (uint8_t)(arg >> 24U);
|
||||||
|
buf[2] = (uint8_t)(arg >> 16U);
|
||||||
|
buf[3] = (uint8_t)(arg >> 8U);
|
||||||
|
buf[4] = (uint8_t)arg;
|
||||||
|
|
||||||
|
// add CRC
|
||||||
|
buf[5] = CRC7(buf, 5);
|
||||||
|
|
||||||
|
// send message
|
||||||
|
spiSend(buf, 6);
|
||||||
|
#else // USE_SD_CRC
|
||||||
|
// send command
|
||||||
|
spiSend(cmd | 0x40);
|
||||||
|
|
||||||
|
// send argument
|
||||||
|
uint8_t *pa = reinterpret_cast<uint8_t *>(&arg);
|
||||||
|
for (int8_t i = 3; i >= 0; i--) {
|
||||||
|
spiSend(pa[i]);
|
||||||
|
}
|
||||||
|
// send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
|
||||||
|
spiSend(cmd == CMD0 ? 0X95 : 0X87);
|
||||||
|
#endif // USE_SD_CRC
|
||||||
|
|
||||||
|
// discard first fill byte to avoid MISO pull-up problem.
|
||||||
|
spiReceive();
|
||||||
|
|
||||||
|
// there are 1-8 fill bytes before response. fill bytes should be 0XFF.
|
||||||
|
for (uint8_t i = 0; ((m_status = spiReceive()) & 0X80) && i < 10; i++) {
|
||||||
|
}
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
uint32_t SdSpiCard::cardCapacity() {
|
||||||
|
csd_t csd;
|
||||||
|
return readCSD(&csd) ? sdCardCapacity(&csd) : 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void SdSpiCard::dbgClearStats() {::dbgClearStats();}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void SdSpiCard::dbgPrintStats() {::dbgPrintStats();}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::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 (m_type != SD_CARD_TYPE_SDHC) {
|
||||||
|
firstBlock <<= 9;
|
||||||
|
lastBlock <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD32, firstBlock)
|
||||||
|
|| cardCommand(CMD33, lastBlock)
|
||||||
|
|| cardCommand(CMD38, 0)) {
|
||||||
|
error(SD_CARD_ERROR_ERASE);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
DBG_BEGIN_TIME(DBG_ERASE_BUSY);
|
||||||
|
if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
|
||||||
|
error(SD_CARD_ERROR_ERASE_TIMEOUT);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
DBG_END_TIME(DBG_ERASE_BUSY);
|
||||||
|
spiStop();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::eraseSingleBlockEnable() {
|
||||||
|
csd_t csd;
|
||||||
|
return readCSD(&csd) ? csd.v1.erase_blk_en : false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::isBusy() {
|
||||||
|
bool rtn = true;
|
||||||
|
bool spiActive = m_spiActive;
|
||||||
|
if (!spiActive) {
|
||||||
|
spiStart();
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
if (0XFF == spiReceive()) {
|
||||||
|
rtn = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!spiActive) {
|
||||||
|
spiStop();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::isTimedOut(uint16_t startMS, uint16_t timeoutMS) {
|
||||||
|
#if WDT_YIELD_TIME_MICROS
|
||||||
|
static uint32_t last;
|
||||||
|
if ((micros() - last) > WDT_YIELD_TIME_MICROS) {
|
||||||
|
SysCall::yield();
|
||||||
|
last = micros();
|
||||||
|
}
|
||||||
|
#endif // WDT_YIELD_TIME_MICROS
|
||||||
|
return (curTimeMS() - startMS) > timeoutMS;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::readBlock(uint32_t blockNumber, uint8_t* dst) {
|
||||||
|
SD_TRACE("RB", blockNumber);
|
||||||
|
// use address if not SDHC card
|
||||||
|
if (type() != SD_CARD_TYPE_SDHC) {
|
||||||
|
blockNumber <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD17, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD17);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!readData(dst, 512)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
spiStop();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::readBlocks(uint32_t block, uint8_t* dst, size_t count) {
|
||||||
|
if (!readStart(block)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (uint16_t b = 0; b < count; b++, dst += 512) {
|
||||||
|
if (!readData(dst, 512)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return readStop();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::readData(uint8_t *dst) {
|
||||||
|
return readData(dst, 512);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::readData(uint8_t* dst, size_t count) {
|
||||||
|
#if USE_SD_CRC
|
||||||
|
uint16_t crc;
|
||||||
|
#endif // USE_SD_CRC
|
||||||
|
DBG_BEGIN_TIME(DBG_WAIT_READ);
|
||||||
|
// wait for start block token
|
||||||
|
uint16_t t0 = curTimeMS();
|
||||||
|
while ((m_status = spiReceive()) == 0XFF) {
|
||||||
|
if (isTimedOut(t0, SD_READ_TIMEOUT)) {
|
||||||
|
error(SD_CARD_ERROR_READ_TIMEOUT);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG_END_TIME(DBG_WAIT_READ);
|
||||||
|
if (m_status != DATA_START_BLOCK) {
|
||||||
|
error(SD_CARD_ERROR_READ);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// transfer data
|
||||||
|
if ((m_status = spiReceive(dst, count))) {
|
||||||
|
error(SD_CARD_ERROR_DMA);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_SD_CRC
|
||||||
|
// get crc
|
||||||
|
crc = (spiReceive() << 8) | spiReceive();
|
||||||
|
if (crc != CRC_CCITT(dst, count)) {
|
||||||
|
error(SD_CARD_ERROR_READ_CRC);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// discard crc
|
||||||
|
spiReceive();
|
||||||
|
spiReceive();
|
||||||
|
#endif // USE_SD_CRC
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::readOCR(uint32_t* ocr) {
|
||||||
|
uint8_t *p = reinterpret_cast<uint8_t*>(ocr);
|
||||||
|
if (cardCommand(CMD58, 0)) {
|
||||||
|
error(SD_CARD_ERROR_CMD58);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < 4; i++) {
|
||||||
|
p[3 - i] = spiReceive();
|
||||||
|
}
|
||||||
|
|
||||||
|
spiStop();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** read CID or CSR register */
|
||||||
|
bool SdSpiCard::readRegister(uint8_t cmd, void* buf) {
|
||||||
|
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
||||||
|
if (cardCommand(cmd, 0)) {
|
||||||
|
error(SD_CARD_ERROR_READ_REG);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!readData(dst, 16)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
spiStop();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::readStart(uint32_t blockNumber) {
|
||||||
|
SD_TRACE("RS", blockNumber);
|
||||||
|
if (type() != SD_CARD_TYPE_SDHC) {
|
||||||
|
blockNumber <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD18, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD18);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// spiStop();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::readStatus(uint8_t* status) {
|
||||||
|
// retrun is R2 so read extra status byte.
|
||||||
|
if (cardAcmd(ACMD13, 0) || spiReceive()) {
|
||||||
|
error(SD_CARD_ERROR_ACMD13);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!readData(status, 64)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
spiStop();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void SdSpiCard::spiStart() {
|
||||||
|
if (!m_spiActive) {
|
||||||
|
spiActivate();
|
||||||
|
spiSelect();
|
||||||
|
m_spiActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void SdSpiCard::spiStop() {
|
||||||
|
if (m_spiActive) {
|
||||||
|
spiUnselect();
|
||||||
|
spiSend(0XFF);
|
||||||
|
spiDeactivate();
|
||||||
|
m_spiActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::readStop() {
|
||||||
|
if (cardCommand(CMD12, 0)) {
|
||||||
|
error(SD_CARD_ERROR_CMD12);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
spiStop();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// wait for card to go not busy
|
||||||
|
bool SdSpiCard::waitNotBusy(uint16_t timeoutMS) {
|
||||||
|
uint16_t t0 = curTimeMS();
|
||||||
|
#if WDT_YIELD_TIME_MICROS
|
||||||
|
// Call isTimedOut first to insure yield is called.
|
||||||
|
while (!isTimedOut(t0, timeoutMS)) {
|
||||||
|
if (spiReceive() == 0XFF) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
#else // WDT_YIELD_TIME_MICROS
|
||||||
|
// Check not busy first since yield is not called in isTimedOut.
|
||||||
|
while (spiReceive() != 0XFF) {
|
||||||
|
if (isTimedOut(t0, timeoutMS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
#endif // WDT_YIELD_TIME_MICROS
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::writeBlock(uint32_t blockNumber, const uint8_t* src) {
|
||||||
|
SD_TRACE("WB", blockNumber);
|
||||||
|
// use address if not SDHC card
|
||||||
|
if (type() != SD_CARD_TYPE_SDHC) {
|
||||||
|
blockNumber <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD24, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD24);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!writeData(DATA_START_BLOCK, src)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if CHECK_FLASH_PROGRAMMING
|
||||||
|
// wait for flash programming to complete
|
||||||
|
DBG_BEGIN_TIME(DBG_WRITE_FLASH);
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||||
|
error(SD_CARD_ERROR_FLASH_PROGRAMMING);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
DBG_END_TIME(DBG_WRITE_FLASH);
|
||||||
|
// response is r2 so get and check two bytes for nonzero
|
||||||
|
if (cardCommand(CMD13, 0) || spiReceive()) {
|
||||||
|
error(SD_CARD_ERROR_CMD13);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif // CHECK_PROGRAMMING
|
||||||
|
|
||||||
|
spiStop();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::writeBlocks(uint32_t block, const uint8_t* src, size_t count) {
|
||||||
|
if (!writeStart(block)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
for (size_t b = 0; b < count; b++, src += 512) {
|
||||||
|
if (!writeData(src)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return writeStop();
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::writeData(const uint8_t* src) {
|
||||||
|
// wait for previous write to finish
|
||||||
|
DBG_BEGIN_TIME(DBG_WRITE_BUSY);
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||||
|
error(SD_CARD_ERROR_WRITE_TIMEOUT);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
DBG_END_TIME(DBG_WRITE_BUSY);
|
||||||
|
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// send one block of data for write block or write multiple blocks
|
||||||
|
bool SdSpiCard::writeData(uint8_t token, const uint8_t* src) {
|
||||||
|
#if USE_SD_CRC
|
||||||
|
uint16_t crc = CRC_CCITT(src, 512);
|
||||||
|
#else // USE_SD_CRC
|
||||||
|
uint16_t crc = 0XFFFF;
|
||||||
|
#endif // USE_SD_CRC
|
||||||
|
spiSend(token);
|
||||||
|
spiSend(src, 512);
|
||||||
|
spiSend(crc >> 8);
|
||||||
|
spiSend(crc & 0XFF);
|
||||||
|
|
||||||
|
m_status = spiReceive();
|
||||||
|
if ((m_status & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
||||||
|
error(SD_CARD_ERROR_WRITE);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::writeStart(uint32_t blockNumber) {
|
||||||
|
// use address if not SDHC card
|
||||||
|
if (type() != SD_CARD_TYPE_SDHC) {
|
||||||
|
blockNumber <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD25, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD25);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
||||||
|
SD_TRACE("WS", blockNumber);
|
||||||
|
// send pre-erase count
|
||||||
|
if (cardAcmd(ACMD23, eraseCount)) {
|
||||||
|
error(SD_CARD_ERROR_ACMD23);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
// use address if not SDHC card
|
||||||
|
if (type() != SD_CARD_TYPE_SDHC) {
|
||||||
|
blockNumber <<= 9;
|
||||||
|
}
|
||||||
|
if (cardCommand(CMD25, blockNumber)) {
|
||||||
|
error(SD_CARD_ERROR_CMD25);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
bool SdSpiCard::writeStop() {
|
||||||
|
DBG_BEGIN_TIME(DBG_WRITE_STOP);
|
||||||
|
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
DBG_END_TIME(DBG_WRITE_STOP);
|
||||||
|
spiSend(STOP_TRAN_TOKEN);
|
||||||
|
spiStop();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
error(SD_CARD_ERROR_STOP_TRAN);
|
||||||
|
spiStop();
|
||||||
|
return false;
|
||||||
|
}
|
379
hardware/_controller/src/SdFat/SdCard/SdSpiCard.h
Normal file
379
hardware/_controller/src/SdFat/SdCard/SdSpiCard.h
Normal file
|
@ -0,0 +1,379 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SdSpiCard_h
|
||||||
|
#define SdSpiCard_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief SdSpiCard class for V2 SD/SDHC cards
|
||||||
|
*/
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "../SysCall.h"
|
||||||
|
#include "SdInfo.h"
|
||||||
|
#include "../FatLib/BaseBlockDriver.h"
|
||||||
|
#include "../SpiDriver/SdSpiDriver.h"
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class SdSpiCard
|
||||||
|
* \brief Raw access to SD and SDHC flash memory cards via SPI protocol.
|
||||||
|
*/
|
||||||
|
#if ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
|
||||||
|
class SdSpiCard : public BaseBlockDriver {
|
||||||
|
#else // ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
|
||||||
|
class SdSpiCard {
|
||||||
|
#endif // ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
|
||||||
|
public:
|
||||||
|
/** Construct an instance of SdSpiCard. */
|
||||||
|
SdSpiCard() : m_errorCode(SD_CARD_ERROR_INIT_NOT_CALLED), m_type(0) {}
|
||||||
|
/** Initialize the SD card.
|
||||||
|
* \param[in] spi SPI driver for card.
|
||||||
|
* \param[in] csPin card chip select pin.
|
||||||
|
* \param[in] spiSettings SPI speed, mode, and bit order.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool begin(SdSpiDriver* spi, uint8_t csPin, SPISettings spiSettings);
|
||||||
|
/**
|
||||||
|
* Determine the size of an SD flash memory card.
|
||||||
|
*
|
||||||
|
* \return The number of 512 byte sectors in the card
|
||||||
|
* or zero if an error occurs.
|
||||||
|
*/
|
||||||
|
uint32_t cardCapacity();
|
||||||
|
/** \return Card size in sectors or zero if an error occurs. */
|
||||||
|
uint32_t cardSize() {return cardCapacity();}
|
||||||
|
/** Clear debug stats. */
|
||||||
|
void dbgClearStats();
|
||||||
|
/** Print debug stats. */
|
||||||
|
void dbgPrintStats();
|
||||||
|
/** Erase a range of blocks.
|
||||||
|
*
|
||||||
|
* \param[in] firstBlock The address of the first block in the range.
|
||||||
|
* \param[in] lastBlock The address of the last block in the range.
|
||||||
|
*
|
||||||
|
* \note This function requests the SD card to do a flash erase for a
|
||||||
|
* range of blocks. The data on the card after an erase operation is
|
||||||
|
* either 0 or 1, depends on the card vendor. The card must support
|
||||||
|
* single block erase.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool erase(uint32_t firstBlock, uint32_t lastBlock);
|
||||||
|
/** Determine if card supports single block erase.
|
||||||
|
*
|
||||||
|
* \return true is returned if single block erase is supported.
|
||||||
|
* false is returned if single block erase is not supported.
|
||||||
|
*/
|
||||||
|
bool eraseSingleBlockEnable();
|
||||||
|
/**
|
||||||
|
* Set SD error code.
|
||||||
|
* \param[in] code value for error code.
|
||||||
|
*/
|
||||||
|
void error(uint8_t code) {
|
||||||
|
m_errorCode = code;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \return code for the last error. See SdInfo.h for a list of error codes.
|
||||||
|
*/
|
||||||
|
int errorCode() const {
|
||||||
|
return m_errorCode;
|
||||||
|
}
|
||||||
|
/** \return error data for last error. */
|
||||||
|
int errorData() const {
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Check for busy. MISO low indicates the card is busy.
|
||||||
|
*
|
||||||
|
* \return true if busy else false.
|
||||||
|
*/
|
||||||
|
bool isBusy();
|
||||||
|
/**
|
||||||
|
* Read a 512 byte block from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] lba Logical block to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readBlock(uint32_t lba, uint8_t* dst);
|
||||||
|
/**
|
||||||
|
* Read multiple 512 byte blocks from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] lba Logical block to be read.
|
||||||
|
* \param[in] nb Number of blocks to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readBlocks(uint32_t lba, uint8_t* dst, size_t nb);
|
||||||
|
/**
|
||||||
|
* Read a card's CID register. The CID contains card identification
|
||||||
|
* information such as Manufacturer ID, Product name, Product serial
|
||||||
|
* number and Manufacturing date.
|
||||||
|
*
|
||||||
|
* \param[out] cid pointer to area for returned data.
|
||||||
|
*
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool readCID(cid_t* cid) {
|
||||||
|
return readRegister(CMD10, cid);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Read a card's CSD register. The CSD contains Card-Specific Data that
|
||||||
|
* provides information regarding access to the card's contents.
|
||||||
|
*
|
||||||
|
* \param[out] csd pointer to area for returned data.
|
||||||
|
*
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool readCSD(csd_t* csd) {
|
||||||
|
return readRegister(CMD9, csd);
|
||||||
|
}
|
||||||
|
/** Read one data block in a multiple block read sequence
|
||||||
|
*
|
||||||
|
* \param[out] dst Pointer to the location for the data to be read.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readData(uint8_t *dst);
|
||||||
|
/** Read OCR register.
|
||||||
|
*
|
||||||
|
* \param[out] ocr Value of OCR register.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool readOCR(uint32_t* ocr);
|
||||||
|
/** Start a read multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \param[in] blockNumber Address of first block in sequence.
|
||||||
|
*
|
||||||
|
* \note This function is used with readData() and readStop() for optimized
|
||||||
|
* multiple block reads. SPI chipSelect must be low for the entire sequence.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readStart(uint32_t blockNumber);
|
||||||
|
/** Return the 64 byte card status
|
||||||
|
* \param[out] status location for 64 status bytes.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readStatus(uint8_t* status);
|
||||||
|
/** End a read multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readStop();
|
||||||
|
/** \return success if sync successful. Not for user apps. */
|
||||||
|
bool syncBlocks() {return true;}
|
||||||
|
/** Return the card type: SD V1, SD V2 or SDHC
|
||||||
|
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
|
||||||
|
*/
|
||||||
|
int type() const {
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Writes a 512 byte block to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] lba Logical block to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeBlock(uint32_t lba, const uint8_t* src);
|
||||||
|
/**
|
||||||
|
* Write multiple 512 byte blocks to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] lba Logical block to be written.
|
||||||
|
* \param[in] nb Number of blocks to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeBlocks(uint32_t lba, const uint8_t* src, size_t nb);
|
||||||
|
/** 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 true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeData(const uint8_t* src);
|
||||||
|
/** Start a write multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \param[in] blockNumber Address of first block in sequence.
|
||||||
|
*
|
||||||
|
* \note This function is used with writeData() and writeStop()
|
||||||
|
* for optimized multiple block writes.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeStart(uint32_t blockNumber);
|
||||||
|
|
||||||
|
/** Start a write multiple blocks sequence with pre-erase.
|
||||||
|
*
|
||||||
|
* \param[in] blockNumber Address of first block in sequence.
|
||||||
|
* \param[in] eraseCount The number of blocks to be pre-erased.
|
||||||
|
*
|
||||||
|
* \note This function is used with writeData() and writeStop()
|
||||||
|
* for optimized multiple block writes.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
|
||||||
|
/** End a write multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeStop();
|
||||||
|
/** Set CS low and activate the card. */
|
||||||
|
void spiStart();
|
||||||
|
/** Set CS high and deactivate the card. */
|
||||||
|
void spiStop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// private functions
|
||||||
|
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
|
||||||
|
cardCommand(CMD55, 0);
|
||||||
|
return cardCommand(cmd, arg);
|
||||||
|
}
|
||||||
|
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
|
||||||
|
bool isTimedOut(uint16_t startMS, uint16_t timeoutMS);
|
||||||
|
bool readData(uint8_t* dst, size_t count);
|
||||||
|
bool readRegister(uint8_t cmd, void* buf);
|
||||||
|
|
||||||
|
void type(uint8_t value) {
|
||||||
|
m_type = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool waitNotBusy(uint16_t timeoutMS);
|
||||||
|
bool writeData(uint8_t token, const uint8_t* src);
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// functions defined in SdSpiDriver.h
|
||||||
|
void spiActivate() {
|
||||||
|
m_spiDriver->activate();
|
||||||
|
}
|
||||||
|
void spiDeactivate() {
|
||||||
|
m_spiDriver->deactivate();
|
||||||
|
}
|
||||||
|
uint8_t spiReceive() {
|
||||||
|
return m_spiDriver->receive();
|
||||||
|
}
|
||||||
|
uint8_t spiReceive(uint8_t* buf, size_t n) {
|
||||||
|
return m_spiDriver->receive(buf, n);
|
||||||
|
}
|
||||||
|
void spiSend(uint8_t data) {
|
||||||
|
m_spiDriver->send(data);
|
||||||
|
}
|
||||||
|
void spiSend(const uint8_t* buf, size_t n) {
|
||||||
|
m_spiDriver->send(buf, n);
|
||||||
|
}
|
||||||
|
void spiSelect() {
|
||||||
|
m_spiDriver->select();
|
||||||
|
}
|
||||||
|
void spiUnselect() {
|
||||||
|
m_spiDriver->unselect();
|
||||||
|
}
|
||||||
|
uint8_t m_errorCode;
|
||||||
|
SdSpiDriver *m_spiDriver;
|
||||||
|
bool m_spiActive;
|
||||||
|
uint8_t m_status;
|
||||||
|
uint8_t m_type;
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class SdSpiCardEX
|
||||||
|
* \brief Extended SD I/O block driver.
|
||||||
|
*/
|
||||||
|
class SdSpiCardEX : public SdSpiCard {
|
||||||
|
public:
|
||||||
|
/** Initialize the SD card
|
||||||
|
*
|
||||||
|
* \param[in] spi SPI driver.
|
||||||
|
* \param[in] csPin Card chip select pin number.
|
||||||
|
* \param[in] spiSettings SPI speed, mode, and bit order.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool begin(SdSpiDriver* spi, uint8_t csPin, SPISettings spiSettings) {
|
||||||
|
m_curState = IDLE_STATE;
|
||||||
|
return SdSpiCard::begin(spi, csPin, spiSettings);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Read a 512 byte block from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readBlock(uint32_t block, uint8_t* dst);
|
||||||
|
/** End multi-block transfer and go to idle state.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool syncBlocks();
|
||||||
|
/**
|
||||||
|
* Writes a 512 byte block to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeBlock(uint32_t block, const uint8_t* src);
|
||||||
|
/**
|
||||||
|
* Read multiple 512 byte blocks from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be read.
|
||||||
|
* \param[in] nb Number of blocks to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readBlocks(uint32_t block, uint8_t* dst, size_t nb);
|
||||||
|
/**
|
||||||
|
* Write multiple 512 byte blocks to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be written.
|
||||||
|
* \param[in] nb Number of blocks to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const uint32_t IDLE_STATE = 0;
|
||||||
|
static const uint32_t READ_STATE = 1;
|
||||||
|
static const uint32_t WRITE_STATE = 2;
|
||||||
|
uint32_t m_curBlock;
|
||||||
|
uint8_t m_curState;
|
||||||
|
};
|
||||||
|
#endif // SdSpiCard_h
|
94
hardware/_controller/src/SdFat/SdCard/SdSpiCardEX.cpp
Normal file
94
hardware/_controller/src/SdFat/SdCard/SdSpiCardEX.cpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "SdSpiCard.h"
|
||||||
|
bool SdSpiCardEX::readBlock(uint32_t block, uint8_t* dst) {
|
||||||
|
if (m_curState != READ_STATE || block != m_curBlock) {
|
||||||
|
if (!syncBlocks()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!SdSpiCard::readStart(block)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_curBlock = block;
|
||||||
|
m_curState = READ_STATE;
|
||||||
|
}
|
||||||
|
if (!SdSpiCard::readData(dst)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_curBlock++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdSpiCardEX::readBlocks(uint32_t block, uint8_t* dst, size_t nb) {
|
||||||
|
for (size_t i = 0; i < nb; i++) {
|
||||||
|
if (!readBlock(block + i, dst + i*512UL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdSpiCardEX::syncBlocks() {
|
||||||
|
if (m_curState == READ_STATE) {
|
||||||
|
m_curState = IDLE_STATE;
|
||||||
|
if (!SdSpiCard::readStop()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (m_curState == WRITE_STATE) {
|
||||||
|
m_curState = IDLE_STATE;
|
||||||
|
if (!SdSpiCard::writeStop()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdSpiCardEX::writeBlock(uint32_t block, const uint8_t* src) {
|
||||||
|
if (m_curState != WRITE_STATE || m_curBlock != block) {
|
||||||
|
if (!syncBlocks()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!SdSpiCard::writeStart(block)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_curBlock = block;
|
||||||
|
m_curState = WRITE_STATE;
|
||||||
|
}
|
||||||
|
if (!SdSpiCard::writeData(src)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_curBlock++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdSpiCardEX::writeBlocks(uint32_t block,
|
||||||
|
const uint8_t* src, size_t nb) {
|
||||||
|
for (size_t i = 0; i < nb; i++) {
|
||||||
|
if (!writeBlock(block + i, src + i*512UL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
303
hardware/_controller/src/SdFat/SdCard/SdioCard.h
Normal file
303
hardware/_controller/src/SdFat/SdCard/SdioCard.h
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SdioCard_h
|
||||||
|
#define SdioCard_h
|
||||||
|
#include "../SysCall.h"
|
||||||
|
#include "../BlockDriver.h"
|
||||||
|
/**
|
||||||
|
* \class SdioCard
|
||||||
|
* \brief Raw SDIO access to SD and SDHC flash memory cards.
|
||||||
|
*/
|
||||||
|
class SdioCard : public BaseBlockDriver {
|
||||||
|
public:
|
||||||
|
/** Initialize the SD card.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool begin();
|
||||||
|
/**
|
||||||
|
* Determine the size of an SD flash memory card.
|
||||||
|
*
|
||||||
|
* \return The number of 512 byte sectors in the card
|
||||||
|
* or zero if an error occurs.
|
||||||
|
*/
|
||||||
|
uint32_t cardCapacity();
|
||||||
|
/** \return Card size in sectors or zero if an error occurs. */
|
||||||
|
uint32_t cardSize() {return cardCapacity();}
|
||||||
|
/** Erase a range of blocks.
|
||||||
|
*
|
||||||
|
* \param[in] firstBlock The address of the first block in the range.
|
||||||
|
* \param[in] lastBlock The address of the last block in the range.
|
||||||
|
*
|
||||||
|
* \note This function requests the SD card to do a flash erase for a
|
||||||
|
* range of blocks. The data on the card after an erase operation is
|
||||||
|
* either 0 or 1, depends on the card vendor. The card must support
|
||||||
|
* single block erase.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool erase(uint32_t firstBlock, uint32_t lastBlock);
|
||||||
|
/**
|
||||||
|
* \return code for the last error. See SdInfo.h for a list of error codes.
|
||||||
|
*/
|
||||||
|
uint8_t errorCode();
|
||||||
|
/** \return error data for last error. */
|
||||||
|
uint32_t errorData();
|
||||||
|
/** \return error line for last error. Tmp function for debug. */
|
||||||
|
uint32_t errorLine();
|
||||||
|
/**
|
||||||
|
* Check for busy with CMD13.
|
||||||
|
*
|
||||||
|
* \return true if busy else false.
|
||||||
|
*/
|
||||||
|
bool isBusy();
|
||||||
|
/** \return the SD clock frequency in kHz. */
|
||||||
|
uint32_t kHzSdClk();
|
||||||
|
/**
|
||||||
|
* Read a 512 byte block from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] lba Logical block to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readBlock(uint32_t lba, uint8_t* dst);
|
||||||
|
/**
|
||||||
|
* Read multiple 512 byte blocks from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] lba Logical block to be read.
|
||||||
|
* \param[in] nb Number of blocks to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readBlocks(uint32_t lba, uint8_t* dst, size_t nb);
|
||||||
|
/**
|
||||||
|
* Read a card's CID register. The CID contains card identification
|
||||||
|
* information such as Manufacturer ID, Product name, Product serial
|
||||||
|
* number and Manufacturing date.
|
||||||
|
*
|
||||||
|
* \param[out] cid pointer to area for returned data.
|
||||||
|
*
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool readCID(void* cid);
|
||||||
|
/**
|
||||||
|
* Read a card's CSD register. The CSD contains Card-Specific Data that
|
||||||
|
* provides information regarding access to the card's contents.
|
||||||
|
*
|
||||||
|
* \param[out] csd pointer to area for returned data.
|
||||||
|
*
|
||||||
|
* \return true for success or false for failure.
|
||||||
|
*/
|
||||||
|
bool readCSD(void* csd);
|
||||||
|
/** Read one data block in a multiple block read sequence
|
||||||
|
*
|
||||||
|
* \param[out] dst Pointer to the location for the data to be read.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readData(uint8_t *dst);
|
||||||
|
/** Read OCR register.
|
||||||
|
*
|
||||||
|
* \param[out] ocr Value of OCR register.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool readOCR(uint32_t* ocr);
|
||||||
|
/** Start a read multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \param[in] lba 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 true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readStart(uint32_t lba);
|
||||||
|
/** Start a read multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \param[in] lba Address of first block in sequence.
|
||||||
|
* \param[in] count Maximum block count.
|
||||||
|
* \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 true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readStart(uint32_t lba, uint32_t count);
|
||||||
|
/** End a read multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readStop();
|
||||||
|
/** \return success if sync successful. Not for user apps. */
|
||||||
|
bool syncBlocks();
|
||||||
|
/** Return the card type: SD V1, SD V2 or SDHC
|
||||||
|
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
|
||||||
|
*/
|
||||||
|
uint8_t type();
|
||||||
|
/**
|
||||||
|
* Writes a 512 byte block to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] lba Logical block to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeBlock(uint32_t lba, const uint8_t* src);
|
||||||
|
/**
|
||||||
|
* Write multiple 512 byte blocks to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] lba Logical block to be written.
|
||||||
|
* \param[in] nb Number of blocks to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeBlocks(uint32_t lba, const uint8_t* src, size_t nb);
|
||||||
|
/** 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 true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeData(const uint8_t* src);
|
||||||
|
/** Start a write multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \param[in] lba Address of first block in sequence.
|
||||||
|
*
|
||||||
|
* \note This function is used with writeData() and writeStop()
|
||||||
|
* for optimized multiple block writes.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeStart(uint32_t lba);
|
||||||
|
/** Start a write multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \param[in] lba Address of first block in sequence.
|
||||||
|
* \param[in] count Maximum block count.
|
||||||
|
* \note This function is used with writeData() and writeStop()
|
||||||
|
* for optimized multiple block writes.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeStart(uint32_t lba, uint32_t count);
|
||||||
|
|
||||||
|
/** End a write multiple blocks sequence.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeStop();
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class SdioCardEX
|
||||||
|
* \brief Extended SD I/O block driver.
|
||||||
|
*/
|
||||||
|
class SdioCardEX : public SdioCard {
|
||||||
|
public:
|
||||||
|
/** Initialize the SD card
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool begin() {
|
||||||
|
m_curState = IDLE_STATE;
|
||||||
|
return SdioCard::begin();
|
||||||
|
}
|
||||||
|
/** Erase a range of blocks.
|
||||||
|
*
|
||||||
|
* \param[in] firstBlock The address of the first block in the range.
|
||||||
|
* \param[in] lastBlock The address of the last block in the range.
|
||||||
|
*
|
||||||
|
* \note This function requests the SD card to do a flash erase for a
|
||||||
|
* range of blocks. The data on the card after an erase operation is
|
||||||
|
* either 0 or 1, depends on the card vendor. The card must support
|
||||||
|
* single block erase.
|
||||||
|
*
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool erase(uint32_t firstBlock, uint32_t lastBlock) {
|
||||||
|
return syncBlocks() && SdioCard::erase(firstBlock, lastBlock);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Read a 512 byte block from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readBlock(uint32_t block, uint8_t* dst);
|
||||||
|
/** End multi-block transfer and go to idle state.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool syncBlocks();
|
||||||
|
/**
|
||||||
|
* Writes a 512 byte block to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeBlock(uint32_t block, const uint8_t* src);
|
||||||
|
/**
|
||||||
|
* Read multiple 512 byte blocks from an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be read.
|
||||||
|
* \param[in] nb Number of blocks to be read.
|
||||||
|
* \param[out] dst Pointer to the location that will receive the data.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool readBlocks(uint32_t block, uint8_t* dst, size_t nb);
|
||||||
|
/**
|
||||||
|
* Write multiple 512 byte blocks to an SD card.
|
||||||
|
*
|
||||||
|
* \param[in] block Logical block to be written.
|
||||||
|
* \param[in] nb Number of blocks to be written.
|
||||||
|
* \param[in] src Pointer to the location of the data to be written.
|
||||||
|
* \return The value true is returned for success and
|
||||||
|
* the value false is returned for failure.
|
||||||
|
*/
|
||||||
|
bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const uint32_t IDLE_STATE = 0;
|
||||||
|
static const uint32_t READ_STATE = 1;
|
||||||
|
static const uint32_t WRITE_STATE = 2;
|
||||||
|
uint32_t m_curLba;
|
||||||
|
uint32_t m_limitLba;
|
||||||
|
uint8_t m_curState;
|
||||||
|
};
|
||||||
|
#endif // SdioCard_h
|
108
hardware/_controller/src/SdFat/SdCard/SdioCardEX.cpp
Normal file
108
hardware/_controller/src/SdFat/SdCard/SdioCardEX.cpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "SdioCard.h"
|
||||||
|
|
||||||
|
// limit of K66 due to errata KINETIS_K_0N65N.
|
||||||
|
const uint32_t MAX_SDHC_COUNT = 0XFFFF;
|
||||||
|
|
||||||
|
// Max RU is 1024 blocks.
|
||||||
|
const uint32_t RU_MASK = 0X03FF;
|
||||||
|
|
||||||
|
bool SdioCardEX::readBlock(uint32_t lba, uint8_t* dst) {
|
||||||
|
if (m_curState != READ_STATE || lba != m_curLba) {
|
||||||
|
if (!syncBlocks()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_limitLba = (lba + MAX_SDHC_COUNT) & ~RU_MASK;
|
||||||
|
if (!SdioCard::readStart(lba, m_limitLba - lba)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_curLba = lba;
|
||||||
|
m_curState = READ_STATE;
|
||||||
|
}
|
||||||
|
if (!SdioCard::readData(dst)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_curLba++;
|
||||||
|
if (m_curLba >= m_limitLba) {
|
||||||
|
m_curState = IDLE_STATE;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCardEX::readBlocks(uint32_t lba, uint8_t* dst, size_t nb) {
|
||||||
|
for (size_t i = 0; i < nb; i++) {
|
||||||
|
if (!readBlock(lba + i, dst + i*512UL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCardEX::syncBlocks() {
|
||||||
|
if (m_curState == READ_STATE) {
|
||||||
|
m_curState = IDLE_STATE;
|
||||||
|
if (!SdioCard::readStop()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (m_curState == WRITE_STATE) {
|
||||||
|
m_curState = IDLE_STATE;
|
||||||
|
if (!SdioCard::writeStop()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCardEX::writeBlock(uint32_t lba, const uint8_t* src) {
|
||||||
|
if (m_curState != WRITE_STATE || m_curLba != lba) {
|
||||||
|
if (!syncBlocks()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_limitLba = (lba + MAX_SDHC_COUNT) & ~RU_MASK;
|
||||||
|
if (!SdioCard::writeStart(lba , m_limitLba - lba)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_curLba = lba;
|
||||||
|
m_curState = WRITE_STATE;
|
||||||
|
}
|
||||||
|
if (!SdioCard::writeData(src)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_curLba++;
|
||||||
|
if (m_curLba >= m_limitLba) {
|
||||||
|
m_curState = IDLE_STATE;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCardEX::writeBlocks(uint32_t lba, const uint8_t* src, size_t nb) {
|
||||||
|
for (size_t i = 0; i < nb; i++) {
|
||||||
|
if (!writeBlock(lba + i, src + i*512UL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
800
hardware/_controller/src/SdFat/SdCard/SdioTeensy.cpp
Normal file
800
hardware/_controller/src/SdFat/SdCard/SdioTeensy.cpp
Normal file
|
@ -0,0 +1,800 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||||
|
#include "SdioCard.h"
|
||||||
|
//==============================================================================
|
||||||
|
#define SDHC_PROCTL_DTW_4BIT 0x01
|
||||||
|
const uint32_t FIFO_WML = 16;
|
||||||
|
const uint32_t CMD8_RETRIES = 10;
|
||||||
|
const uint32_t BUSY_TIMEOUT_MICROS = 500000;
|
||||||
|
//==============================================================================
|
||||||
|
const uint32_t SDHC_IRQSTATEN_MASK =
|
||||||
|
SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_AC12ESEN |
|
||||||
|
SDHC_IRQSTATEN_DEBESEN | SDHC_IRQSTATEN_DCESEN |
|
||||||
|
SDHC_IRQSTATEN_DTOESEN | SDHC_IRQSTATEN_CIESEN |
|
||||||
|
SDHC_IRQSTATEN_CEBESEN | SDHC_IRQSTATEN_CCESEN |
|
||||||
|
SDHC_IRQSTATEN_CTOESEN | SDHC_IRQSTATEN_DINTSEN |
|
||||||
|
SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN;
|
||||||
|
|
||||||
|
const uint32_t SDHC_IRQSTAT_CMD_ERROR =
|
||||||
|
SDHC_IRQSTAT_CIE | SDHC_IRQSTAT_CEBE |
|
||||||
|
SDHC_IRQSTAT_CCE | SDHC_IRQSTAT_CTOE;
|
||||||
|
|
||||||
|
const uint32_t SDHC_IRQSTAT_DATA_ERROR =
|
||||||
|
SDHC_IRQSTAT_AC12E | SDHC_IRQSTAT_DEBE |
|
||||||
|
SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE;
|
||||||
|
|
||||||
|
const uint32_t SDHC_IRQSTAT_ERROR =
|
||||||
|
SDHC_IRQSTAT_DMAE | SDHC_IRQSTAT_CMD_ERROR |
|
||||||
|
SDHC_IRQSTAT_DATA_ERROR;
|
||||||
|
|
||||||
|
const uint32_t SDHC_IRQSIGEN_MASK =
|
||||||
|
SDHC_IRQSIGEN_DMAEIEN | SDHC_IRQSIGEN_AC12EIEN |
|
||||||
|
SDHC_IRQSIGEN_DEBEIEN | SDHC_IRQSIGEN_DCEIEN |
|
||||||
|
SDHC_IRQSIGEN_DTOEIEN | SDHC_IRQSIGEN_CIEIEN |
|
||||||
|
SDHC_IRQSIGEN_CEBEIEN | SDHC_IRQSIGEN_CCEIEN |
|
||||||
|
SDHC_IRQSIGEN_CTOEIEN | SDHC_IRQSIGEN_TCIEN;
|
||||||
|
//=============================================================================
|
||||||
|
const uint32_t CMD_RESP_NONE = SDHC_XFERTYP_RSPTYP(0);
|
||||||
|
|
||||||
|
const uint32_t CMD_RESP_R1 = SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN |
|
||||||
|
SDHC_XFERTYP_RSPTYP(2);
|
||||||
|
|
||||||
|
const uint32_t CMD_RESP_R1b = SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN |
|
||||||
|
SDHC_XFERTYP_RSPTYP(3);
|
||||||
|
|
||||||
|
const uint32_t CMD_RESP_R2 = SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(1);
|
||||||
|
|
||||||
|
const uint32_t CMD_RESP_R3 = SDHC_XFERTYP_RSPTYP(2);
|
||||||
|
|
||||||
|
const uint32_t CMD_RESP_R6 = CMD_RESP_R1;
|
||||||
|
|
||||||
|
const uint32_t CMD_RESP_R7 = CMD_RESP_R1;
|
||||||
|
|
||||||
|
const uint32_t DATA_READ = SDHC_XFERTYP_DTDSEL | SDHC_XFERTYP_DPSEL;
|
||||||
|
|
||||||
|
const uint32_t DATA_READ_DMA = DATA_READ | SDHC_XFERTYP_DMAEN;
|
||||||
|
|
||||||
|
const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_XFERTYP_MSBSEL |
|
||||||
|
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN;
|
||||||
|
|
||||||
|
const uint32_t DATA_READ_MULTI_PGM = DATA_READ | SDHC_XFERTYP_MSBSEL |
|
||||||
|
SDHC_XFERTYP_BCEN | SDHC_XFERTYP_AC12EN;
|
||||||
|
|
||||||
|
const uint32_t DATA_WRITE_DMA = SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN;
|
||||||
|
|
||||||
|
const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_XFERTYP_MSBSEL |
|
||||||
|
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN;
|
||||||
|
|
||||||
|
const uint32_t DATA_WRITE_MULTI_PGM = SDHC_XFERTYP_DPSEL |
|
||||||
|
SDHC_XFERTYP_MSBSEL |
|
||||||
|
SDHC_XFERTYP_BCEN | SDHC_XFERTYP_AC12EN;
|
||||||
|
|
||||||
|
const uint32_t ACMD6_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD6) | CMD_RESP_R1;
|
||||||
|
|
||||||
|
const uint32_t ACMD41_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD41) | CMD_RESP_R3;
|
||||||
|
|
||||||
|
const uint32_t CMD0_XFERTYP = SDHC_XFERTYP_CMDINX(CMD0) | CMD_RESP_NONE;
|
||||||
|
|
||||||
|
const uint32_t CMD2_XFERTYP = SDHC_XFERTYP_CMDINX(CMD2) | CMD_RESP_R2;
|
||||||
|
|
||||||
|
const uint32_t CMD3_XFERTYP = SDHC_XFERTYP_CMDINX(CMD3) | CMD_RESP_R6;
|
||||||
|
|
||||||
|
const uint32_t CMD6_XFERTYP = SDHC_XFERTYP_CMDINX(CMD6) | CMD_RESP_R1 |
|
||||||
|
DATA_READ_DMA;
|
||||||
|
|
||||||
|
const uint32_t CMD7_XFERTYP = SDHC_XFERTYP_CMDINX(CMD7) | CMD_RESP_R1b;
|
||||||
|
|
||||||
|
const uint32_t CMD8_XFERTYP = SDHC_XFERTYP_CMDINX(CMD8) | CMD_RESP_R7;
|
||||||
|
|
||||||
|
const uint32_t CMD9_XFERTYP = SDHC_XFERTYP_CMDINX(CMD9) | CMD_RESP_R2;
|
||||||
|
|
||||||
|
const uint32_t CMD10_XFERTYP = SDHC_XFERTYP_CMDINX(CMD10) | CMD_RESP_R2;
|
||||||
|
|
||||||
|
const uint32_t CMD12_XFERTYP = SDHC_XFERTYP_CMDINX(CMD12) | CMD_RESP_R1b |
|
||||||
|
SDHC_XFERTYP_CMDTYP(3);
|
||||||
|
|
||||||
|
const uint32_t CMD13_XFERTYP = SDHC_XFERTYP_CMDINX(CMD13) | CMD_RESP_R1;
|
||||||
|
|
||||||
|
const uint32_t CMD17_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD17) | CMD_RESP_R1 |
|
||||||
|
DATA_READ_DMA;
|
||||||
|
|
||||||
|
const uint32_t CMD18_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
|
||||||
|
DATA_READ_MULTI_DMA;
|
||||||
|
|
||||||
|
const uint32_t CMD18_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
|
||||||
|
DATA_READ_MULTI_PGM;
|
||||||
|
|
||||||
|
const uint32_t CMD24_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD24) | CMD_RESP_R1 |
|
||||||
|
DATA_WRITE_DMA;
|
||||||
|
|
||||||
|
const uint32_t CMD25_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
|
||||||
|
DATA_WRITE_MULTI_DMA;
|
||||||
|
|
||||||
|
const uint32_t CMD25_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
|
||||||
|
DATA_WRITE_MULTI_PGM;
|
||||||
|
|
||||||
|
const uint32_t CMD32_XFERTYP = SDHC_XFERTYP_CMDINX(CMD32) | CMD_RESP_R1;
|
||||||
|
|
||||||
|
const uint32_t CMD33_XFERTYP = SDHC_XFERTYP_CMDINX(CMD33) | CMD_RESP_R1;
|
||||||
|
|
||||||
|
const uint32_t CMD38_XFERTYP = SDHC_XFERTYP_CMDINX(CMD38) | CMD_RESP_R1b;
|
||||||
|
|
||||||
|
const uint32_t CMD55_XFERTYP = SDHC_XFERTYP_CMDINX(CMD55) | CMD_RESP_R1;
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
static bool cardCommand(uint32_t xfertyp, uint32_t arg);
|
||||||
|
static void enableGPIO(bool enable);
|
||||||
|
static void enableDmaIrs();
|
||||||
|
static void initSDHC();
|
||||||
|
static bool isBusyCMD13();
|
||||||
|
static bool isBusyCommandComplete();
|
||||||
|
static bool isBusyCommandInhibit();
|
||||||
|
static bool readReg16(uint32_t xfertyp, void* data);
|
||||||
|
static void setSdclk(uint32_t kHzMax);
|
||||||
|
static bool yieldTimeout(bool (*fcn)());
|
||||||
|
static bool waitDmaStatus();
|
||||||
|
static bool waitTimeout(bool (*fcn)());
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool (*m_busyFcn)() = 0;
|
||||||
|
static bool m_initDone = false;
|
||||||
|
static bool m_version2;
|
||||||
|
static bool m_highCapacity;
|
||||||
|
static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
|
||||||
|
static uint32_t m_errorLine = 0;
|
||||||
|
static uint32_t m_rca;
|
||||||
|
static volatile bool m_dmaBusy = false;
|
||||||
|
static volatile uint32_t m_irqstat;
|
||||||
|
static uint32_t m_sdClkKhz = 0;
|
||||||
|
static uint32_t m_ocr;
|
||||||
|
static cid_t m_cid;
|
||||||
|
static csd_t m_csd;
|
||||||
|
//=============================================================================
|
||||||
|
#define USE_DEBUG_MODE 0
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
#define DBG_IRQSTAT() if (SDHC_IRQSTAT) {Serial.print(__LINE__);\
|
||||||
|
Serial.print(" IRQSTAT "); Serial.println(SDHC_IRQSTAT, HEX);}
|
||||||
|
|
||||||
|
static void printRegs(uint32_t line) {
|
||||||
|
Serial.print(line);
|
||||||
|
Serial.print(" PRSSTAT ");
|
||||||
|
Serial.print(SDHC_PRSSTAT, HEX);
|
||||||
|
Serial.print(" PROCTL ");
|
||||||
|
Serial.print(SDHC_PROCTL, HEX);
|
||||||
|
Serial.print(" IRQSTAT ");
|
||||||
|
Serial.print(SDHC_IRQSTAT, HEX);
|
||||||
|
Serial.print(" m_irqstat ");
|
||||||
|
Serial.println(m_irqstat, HEX);
|
||||||
|
}
|
||||||
|
#else // USE_DEBUG_MODE
|
||||||
|
#define DBG_IRQSTAT()
|
||||||
|
#endif // USE_DEBUG_MODE
|
||||||
|
//=============================================================================
|
||||||
|
// Error function and macro.
|
||||||
|
#define sdError(code) setSdErrorCode(code, __LINE__)
|
||||||
|
inline bool setSdErrorCode(uint8_t code, uint32_t line) {
|
||||||
|
m_errorCode = code;
|
||||||
|
m_errorLine = line;
|
||||||
|
return false; // setSdErrorCode
|
||||||
|
}
|
||||||
|
//=============================================================================
|
||||||
|
// ISR
|
||||||
|
void sdhc_isr() {
|
||||||
|
SDHC_IRQSIGEN = 0;
|
||||||
|
m_irqstat = SDHC_IRQSTAT;
|
||||||
|
SDHC_IRQSTAT = m_irqstat;
|
||||||
|
m_dmaBusy = false;
|
||||||
|
}
|
||||||
|
//=============================================================================
|
||||||
|
// Static functions.
|
||||||
|
static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) {
|
||||||
|
return cardCommand(CMD55_XFERTYP, rca) && cardCommand (xfertyp, arg);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool cardCommand(uint32_t xfertyp, uint32_t arg) {
|
||||||
|
DBG_IRQSTAT();
|
||||||
|
if (waitTimeout(isBusyCommandInhibit)) {
|
||||||
|
return false; // Caller will set errorCode.
|
||||||
|
}
|
||||||
|
SDHC_CMDARG = arg;
|
||||||
|
SDHC_XFERTYP = xfertyp;
|
||||||
|
if (waitTimeout(isBusyCommandComplete)) {
|
||||||
|
return false; // Caller will set errorCode.
|
||||||
|
}
|
||||||
|
m_irqstat = SDHC_IRQSTAT;
|
||||||
|
SDHC_IRQSTAT = m_irqstat;
|
||||||
|
|
||||||
|
return (m_irqstat & SDHC_IRQSTAT_CC) &&
|
||||||
|
!(m_irqstat & SDHC_IRQSTAT_CMD_ERROR);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool cardCMD6(uint32_t arg, uint8_t* status) {
|
||||||
|
// CMD6 returns 64 bytes.
|
||||||
|
if (waitTimeout(isBusyCMD13)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD13);
|
||||||
|
}
|
||||||
|
enableDmaIrs();
|
||||||
|
SDHC_DSADDR = (uint32_t)status;
|
||||||
|
SDHC_CMDARG = arg;
|
||||||
|
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);
|
||||||
|
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
|
||||||
|
SDHC_XFERTYP = CMD6_XFERTYP;
|
||||||
|
|
||||||
|
if (!waitDmaStatus()) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD6);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static void enableGPIO(bool enable) {
|
||||||
|
const uint32_t PORT_CLK = PORT_PCR_MUX(4) | PORT_PCR_DSE;
|
||||||
|
const uint32_t PORT_CMD_DATA = PORT_CLK | PORT_PCR_PS | PORT_PCR_PE;
|
||||||
|
|
||||||
|
PORTE_PCR0 = enable ? PORT_CMD_DATA : 0; // SDHC_D1
|
||||||
|
PORTE_PCR1 = enable ? PORT_CMD_DATA : 0; // SDHC_D0
|
||||||
|
PORTE_PCR2 = enable ? PORT_CLK : 0; // SDHC_CLK
|
||||||
|
PORTE_PCR3 = enable ? PORT_CMD_DATA : 0; // SDHC_CMD
|
||||||
|
PORTE_PCR4 = enable ? PORT_CMD_DATA : 0; // SDHC_D3
|
||||||
|
PORTE_PCR5 = enable ? PORT_CMD_DATA : 0; // SDHC_D2
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static void enableDmaIrs() {
|
||||||
|
m_dmaBusy = true;
|
||||||
|
m_irqstat = 0;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static void initSDHC() {
|
||||||
|
#ifdef HAS_KINETIS_MPU
|
||||||
|
// Allow SDHC Bus Master access.
|
||||||
|
MPU_RGDAAC0 |= 0x0C000000;
|
||||||
|
#endif
|
||||||
|
// Enable SDHC clock.
|
||||||
|
SIM_SCGC3 |= SIM_SCGC3_SDHC;
|
||||||
|
|
||||||
|
// Disable GPIO clock.
|
||||||
|
enableGPIO(false);
|
||||||
|
|
||||||
|
// Reset SDHC. Use default Water Mark Level of 16.
|
||||||
|
SDHC_SYSCTL = SDHC_SYSCTL_RSTA;
|
||||||
|
while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) {
|
||||||
|
}
|
||||||
|
// Set initial SCK rate.
|
||||||
|
setSdclk(400);
|
||||||
|
|
||||||
|
enableGPIO(true);
|
||||||
|
|
||||||
|
// Enable desired IRQSTAT bits.
|
||||||
|
SDHC_IRQSTATEN = SDHC_IRQSTATEN_MASK;
|
||||||
|
|
||||||
|
NVIC_SET_PRIORITY(IRQ_SDHC, 6*16);
|
||||||
|
NVIC_ENABLE_IRQ(IRQ_SDHC);
|
||||||
|
|
||||||
|
// Send 80 clocks to card.
|
||||||
|
SDHC_SYSCTL |= SDHC_SYSCTL_INITA;
|
||||||
|
while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool isBusyCMD13() {
|
||||||
|
if (!cardCommand(CMD13_XFERTYP, m_rca)) {
|
||||||
|
// Caller will timeout.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool isBusyCommandComplete() {
|
||||||
|
return !(SDHC_IRQSTAT &(SDHC_IRQSTAT_CC | SDHC_IRQSTAT_CMD_ERROR));
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool isBusyCommandInhibit() {
|
||||||
|
return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool isBusyDMA() {
|
||||||
|
return m_dmaBusy;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool isBusyFifoRead() {
|
||||||
|
return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool isBusyFifoWrite() {
|
||||||
|
return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool isBusyTransferComplete() {
|
||||||
|
return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_ERROR));
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool rdWrBlocks(uint32_t xfertyp,
|
||||||
|
uint32_t lba, uint8_t* buf, size_t n) {
|
||||||
|
if ((3 & (uint32_t)buf) || n == 0) {
|
||||||
|
return sdError(SD_CARD_ERROR_DMA);
|
||||||
|
}
|
||||||
|
if (yieldTimeout(isBusyCMD13)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD13);
|
||||||
|
}
|
||||||
|
enableDmaIrs();
|
||||||
|
SDHC_DSADDR = (uint32_t)buf;
|
||||||
|
SDHC_CMDARG = m_highCapacity ? lba : 512*lba;
|
||||||
|
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(n) | SDHC_BLKATTR_BLKSIZE(512);
|
||||||
|
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
|
||||||
|
SDHC_XFERTYP = xfertyp;
|
||||||
|
|
||||||
|
return waitDmaStatus();
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Read 16 byte CID or CSD register.
|
||||||
|
static bool readReg16(uint32_t xfertyp, void* data) {
|
||||||
|
uint8_t* d = reinterpret_cast<uint8_t*>(data);
|
||||||
|
if (!cardCommand(xfertyp, m_rca)) {
|
||||||
|
return false; // Caller will set errorCode.
|
||||||
|
}
|
||||||
|
uint32_t sr[] = {SDHC_CMDRSP0, SDHC_CMDRSP1, SDHC_CMDRSP2, SDHC_CMDRSP3};
|
||||||
|
for (int i = 0; i < 15; i++) {
|
||||||
|
d[14 - i] = sr[i/4] >> 8*(i%4);
|
||||||
|
}
|
||||||
|
d[15] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static void setSdclk(uint32_t kHzMax) {
|
||||||
|
const uint32_t DVS_LIMIT = 0X10;
|
||||||
|
const uint32_t SDCLKFS_LIMIT = 0X100;
|
||||||
|
uint32_t dvs = 1;
|
||||||
|
uint32_t sdclkfs = 1;
|
||||||
|
uint32_t maxSdclk = 1000*kHzMax;
|
||||||
|
|
||||||
|
while ((F_CPU/(sdclkfs*DVS_LIMIT) > maxSdclk) && (sdclkfs < SDCLKFS_LIMIT)) {
|
||||||
|
sdclkfs <<= 1;
|
||||||
|
}
|
||||||
|
while ((F_CPU/(sdclkfs*dvs) > maxSdclk) && (dvs < DVS_LIMIT)) {
|
||||||
|
dvs++;
|
||||||
|
}
|
||||||
|
m_sdClkKhz = F_CPU/(1000*sdclkfs*dvs);
|
||||||
|
sdclkfs >>= 1;
|
||||||
|
dvs--;
|
||||||
|
|
||||||
|
// Disable SDHC clock.
|
||||||
|
SDHC_SYSCTL &= ~SDHC_SYSCTL_SDCLKEN;
|
||||||
|
|
||||||
|
// Change dividers.
|
||||||
|
uint32_t sysctl = SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK
|
||||||
|
| SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK);
|
||||||
|
|
||||||
|
SDHC_SYSCTL = sysctl | SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_DVS(dvs)
|
||||||
|
| SDHC_SYSCTL_SDCLKFS(sdclkfs);
|
||||||
|
|
||||||
|
// Wait until the SDHC clock is stable.
|
||||||
|
while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_SDSTB)) {
|
||||||
|
}
|
||||||
|
// Enable the SDHC clock.
|
||||||
|
SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool transferStop() {
|
||||||
|
DBG_IRQSTAT();
|
||||||
|
|
||||||
|
if (!cardCommand(CMD12_XFERTYP, 0)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD12);
|
||||||
|
}
|
||||||
|
if (yieldTimeout(isBusyCMD13)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD13);
|
||||||
|
}
|
||||||
|
// Save registers before reset DAT lines.
|
||||||
|
uint32_t irqsststen = SDHC_IRQSTATEN;
|
||||||
|
uint32_t proctl = SDHC_PROCTL & ~SDHC_PROCTL_SABGREQ;
|
||||||
|
|
||||||
|
// Do reset to clear CDIHB. Should be a better way!
|
||||||
|
SDHC_SYSCTL |= SDHC_SYSCTL_RSTD;
|
||||||
|
|
||||||
|
// Restore registers.
|
||||||
|
SDHC_IRQSTATEN = irqsststen;
|
||||||
|
SDHC_PROCTL = proctl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Return true if timeout occurs.
|
||||||
|
static bool yieldTimeout(bool (*fcn)()) {
|
||||||
|
m_busyFcn = fcn;
|
||||||
|
uint32_t m = micros();
|
||||||
|
while (fcn()) {
|
||||||
|
if ((micros() - m) > BUSY_TIMEOUT_MICROS) {
|
||||||
|
m_busyFcn = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
m_busyFcn = 0;
|
||||||
|
return false; // Caller will set errorCode.
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static bool waitDmaStatus() {
|
||||||
|
if (yieldTimeout(isBusyDMA)) {
|
||||||
|
return false; // Caller will set errorCode.
|
||||||
|
}
|
||||||
|
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Return true if timeout occurs.
|
||||||
|
static bool waitTimeout(bool (*fcn)()) {
|
||||||
|
uint32_t m = micros();
|
||||||
|
while (fcn()) {
|
||||||
|
if ((micros() - m) > BUSY_TIMEOUT_MICROS) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false; // Caller will set errorCode.
|
||||||
|
}
|
||||||
|
//=============================================================================
|
||||||
|
bool SdioCard::begin() {
|
||||||
|
uint32_t kHzSdClk;
|
||||||
|
uint32_t arg;
|
||||||
|
m_initDone = false;
|
||||||
|
m_errorCode = SD_CARD_ERROR_NONE;
|
||||||
|
m_highCapacity = false;
|
||||||
|
m_version2 = false;
|
||||||
|
|
||||||
|
// initialize controller.
|
||||||
|
initSDHC();
|
||||||
|
|
||||||
|
if (!cardCommand(CMD0_XFERTYP, 0)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD0);
|
||||||
|
}
|
||||||
|
// Try several times for case of reset delay.
|
||||||
|
for (uint32_t i = 0; i < CMD8_RETRIES; i++) {
|
||||||
|
if (cardCommand(CMD8_XFERTYP, 0X1AA)) {
|
||||||
|
if (SDHC_CMDRSP0 != 0X1AA) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD8);
|
||||||
|
}
|
||||||
|
m_version2 = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arg = m_version2 ? 0X40300000 : 0x00300000;
|
||||||
|
uint32_t m = micros();
|
||||||
|
do {
|
||||||
|
if (!cardAcmd(0, ACMD41_XFERTYP, arg) ||
|
||||||
|
((micros() - m) > BUSY_TIMEOUT_MICROS)) {
|
||||||
|
return sdError(SD_CARD_ERROR_ACMD41);
|
||||||
|
}
|
||||||
|
} while ((SDHC_CMDRSP0 & 0x80000000) == 0);
|
||||||
|
|
||||||
|
m_ocr = SDHC_CMDRSP0;
|
||||||
|
if (SDHC_CMDRSP0 & 0x40000000) {
|
||||||
|
// Is high capacity.
|
||||||
|
m_highCapacity = true;
|
||||||
|
}
|
||||||
|
if (!cardCommand(CMD2_XFERTYP, 0)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD2);
|
||||||
|
}
|
||||||
|
if (!cardCommand(CMD3_XFERTYP, 0)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD3);
|
||||||
|
}
|
||||||
|
m_rca = SDHC_CMDRSP0 & 0xFFFF0000;
|
||||||
|
|
||||||
|
if (!readReg16(CMD9_XFERTYP, &m_csd)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD9);
|
||||||
|
}
|
||||||
|
if (!readReg16(CMD10_XFERTYP, &m_cid)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD10);
|
||||||
|
}
|
||||||
|
if (!cardCommand(CMD7_XFERTYP, m_rca)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD7);
|
||||||
|
}
|
||||||
|
// Set card to bus width four.
|
||||||
|
if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) {
|
||||||
|
return sdError(SD_CARD_ERROR_ACMD6);
|
||||||
|
}
|
||||||
|
// Set SDHC to bus width four.
|
||||||
|
SDHC_PROCTL &= ~SDHC_PROCTL_DTW_MASK;
|
||||||
|
SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT);
|
||||||
|
|
||||||
|
SDHC_WML = SDHC_WML_RDWML(FIFO_WML) | SDHC_WML_WRWML(FIFO_WML);
|
||||||
|
|
||||||
|
// Determine if High Speed mode is supported and set frequency.
|
||||||
|
uint8_t status[64];
|
||||||
|
if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
|
||||||
|
cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) {
|
||||||
|
kHzSdClk = 50000;
|
||||||
|
} else {
|
||||||
|
kHzSdClk = 25000;
|
||||||
|
}
|
||||||
|
// disable GPIO
|
||||||
|
enableGPIO(false);
|
||||||
|
|
||||||
|
// Set the SDHC SCK frequency.
|
||||||
|
setSdclk(kHzSdClk);
|
||||||
|
|
||||||
|
// enable GPIO
|
||||||
|
enableGPIO(true);
|
||||||
|
m_initDone = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
uint32_t SdioCard::cardCapacity() {
|
||||||
|
return sdCardCapacity(&m_csd);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
|
||||||
|
// check for single block erase
|
||||||
|
if (!m_csd.v1.erase_blk_en) {
|
||||||
|
// erase size mask
|
||||||
|
uint8_t m = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
|
||||||
|
if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
|
||||||
|
// error card can't erase specified area
|
||||||
|
return sdError(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!m_highCapacity) {
|
||||||
|
firstBlock <<= 9;
|
||||||
|
lastBlock <<= 9;
|
||||||
|
}
|
||||||
|
if (!cardCommand(CMD32_XFERTYP, firstBlock)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD32);
|
||||||
|
}
|
||||||
|
if (!cardCommand(CMD33_XFERTYP, lastBlock)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD33);
|
||||||
|
}
|
||||||
|
if (!cardCommand(CMD38_XFERTYP, 0)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD38);
|
||||||
|
}
|
||||||
|
if (waitTimeout(isBusyCMD13)) {
|
||||||
|
return sdError(SD_CARD_ERROR_ERASE_TIMEOUT);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
uint8_t SdioCard::errorCode() {
|
||||||
|
return m_errorCode;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
uint32_t SdioCard::errorData() {
|
||||||
|
return m_irqstat;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
uint32_t SdioCard::errorLine() {
|
||||||
|
return m_errorLine;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::isBusy() {
|
||||||
|
return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13();
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
uint32_t SdioCard::kHzSdClk() {
|
||||||
|
return m_sdClkKhz;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) {
|
||||||
|
uint8_t aligned[512];
|
||||||
|
|
||||||
|
uint8_t* ptr = (uint32_t)buf & 3 ? aligned : buf;
|
||||||
|
|
||||||
|
if (!rdWrBlocks(CMD17_DMA_XFERTYP, lba, ptr, 1)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD18);
|
||||||
|
}
|
||||||
|
if (ptr != buf) {
|
||||||
|
memcpy(buf, aligned, 512);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) {
|
||||||
|
if ((uint32_t)buf & 3) {
|
||||||
|
for (size_t i = 0; i < n; i++, lba++, buf += 512) {
|
||||||
|
if (!readBlock(lba, buf)) {
|
||||||
|
return false; // readBlock will set errorCode.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!rdWrBlocks(CMD18_DMA_XFERTYP, lba, buf, n)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD18);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::readCID(void* cid) {
|
||||||
|
memcpy(cid, &m_cid, 16);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::readCSD(void* csd) {
|
||||||
|
memcpy(csd, &m_csd, 16);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::readData(uint8_t *dst) {
|
||||||
|
DBG_IRQSTAT();
|
||||||
|
uint32_t *p32 = reinterpret_cast<uint32_t*>(dst);
|
||||||
|
|
||||||
|
if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_RTA)) {
|
||||||
|
SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
|
||||||
|
if ((SDHC_BLKATTR & 0XFFFF0000) == 0X10000) {
|
||||||
|
// Don't stop at block gap if last block. Allows auto CMD12.
|
||||||
|
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
|
||||||
|
} else {
|
||||||
|
noInterrupts();
|
||||||
|
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
|
||||||
|
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (waitTimeout(isBusyFifoRead)) {
|
||||||
|
return sdError(SD_CARD_ERROR_READ_FIFO);
|
||||||
|
}
|
||||||
|
for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) {
|
||||||
|
while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) {
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < FIFO_WML; i++) {
|
||||||
|
p32[i] = SDHC_DATPORT;
|
||||||
|
}
|
||||||
|
p32 += FIFO_WML;
|
||||||
|
}
|
||||||
|
if (waitTimeout(isBusyTransferComplete)) {
|
||||||
|
return sdError(SD_CARD_ERROR_READ_TIMEOUT);
|
||||||
|
}
|
||||||
|
m_irqstat = SDHC_IRQSTAT;
|
||||||
|
SDHC_IRQSTAT = m_irqstat;
|
||||||
|
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::readOCR(uint32_t* ocr) {
|
||||||
|
*ocr = m_ocr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::readStart(uint32_t lba) {
|
||||||
|
// K66/K65 Errata - SDHC: Does not support Infinite Block Transfer Mode.
|
||||||
|
return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// SDHC will do Auto CMD12 after count blocks.
|
||||||
|
bool SdioCard::readStart(uint32_t lba, uint32_t count) {
|
||||||
|
DBG_IRQSTAT();
|
||||||
|
if (count > 0XFFFF) {
|
||||||
|
return sdError(SD_CARD_ERROR_READ_START);
|
||||||
|
}
|
||||||
|
if (yieldTimeout(isBusyCMD13)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD13);
|
||||||
|
}
|
||||||
|
if (count > 1) {
|
||||||
|
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
|
||||||
|
}
|
||||||
|
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512);
|
||||||
|
if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? lba : 512*lba)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD18);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::readStop() {
|
||||||
|
return transferStop();
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::syncBlocks() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
uint8_t SdioCard::type() {
|
||||||
|
return m_version2 ? m_highCapacity ?
|
||||||
|
SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2 : SD_CARD_TYPE_SD1;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) {
|
||||||
|
uint8_t *ptr;
|
||||||
|
uint8_t aligned[512];
|
||||||
|
if (3 & (uint32_t)buf) {
|
||||||
|
ptr = aligned;
|
||||||
|
memcpy(aligned, buf, 512);
|
||||||
|
} else {
|
||||||
|
ptr = const_cast<uint8_t*>(buf);
|
||||||
|
}
|
||||||
|
if (!rdWrBlocks(CMD24_DMA_XFERTYP, lba, ptr, 1)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD24);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) {
|
||||||
|
uint8_t* ptr = const_cast<uint8_t*>(buf);
|
||||||
|
if (3 & (uint32_t)ptr) {
|
||||||
|
for (size_t i = 0; i < n; i++, lba++, ptr += 512) {
|
||||||
|
if (!writeBlock(lba, ptr)) {
|
||||||
|
return false; // writeBlock will set errorCode.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!rdWrBlocks(CMD25_DMA_XFERTYP, lba, ptr, n)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD25);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::writeData(const uint8_t* src) {
|
||||||
|
DBG_IRQSTAT();
|
||||||
|
const uint32_t* p32 = reinterpret_cast<const uint32_t*>(src);
|
||||||
|
|
||||||
|
if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_WTA)) {
|
||||||
|
SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
|
||||||
|
// Don't stop at block gap if last block. Allows auto CMD12.
|
||||||
|
if ((SDHC_BLKATTR & 0XFFFF0000) == 0X10000) {
|
||||||
|
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
|
||||||
|
} else {
|
||||||
|
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
|
||||||
|
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (waitTimeout(isBusyFifoWrite)) {
|
||||||
|
return sdError(SD_CARD_ERROR_WRITE_FIFO);
|
||||||
|
}
|
||||||
|
for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) {
|
||||||
|
while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN)) {
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < FIFO_WML; i++) {
|
||||||
|
SDHC_DATPORT = p32[i];
|
||||||
|
}
|
||||||
|
p32 += FIFO_WML;
|
||||||
|
}
|
||||||
|
if (waitTimeout(isBusyTransferComplete)) {
|
||||||
|
return sdError(SD_CARD_ERROR_WRITE_TIMEOUT);
|
||||||
|
}
|
||||||
|
m_irqstat = SDHC_IRQSTAT;
|
||||||
|
SDHC_IRQSTAT = m_irqstat;
|
||||||
|
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::writeStart(uint32_t lba) {
|
||||||
|
// K66/K65 Errata - SDHC: Does not support Infinite Block Transfer Mode.
|
||||||
|
return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// SDHC will do Auto CMD12 after count blocks.
|
||||||
|
bool SdioCard::writeStart(uint32_t lba, uint32_t count) {
|
||||||
|
if (count > 0XFFFF) {
|
||||||
|
return sdError(SD_CARD_ERROR_WRITE_START);
|
||||||
|
}
|
||||||
|
DBG_IRQSTAT();
|
||||||
|
if (yieldTimeout(isBusyCMD13)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD13);
|
||||||
|
}
|
||||||
|
if (count > 1) {
|
||||||
|
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
|
||||||
|
}
|
||||||
|
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512);
|
||||||
|
|
||||||
|
if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? lba : 512*lba)) {
|
||||||
|
return sdError(SD_CARD_ERROR_CMD25);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
bool SdioCard::writeStop() {
|
||||||
|
return transferStop();
|
||||||
|
}
|
||||||
|
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
512
hardware/_controller/src/SdFat/SdFat.h
Normal file
512
hardware/_controller/src/SdFat/SdFat.h
Normal file
|
@ -0,0 +1,512 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SdFat_h
|
||||||
|
#define SdFat_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief SdFat class
|
||||||
|
*/
|
||||||
|
#include "SysCall.h"
|
||||||
|
#include "BlockDriver.h"
|
||||||
|
#include "FatLib/FatLib.h"
|
||||||
|
#include "SdCard/SdioCard.h"
|
||||||
|
#if INCLUDE_SDIOS
|
||||||
|
#include "sdios.h"
|
||||||
|
#endif // INCLUDE_SDIOS
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SdFat version 1.1.2 */
|
||||||
|
#define SD_FAT_VERSION 10102
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class SdBaseFile
|
||||||
|
* \brief Class for backward compatibility.
|
||||||
|
*/
|
||||||
|
class SdBaseFile : public FatFile {
|
||||||
|
public:
|
||||||
|
SdBaseFile() {}
|
||||||
|
/** Create a file object and open it in the current working directory.
|
||||||
|
*
|
||||||
|
* \param[in] path A path for a file to be opened.
|
||||||
|
*
|
||||||
|
* \param[in] oflag Values for \a oflag are constructed by a
|
||||||
|
* bitwise-inclusive OR of open flags. see
|
||||||
|
* FatFile::open(FatFile*, const char*, oflag_t).
|
||||||
|
*/
|
||||||
|
SdBaseFile(const char* path, oflag_t oflag) : FatFile(path, oflag) {}
|
||||||
|
};
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#if ENABLE_ARDUINO_FEATURES
|
||||||
|
/**
|
||||||
|
* \class SdFile
|
||||||
|
* \brief Class for backward compatibility.
|
||||||
|
*/
|
||||||
|
class SdFile : public PrintFile {
|
||||||
|
public:
|
||||||
|
SdFile() {}
|
||||||
|
/** Create a file object and open it in the current working directory.
|
||||||
|
*
|
||||||
|
* \param[in] path A path for a file to be opened.
|
||||||
|
*
|
||||||
|
* \param[in] oflag Values for \a oflag are constructed by a
|
||||||
|
* bitwise-inclusive OR of open flags. see
|
||||||
|
* FatFile::open(FatFile*, const char*, oflag_t).
|
||||||
|
*/
|
||||||
|
SdFile(const char* path, oflag_t oflag) : PrintFile(path, oflag) {}
|
||||||
|
};
|
||||||
|
#endif // #if ENABLE_ARDUINO_FEATURES
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \class SdFileSystem
|
||||||
|
* \brief Virtual base class for %SdFat library.
|
||||||
|
*/
|
||||||
|
template<class SdDriverClass>
|
||||||
|
class SdFileSystem : public FatFileSystem {
|
||||||
|
public:
|
||||||
|
/** Initialize file system.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool begin() {
|
||||||
|
return FatFileSystem::begin(&m_card);
|
||||||
|
}
|
||||||
|
/** \return Pointer to SD card object */
|
||||||
|
SdDriverClass *card() {
|
||||||
|
m_card.syncBlocks();
|
||||||
|
return &m_card;
|
||||||
|
}
|
||||||
|
/** %Print any SD error code to Serial and halt. */
|
||||||
|
void errorHalt() {
|
||||||
|
errorHalt(&Serial);
|
||||||
|
}
|
||||||
|
/** %Print any SD error code and halt.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print destination.
|
||||||
|
*/
|
||||||
|
void errorHalt(Print* pr) {
|
||||||
|
errorPrint(pr);
|
||||||
|
SysCall::halt();
|
||||||
|
}
|
||||||
|
/** %Print msg, any SD error code and halt.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void errorHalt(char const* msg) {
|
||||||
|
errorHalt(&Serial, msg);
|
||||||
|
}
|
||||||
|
/** %Print msg, any SD error code, and halt.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print destination.
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void errorHalt(Print* pr, char const* msg) {
|
||||||
|
errorPrint(pr, msg);
|
||||||
|
SysCall::halt();
|
||||||
|
}
|
||||||
|
/** %Print any SD error code to Serial */
|
||||||
|
void errorPrint() {
|
||||||
|
errorPrint(&Serial);
|
||||||
|
}
|
||||||
|
/** %Print any SD error code.
|
||||||
|
* \param[in] pr Print device.
|
||||||
|
*/
|
||||||
|
void errorPrint(Print* pr) {
|
||||||
|
if (!cardErrorCode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pr->print(F("SD errorCode: 0X"));
|
||||||
|
pr->print(cardErrorCode(), HEX);
|
||||||
|
pr->print(F(",0X"));
|
||||||
|
pr->println(cardErrorData(), HEX);
|
||||||
|
}
|
||||||
|
/** %Print msg, any SD error code.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void errorPrint(const char* msg) {
|
||||||
|
errorPrint(&Serial, msg);
|
||||||
|
}
|
||||||
|
/** %Print msg, any SD error code.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print destination.
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void errorPrint(Print* pr, char const* msg) {
|
||||||
|
pr->print(F("error: "));
|
||||||
|
pr->println(msg);
|
||||||
|
errorPrint(pr);
|
||||||
|
}
|
||||||
|
/** %Print any SD error code and halt. */
|
||||||
|
void initErrorHalt() {
|
||||||
|
initErrorHalt(&Serial);
|
||||||
|
}
|
||||||
|
/** %Print error details and halt after begin fails.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print destination.
|
||||||
|
*/
|
||||||
|
void initErrorHalt(Print* pr) {
|
||||||
|
initErrorPrint(pr);
|
||||||
|
SysCall::halt();
|
||||||
|
}
|
||||||
|
/**Print message, error details, and halt after begin() fails.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void initErrorHalt(char const *msg) {
|
||||||
|
initErrorHalt(&Serial, msg);
|
||||||
|
}
|
||||||
|
/**Print message, error details, and halt after begin() fails.
|
||||||
|
* \param[in] pr Print device.
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void initErrorHalt(Print* pr, char const *msg) {
|
||||||
|
pr->println(msg);
|
||||||
|
initErrorHalt(pr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Print error details after begin() fails. */
|
||||||
|
void initErrorPrint() {
|
||||||
|
initErrorPrint(&Serial);
|
||||||
|
}
|
||||||
|
/** Print error details after begin() fails.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print destination.
|
||||||
|
*/
|
||||||
|
void initErrorPrint(Print* pr) {
|
||||||
|
if (cardErrorCode()) {
|
||||||
|
pr->println(F("Can't access SD card. Do not reformat."));
|
||||||
|
if (cardErrorCode() == SD_CARD_ERROR_CMD0) {
|
||||||
|
pr->println(F("No card, wrong chip select pin, or SPI problem?"));
|
||||||
|
}
|
||||||
|
errorPrint(pr);
|
||||||
|
} else if (vol()->fatType() == 0) {
|
||||||
|
pr->println(F("Invalid format, reformat SD."));
|
||||||
|
} else if (!vwd()->isOpen()) {
|
||||||
|
pr->println(F("Can't open root directory."));
|
||||||
|
} else {
|
||||||
|
pr->println(F("No error found."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**Print message and error details and halt after begin() fails.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void initErrorPrint(char const *msg) {
|
||||||
|
initErrorPrint(&Serial, msg);
|
||||||
|
}
|
||||||
|
/**Print message and error details and halt after begin() fails.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print destination.
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void initErrorPrint(Print* pr, char const *msg) {
|
||||||
|
pr->println(msg);
|
||||||
|
initErrorPrint(pr);
|
||||||
|
}
|
||||||
|
#if defined(ARDUINO) || defined(DOXYGEN)
|
||||||
|
/** %Print msg, any SD error code, and halt.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void errorHalt(const __FlashStringHelper* msg) {
|
||||||
|
errorHalt(&Serial, msg);
|
||||||
|
}
|
||||||
|
/** %Print msg, any SD error code, and halt.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print destination.
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void errorHalt(Print* pr, const __FlashStringHelper* msg) {
|
||||||
|
errorPrint(pr, msg);
|
||||||
|
SysCall::halt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** %Print msg, any SD error code.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void errorPrint(const __FlashStringHelper* msg) {
|
||||||
|
errorPrint(&Serial, msg);
|
||||||
|
}
|
||||||
|
/** %Print msg, any SD error code.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print destination.
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void errorPrint(Print* pr, const __FlashStringHelper* msg) {
|
||||||
|
pr->print(F("error: "));
|
||||||
|
pr->println(msg);
|
||||||
|
errorPrint(pr);
|
||||||
|
}
|
||||||
|
/**Print message, error details, and halt after begin() fails.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void initErrorHalt(const __FlashStringHelper* msg) {
|
||||||
|
initErrorHalt(&Serial, msg);
|
||||||
|
}
|
||||||
|
/**Print message, error details, and halt after begin() fails.
|
||||||
|
* \param[in] pr Print device for message.
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void initErrorHalt(Print* pr, const __FlashStringHelper* msg) {
|
||||||
|
pr->println(msg);
|
||||||
|
initErrorHalt(pr);
|
||||||
|
}
|
||||||
|
/**Print message and error details and halt after begin() fails.
|
||||||
|
*
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void initErrorPrint(const __FlashStringHelper* msg) {
|
||||||
|
initErrorPrint(&Serial, msg);
|
||||||
|
}
|
||||||
|
/**Print message and error details and halt after begin() fails.
|
||||||
|
*
|
||||||
|
* \param[in] pr Print destination.
|
||||||
|
* \param[in] msg Message to print.
|
||||||
|
*/
|
||||||
|
void initErrorPrint(Print* pr, const __FlashStringHelper* msg) {
|
||||||
|
pr->println(msg);
|
||||||
|
initErrorPrint(pr);
|
||||||
|
}
|
||||||
|
#endif // defined(ARDUINO) || defined(DOXYGEN)
|
||||||
|
/** \return The card error code */
|
||||||
|
uint8_t cardErrorCode() {
|
||||||
|
return m_card.errorCode();
|
||||||
|
}
|
||||||
|
/** \return the card error data */
|
||||||
|
uint32_t cardErrorData() {
|
||||||
|
return m_card.errorData();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SdDriverClass m_card;
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* \class SdFat
|
||||||
|
* \brief Main file system class for %SdFat library.
|
||||||
|
*/
|
||||||
|
class SdFat : public SdFileSystem<SdSpiCard> {
|
||||||
|
public:
|
||||||
|
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
|
||||||
|
SdFat() {
|
||||||
|
m_spi.setPort(nullptr);
|
||||||
|
}
|
||||||
|
/** Constructor with SPI port selection.
|
||||||
|
* \param[in] spiPort SPI port number.
|
||||||
|
*/
|
||||||
|
explicit SdFat(SPIClass* spiPort) {
|
||||||
|
m_spi.setPort(spiPort);
|
||||||
|
}
|
||||||
|
#endif // IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
/** Initialize SD card and file system.
|
||||||
|
*
|
||||||
|
* \param[in] csPin SD card chip select pin.
|
||||||
|
* \param[in] spiSettings SPI speed, mode, and bit order.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
|
||||||
|
return m_card.begin(&m_spi, csPin, spiSettings) &&
|
||||||
|
SdFileSystem::begin();
|
||||||
|
}
|
||||||
|
/** Initialize SD card for diagnostic use only.
|
||||||
|
*
|
||||||
|
* \param[in] csPin SD card chip select pin.
|
||||||
|
* \param[in] settings SPI speed, mode, and bit order.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool cardBegin(uint8_t csPin = SS, SPISettings settings = SPI_FULL_SPEED) {
|
||||||
|
return m_card.begin(&m_spi, csPin, settings);
|
||||||
|
}
|
||||||
|
/** Initialize file system for diagnostic use only.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool fsBegin() {
|
||||||
|
return FatFileSystem::begin(card());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SdFatSpiDriver m_spi;
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
#if ENABLE_SDIO_CLASS || defined(DOXYGEN)
|
||||||
|
/**
|
||||||
|
* \class SdFatSdio
|
||||||
|
* \brief SdFat class using SDIO.
|
||||||
|
*/
|
||||||
|
class SdFatSdio : public SdFileSystem<SdioCard> {
|
||||||
|
public:
|
||||||
|
/** Initialize SD card and file system.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool begin() {
|
||||||
|
return m_card.begin() && SdFileSystem::begin();
|
||||||
|
}
|
||||||
|
/** Initialize SD card for diagnostic use only.
|
||||||
|
*
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool cardBegin() {
|
||||||
|
return m_card.begin();
|
||||||
|
}
|
||||||
|
/** Initialize file system for diagnostic use only.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool fsBegin() {
|
||||||
|
return SdFileSystem::begin();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#if ENABLE_SDIOEX_CLASS || defined(DOXYGEN)
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \class SdFatSdioEX
|
||||||
|
* \brief SdFat class using SDIO.
|
||||||
|
*/
|
||||||
|
class SdFatSdioEX : public SdFileSystem<SdioCardEX> {
|
||||||
|
public:
|
||||||
|
/** Initialize SD card and file system.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool begin() {
|
||||||
|
return m_card.begin() && SdFileSystem::begin();
|
||||||
|
}
|
||||||
|
/** \return Pointer to SD card object */
|
||||||
|
SdioCardEX* card() {
|
||||||
|
return &m_card;
|
||||||
|
}
|
||||||
|
/** Initialize SD card for diagnostic use only.
|
||||||
|
*
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool cardBegin() {
|
||||||
|
return m_card.begin();
|
||||||
|
}
|
||||||
|
/** Initialize file system for diagnostic use only.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool fsBegin() {
|
||||||
|
return SdFileSystem::begin();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // ENABLE_SDIOEX_CLASS || defined(DOXYGEN)
|
||||||
|
#endif // ENABLE_SDIO_CLASS || defined(DOXYGEN)
|
||||||
|
//=============================================================================
|
||||||
|
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
|
||||||
|
/**
|
||||||
|
* \class SdFatSoftSpi
|
||||||
|
* \brief SdFat class using software SPI.
|
||||||
|
*/
|
||||||
|
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
|
||||||
|
class SdFatSoftSpi : public SdFileSystem<SdSpiCard> {
|
||||||
|
public:
|
||||||
|
/** Initialize SD card and file system.
|
||||||
|
*
|
||||||
|
* \param[in] csPin SD card chip select pin.
|
||||||
|
* \param[in] spiSettings ignored for software SPI..
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
|
||||||
|
return m_card.begin(&m_spi, csPin, spiSettings) &&
|
||||||
|
SdFileSystem::begin();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
SdSpiSoftDriver<MisoPin, MosiPin, SckPin> m_spi;
|
||||||
|
};
|
||||||
|
#endif // #if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
|
||||||
|
//==============================================================================
|
||||||
|
#if ENABLE_EXTENDED_TRANSFER_CLASS || defined(DOXYGEN)
|
||||||
|
/**
|
||||||
|
* \class SdFatEX
|
||||||
|
* \brief SdFat class with extended SD I/O.
|
||||||
|
*/
|
||||||
|
class SdFatEX : public SdFileSystem<SdSpiCardEX> {
|
||||||
|
public:
|
||||||
|
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
|
||||||
|
SdFatEX() {
|
||||||
|
m_spi.setPort(nullptr);
|
||||||
|
}
|
||||||
|
/** Constructor with SPI port selection.
|
||||||
|
* \param[in] spiPort SPI port number.
|
||||||
|
*/
|
||||||
|
explicit SdFatEX(SPIClass* spiPort) {
|
||||||
|
m_spi.setPort(spiPort);
|
||||||
|
}
|
||||||
|
#endif // IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
/** Initialize SD card and file system.
|
||||||
|
*
|
||||||
|
* \param[in] csPin SD card chip select pin.
|
||||||
|
* \param[in] spiSettings SPI speed, mode, and bit order.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
|
||||||
|
return m_card.begin(&m_spi, csPin, spiSettings) &&
|
||||||
|
SdFileSystem::begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SdFatSpiDriver m_spi;
|
||||||
|
};
|
||||||
|
//==============================================================================
|
||||||
|
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
|
||||||
|
/**
|
||||||
|
* \class SdFatSoftSpiEX
|
||||||
|
* \brief SdFat class using software SPI and extended SD I/O.
|
||||||
|
*/
|
||||||
|
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
|
||||||
|
class SdFatSoftSpiEX : public SdFileSystem<SdSpiCardEX> {
|
||||||
|
public:
|
||||||
|
/** Initialize SD card and file system.
|
||||||
|
*
|
||||||
|
* \param[in] csPin SD card chip select pin.
|
||||||
|
* \param[in] spiSettings ignored for software SPI.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
|
||||||
|
return m_card.begin(&m_spi, csPin, spiSettings) &&
|
||||||
|
SdFileSystem::begin();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
SdSpiSoftDriver<MisoPin, MosiPin, SckPin> m_spi;
|
||||||
|
};
|
||||||
|
#endif // #if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
|
||||||
|
#endif // ENABLE_EXTENDED_TRANSFER_CLASS || defined(DOXYGEN)
|
||||||
|
//=============================================================================
|
||||||
|
/**
|
||||||
|
* \class Sd2Card
|
||||||
|
* \brief Raw access to SD and SDHC card using default SPI library.
|
||||||
|
*/
|
||||||
|
class Sd2Card : public SdSpiCard {
|
||||||
|
public:
|
||||||
|
/** Initialize the SD card.
|
||||||
|
* \param[in] csPin SD chip select pin.
|
||||||
|
* \param[in] settings SPI speed, mode, and bit order.
|
||||||
|
* \return true for success else false.
|
||||||
|
*/
|
||||||
|
bool begin(uint8_t csPin = SS, SPISettings settings = SD_SCK_MHZ(50)) {
|
||||||
|
return SdSpiCard::begin(&m_spi, csPin, settings);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
SdFatSpiDriver m_spi;
|
||||||
|
};
|
||||||
|
#endif // SdFat_h
|
235
hardware/_controller/src/SdFat/SdFatConfig.h
Normal file
235
hardware/_controller/src/SdFat/SdFatConfig.h
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief configuration definitions
|
||||||
|
*/
|
||||||
|
#ifndef SdFatConfig_h
|
||||||
|
#define SdFatConfig_h
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#ifdef __AVR__
|
||||||
|
#include <avr/io.h>
|
||||||
|
#endif // __AVR__
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set INCLUDE_SDIOS nonzero to include sdios.h in SdFat.h.
|
||||||
|
* sdios.h provides C++ style IO Streams.
|
||||||
|
*/
|
||||||
|
#define INCLUDE_SDIOS 1
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set USE_LONG_FILE_NAMES nonzero to use long file names (LFN).
|
||||||
|
* Long File Name are limited to a maximum length of 255 characters.
|
||||||
|
*
|
||||||
|
* This implementation allows 7-bit characters in the range
|
||||||
|
* 0X20 to 0X7E except the following characters are not allowed:
|
||||||
|
*
|
||||||
|
* < (less than)
|
||||||
|
* > (greater than)
|
||||||
|
* : (colon)
|
||||||
|
* " (double quote)
|
||||||
|
* / (forward slash)
|
||||||
|
* \ (backslash)
|
||||||
|
* | (vertical bar or pipe)
|
||||||
|
* ? (question mark)
|
||||||
|
* * (asterisk)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define USE_LONG_FILE_NAMES 1
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* If the symbol ENABLE_EXTENDED_TRANSFER_CLASS is nonzero, the class SdFatEX
|
||||||
|
* will be defined. If the symbol ENABLE_SOFTWARE_SPI_CLASS is also nonzero,
|
||||||
|
* the class SdFatSoftSpiEX will be defined.
|
||||||
|
*
|
||||||
|
* These classes used extended multi-block SD I/O for better performance.
|
||||||
|
* the SPI bus may not be shared with other devices in this mode.
|
||||||
|
*/
|
||||||
|
#define ENABLE_EXTENDED_TRANSFER_CLASS 0
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* If the symbol USE_STANDARD_SPI_LIBRARY is zero, an optimized custom SPI
|
||||||
|
* driver is used if it exists. If the symbol USE_STANDARD_SPI_LIBRARY is
|
||||||
|
* one, the standard Arduino SPI.h library is used with SPI. If the symbol
|
||||||
|
* USE_STANDARD_SPI_LIBRARY is two, the SPI port can be selected with the
|
||||||
|
* constructors SdFat(SPIClass* spiPort) and SdFatEX(SPIClass* spiPort).
|
||||||
|
*/
|
||||||
|
#define USE_STANDARD_SPI_LIBRARY 0
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* If the symbol ENABLE_SOFTWARE_SPI_CLASS is nonzero, the class SdFatSoftSpi
|
||||||
|
* will be defined. If ENABLE_EXTENDED_TRANSFER_CLASS is also nonzero,
|
||||||
|
* the class SdFatSoftSpiEX will be defined.
|
||||||
|
*/
|
||||||
|
#define ENABLE_SOFTWARE_SPI_CLASS 1
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** If the symbol USE_FCNTL_H is nonzero, open flags for access modes O_RDONLY,
|
||||||
|
* O_WRONLY, O_RDWR and the open modifiers O_APPEND, O_CREAT, O_EXCL, O_SYNC
|
||||||
|
* will be defined by including the system file fcntl.h.
|
||||||
|
*/
|
||||||
|
#if defined(__AVR__)
|
||||||
|
// AVR fcntl.h does not define open flags.
|
||||||
|
#define USE_FCNTL_H 0
|
||||||
|
#elif defined(PLATFORM_ID)
|
||||||
|
// Particle boards - use fcntl.h.
|
||||||
|
#define USE_FCNTL_H 1
|
||||||
|
#elif defined(__arm__)
|
||||||
|
// ARM gcc defines open flags.
|
||||||
|
#define USE_FCNTL_H 1
|
||||||
|
#elif defined(ESP32)
|
||||||
|
#define USE_FCNTL_H 1
|
||||||
|
#else // defined(__AVR__)
|
||||||
|
#define USE_FCNTL_H 0
|
||||||
|
#endif // defined(__AVR__)
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* If CHECK_FLASH_PROGRAMMING is zero, overlap of single sector flash
|
||||||
|
* programming and other operations will be allowed for faster write
|
||||||
|
* performance.
|
||||||
|
*
|
||||||
|
* Some cards will not sleep in low power mode unless CHECK_FLASH_PROGRAMMING
|
||||||
|
* is non-zero.
|
||||||
|
*/
|
||||||
|
#define CHECK_FLASH_PROGRAMMING 1
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters
|
||||||
|
* updated. This will increase the speed of the freeClusterCount() call
|
||||||
|
* after the first call. Extra flash will be required.
|
||||||
|
*/
|
||||||
|
#define MAINTAIN_FREE_CLUSTER_COUNT 0
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* To enable SD card CRC checking set USE_SD_CRC nonzero.
|
||||||
|
*
|
||||||
|
* Set USE_SD_CRC to 1 to use a smaller CRC-CCITT function. This function
|
||||||
|
* is slower for AVR but may be fast for ARM and other processors.
|
||||||
|
*
|
||||||
|
* Set USE_SD_CRC to 2 to used a larger table driven CRC-CCITT function. This
|
||||||
|
* function is faster for AVR but may be slower for ARM and other processors.
|
||||||
|
*/
|
||||||
|
#define USE_SD_CRC 1
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Handle Watchdog Timer for WiFi modules.
|
||||||
|
*
|
||||||
|
* Yield will be called before accessing the SPI bus if it has been more
|
||||||
|
* than WDT_YIELD_TIME_MICROS microseconds since the last yield call by SdFat.
|
||||||
|
*/
|
||||||
|
#if defined(PLATFORM_ID) || defined(ESP8266)
|
||||||
|
// If Particle device or ESP8266 call yield.
|
||||||
|
#define WDT_YIELD_TIME_MICROS 100000
|
||||||
|
#else
|
||||||
|
#define WDT_YIELD_TIME_MICROS 0
|
||||||
|
#endif
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set FAT12_SUPPORT nonzero to enable use of FAT12 volumes.
|
||||||
|
* FAT12 has not been well tested and requires additional flash.
|
||||||
|
*/
|
||||||
|
#define FAT12_SUPPORT 0
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor.
|
||||||
|
*
|
||||||
|
* Causes use of lots of heap in ARM.
|
||||||
|
*/
|
||||||
|
#define DESTRUCTOR_CLOSES_FILE 1
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set USE_SEPARATE_FAT_CACHE nonzero to use a second 512 byte cache
|
||||||
|
* for FAT table entries. This improves performance for large writes
|
||||||
|
* that are not a multiple of 512 bytes.
|
||||||
|
*/
|
||||||
|
#ifdef __arm__
|
||||||
|
#define USE_SEPARATE_FAT_CACHE 1
|
||||||
|
#else // __arm__
|
||||||
|
#define USE_SEPARATE_FAT_CACHE 0
|
||||||
|
#endif // __arm__
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set USE_MULTI_BLOCK_IO nonzero to use multi-block SD read/write.
|
||||||
|
*
|
||||||
|
* Don't use mult-block read/write on small AVR boards.
|
||||||
|
*/
|
||||||
|
#if defined(RAMEND) && RAMEND < 3000
|
||||||
|
#define USE_MULTI_BLOCK_IO 0
|
||||||
|
#else // RAMEND
|
||||||
|
#define USE_MULTI_BLOCK_IO 1
|
||||||
|
#endif // RAMEND
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
/** Enable SDIO driver if available. */
|
||||||
|
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||||
|
#define ENABLE_SDIO_CLASS 1
|
||||||
|
#define ENABLE_SDIOEX_CLASS 1
|
||||||
|
#else // ENABLE_SDIO_CLASS
|
||||||
|
#define ENABLE_SDIO_CLASS 0
|
||||||
|
#endif // ENABLE_SDIO_CLASS
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Determine the default SPI configuration.
|
||||||
|
*/
|
||||||
|
#if defined(__STM32F1__) || defined(__STM32F4__) || defined(PLATFORM_ID)
|
||||||
|
// has multiple SPI ports
|
||||||
|
#define SD_HAS_CUSTOM_SPI 2
|
||||||
|
#elif defined(__AVR__)\
|
||||||
|
|| defined(__SAM3X8E__) || defined(__SAM3X8H__)\
|
||||||
|
|| (defined(__arm__) && defined(CORE_TEENSY))\
|
||||||
|
|| defined(ESP8266)
|
||||||
|
#define SD_HAS_CUSTOM_SPI 1
|
||||||
|
#else // SD_HAS_CUSTOM_SPI
|
||||||
|
// Use standard SPI library.
|
||||||
|
#define SD_HAS_CUSTOM_SPI 0
|
||||||
|
#endif // SD_HAS_CUSTOM_SPI
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Check if API to select HW SPI port is needed.
|
||||||
|
*/
|
||||||
|
#if USE_STANDARD_SPI_LIBRARY > 1 || SD_HAS_CUSTOM_SPI > 1
|
||||||
|
#define IMPLEMENT_SPI_PORT_SELECTION 1
|
||||||
|
#else // IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
#define IMPLEMENT_SPI_PORT_SELECTION 0
|
||||||
|
#endif // IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
#endif // SdFatConfig_h
|
386
hardware/_controller/src/SdFat/SpiDriver/DigitalPin.h
Normal file
386
hardware/_controller/src/SdFat/SpiDriver/DigitalPin.h
Normal file
|
@ -0,0 +1,386 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Fast Digital Pin functions
|
||||||
|
*
|
||||||
|
* @defgroup digitalPin Fast Pin I/O
|
||||||
|
* @details Fast Digital I/O functions and template class.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#ifndef DigitalPin_h
|
||||||
|
#define DigitalPin_h
|
||||||
|
#if defined(__AVR__) || defined(DOXYGEN)
|
||||||
|
#include <avr/io.h>
|
||||||
|
/** GpioPinMap type */
|
||||||
|
struct GpioPinMap_t {
|
||||||
|
volatile uint8_t* pin; /**< address of PIN for this pin */
|
||||||
|
volatile uint8_t* ddr; /**< address of DDR for this pin */
|
||||||
|
volatile uint8_t* port; /**< address of PORT for this pin */
|
||||||
|
uint8_t mask; /**< bit mask for this pin */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Initializer macro. */
|
||||||
|
#define GPIO_PIN(reg, bit) {&PIN##reg, &DDR##reg, &PORT##reg, 1 << bit}
|
||||||
|
|
||||||
|
// Include pin map for current board.
|
||||||
|
#include "boards/GpioPinMap.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** generate bad pin number error */
|
||||||
|
void badPinNumber(void)
|
||||||
|
__attribute__((error("Pin number is too large or not a constant")));
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Check for valid pin number
|
||||||
|
* @param[in] pin Number of pin to be checked.
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void badPinCheck(uint8_t pin) {
|
||||||
|
if (!__builtin_constant_p(pin) || pin >= NUM_DIGITAL_PINS) {
|
||||||
|
badPinNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** DDR register address
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @return register address
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
volatile uint8_t* ddrReg(uint8_t pin) {
|
||||||
|
badPinCheck(pin);
|
||||||
|
return GpioPinMap[pin].ddr;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Bit mask for pin
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @return mask
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
uint8_t pinMask(uint8_t pin) {
|
||||||
|
badPinCheck(pin);
|
||||||
|
return GpioPinMap[pin].mask;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** PIN register address
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @return register address
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
volatile uint8_t* pinReg(uint8_t pin) {
|
||||||
|
badPinCheck(pin);
|
||||||
|
return GpioPinMap[pin].pin;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** PORT register address
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @return register address
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
volatile uint8_t* portReg(uint8_t pin) {
|
||||||
|
badPinCheck(pin);
|
||||||
|
return GpioPinMap[pin].port;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Fast write helper.
|
||||||
|
* @param[in] address I/O register address
|
||||||
|
* @param[in] mask bit mask for pin
|
||||||
|
* @param[in] level value for bit
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void fastBitWriteSafe(volatile uint8_t* address, uint8_t mask, bool level) {
|
||||||
|
uint8_t s;
|
||||||
|
if (address > reinterpret_cast<uint8_t*>(0X3F)) {
|
||||||
|
s = SREG;
|
||||||
|
cli();
|
||||||
|
}
|
||||||
|
if (level) {
|
||||||
|
*address |= mask;
|
||||||
|
} else {
|
||||||
|
*address &= ~mask;
|
||||||
|
}
|
||||||
|
if (address > reinterpret_cast<uint8_t*>(0X3F)) {
|
||||||
|
SREG = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Read pin value.
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @return value read
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
bool fastDigitalRead(uint8_t pin) {
|
||||||
|
return *pinReg(pin) & pinMask(pin);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Toggle a pin.
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
*
|
||||||
|
* If the pin is in output mode toggle the pin level.
|
||||||
|
* If the pin is in input mode toggle the state of the 20K pullup.
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void fastDigitalToggle(uint8_t pin) {
|
||||||
|
if (pinReg(pin) > reinterpret_cast<uint8_t*>(0X3F)) {
|
||||||
|
// must write bit to high address port
|
||||||
|
*pinReg(pin) = pinMask(pin);
|
||||||
|
} else {
|
||||||
|
// will compile to sbi and PIN register will not be read.
|
||||||
|
*pinReg(pin) |= pinMask(pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Set pin value.
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @param[in] level value to write
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void fastDigitalWrite(uint8_t pin, bool level) {
|
||||||
|
fastBitWriteSafe(portReg(pin), pinMask(pin), level);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Write the DDR register.
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @param[in] level value to write
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void fastDdrWrite(uint8_t pin, bool level) {
|
||||||
|
fastBitWriteSafe(ddrReg(pin), pinMask(pin), level);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Set pin mode.
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @param[in] mode INPUT, OUTPUT, or INPUT_PULLUP.
|
||||||
|
*
|
||||||
|
* The internal pullup resistors will be enabled if mode is INPUT_PULLUP
|
||||||
|
* and disabled if the mode is INPUT.
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void fastPinMode(uint8_t pin, uint8_t mode) {
|
||||||
|
fastDdrWrite(pin, mode == OUTPUT);
|
||||||
|
if (mode != OUTPUT) {
|
||||||
|
fastDigitalWrite(pin, mode == INPUT_PULLUP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else // defined(__AVR__)
|
||||||
|
#if defined(CORE_TEENSY)
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** read pin value
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @return value read
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
bool fastDigitalRead(uint8_t pin) {
|
||||||
|
return *portInputRegister(pin);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Set pin value
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @param[in] level value to write
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void fastDigitalWrite(uint8_t pin, bool value) {
|
||||||
|
if (value) {
|
||||||
|
*portSetRegister(pin) = 1;
|
||||||
|
} else {
|
||||||
|
*portClearRegister(pin) = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(__SAM3X8E__) || defined(__SAM3X8H__)
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** read pin value
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @return value read
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
bool fastDigitalRead(uint8_t pin) {
|
||||||
|
return g_APinDescription[pin].pPort->PIO_PDSR & g_APinDescription[pin].ulPin;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Set pin value
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @param[in] level value to write
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void fastDigitalWrite(uint8_t pin, bool value) {
|
||||||
|
if (value) {
|
||||||
|
g_APinDescription[pin].pPort->PIO_SODR = g_APinDescription[pin].ulPin;
|
||||||
|
} else {
|
||||||
|
g_APinDescription[pin].pPort->PIO_CODR = g_APinDescription[pin].ulPin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(ESP8266)
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Set pin value
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @param[in] val value to write
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void fastDigitalWrite(uint8_t pin, uint8_t val) {
|
||||||
|
if (pin < 16) {
|
||||||
|
if (val) {
|
||||||
|
GPOS = (1 << pin);
|
||||||
|
} else {
|
||||||
|
GPOC = (1 << pin);
|
||||||
|
}
|
||||||
|
} else if (pin == 16) {
|
||||||
|
if (val) {
|
||||||
|
GP16O |= 1;
|
||||||
|
} else {
|
||||||
|
GP16O &= ~1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Read pin value
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @return value read
|
||||||
|
*/
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
bool fastDigitalRead(uint8_t pin) {
|
||||||
|
if (pin < 16) {
|
||||||
|
return GPIP(pin);
|
||||||
|
} else if (pin == 16) {
|
||||||
|
return GP16I & 0x01;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else // CORE_TEENSY
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline void fastDigitalWrite(uint8_t pin, bool value) {
|
||||||
|
digitalWrite(pin, value);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline bool fastDigitalRead(uint8_t pin) {
|
||||||
|
return digitalRead(pin);
|
||||||
|
}
|
||||||
|
#endif // CORE_TEENSY
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline void fastDigitalToggle(uint8_t pin) {
|
||||||
|
fastDigitalWrite(pin, !fastDigitalRead(pin));
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline void fastPinMode(uint8_t pin, uint8_t mode) {
|
||||||
|
pinMode(pin, mode);
|
||||||
|
}
|
||||||
|
#endif // __AVR__
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** set pin configuration
|
||||||
|
* @param[in] pin Arduino pin number
|
||||||
|
* @param[in] mode mode INPUT or OUTPUT.
|
||||||
|
* @param[in] level If mode is output, set level high/low.
|
||||||
|
* If mode is input, enable or disable the pin's 20K pullup.
|
||||||
|
*/
|
||||||
|
#define fastPinConfig(pin, mode, level)\
|
||||||
|
{fastPinMode(pin, mode); fastDigitalWrite(pin, level);}
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
* @class DigitalPin
|
||||||
|
* @brief Fast digital port I/O
|
||||||
|
*/
|
||||||
|
template<uint8_t PinNumber>
|
||||||
|
class DigitalPin {
|
||||||
|
public:
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Constructor */
|
||||||
|
DigitalPin() {}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Asignment operator.
|
||||||
|
* @param[in] value If true set the pin's level high else set the
|
||||||
|
* pin's level low.
|
||||||
|
*
|
||||||
|
* @return This DigitalPin instance.
|
||||||
|
*/
|
||||||
|
inline DigitalPin & operator = (bool value) __attribute__((always_inline)) {
|
||||||
|
write(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Parenthesis operator.
|
||||||
|
* @return Pin's level
|
||||||
|
*/
|
||||||
|
inline operator bool () const __attribute__((always_inline)) {
|
||||||
|
return read();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Set pin configuration.
|
||||||
|
* @param[in] mode: INPUT or OUTPUT.
|
||||||
|
* @param[in] level If mode is OUTPUT, set level high/low.
|
||||||
|
* If mode is INPUT, enable or disable the pin's 20K pullup.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
void config(uint8_t mode, bool level) {
|
||||||
|
fastPinConfig(PinNumber, mode, level);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set pin level high if output mode or enable 20K pullup if input mode.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
void high() {write(true);}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set pin level low if output mode or disable 20K pullup if input mode.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
void low() {write(false);}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Set pin mode.
|
||||||
|
* @param[in] mode: INPUT, OUTPUT, or INPUT_PULLUP.
|
||||||
|
*
|
||||||
|
* The internal pullup resistors will be enabled if mode is INPUT_PULLUP
|
||||||
|
* and disabled if the mode is INPUT.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
void mode(uint8_t mode) {
|
||||||
|
fastPinMode(PinNumber, mode);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** @return Pin's level. */
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
bool read() const {
|
||||||
|
return fastDigitalRead(PinNumber);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Toggle a pin.
|
||||||
|
*
|
||||||
|
* If the pin is in output mode toggle the pin's level.
|
||||||
|
* If the pin is in input mode toggle the state of the 20K pullup.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
void toggle() {
|
||||||
|
fastDigitalToggle(PinNumber);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Write the pin's level.
|
||||||
|
* @param[in] value If true set the pin's level high else set the
|
||||||
|
* pin's level low.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
void write(bool value) {
|
||||||
|
fastDigitalWrite(PinNumber, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // DigitalPin_h
|
||||||
|
/** @} */
|
79
hardware/_controller/src/SdFat/SpiDriver/SdSpiBaseDriver.h
Normal file
79
hardware/_controller/src/SdFat/SpiDriver/SdSpiBaseDriver.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SdSpiBaseDriver_h
|
||||||
|
#define SdSpiBaseDriver_h
|
||||||
|
/**
|
||||||
|
* \class SdSpiBaseDriver
|
||||||
|
* \brief SPI base driver.
|
||||||
|
*/
|
||||||
|
class SdSpiBaseDriver {
|
||||||
|
public:
|
||||||
|
/** Set SPI options for access to SD/SDHC cards.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
virtual void activate() = 0;
|
||||||
|
/** Initialize the SPI bus.
|
||||||
|
*
|
||||||
|
* \param[in] chipSelectPin SD card chip select pin.
|
||||||
|
*/
|
||||||
|
virtual void begin(uint8_t chipSelectPin) = 0;
|
||||||
|
/**
|
||||||
|
* End SPI transaction.
|
||||||
|
*/
|
||||||
|
virtual void deactivate() = 0;
|
||||||
|
/** Receive a byte.
|
||||||
|
*
|
||||||
|
* \return The byte.
|
||||||
|
*/
|
||||||
|
virtual uint8_t receive() = 0;
|
||||||
|
/** Receive multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[out] buf Buffer to receive the data.
|
||||||
|
* \param[in] n Number of bytes to receive.
|
||||||
|
*
|
||||||
|
* \return Zero for no error or nonzero error code.
|
||||||
|
*/
|
||||||
|
virtual uint8_t receive(uint8_t* buf, size_t n) = 0;
|
||||||
|
/** Send a byte.
|
||||||
|
*
|
||||||
|
* \param[in] data Byte to send
|
||||||
|
*/
|
||||||
|
virtual void send(uint8_t data) = 0;
|
||||||
|
/** Send multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[in] buf Buffer for data to be sent.
|
||||||
|
* \param[in] n Number of bytes to send.
|
||||||
|
*/
|
||||||
|
virtual void send(const uint8_t* buf, size_t n) = 0;
|
||||||
|
/** Set CS low. */
|
||||||
|
virtual void select() = 0;
|
||||||
|
/** Save SPI settings.
|
||||||
|
* \param[in] spiSettings SPI speed, mode, and bit order.
|
||||||
|
*/
|
||||||
|
virtual void setSpiSettings(SPISettings spiSettings) = 0;
|
||||||
|
/** Set CS high. */
|
||||||
|
virtual void unselect() = 0;
|
||||||
|
};
|
||||||
|
#endif // SdSpiBaseDriver_h
|
438
hardware/_controller/src/SdFat/SpiDriver/SdSpiDriver.h
Normal file
438
hardware/_controller/src/SdFat/SpiDriver/SdSpiDriver.h
Normal file
|
@ -0,0 +1,438 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief SpiDriver classes
|
||||||
|
*/
|
||||||
|
#ifndef SdSpiDriver_h
|
||||||
|
#define SdSpiDriver_h
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "SPI.h"
|
||||||
|
#include "SdSpiBaseDriver.h"
|
||||||
|
#include "../SdFatConfig.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SDCARD_SPI is defined if board has built-in SD card socket */
|
||||||
|
#ifndef SDCARD_SPI
|
||||||
|
#define SDCARD_SPI SPI
|
||||||
|
#endif // SDCARD_SPI
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \class SdSpiLibDriver
|
||||||
|
* \brief SdSpiLibDriver - use standard SPI library.
|
||||||
|
*/
|
||||||
|
#if ENABLE_SOFTWARE_SPI_CLASS
|
||||||
|
class SdSpiLibDriver : public SdSpiBaseDriver {
|
||||||
|
#else // ENABLE_SOFTWARE_SPI_CLASS
|
||||||
|
class SdSpiLibDriver {
|
||||||
|
#endif // ENABLE_SOFTWARE_SPI_CLASS
|
||||||
|
public:
|
||||||
|
#if IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
/** Activate SPI hardware. */
|
||||||
|
void activate() {
|
||||||
|
m_spi->beginTransaction(m_spiSettings);
|
||||||
|
}
|
||||||
|
/** Deactivate SPI hardware. */
|
||||||
|
void deactivate() {
|
||||||
|
m_spi->endTransaction();
|
||||||
|
}
|
||||||
|
/** Initialize the SPI bus.
|
||||||
|
*
|
||||||
|
* \param[in] csPin SD card chip select pin.
|
||||||
|
*/
|
||||||
|
void begin(uint8_t csPin) {
|
||||||
|
m_csPin = csPin;
|
||||||
|
digitalWrite(csPin, HIGH);
|
||||||
|
pinMode(csPin, OUTPUT);
|
||||||
|
m_spi->begin();
|
||||||
|
}
|
||||||
|
/** Receive a byte.
|
||||||
|
*
|
||||||
|
* \return The byte.
|
||||||
|
*/
|
||||||
|
uint8_t receive() {
|
||||||
|
return m_spi->transfer( 0XFF);
|
||||||
|
}
|
||||||
|
/** Receive multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[out] buf Buffer to receive the data.
|
||||||
|
* \param[in] n Number of bytes to receive.
|
||||||
|
*
|
||||||
|
* \return Zero for no error or nonzero error code.
|
||||||
|
*/
|
||||||
|
uint8_t receive(uint8_t* buf, size_t n) {
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
buf[i] = m_spi->transfer(0XFF);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/** Send a byte.
|
||||||
|
*
|
||||||
|
* \param[in] data Byte to send
|
||||||
|
*/
|
||||||
|
void send(uint8_t data) {
|
||||||
|
m_spi->transfer(data);
|
||||||
|
}
|
||||||
|
/** Send multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[in] buf Buffer for data to be sent.
|
||||||
|
* \param[in] n Number of bytes to send.
|
||||||
|
*/
|
||||||
|
void send(const uint8_t* buf, size_t n) {
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
m_spi->transfer(buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else // IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
/** Activate SPI hardware. */
|
||||||
|
void activate() {
|
||||||
|
SDCARD_SPI.beginTransaction(m_spiSettings);
|
||||||
|
}
|
||||||
|
/** Deactivate SPI hardware. */
|
||||||
|
void deactivate() {
|
||||||
|
SDCARD_SPI.endTransaction();
|
||||||
|
}
|
||||||
|
/** Initialize the SPI bus.
|
||||||
|
*
|
||||||
|
* \param[in] csPin SD card chip select pin.
|
||||||
|
*/
|
||||||
|
void begin(uint8_t csPin) {
|
||||||
|
m_csPin = csPin;
|
||||||
|
digitalWrite(csPin, HIGH);
|
||||||
|
pinMode(csPin, OUTPUT);
|
||||||
|
SDCARD_SPI.begin();
|
||||||
|
}
|
||||||
|
/** Receive a byte.
|
||||||
|
*
|
||||||
|
* \return The byte.
|
||||||
|
*/
|
||||||
|
uint8_t receive() {
|
||||||
|
return SDCARD_SPI.transfer( 0XFF);
|
||||||
|
}
|
||||||
|
/** Receive multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[out] buf Buffer to receive the data.
|
||||||
|
* \param[in] n Number of bytes to receive.
|
||||||
|
*
|
||||||
|
* \return Zero for no error or nonzero error code.
|
||||||
|
*/
|
||||||
|
uint8_t receive(uint8_t* buf, size_t n) {
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
buf[i] = SDCARD_SPI.transfer(0XFF);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/** Send a byte.
|
||||||
|
*
|
||||||
|
* \param[in] data Byte to send
|
||||||
|
*/
|
||||||
|
void send(uint8_t data) {
|
||||||
|
SDCARD_SPI.transfer(data);
|
||||||
|
}
|
||||||
|
/** Send multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[in] buf Buffer for data to be sent.
|
||||||
|
* \param[in] n Number of bytes to send.
|
||||||
|
*/
|
||||||
|
void send(const uint8_t* buf, size_t n) {
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
SDCARD_SPI.transfer(buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
/** Set CS low. */
|
||||||
|
void select() {
|
||||||
|
digitalWrite(m_csPin, LOW);
|
||||||
|
}
|
||||||
|
/** Save SPISettings.
|
||||||
|
*
|
||||||
|
* \param[in] spiSettings SPI speed, mode, and byte order.
|
||||||
|
*/
|
||||||
|
void setSpiSettings(SPISettings spiSettings) {
|
||||||
|
m_spiSettings = spiSettings;
|
||||||
|
}
|
||||||
|
/** Set CS high. */
|
||||||
|
void unselect() {
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
}
|
||||||
|
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
|
||||||
|
/** Set SPI port.
|
||||||
|
* \param[in] spiPort Hardware SPI port.
|
||||||
|
*/
|
||||||
|
void setPort(SPIClass* spiPort) {
|
||||||
|
m_spi = spiPort ? spiPort : &SDCARD_SPI;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
SPIClass* m_spi;
|
||||||
|
#else // IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
private:
|
||||||
|
#endif // IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
SPISettings m_spiSettings;
|
||||||
|
uint8_t m_csPin;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \class SdSpiAltDriver
|
||||||
|
* \brief Optimized SPI class for access to SD and SDHC flash memory cards.
|
||||||
|
*/
|
||||||
|
#if ENABLE_SOFTWARE_SPI_CLASS
|
||||||
|
class SdSpiAltDriver : public SdSpiBaseDriver {
|
||||||
|
#else // ENABLE_SOFTWARE_SPI_CLASS
|
||||||
|
class SdSpiAltDriver {
|
||||||
|
#endif // ENABLE_SOFTWARE_SPI_CLASS
|
||||||
|
public:
|
||||||
|
/** Activate SPI hardware. */
|
||||||
|
void activate();
|
||||||
|
/** Deactivate SPI hardware. */
|
||||||
|
void deactivate();
|
||||||
|
/** Initialize the SPI bus.
|
||||||
|
*
|
||||||
|
* \param[in] csPin SD card chip select pin.
|
||||||
|
*/
|
||||||
|
void begin(uint8_t csPin);
|
||||||
|
/** Receive a byte.
|
||||||
|
*
|
||||||
|
* \return The byte.
|
||||||
|
*/
|
||||||
|
uint8_t receive();
|
||||||
|
/** Receive multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[out] buf Buffer to receive the data.
|
||||||
|
* \param[in] n Number of bytes to receive.
|
||||||
|
*
|
||||||
|
* \return Zero for no error or nonzero error code.
|
||||||
|
*/
|
||||||
|
uint8_t receive(uint8_t* buf, size_t n);
|
||||||
|
/** Send a byte.
|
||||||
|
*
|
||||||
|
* \param[in] data Byte to send
|
||||||
|
*/
|
||||||
|
void send(uint8_t data);
|
||||||
|
/** Send multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[in] buf Buffer for data to be sent.
|
||||||
|
* \param[in] n Number of bytes to send.
|
||||||
|
*/
|
||||||
|
void send(const uint8_t* buf, size_t n);
|
||||||
|
/** Set CS low. */
|
||||||
|
void select() {
|
||||||
|
digitalWrite(m_csPin, LOW);
|
||||||
|
}
|
||||||
|
/** Save SPISettings.
|
||||||
|
*
|
||||||
|
* \param[in] spiSettings SPI speed, mode, and byte order.
|
||||||
|
*/
|
||||||
|
void setSpiSettings(SPISettings spiSettings) {
|
||||||
|
m_spiSettings = spiSettings;
|
||||||
|
}
|
||||||
|
/** Set CS high. */
|
||||||
|
void unselect() {
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
}
|
||||||
|
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
|
||||||
|
/** Set SPI port number.
|
||||||
|
* \param[in] spiPort Hardware SPI port.
|
||||||
|
*/
|
||||||
|
void setPort(SPIClass* spiPort) {
|
||||||
|
m_spi = spiPort ? spiPort : &SDCARD_SPI;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
SPIClass* m_spi;
|
||||||
|
#else // IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
private:
|
||||||
|
#endif // IMPLEMENT_SPI_PORT_SELECTION
|
||||||
|
SPISettings m_spiSettings;
|
||||||
|
uint8_t m_csPin;
|
||||||
|
};
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
|
||||||
|
#ifdef ARDUINO
|
||||||
|
#include "SoftSPI.h"
|
||||||
|
#elif defined(PLATFORM_ID) // Only defined if a Particle device
|
||||||
|
#include "SoftSPIParticle.h"
|
||||||
|
#endif // ARDUINO
|
||||||
|
/**
|
||||||
|
* \class SdSpiSoftDriver
|
||||||
|
* \brief Software SPI class for access to SD and SDHC flash memory cards.
|
||||||
|
*/
|
||||||
|
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
|
||||||
|
class SdSpiSoftDriver : public SdSpiBaseDriver {
|
||||||
|
public:
|
||||||
|
/** Dummy activate SPI hardware for software SPI */
|
||||||
|
void activate() {}
|
||||||
|
/** Dummy deactivate SPI hardware for software SPI */
|
||||||
|
void deactivate() {}
|
||||||
|
/** Initialize the SPI bus.
|
||||||
|
*
|
||||||
|
* \param[in] csPin SD card chip select pin.
|
||||||
|
*/
|
||||||
|
void begin(uint8_t csPin) {
|
||||||
|
m_csPin = csPin;
|
||||||
|
pinMode(m_csPin, OUTPUT);
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
m_spi.begin();
|
||||||
|
}
|
||||||
|
/** Receive a byte.
|
||||||
|
*
|
||||||
|
* \return The byte.
|
||||||
|
*/
|
||||||
|
uint8_t receive() {
|
||||||
|
return m_spi.receive();
|
||||||
|
}
|
||||||
|
/** Receive multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[out] buf Buffer to receive the data.
|
||||||
|
* \param[in] n Number of bytes to receive.
|
||||||
|
*
|
||||||
|
* \return Zero for no error or nonzero error code.
|
||||||
|
*/
|
||||||
|
uint8_t receive(uint8_t* buf, size_t n) {
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
buf[i] = receive();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/** Send a byte.
|
||||||
|
*
|
||||||
|
* \param[in] data Byte to send
|
||||||
|
*/
|
||||||
|
void send(uint8_t data) {
|
||||||
|
m_spi.send(data);
|
||||||
|
}
|
||||||
|
/** Send multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[in] buf Buffer for data to be sent.
|
||||||
|
* \param[in] n Number of bytes to send.
|
||||||
|
*/
|
||||||
|
void send(const uint8_t* buf , size_t n) {
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
send(buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** Set CS low. */
|
||||||
|
void select() {
|
||||||
|
digitalWrite(m_csPin, LOW);
|
||||||
|
}
|
||||||
|
/** Save SPISettings.
|
||||||
|
*
|
||||||
|
* \param[in] spiSettings SPI speed, mode, and byte order.
|
||||||
|
*/
|
||||||
|
void setSpiSettings(SPISettings spiSettings) {
|
||||||
|
(void)spiSettings;
|
||||||
|
}
|
||||||
|
/** Set CS high. */
|
||||||
|
void unselect() {
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t m_csPin;
|
||||||
|
SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi;
|
||||||
|
};
|
||||||
|
#endif // ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Choose SPI driver for SdFat and SdFatEX classes.
|
||||||
|
#if USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI
|
||||||
|
/** SdFat uses Arduino library SPI. */
|
||||||
|
typedef SdSpiLibDriver SdFatSpiDriver;
|
||||||
|
#else // USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI
|
||||||
|
/** SdFat uses custom fast SPI. */
|
||||||
|
typedef SdSpiAltDriver SdFatSpiDriver;
|
||||||
|
#endif // USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI
|
||||||
|
|
||||||
|
/** typedef for for SdSpiCard class. */
|
||||||
|
#if ENABLE_SOFTWARE_SPI_CLASS
|
||||||
|
// Need virtual driver.
|
||||||
|
typedef SdSpiBaseDriver SdSpiDriver;
|
||||||
|
#else // ENABLE_SOFTWARE_SPI_CLASS
|
||||||
|
// Don't need virtual driver.
|
||||||
|
typedef SdFatSpiDriver SdSpiDriver;
|
||||||
|
#endif // ENABLE_SOFTWARE_SPI_CLASS
|
||||||
|
//==============================================================================
|
||||||
|
// Use of in-line for AVR to save flash.
|
||||||
|
#ifdef __AVR__
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline void SdSpiAltDriver::begin(uint8_t csPin) {
|
||||||
|
m_csPin = csPin;
|
||||||
|
pinMode(m_csPin, OUTPUT);
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
SPI.begin();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline void SdSpiAltDriver::activate() {
|
||||||
|
SPI.beginTransaction(m_spiSettings);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline void SdSpiAltDriver::deactivate() {
|
||||||
|
SPI.endTransaction();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline uint8_t SdSpiAltDriver::receive() {
|
||||||
|
SPDR = 0XFF;
|
||||||
|
while (!(SPSR & (1 << SPIF))) {}
|
||||||
|
return SPDR;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
|
||||||
|
if (n-- == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SPDR = 0XFF;
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
while (!(SPSR & (1 << SPIF))) {}
|
||||||
|
uint8_t b = SPDR;
|
||||||
|
SPDR = 0XFF;
|
||||||
|
buf[i] = b;
|
||||||
|
}
|
||||||
|
while (!(SPSR & (1 << SPIF))) {}
|
||||||
|
buf[n] = SPDR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline void SdSpiAltDriver::send(uint8_t data) {
|
||||||
|
SPDR = data;
|
||||||
|
while (!(SPSR & (1 << SPIF))) {}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
inline void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
|
||||||
|
if (n == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SPDR = buf[0];
|
||||||
|
if (n > 1) {
|
||||||
|
uint8_t b = buf[1];
|
||||||
|
size_t i = 2;
|
||||||
|
while (1) {
|
||||||
|
while (!(SPSR & (1 << SPIF))) {}
|
||||||
|
SPDR = b;
|
||||||
|
if (i == n) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
b = buf[i++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!(SPSR & (1 << SPIF))) {}
|
||||||
|
}
|
||||||
|
#endif // __AVR__
|
||||||
|
#endif // SdSpiDriver_h
|
104
hardware/_controller/src/SdFat/SpiDriver/SdSpiESP8266.cpp
Normal file
104
hardware/_controller/src/SdFat/SpiDriver/SdSpiESP8266.cpp
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#if defined(ESP8266)
|
||||||
|
#include "SdSpiDriver.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Initialize the SPI bus.
|
||||||
|
*
|
||||||
|
* \param[in] chipSelectPin SD card chip select pin.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::begin(uint8_t csPin) {
|
||||||
|
m_csPin = csPin;
|
||||||
|
pinMode(m_csPin, OUTPUT);
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
SPI.begin();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Set SPI options for access to SD/SDHC cards.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::activate() {
|
||||||
|
SPI.beginTransaction(m_spiSettings);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void SdSpiAltDriver::deactivate() {
|
||||||
|
// Note: endTransaction is an empty function on ESP8266.
|
||||||
|
SPI.endTransaction();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Receive a byte.
|
||||||
|
*
|
||||||
|
* \return The byte.
|
||||||
|
*/
|
||||||
|
uint8_t SdSpiAltDriver::receive() {
|
||||||
|
return SPI.transfer(0XFF);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Receive multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[out] buf Buffer to receive the data.
|
||||||
|
* \param[in] n Number of bytes to receive.
|
||||||
|
*
|
||||||
|
* \return Zero for no error or nonzero error code.
|
||||||
|
*/
|
||||||
|
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
|
||||||
|
// Adjust to 32-bit alignment.
|
||||||
|
while ((reinterpret_cast<uintptr_t>(buf) & 0X3) && n) {
|
||||||
|
*buf++ = SPI.transfer(0xff);
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
// Do multiple of four byte transfers.
|
||||||
|
size_t n4 = 4*(n/4);
|
||||||
|
SPI.transferBytes(0, buf, n4);
|
||||||
|
|
||||||
|
// Transfer up to three remaining bytes.
|
||||||
|
for (buf += n4, n -= n4; n; n--) {
|
||||||
|
*buf++ = SPI.transfer(0xff);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Send a byte.
|
||||||
|
*
|
||||||
|
* \param[in] b Byte to send
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::send(uint8_t b) {
|
||||||
|
SPI.transfer(b);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Send multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[in] buf Buffer for data to be sent.
|
||||||
|
* \param[in] n Number of bytes to send.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
|
||||||
|
// Adjust to 32-bit alignment.
|
||||||
|
while ((reinterpret_cast<uintptr_t>(buf) & 0X3) && n) {
|
||||||
|
SPI.transfer(*buf++);
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
SPI.transferBytes(const_cast<uint8_t*>(buf), 0, n);
|
||||||
|
}
|
||||||
|
#endif // defined(ESP8266)
|
102
hardware/_controller/src/SdFat/SpiDriver/SdSpiParticle.cpp
Normal file
102
hardware/_controller/src/SdFat/SpiDriver/SdSpiParticle.cpp
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#if defined(PLATFORM_ID)
|
||||||
|
#include "SdSpiDriver.h"
|
||||||
|
static volatile bool SPI_DMA_TransferCompleted = false;
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static void SD_SPI_DMA_TransferComplete_Callback(void) {
|
||||||
|
SPI_DMA_TransferCompleted = true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Set SPI options for access to SD/SDHC cards.
|
||||||
|
*
|
||||||
|
* \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::activate() {
|
||||||
|
m_spi->beginTransaction(m_spiSettings);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Initialize the SPI bus.
|
||||||
|
*
|
||||||
|
* \param[in] chipSelectPin SD card chip select pin.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::begin(uint8_t csPin) {
|
||||||
|
m_csPin = csPin;
|
||||||
|
m_spi->begin();
|
||||||
|
pinMode(m_csPin, OUTPUT);
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* End SPI transaction.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::deactivate() {
|
||||||
|
m_spi->endTransaction();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Receive a byte.
|
||||||
|
*
|
||||||
|
* \return The byte.
|
||||||
|
*/
|
||||||
|
uint8_t SdSpiAltDriver::receive() {
|
||||||
|
return m_spi->transfer(0XFF);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Receive multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[out] buf Buffer to receive the data.
|
||||||
|
* \param[in] n Number of bytes to receive.
|
||||||
|
*
|
||||||
|
* \return Zero for no error or nonzero error code.
|
||||||
|
*/
|
||||||
|
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
|
||||||
|
SPI_DMA_TransferCompleted = false;
|
||||||
|
m_spi->transfer(nullptr, buf, n, SD_SPI_DMA_TransferComplete_Callback);
|
||||||
|
while (!SPI_DMA_TransferCompleted) {}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Send a byte.
|
||||||
|
*
|
||||||
|
* \param[in] b Byte to send
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::send(uint8_t b) {
|
||||||
|
m_spi->transfer(b);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Send multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[in] buf Buffer for data to be sent.
|
||||||
|
* \param[in] n Number of bytes to send.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
|
||||||
|
SPI_DMA_TransferCompleted = false;
|
||||||
|
|
||||||
|
m_spi->transfer(const_cast<uint8_t*>(buf), nullptr, n,
|
||||||
|
SD_SPI_DMA_TransferComplete_Callback);
|
||||||
|
|
||||||
|
while (!SPI_DMA_TransferCompleted) {}
|
||||||
|
}
|
||||||
|
#endif // defined(PLATFORM_ID)
|
218
hardware/_controller/src/SdFat/SpiDriver/SdSpiSAM3X.cpp
Normal file
218
hardware/_controller/src/SdFat/SpiDriver/SdSpiSAM3X.cpp
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "SdSpiDriver.h"
|
||||||
|
#if defined(__SAM3X8E__) || defined(__SAM3X8H__)
|
||||||
|
/** Use SAM3X DMAC if nonzero */
|
||||||
|
#define USE_SAM3X_DMAC 1
|
||||||
|
/** Use extra Bus Matrix arbitration fix if nonzero */
|
||||||
|
#define USE_SAM3X_BUS_MATRIX_FIX 0
|
||||||
|
/** Time in ms for DMA receive timeout */
|
||||||
|
#define SAM3X_DMA_TIMEOUT 100
|
||||||
|
/** chip select register number */
|
||||||
|
#define SPI_CHIP_SEL 3
|
||||||
|
/** DMAC receive channel */
|
||||||
|
#define SPI_DMAC_RX_CH 1
|
||||||
|
/** DMAC transmit channel */
|
||||||
|
#define SPI_DMAC_TX_CH 0
|
||||||
|
/** DMAC Channel HW Interface Number for SPI TX. */
|
||||||
|
#define SPI_TX_IDX 1
|
||||||
|
/** DMAC Channel HW Interface Number for SPI RX. */
|
||||||
|
#define SPI_RX_IDX 2
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Disable DMA Controller. */
|
||||||
|
static void dmac_disable() {
|
||||||
|
DMAC->DMAC_EN &= (~DMAC_EN_ENABLE);
|
||||||
|
}
|
||||||
|
/** Enable DMA Controller. */
|
||||||
|
static void dmac_enable() {
|
||||||
|
DMAC->DMAC_EN = DMAC_EN_ENABLE;
|
||||||
|
}
|
||||||
|
/** Disable DMA Channel. */
|
||||||
|
static void dmac_channel_disable(uint32_t ul_num) {
|
||||||
|
DMAC->DMAC_CHDR = DMAC_CHDR_DIS0 << ul_num;
|
||||||
|
}
|
||||||
|
/** Enable DMA Channel. */
|
||||||
|
static void dmac_channel_enable(uint32_t ul_num) {
|
||||||
|
DMAC->DMAC_CHER = DMAC_CHER_ENA0 << ul_num;
|
||||||
|
}
|
||||||
|
/** Poll for transfer complete. */
|
||||||
|
static bool dmac_channel_transfer_done(uint32_t ul_num) {
|
||||||
|
return (DMAC->DMAC_CHSR & (DMAC_CHSR_ENA0 << ul_num)) ? false : true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void SdSpiAltDriver::begin(uint8_t csPin) {
|
||||||
|
m_csPin = csPin;
|
||||||
|
pinMode(m_csPin, OUTPUT);
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
SPI.begin();
|
||||||
|
#if USE_SAM3X_DMAC
|
||||||
|
pmc_enable_periph_clk(ID_DMAC);
|
||||||
|
dmac_disable();
|
||||||
|
DMAC->DMAC_GCFG = DMAC_GCFG_ARB_CFG_FIXED;
|
||||||
|
dmac_enable();
|
||||||
|
#if USE_SAM3X_BUS_MATRIX_FIX
|
||||||
|
MATRIX->MATRIX_WPMR = 0x4d415400;
|
||||||
|
MATRIX->MATRIX_MCFG[1] = 1;
|
||||||
|
MATRIX->MATRIX_MCFG[2] = 1;
|
||||||
|
MATRIX->MATRIX_SCFG[0] = 0x01000010;
|
||||||
|
MATRIX->MATRIX_SCFG[1] = 0x01000010;
|
||||||
|
MATRIX->MATRIX_SCFG[7] = 0x01000010;
|
||||||
|
#endif // USE_SAM3X_BUS_MATRIX_FIX
|
||||||
|
#endif // USE_SAM3X_DMAC
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// start RX DMA
|
||||||
|
static void spiDmaRX(uint8_t* dst, uint16_t count) {
|
||||||
|
dmac_channel_disable(SPI_DMAC_RX_CH);
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_SADDR = (uint32_t)&SPI0->SPI_RDR;
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DADDR = (uint32_t)dst;
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DSCR = 0;
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLA = count |
|
||||||
|
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
|
||||||
|
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
|
||||||
|
DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING;
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CFG = DMAC_CFG_SRC_PER(SPI_RX_IDX) |
|
||||||
|
DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG;
|
||||||
|
dmac_channel_enable(SPI_DMAC_RX_CH);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// start TX DMA
|
||||||
|
static void spiDmaTX(const uint8_t* src, uint16_t count) {
|
||||||
|
static uint8_t ff = 0XFF;
|
||||||
|
uint32_t src_incr = DMAC_CTRLB_SRC_INCR_INCREMENTING;
|
||||||
|
if (!src) {
|
||||||
|
src = &ff;
|
||||||
|
src_incr = DMAC_CTRLB_SRC_INCR_FIXED;
|
||||||
|
}
|
||||||
|
dmac_channel_disable(SPI_DMAC_TX_CH);
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_SADDR = (uint32_t)src;
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DADDR = (uint32_t)&SPI0->SPI_TDR;
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DSCR = 0;
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLA = count |
|
||||||
|
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
|
||||||
|
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
|
||||||
|
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
|
||||||
|
src_incr | DMAC_CTRLB_DST_INCR_FIXED;
|
||||||
|
|
||||||
|
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CFG = DMAC_CFG_DST_PER(SPI_TX_IDX) |
|
||||||
|
DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
|
||||||
|
|
||||||
|
dmac_channel_enable(SPI_DMAC_TX_CH);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// initialize SPI controller
|
||||||
|
void SdSpiAltDriver::activate() {
|
||||||
|
SPI.beginTransaction(m_spiSettings);
|
||||||
|
|
||||||
|
Spi* pSpi = SPI0;
|
||||||
|
// Save the divisor
|
||||||
|
uint32_t scbr = pSpi->SPI_CSR[SPI_CHIP_SEL] & 0XFF00;
|
||||||
|
// Disable SPI
|
||||||
|
pSpi->SPI_CR = SPI_CR_SPIDIS;
|
||||||
|
// reset SPI
|
||||||
|
pSpi->SPI_CR = SPI_CR_SWRST;
|
||||||
|
// no mode fault detection, set master mode
|
||||||
|
pSpi->SPI_MR = SPI_PCS(SPI_CHIP_SEL) | SPI_MR_MODFDIS | SPI_MR_MSTR;
|
||||||
|
// mode 0, 8-bit,
|
||||||
|
pSpi->SPI_CSR[SPI_CHIP_SEL] = scbr | SPI_CSR_CSAAT | SPI_CSR_NCPHA;
|
||||||
|
// enable SPI
|
||||||
|
pSpi->SPI_CR |= SPI_CR_SPIEN;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void SdSpiAltDriver::deactivate() {
|
||||||
|
SPI.endTransaction();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static inline uint8_t spiTransfer(uint8_t b) {
|
||||||
|
Spi* pSpi = SPI0;
|
||||||
|
|
||||||
|
pSpi->SPI_TDR = b;
|
||||||
|
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
|
||||||
|
b = pSpi->SPI_RDR;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI receive a byte */
|
||||||
|
uint8_t SdSpiAltDriver::receive() {
|
||||||
|
return spiTransfer(0XFF);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI receive multiple bytes */
|
||||||
|
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
|
||||||
|
Spi* pSpi = SPI0;
|
||||||
|
int rtn = 0;
|
||||||
|
#if USE_SAM3X_DMAC
|
||||||
|
// clear overrun error
|
||||||
|
pSpi->SPI_SR;
|
||||||
|
|
||||||
|
spiDmaRX(buf, n);
|
||||||
|
spiDmaTX(0, n);
|
||||||
|
|
||||||
|
uint32_t m = millis();
|
||||||
|
while (!dmac_channel_transfer_done(SPI_DMAC_RX_CH)) {
|
||||||
|
if ((millis() - m) > SAM3X_DMA_TIMEOUT) {
|
||||||
|
dmac_channel_disable(SPI_DMAC_RX_CH);
|
||||||
|
dmac_channel_disable(SPI_DMAC_TX_CH);
|
||||||
|
rtn = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pSpi->SPI_SR & SPI_SR_OVRES) {
|
||||||
|
rtn |= 1;
|
||||||
|
}
|
||||||
|
#else // USE_SAM3X_DMAC
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
pSpi->SPI_TDR = 0XFF;
|
||||||
|
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
|
||||||
|
buf[i] = pSpi->SPI_RDR;
|
||||||
|
}
|
||||||
|
#endif // USE_SAM3X_DMAC
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI send a byte */
|
||||||
|
void SdSpiAltDriver::send(uint8_t b) {
|
||||||
|
spiTransfer(b);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
|
||||||
|
Spi* pSpi = SPI0;
|
||||||
|
#if USE_SAM3X_DMAC
|
||||||
|
spiDmaTX(buf, n);
|
||||||
|
while (!dmac_channel_transfer_done(SPI_DMAC_TX_CH)) {}
|
||||||
|
#else // #if USE_SAM3X_DMAC
|
||||||
|
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
pSpi->SPI_TDR = buf[i];
|
||||||
|
while ((pSpi->SPI_SR & SPI_SR_TDRE) == 0) {}
|
||||||
|
}
|
||||||
|
#endif // #if USE_SAM3X_DMAC
|
||||||
|
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
|
||||||
|
// leave RDR empty
|
||||||
|
pSpi->SPI_RDR;
|
||||||
|
}
|
||||||
|
#endif // defined(__SAM3X8E__) || defined(__SAM3X8H__)
|
105
hardware/_controller/src/SdFat/SpiDriver/SdSpiSTM32.cpp
Normal file
105
hardware/_controller/src/SdFat/SpiDriver/SdSpiSTM32.cpp
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#if defined(__STM32F1__) || defined(__STM32F4__)
|
||||||
|
#include "SdSpiDriver.h"
|
||||||
|
#if defined(__STM32F1__)
|
||||||
|
#define USE_STM32_DMA 1
|
||||||
|
#elif defined(__STM32F4__)
|
||||||
|
#define USE_STM32_DMA 1
|
||||||
|
#else // defined(__STM32F1__)
|
||||||
|
#error Unknown STM32 type
|
||||||
|
#endif // defined(__STM32F1__)
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Set SPI options for access to SD/SDHC cards.
|
||||||
|
*
|
||||||
|
* \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::activate() {
|
||||||
|
m_spi->beginTransaction(m_spiSettings);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Initialize the SPI bus.
|
||||||
|
*
|
||||||
|
* \param[in] chipSelectPin SD card chip select pin.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::begin(uint8_t csPin) {
|
||||||
|
m_csPin = csPin;
|
||||||
|
pinMode(m_csPin, OUTPUT);
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
m_spi->begin();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* End SPI transaction.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::deactivate() {
|
||||||
|
m_spi->endTransaction();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Receive a byte.
|
||||||
|
*
|
||||||
|
* \return The byte.
|
||||||
|
*/
|
||||||
|
uint8_t SdSpiAltDriver::receive() {
|
||||||
|
return m_spi->transfer(0XFF);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Receive multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[out] buf Buffer to receive the data.
|
||||||
|
* \param[in] n Number of bytes to receive.
|
||||||
|
*
|
||||||
|
* \return Zero for no error or nonzero error code.
|
||||||
|
*/
|
||||||
|
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
|
||||||
|
#if USE_STM32_DMA
|
||||||
|
return m_spi->dmaTransfer(nullptr, buf, n);
|
||||||
|
#else // USE_STM32_DMA
|
||||||
|
m_spi->read(buf, n);
|
||||||
|
return 0;
|
||||||
|
#endif // USE_STM32_DMA
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Send a byte.
|
||||||
|
*
|
||||||
|
* \param[in] b Byte to send
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::send(uint8_t b) {
|
||||||
|
m_spi->transfer(b);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Send multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[in] buf Buffer for data to be sent.
|
||||||
|
* \param[in] n Number of bytes to send.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
|
||||||
|
#if USE_STM32_DMA
|
||||||
|
m_spi->dmaTransfer(const_cast<uint8*>(buf), nullptr, n);
|
||||||
|
#else // USE_STM32_DMA
|
||||||
|
m_spi->write(const_cast<uint8*>(buf), n);
|
||||||
|
#endif // USE_STM32_DMA
|
||||||
|
}
|
||||||
|
#endif // defined(__STM32F1__) || defined(__STM32F4__)
|
233
hardware/_controller/src/SdFat/SpiDriver/SdSpiTeensy3.cpp
Normal file
233
hardware/_controller/src/SdFat/SpiDriver/SdSpiTeensy3.cpp
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "SdSpiDriver.h"
|
||||||
|
#if defined(__arm__) && defined(CORE_TEENSY)
|
||||||
|
// SPI definitions
|
||||||
|
// #include "kinetis.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void SdSpiAltDriver::activate() {
|
||||||
|
SPI.beginTransaction(m_spiSettings);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void SdSpiAltDriver::begin(uint8_t chipSelectPin) {
|
||||||
|
m_csPin = chipSelectPin;
|
||||||
|
pinMode(m_csPin, OUTPUT);
|
||||||
|
digitalWrite(m_csPin, HIGH);
|
||||||
|
SPI.begin();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void SdSpiAltDriver::deactivate() {
|
||||||
|
SPI.endTransaction();
|
||||||
|
}
|
||||||
|
//==============================================================================
|
||||||
|
#ifdef KINETISK
|
||||||
|
|
||||||
|
// use 16-bit frame if SPI_USE_8BIT_FRAME is zero
|
||||||
|
#define SPI_USE_8BIT_FRAME 0
|
||||||
|
// Limit initial fifo to three entries to avoid fifo overrun
|
||||||
|
#define SPI_INITIAL_FIFO_DEPTH 3
|
||||||
|
// define some symbols that are not in mk20dx128.h
|
||||||
|
#ifndef SPI_SR_RXCTR
|
||||||
|
#define SPI_SR_RXCTR 0XF0
|
||||||
|
#endif // SPI_SR_RXCTR
|
||||||
|
#ifndef SPI_PUSHR_CONT
|
||||||
|
#define SPI_PUSHR_CONT 0X80000000
|
||||||
|
#endif // SPI_PUSHR_CONT
|
||||||
|
#ifndef SPI_PUSHR_CTAS
|
||||||
|
#define SPI_PUSHR_CTAS(n) (((n) & 7) << 28)
|
||||||
|
#endif // SPI_PUSHR_CTAS
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI receive a byte */
|
||||||
|
uint8_t SdSpiAltDriver::receive() {
|
||||||
|
SPI0_MCR |= SPI_MCR_CLR_RXF;
|
||||||
|
SPI0_SR = SPI_SR_TCF;
|
||||||
|
SPI0_PUSHR = 0xFF;
|
||||||
|
while (!(SPI0_SR & SPI_SR_TCF)) {}
|
||||||
|
return SPI0_POPR;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI receive multiple bytes */
|
||||||
|
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
|
||||||
|
// clear any data in RX FIFO
|
||||||
|
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
|
||||||
|
#if SPI_USE_8BIT_FRAME
|
||||||
|
// initial number of bytes to push into TX FIFO
|
||||||
|
int nf = n < SPI_INITIAL_FIFO_DEPTH ? n : SPI_INITIAL_FIFO_DEPTH;
|
||||||
|
for (int i = 0; i < nf; i++) {
|
||||||
|
SPI0_PUSHR = 0XFF;
|
||||||
|
}
|
||||||
|
// limit for pushing dummy data into TX FIFO
|
||||||
|
uint8_t* limit = buf + n - nf;
|
||||||
|
while (buf < limit) {
|
||||||
|
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
|
||||||
|
SPI0_PUSHR = 0XFF;
|
||||||
|
*buf++ = SPI0_POPR;
|
||||||
|
}
|
||||||
|
// limit for rest of RX data
|
||||||
|
limit += nf;
|
||||||
|
while (buf < limit) {
|
||||||
|
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
|
||||||
|
*buf++ = SPI0_POPR;
|
||||||
|
}
|
||||||
|
#else // SPI_USE_8BIT_FRAME
|
||||||
|
// use 16 bit frame to avoid TD delay between frames
|
||||||
|
// get one byte if n is odd
|
||||||
|
if (n & 1) {
|
||||||
|
*buf++ = receive();
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
// initial number of words to push into TX FIFO
|
||||||
|
int nf = n/2 < SPI_INITIAL_FIFO_DEPTH ? n/2 : SPI_INITIAL_FIFO_DEPTH;
|
||||||
|
for (int i = 0; i < nf; i++) {
|
||||||
|
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
|
||||||
|
}
|
||||||
|
uint8_t* limit = buf + n - 2*nf;
|
||||||
|
while (buf < limit) {
|
||||||
|
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
|
||||||
|
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
|
||||||
|
uint16_t w = SPI0_POPR;
|
||||||
|
*buf++ = w >> 8;
|
||||||
|
*buf++ = w & 0XFF;
|
||||||
|
}
|
||||||
|
// limit for rest of RX data
|
||||||
|
limit += 2*nf;
|
||||||
|
while (buf < limit) {
|
||||||
|
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
|
||||||
|
uint16_t w = SPI0_POPR;
|
||||||
|
*buf++ = w >> 8;
|
||||||
|
*buf++ = w & 0XFF;
|
||||||
|
}
|
||||||
|
#endif // SPI_USE_8BIT_FRAME
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI send a byte */
|
||||||
|
void SdSpiAltDriver::send(uint8_t b) {
|
||||||
|
SPI0_MCR |= SPI_MCR_CLR_RXF;
|
||||||
|
SPI0_SR = SPI_SR_TCF;
|
||||||
|
SPI0_PUSHR = b;
|
||||||
|
while (!(SPI0_SR & SPI_SR_TCF)) {}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** SPI send multiple bytes */
|
||||||
|
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
|
||||||
|
// clear any data in RX FIFO
|
||||||
|
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
|
||||||
|
#if SPI_USE_8BIT_FRAME
|
||||||
|
// initial number of bytes to push into TX FIFO
|
||||||
|
int nf = n < SPI_INITIAL_FIFO_DEPTH ? n : SPI_INITIAL_FIFO_DEPTH;
|
||||||
|
// limit for pushing data into TX fifo
|
||||||
|
const uint8_t* limit = buf + n;
|
||||||
|
for (int i = 0; i < nf; i++) {
|
||||||
|
SPI0_PUSHR = *buf++;
|
||||||
|
}
|
||||||
|
// write data to TX FIFO
|
||||||
|
while (buf < limit) {
|
||||||
|
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
|
||||||
|
SPI0_PUSHR = *buf++;
|
||||||
|
SPI0_POPR;
|
||||||
|
}
|
||||||
|
// wait for data to be sent
|
||||||
|
while (nf) {
|
||||||
|
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
|
||||||
|
SPI0_POPR;
|
||||||
|
nf--;
|
||||||
|
}
|
||||||
|
#else // SPI_USE_8BIT_FRAME
|
||||||
|
// use 16 bit frame to avoid TD delay between frames
|
||||||
|
// send one byte if n is odd
|
||||||
|
if (n & 1) {
|
||||||
|
send(*buf++);
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
// initial number of words to push into TX FIFO
|
||||||
|
int nf = n/2 < SPI_INITIAL_FIFO_DEPTH ? n/2 : SPI_INITIAL_FIFO_DEPTH;
|
||||||
|
// limit for pushing data into TX fifo
|
||||||
|
const uint8_t* limit = buf + n;
|
||||||
|
for (int i = 0; i < nf; i++) {
|
||||||
|
uint16_t w = (*buf++) << 8;
|
||||||
|
w |= *buf++;
|
||||||
|
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | w;
|
||||||
|
}
|
||||||
|
// write data to TX FIFO
|
||||||
|
while (buf < limit) {
|
||||||
|
uint16_t w = *buf++ << 8;
|
||||||
|
w |= *buf++;
|
||||||
|
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
|
||||||
|
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | w;
|
||||||
|
SPI0_POPR;
|
||||||
|
}
|
||||||
|
// wait for data to be sent
|
||||||
|
while (nf) {
|
||||||
|
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
|
||||||
|
SPI0_POPR;
|
||||||
|
nf--;
|
||||||
|
}
|
||||||
|
#endif // SPI_USE_8BIT_FRAME
|
||||||
|
}
|
||||||
|
#else // KINETISK
|
||||||
|
//==============================================================================
|
||||||
|
// Use standard SPI library if not KINETISK
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Receive a byte.
|
||||||
|
*
|
||||||
|
* \return The byte.
|
||||||
|
*/
|
||||||
|
uint8_t SdSpiAltDriver::receive() {
|
||||||
|
return SPI.transfer(0XFF);
|
||||||
|
}
|
||||||
|
/** Receive multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[out] buf Buffer to receive the data.
|
||||||
|
* \param[in] n Number of bytes to receive.
|
||||||
|
*
|
||||||
|
* \return Zero for no error or nonzero error code.
|
||||||
|
*/
|
||||||
|
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
buf[i] = SPI.transfer(0XFF);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/** Send a byte.
|
||||||
|
*
|
||||||
|
* \param[in] b Byte to send
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::send(uint8_t b) {
|
||||||
|
SPI.transfer(b);
|
||||||
|
}
|
||||||
|
/** Send multiple bytes.
|
||||||
|
*
|
||||||
|
* \param[in] buf Buffer for data to be sent.
|
||||||
|
* \param[in] n Number of bytes to send.
|
||||||
|
*/
|
||||||
|
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
SPI.transfer(buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // KINETISK
|
||||||
|
#endif // defined(__arm__) && defined(CORE_TEENSY)
|
167
hardware/_controller/src/SdFat/SpiDriver/SoftSPI.h
Normal file
167
hardware/_controller/src/SdFat/SpiDriver/SoftSPI.h
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Software SPI.
|
||||||
|
*
|
||||||
|
* @defgroup softSPI Software SPI
|
||||||
|
* @details Software SPI Template Class.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SoftSPI_h
|
||||||
|
#define SoftSPI_h
|
||||||
|
#include "DigitalPin.h"
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Nop for timing. */
|
||||||
|
#define nop asm volatile ("nop\n\t")
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** Pin Mode for MISO is input.*/
|
||||||
|
#define MISO_MODE INPUT
|
||||||
|
/** Pullups disabled for MISO are disabled. */
|
||||||
|
#define MISO_LEVEL false
|
||||||
|
/** Pin Mode for MOSI is output.*/
|
||||||
|
#define MOSI_MODE OUTPUT
|
||||||
|
/** Pin Mode for SCK is output. */
|
||||||
|
#define SCK_MODE OUTPUT
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* @class SoftSPI
|
||||||
|
* @brief Fast software SPI.
|
||||||
|
*/
|
||||||
|
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin, uint8_t Mode = 0>
|
||||||
|
class SoftSPI {
|
||||||
|
public:
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Initialize SoftSPI pins. */
|
||||||
|
void begin() {
|
||||||
|
fastPinConfig(MisoPin, MISO_MODE, MISO_LEVEL);
|
||||||
|
fastPinConfig(MosiPin, MOSI_MODE, !MODE_CPHA(Mode));
|
||||||
|
fastPinConfig(SckPin, SCK_MODE, MODE_CPOL(Mode));
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Soft SPI receive byte.
|
||||||
|
* @return Data byte received.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
uint8_t receive() {
|
||||||
|
uint8_t data = 0;
|
||||||
|
receiveBit(7, &data);
|
||||||
|
receiveBit(6, &data);
|
||||||
|
receiveBit(5, &data);
|
||||||
|
receiveBit(4, &data);
|
||||||
|
receiveBit(3, &data);
|
||||||
|
receiveBit(2, &data);
|
||||||
|
receiveBit(1, &data);
|
||||||
|
receiveBit(0, &data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Soft SPI send byte.
|
||||||
|
* @param[in] data Data byte to send.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
void send(uint8_t data) {
|
||||||
|
sendBit(7, data);
|
||||||
|
sendBit(6, data);
|
||||||
|
sendBit(5, data);
|
||||||
|
sendBit(4, data);
|
||||||
|
sendBit(3, data);
|
||||||
|
sendBit(2, data);
|
||||||
|
sendBit(1, data);
|
||||||
|
sendBit(0, data);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
/** Soft SPI transfer byte.
|
||||||
|
* @param[in] txData Data byte to send.
|
||||||
|
* @return Data byte received.
|
||||||
|
*/
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
uint8_t transfer(uint8_t txData) {
|
||||||
|
uint8_t rxData = 0;
|
||||||
|
transferBit(7, &rxData, txData);
|
||||||
|
transferBit(6, &rxData, txData);
|
||||||
|
transferBit(5, &rxData, txData);
|
||||||
|
transferBit(4, &rxData, txData);
|
||||||
|
transferBit(3, &rxData, txData);
|
||||||
|
transferBit(2, &rxData, txData);
|
||||||
|
transferBit(1, &rxData, txData);
|
||||||
|
transferBit(0, &rxData, txData);
|
||||||
|
return rxData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
bool MODE_CPHA(uint8_t mode) {return (mode & 1) != 0;}
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
bool MODE_CPOL(uint8_t mode) {return (mode & 2) != 0;}
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
void receiveBit(uint8_t bit, uint8_t* data) {
|
||||||
|
if (MODE_CPHA(Mode)) {
|
||||||
|
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||||
|
}
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
|
fastDigitalWrite(SckPin,
|
||||||
|
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||||
|
if (fastDigitalRead(MisoPin)) *data |= 1 << bit;
|
||||||
|
if (!MODE_CPHA(Mode)) {
|
||||||
|
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
void sendBit(uint8_t bit, uint8_t data) {
|
||||||
|
if (MODE_CPHA(Mode)) {
|
||||||
|
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||||
|
}
|
||||||
|
fastDigitalWrite(MosiPin, data & (1 << bit));
|
||||||
|
fastDigitalWrite(SckPin,
|
||||||
|
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
|
if (!MODE_CPHA(Mode)) {
|
||||||
|
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
inline __attribute__((always_inline))
|
||||||
|
void transferBit(uint8_t bit, uint8_t* rxData, uint8_t txData) {
|
||||||
|
if (MODE_CPHA(Mode)) {
|
||||||
|
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||||
|
}
|
||||||
|
fastDigitalWrite(MosiPin, txData & (1 << bit));
|
||||||
|
fastDigitalWrite(SckPin,
|
||||||
|
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||||
|
if (fastDigitalRead(MisoPin)) *rxData |= 1 << bit;
|
||||||
|
if (!MODE_CPHA(Mode)) {
|
||||||
|
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
};
|
||||||
|
#endif // SoftSPI_h
|
||||||
|
/** @} */
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef AvrDevelopersGpioPinMap_h
|
||||||
|
#define AvrDevelopersGpioPinMap_h
|
||||||
|
static const GpioPinMap_t GpioPinMap[] = {
|
||||||
|
GPIO_PIN(B, 0), // D0
|
||||||
|
GPIO_PIN(B, 1), // D1
|
||||||
|
GPIO_PIN(B, 2), // D2
|
||||||
|
GPIO_PIN(B, 3), // D3
|
||||||
|
GPIO_PIN(B, 4), // D4
|
||||||
|
GPIO_PIN(B, 5), // D5
|
||||||
|
GPIO_PIN(B, 6), // D6
|
||||||
|
GPIO_PIN(B, 7), // D7
|
||||||
|
GPIO_PIN(D, 0), // D8
|
||||||
|
GPIO_PIN(D, 1), // D9
|
||||||
|
GPIO_PIN(D, 2), // D10
|
||||||
|
GPIO_PIN(D, 3), // D11
|
||||||
|
GPIO_PIN(D, 4), // D12
|
||||||
|
GPIO_PIN(D, 5), // D13
|
||||||
|
GPIO_PIN(D, 6), // D14
|
||||||
|
GPIO_PIN(D, 7), // D15
|
||||||
|
GPIO_PIN(C, 0), // D16
|
||||||
|
GPIO_PIN(C, 1), // D17
|
||||||
|
GPIO_PIN(C, 2), // D18
|
||||||
|
GPIO_PIN(C, 3), // D19
|
||||||
|
GPIO_PIN(C, 4), // D20
|
||||||
|
GPIO_PIN(C, 5), // D21
|
||||||
|
GPIO_PIN(C, 6), // D22
|
||||||
|
GPIO_PIN(C, 7), // D23
|
||||||
|
GPIO_PIN(A, 7), // D24
|
||||||
|
GPIO_PIN(A, 6), // D25
|
||||||
|
GPIO_PIN(A, 5), // D26
|
||||||
|
GPIO_PIN(A, 4), // D27
|
||||||
|
GPIO_PIN(A, 3), // D28
|
||||||
|
GPIO_PIN(A, 2), // D29
|
||||||
|
GPIO_PIN(A, 1), // D30
|
||||||
|
GPIO_PIN(A, 0) // D31
|
||||||
|
};
|
||||||
|
#endif // AvrDevelopersGpioPinMap_h
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef BobuinoGpioPinMap_h
|
||||||
|
#define BobuinoGpioPinMap_h
|
||||||
|
static const GpioPinMap_t GpioPinMap[] = {
|
||||||
|
GPIO_PIN(B, 0), // D0
|
||||||
|
GPIO_PIN(B, 1), // D1
|
||||||
|
GPIO_PIN(B, 2), // D2
|
||||||
|
GPIO_PIN(B, 3), // D3
|
||||||
|
GPIO_PIN(B, 4), // D4
|
||||||
|
GPIO_PIN(B, 5), // D5
|
||||||
|
GPIO_PIN(B, 6), // D6
|
||||||
|
GPIO_PIN(B, 7), // D7
|
||||||
|
GPIO_PIN(D, 0), // D8
|
||||||
|
GPIO_PIN(D, 1), // D9
|
||||||
|
GPIO_PIN(D, 2), // D10
|
||||||
|
GPIO_PIN(D, 3), // D11
|
||||||
|
GPIO_PIN(D, 4), // D12
|
||||||
|
GPIO_PIN(D, 5), // D13
|
||||||
|
GPIO_PIN(D, 6), // D14
|
||||||
|
GPIO_PIN(D, 7), // D15
|
||||||
|
GPIO_PIN(C, 0), // D16
|
||||||
|
GPIO_PIN(C, 1), // D17
|
||||||
|
GPIO_PIN(C, 2), // D18
|
||||||
|
GPIO_PIN(C, 3), // D19
|
||||||
|
GPIO_PIN(C, 4), // D20
|
||||||
|
GPIO_PIN(C, 5), // D21
|
||||||
|
GPIO_PIN(C, 6), // D22
|
||||||
|
GPIO_PIN(C, 7), // D23
|
||||||
|
GPIO_PIN(A, 0), // D24
|
||||||
|
GPIO_PIN(A, 1), // D25
|
||||||
|
GPIO_PIN(A, 2), // D26
|
||||||
|
GPIO_PIN(A, 3), // D27
|
||||||
|
GPIO_PIN(A, 4), // D28
|
||||||
|
GPIO_PIN(A, 5), // D29
|
||||||
|
GPIO_PIN(A, 6), // D30
|
||||||
|
GPIO_PIN(A, 7) // D31
|
||||||
|
};
|
||||||
|
#endif // BobuinoGpioPinMap_h
|
45
hardware/_controller/src/SdFat/SpiDriver/boards/GpioPinMap.h
Normal file
45
hardware/_controller/src/SdFat/SpiDriver/boards/GpioPinMap.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef GpioPinMap_h
|
||||||
|
#define GpioPinMap_h
|
||||||
|
#if defined(__AVR_ATmega168__)\
|
||||||
|
||defined(__AVR_ATmega168P__)\
|
||||||
|
||defined(__AVR_ATmega328P__)
|
||||||
|
// 168 and 328 Arduinos
|
||||||
|
#include "UnoGpioPinMap.h"
|
||||||
|
#elif defined(__AVR_ATmega1280__)\
|
||||||
|
|| defined(__AVR_ATmega2560__)
|
||||||
|
// Mega ADK
|
||||||
|
#include "MegaGpioPinMap.h"
|
||||||
|
#elif defined(__AVR_ATmega32U4__)
|
||||||
|
#ifdef CORE_TEENSY
|
||||||
|
#include "Teensy2GpioPinMap.h"
|
||||||
|
#else // CORE_TEENSY
|
||||||
|
// Leonardo or Yun
|
||||||
|
#include "LeonardoGpioPinMap.h"
|
||||||
|
#endif // CORE_TEENSY
|
||||||
|
#elif defined(__AVR_AT90USB646__)\
|
||||||
|
|| defined(__AVR_AT90USB1286__)
|
||||||
|
// Teensy++ 1.0 & 2.0
|
||||||
|
#include "Teensy2ppGpioPinMap.h"
|
||||||
|
#elif defined(__AVR_ATmega1284P__)\
|
||||||
|
|| defined(__AVR_ATmega1284__)\
|
||||||
|
|| defined(__AVR_ATmega644P__)\
|
||||||
|
|| defined(__AVR_ATmega644__)\
|
||||||
|
|| defined(__AVR_ATmega64__)\
|
||||||
|
|| defined(__AVR_ATmega32__)\
|
||||||
|
|| defined(__AVR_ATmega324__)\
|
||||||
|
|| defined(__AVR_ATmega16__)
|
||||||
|
#ifdef ARDUINO_1284P_AVR_DEVELOPERS
|
||||||
|
#include "AvrDevelopersGpioPinMap.h"
|
||||||
|
#elif defined(BOBUINO_PINOUT) || defined(ARDUINO_1284P_BOBUINO)
|
||||||
|
#include "BobuinoGpioPinMap.h"
|
||||||
|
#elif defined(ARDUINO_1284P_SLEEPINGBEAUTY)
|
||||||
|
#include "SleepingBeautyGpioPinMap.h"
|
||||||
|
#elif defined(STANDARD_PINOUT) || defined(ARDUINO_1284P_STANDARD)
|
||||||
|
#include "Standard1284GpioPinMap.h"
|
||||||
|
#else // ARDUINO_1284P_AVR_DEVELOPERS
|
||||||
|
#error Undefined variant 1284, 644, 324
|
||||||
|
#endif // ARDUINO_1284P_AVR_DEVELOPERS
|
||||||
|
#else // 1284P, 1284, 644
|
||||||
|
#error Unknown board type.
|
||||||
|
#endif // end all boards
|
||||||
|
#endif // GpioPinMap_h
|
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef LeonardoGpioPinMap_h
|
||||||
|
#define LeonardoGpioPinMap_h
|
||||||
|
static const GpioPinMap_t GpioPinMap[] = {
|
||||||
|
GPIO_PIN(D, 2), // D0
|
||||||
|
GPIO_PIN(D, 3), // D1
|
||||||
|
GPIO_PIN(D, 1), // D2
|
||||||
|
GPIO_PIN(D, 0), // D3
|
||||||
|
GPIO_PIN(D, 4), // D4
|
||||||
|
GPIO_PIN(C, 6), // D5
|
||||||
|
GPIO_PIN(D, 7), // D6
|
||||||
|
GPIO_PIN(E, 6), // D7
|
||||||
|
GPIO_PIN(B, 4), // D8
|
||||||
|
GPIO_PIN(B, 5), // D9
|
||||||
|
GPIO_PIN(B, 6), // D10
|
||||||
|
GPIO_PIN(B, 7), // D11
|
||||||
|
GPIO_PIN(D, 6), // D12
|
||||||
|
GPIO_PIN(C, 7), // D13
|
||||||
|
GPIO_PIN(B, 3), // D14
|
||||||
|
GPIO_PIN(B, 1), // D15
|
||||||
|
GPIO_PIN(B, 2), // D16
|
||||||
|
GPIO_PIN(B, 0), // D17
|
||||||
|
GPIO_PIN(F, 7), // D18
|
||||||
|
GPIO_PIN(F, 6), // D19
|
||||||
|
GPIO_PIN(F, 5), // D20
|
||||||
|
GPIO_PIN(F, 4), // D21
|
||||||
|
GPIO_PIN(F, 1), // D22
|
||||||
|
GPIO_PIN(F, 0), // D23
|
||||||
|
GPIO_PIN(D, 4), // D24
|
||||||
|
GPIO_PIN(D, 7), // D25
|
||||||
|
GPIO_PIN(B, 4), // D26
|
||||||
|
GPIO_PIN(B, 5), // D27
|
||||||
|
GPIO_PIN(B, 6), // D28
|
||||||
|
GPIO_PIN(D, 6) // D29
|
||||||
|
};
|
||||||
|
#endif // LeonardoGpioPinMap_h
|
|
@ -0,0 +1,75 @@
|
||||||
|
#ifndef MegaGpioPinMap_h
|
||||||
|
#define MegaGpioPinMap_h
|
||||||
|
static const GpioPinMap_t GpioPinMap[] = {
|
||||||
|
GPIO_PIN(E, 0), // D0
|
||||||
|
GPIO_PIN(E, 1), // D1
|
||||||
|
GPIO_PIN(E, 4), // D2
|
||||||
|
GPIO_PIN(E, 5), // D3
|
||||||
|
GPIO_PIN(G, 5), // D4
|
||||||
|
GPIO_PIN(E, 3), // D5
|
||||||
|
GPIO_PIN(H, 3), // D6
|
||||||
|
GPIO_PIN(H, 4), // D7
|
||||||
|
GPIO_PIN(H, 5), // D8
|
||||||
|
GPIO_PIN(H, 6), // D9
|
||||||
|
GPIO_PIN(B, 4), // D10
|
||||||
|
GPIO_PIN(B, 5), // D11
|
||||||
|
GPIO_PIN(B, 6), // D12
|
||||||
|
GPIO_PIN(B, 7), // D13
|
||||||
|
GPIO_PIN(J, 1), // D14
|
||||||
|
GPIO_PIN(J, 0), // D15
|
||||||
|
GPIO_PIN(H, 1), // D16
|
||||||
|
GPIO_PIN(H, 0), // D17
|
||||||
|
GPIO_PIN(D, 3), // D18
|
||||||
|
GPIO_PIN(D, 2), // D19
|
||||||
|
GPIO_PIN(D, 1), // D20
|
||||||
|
GPIO_PIN(D, 0), // D21
|
||||||
|
GPIO_PIN(A, 0), // D22
|
||||||
|
GPIO_PIN(A, 1), // D23
|
||||||
|
GPIO_PIN(A, 2), // D24
|
||||||
|
GPIO_PIN(A, 3), // D25
|
||||||
|
GPIO_PIN(A, 4), // D26
|
||||||
|
GPIO_PIN(A, 5), // D27
|
||||||
|
GPIO_PIN(A, 6), // D28
|
||||||
|
GPIO_PIN(A, 7), // D29
|
||||||
|
GPIO_PIN(C, 7), // D30
|
||||||
|
GPIO_PIN(C, 6), // D31
|
||||||
|
GPIO_PIN(C, 5), // D32
|
||||||
|
GPIO_PIN(C, 4), // D33
|
||||||
|
GPIO_PIN(C, 3), // D34
|
||||||
|
GPIO_PIN(C, 2), // D35
|
||||||
|
GPIO_PIN(C, 1), // D36
|
||||||
|
GPIO_PIN(C, 0), // D37
|
||||||
|
GPIO_PIN(D, 7), // D38
|
||||||
|
GPIO_PIN(G, 2), // D39
|
||||||
|
GPIO_PIN(G, 1), // D40
|
||||||
|
GPIO_PIN(G, 0), // D41
|
||||||
|
GPIO_PIN(L, 7), // D42
|
||||||
|
GPIO_PIN(L, 6), // D43
|
||||||
|
GPIO_PIN(L, 5), // D44
|
||||||
|
GPIO_PIN(L, 4), // D45
|
||||||
|
GPIO_PIN(L, 3), // D46
|
||||||
|
GPIO_PIN(L, 2), // D47
|
||||||
|
GPIO_PIN(L, 1), // D48
|
||||||
|
GPIO_PIN(L, 0), // D49
|
||||||
|
GPIO_PIN(B, 3), // D50
|
||||||
|
GPIO_PIN(B, 2), // D51
|
||||||
|
GPIO_PIN(B, 1), // D52
|
||||||
|
GPIO_PIN(B, 0), // D53
|
||||||
|
GPIO_PIN(F, 0), // D54
|
||||||
|
GPIO_PIN(F, 1), // D55
|
||||||
|
GPIO_PIN(F, 2), // D56
|
||||||
|
GPIO_PIN(F, 3), // D57
|
||||||
|
GPIO_PIN(F, 4), // D58
|
||||||
|
GPIO_PIN(F, 5), // D59
|
||||||
|
GPIO_PIN(F, 6), // D60
|
||||||
|
GPIO_PIN(F, 7), // D61
|
||||||
|
GPIO_PIN(K, 0), // D62
|
||||||
|
GPIO_PIN(K, 1), // D63
|
||||||
|
GPIO_PIN(K, 2), // D64
|
||||||
|
GPIO_PIN(K, 3), // D65
|
||||||
|
GPIO_PIN(K, 4), // D66
|
||||||
|
GPIO_PIN(K, 5), // D67
|
||||||
|
GPIO_PIN(K, 6), // D68
|
||||||
|
GPIO_PIN(K, 7) // D69
|
||||||
|
};
|
||||||
|
#endif // MegaGpioPinMap_h
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef SleepingBeautyGpioPinMap_h
|
||||||
|
#define SleepingBeautyGpioPinMap_h
|
||||||
|
static const GpioPinMap_t GpioPinMap[] = {
|
||||||
|
GPIO_PIN(D, 0), // D0
|
||||||
|
GPIO_PIN(D, 1), // D1
|
||||||
|
GPIO_PIN(D, 2), // D2
|
||||||
|
GPIO_PIN(D, 3), // D3
|
||||||
|
GPIO_PIN(B, 0), // D4
|
||||||
|
GPIO_PIN(B, 1), // D5
|
||||||
|
GPIO_PIN(B, 2), // D6
|
||||||
|
GPIO_PIN(B, 3), // D7
|
||||||
|
GPIO_PIN(D, 6), // D8
|
||||||
|
GPIO_PIN(D, 5), // D9
|
||||||
|
GPIO_PIN(B, 4), // D10
|
||||||
|
GPIO_PIN(B, 5), // D11
|
||||||
|
GPIO_PIN(B, 6), // D12
|
||||||
|
GPIO_PIN(B, 7), // D13
|
||||||
|
GPIO_PIN(C, 7), // D14
|
||||||
|
GPIO_PIN(C, 6), // D15
|
||||||
|
GPIO_PIN(A, 5), // D16
|
||||||
|
GPIO_PIN(A, 4), // D17
|
||||||
|
GPIO_PIN(A, 3), // D18
|
||||||
|
GPIO_PIN(A, 2), // D19
|
||||||
|
GPIO_PIN(A, 1), // D20
|
||||||
|
GPIO_PIN(A, 0), // D21
|
||||||
|
GPIO_PIN(D, 4), // D22
|
||||||
|
GPIO_PIN(D, 7), // D23
|
||||||
|
GPIO_PIN(C, 2), // D24
|
||||||
|
GPIO_PIN(C, 3), // D25
|
||||||
|
GPIO_PIN(C, 4), // D26
|
||||||
|
GPIO_PIN(C, 5), // D27
|
||||||
|
GPIO_PIN(C, 1), // D28
|
||||||
|
GPIO_PIN(C, 0), // D29
|
||||||
|
GPIO_PIN(A, 6), // D30
|
||||||
|
GPIO_PIN(A, 7) // D31
|
||||||
|
};
|
||||||
|
#endif // SleepingBeautyGpioPinMap_h
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef Standard1284GpioPinMap_h
|
||||||
|
#define Standard1284GpioPinMap_h
|
||||||
|
static const GpioPinMap_t GpioPinMap[] = {
|
||||||
|
GPIO_PIN(B, 0), // D0
|
||||||
|
GPIO_PIN(B, 1), // D1
|
||||||
|
GPIO_PIN(B, 2), // D2
|
||||||
|
GPIO_PIN(B, 3), // D3
|
||||||
|
GPIO_PIN(B, 4), // D4
|
||||||
|
GPIO_PIN(B, 5), // D5
|
||||||
|
GPIO_PIN(B, 6), // D6
|
||||||
|
GPIO_PIN(B, 7), // D7
|
||||||
|
GPIO_PIN(D, 0), // D8
|
||||||
|
GPIO_PIN(D, 1), // D9
|
||||||
|
GPIO_PIN(D, 2), // D10
|
||||||
|
GPIO_PIN(D, 3), // D11
|
||||||
|
GPIO_PIN(D, 4), // D12
|
||||||
|
GPIO_PIN(D, 5), // D13
|
||||||
|
GPIO_PIN(D, 6), // D14
|
||||||
|
GPIO_PIN(D, 7), // D15
|
||||||
|
GPIO_PIN(C, 0), // D16
|
||||||
|
GPIO_PIN(C, 1), // D17
|
||||||
|
GPIO_PIN(C, 2), // D18
|
||||||
|
GPIO_PIN(C, 3), // D19
|
||||||
|
GPIO_PIN(C, 4), // D20
|
||||||
|
GPIO_PIN(C, 5), // D21
|
||||||
|
GPIO_PIN(C, 6), // D22
|
||||||
|
GPIO_PIN(C, 7), // D23
|
||||||
|
GPIO_PIN(A, 0), // D24
|
||||||
|
GPIO_PIN(A, 1), // D25
|
||||||
|
GPIO_PIN(A, 2), // D26
|
||||||
|
GPIO_PIN(A, 3), // D27
|
||||||
|
GPIO_PIN(A, 4), // D28
|
||||||
|
GPIO_PIN(A, 5), // D29
|
||||||
|
GPIO_PIN(A, 6), // D30
|
||||||
|
GPIO_PIN(A, 7) // D31
|
||||||
|
};
|
||||||
|
#endif // Standard1284GpioPinMap_h
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef Teensy2GpioPinMap_h
|
||||||
|
#define Teensy2GpioPinMap_h
|
||||||
|
static const GpioPinMap_t GpioPinMap[] = {
|
||||||
|
GPIO_PIN(B, 0), // D0
|
||||||
|
GPIO_PIN(B, 1), // D1
|
||||||
|
GPIO_PIN(B, 2), // D2
|
||||||
|
GPIO_PIN(B, 3), // D3
|
||||||
|
GPIO_PIN(B, 7), // D4
|
||||||
|
GPIO_PIN(D, 0), // D5
|
||||||
|
GPIO_PIN(D, 1), // D6
|
||||||
|
GPIO_PIN(D, 2), // D7
|
||||||
|
GPIO_PIN(D, 3), // D8
|
||||||
|
GPIO_PIN(C, 6), // D9
|
||||||
|
GPIO_PIN(C, 7), // D10
|
||||||
|
GPIO_PIN(D, 6), // D11
|
||||||
|
GPIO_PIN(D, 7), // D12
|
||||||
|
GPIO_PIN(B, 4), // D13
|
||||||
|
GPIO_PIN(B, 5), // D14
|
||||||
|
GPIO_PIN(B, 6), // D15
|
||||||
|
GPIO_PIN(F, 7), // D16
|
||||||
|
GPIO_PIN(F, 6), // D17
|
||||||
|
GPIO_PIN(F, 5), // D18
|
||||||
|
GPIO_PIN(F, 4), // D19
|
||||||
|
GPIO_PIN(F, 1), // D20
|
||||||
|
GPIO_PIN(F, 0), // D21
|
||||||
|
GPIO_PIN(D, 4), // D22
|
||||||
|
GPIO_PIN(D, 5), // D23
|
||||||
|
GPIO_PIN(E, 6), // D24
|
||||||
|
};
|
||||||
|
#endif // Teensy2GpioPinMap_h
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef Teensypp2GpioPinMap_h
|
||||||
|
#define Teensypp2GpioPinMap_h
|
||||||
|
static const GpioPinMap_t GpioPinMap[] = {
|
||||||
|
GPIO_PIN(D, 0), // D0
|
||||||
|
GPIO_PIN(D, 1), // D1
|
||||||
|
GPIO_PIN(D, 2), // D2
|
||||||
|
GPIO_PIN(D, 3), // D3
|
||||||
|
GPIO_PIN(D, 4), // D4
|
||||||
|
GPIO_PIN(D, 5), // D5
|
||||||
|
GPIO_PIN(D, 6), // D6
|
||||||
|
GPIO_PIN(D, 7), // D7
|
||||||
|
GPIO_PIN(E, 0), // D8
|
||||||
|
GPIO_PIN(E, 1), // D9
|
||||||
|
GPIO_PIN(C, 0), // D10
|
||||||
|
GPIO_PIN(C, 1), // D11
|
||||||
|
GPIO_PIN(C, 2), // D12
|
||||||
|
GPIO_PIN(C, 3), // D13
|
||||||
|
GPIO_PIN(C, 4), // D14
|
||||||
|
GPIO_PIN(C, 5), // D15
|
||||||
|
GPIO_PIN(C, 6), // D16
|
||||||
|
GPIO_PIN(C, 7), // D17
|
||||||
|
GPIO_PIN(E, 6), // D18
|
||||||
|
GPIO_PIN(E, 7), // D19
|
||||||
|
GPIO_PIN(B, 0), // D20
|
||||||
|
GPIO_PIN(B, 1), // D21
|
||||||
|
GPIO_PIN(B, 2), // D22
|
||||||
|
GPIO_PIN(B, 3), // D23
|
||||||
|
GPIO_PIN(B, 4), // D24
|
||||||
|
GPIO_PIN(B, 5), // D25
|
||||||
|
GPIO_PIN(B, 6), // D26
|
||||||
|
GPIO_PIN(B, 7), // D27
|
||||||
|
GPIO_PIN(A, 0), // D28
|
||||||
|
GPIO_PIN(A, 1), // D29
|
||||||
|
GPIO_PIN(A, 2), // D30
|
||||||
|
GPIO_PIN(A, 3), // D31
|
||||||
|
GPIO_PIN(A, 4), // D32
|
||||||
|
GPIO_PIN(A, 5), // D33
|
||||||
|
GPIO_PIN(A, 6), // D34
|
||||||
|
GPIO_PIN(A, 7), // D35
|
||||||
|
GPIO_PIN(E, 4), // D36
|
||||||
|
GPIO_PIN(E, 5), // D37
|
||||||
|
GPIO_PIN(F, 0), // D38
|
||||||
|
GPIO_PIN(F, 1), // D39
|
||||||
|
GPIO_PIN(F, 2), // D40
|
||||||
|
GPIO_PIN(F, 3), // D41
|
||||||
|
GPIO_PIN(F, 4), // D42
|
||||||
|
GPIO_PIN(F, 5), // D43
|
||||||
|
GPIO_PIN(F, 6), // D44
|
||||||
|
GPIO_PIN(F, 7), // D45
|
||||||
|
};
|
||||||
|
#endif // Teensypp2GpioPinMap_h
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef UnoGpioPinMap_h
|
||||||
|
#define UnoGpioPinMap_h
|
||||||
|
static const GpioPinMap_t GpioPinMap[] = {
|
||||||
|
GPIO_PIN(D, 0), // D0
|
||||||
|
GPIO_PIN(D, 1), // D1
|
||||||
|
GPIO_PIN(D, 2), // D2
|
||||||
|
GPIO_PIN(D, 3), // D3
|
||||||
|
GPIO_PIN(D, 4), // D4
|
||||||
|
GPIO_PIN(D, 5), // D5
|
||||||
|
GPIO_PIN(D, 6), // D6
|
||||||
|
GPIO_PIN(D, 7), // D7
|
||||||
|
GPIO_PIN(B, 0), // D8
|
||||||
|
GPIO_PIN(B, 1), // D9
|
||||||
|
GPIO_PIN(B, 2), // D10
|
||||||
|
GPIO_PIN(B, 3), // D11
|
||||||
|
GPIO_PIN(B, 4), // D12
|
||||||
|
GPIO_PIN(B, 5), // D13
|
||||||
|
GPIO_PIN(C, 0), // D14
|
||||||
|
GPIO_PIN(C, 1), // D15
|
||||||
|
GPIO_PIN(C, 2), // D16
|
||||||
|
GPIO_PIN(C, 3), // D17
|
||||||
|
GPIO_PIN(C, 4), // D18
|
||||||
|
GPIO_PIN(C, 5) // D19
|
||||||
|
};
|
||||||
|
#endif // UnoGpioPinMap_h
|
88
hardware/_controller/src/SdFat/SysCall.h
Normal file
88
hardware/_controller/src/SdFat/SysCall.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SysCall_h
|
||||||
|
#define SysCall_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief SysCall class
|
||||||
|
*/
|
||||||
|
#if defined(ARDUINO)
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#elif defined(PLATFORM_ID) // Only defined if a Particle device
|
||||||
|
#include "application.h"
|
||||||
|
#else // defined(ARDUINO)
|
||||||
|
#error "Unknown system"
|
||||||
|
#endif // defined(ARDUINO)
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#ifdef ESP8266
|
||||||
|
// undefine F macro if ESP8266.
|
||||||
|
#undef F
|
||||||
|
#endif // ESP8266
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
#ifndef F
|
||||||
|
/** Define macro for strings stored in flash. */
|
||||||
|
#define F(str) (str)
|
||||||
|
#endif // F
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/** \return the time in milliseconds. */
|
||||||
|
inline uint16_t curTimeMS() {
|
||||||
|
return millis();
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* \class SysCall
|
||||||
|
* \brief SysCall - Class to wrap system calls.
|
||||||
|
*/
|
||||||
|
class SysCall {
|
||||||
|
public:
|
||||||
|
/** Halt execution of this thread. */
|
||||||
|
static void halt() {
|
||||||
|
while (1) {
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** Yield to other threads. */
|
||||||
|
static void yield();
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(ESP8266)
|
||||||
|
inline void SysCall::yield() {
|
||||||
|
// Avoid ESP8266 bug
|
||||||
|
delay(0);
|
||||||
|
}
|
||||||
|
#elif defined(ARDUINO)
|
||||||
|
inline void SysCall::yield() {
|
||||||
|
// Use the external Arduino yield() function.
|
||||||
|
::yield();
|
||||||
|
}
|
||||||
|
#elif defined(PLATFORM_ID) // Only defined if a Particle device
|
||||||
|
inline void SysCall::yield() {
|
||||||
|
Particle.process();
|
||||||
|
}
|
||||||
|
#else // ESP8266
|
||||||
|
inline void SysCall::yield() {}
|
||||||
|
#endif // ESP8266
|
||||||
|
#endif // SysCall_h
|
33
hardware/_controller/src/SdFat/sdios.h
Normal file
33
hardware/_controller/src/SdFat/sdios.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2011-2018 Bill Greiman
|
||||||
|
* This file is part of the SdFat library for SD memory cards.
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef sdios_h
|
||||||
|
#define sdios_h
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \brief C++ IO Streams features.
|
||||||
|
*/
|
||||||
|
#include "FatLib/fstream.h"
|
||||||
|
#include "FatLib/ArduinoStream.h"
|
||||||
|
#endif // sdios_h
|
|
@ -177,7 +177,7 @@
|
||||||
// - To support SW SPI interface, need to make mod to SdFat lib:
|
// - To support SW SPI interface, need to make mod to SdFat lib:
|
||||||
// - Arduino\libraries\SdFat\src\SdFatConfig.h:
|
// - Arduino\libraries\SdFat\src\SdFatConfig.h:
|
||||||
// - #define ENABLE_SOFTWARE_SPI_CLASS 1 // Change default from 0 to 1
|
// - #define ENABLE_SOFTWARE_SPI_CLASS 1 // Change default from 0 to 1
|
||||||
#include <SdFat.h>
|
#include "../SdFat/SdFat.h"
|
||||||
SdFatSoftSpi<12, 11, 13> SD; // FIXME: Add configurability
|
SdFatSoftSpi<12, 11, 13> SD; // FIXME: Add configurability
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -146,7 +146,7 @@ extern "C" {
|
||||||
// - Note that the inclusion of the SD library consumes considerable
|
// - Note that the inclusion of the SD library consumes considerable
|
||||||
// RAM and flash memory which could be problematic for Arduino models
|
// RAM and flash memory which could be problematic for Arduino models
|
||||||
// with limited resources.
|
// with limited resources.
|
||||||
#define GSLC_SD_EN 0
|
#define GSLC_SD_EN 2
|
||||||
|
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
|
@ -185,7 +185,7 @@ extern "C" {
|
||||||
// - Note that the inclusion of the SD library consumes considerable
|
// - Note that the inclusion of the SD library consumes considerable
|
||||||
// RAM and flash memory which could be problematic for Arduino models
|
// RAM and flash memory which could be problematic for Arduino models
|
||||||
// with limited resources.
|
// with limited resources.
|
||||||
#define GSLC_SD_EN 0
|
#define GSLC_SD_EN 2
|
||||||
|
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
Reference in a new issue