Restructure for RTOS use, getName mods, bug fixes

This commit is contained in:
Bill Greiman 2021-11-24 05:30:36 -08:00
parent fb7415151b
commit bab0061a51
60 changed files with 678 additions and 283 deletions

Binary file not shown.

View file

@ -1,10 +1,10 @@
name=SdFat
version=2.1.1
version=2.1.2
license=MIT
author=Bill Greiman <fat16lib@sbcglobal.net>
maintainer=Bill Greiman <fat16lib@sbcglobal.net>
sentence=FAT16/FAT32/exFAT file system.
paragraph=FAT16/FAT32/exFAT file system.
sentence=Provides access to SD memory cards.
paragraph=The SdFat library supports FAT16, FAT32, and exFAT file systems on Standard SD, SDHC, and SDXC cards.
category=Data Storage
url=https://github.com/greiman/SdFat
repository=https://github.com/greiman/SdFat.git

View file

@ -26,8 +26,8 @@
#define ExFatConfig_h
#include "SdFatConfig.h"
#ifndef READ_ONLY
#define READ_ONLY 0
#endif // READ_ONLY
#ifndef EXFAT_READ_ONLY
#define EXFAT_READ_ONLY 0
#endif // EXFAT_READ_ONLY
#endif // ExFatConfig_h

View file

@ -361,13 +361,13 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
}
// Write, truncate, or at end is an error for a directory or read-only file.
if ((oflag & (O_TRUNC | O_AT_END)) || (m_flags & FILE_FLAG_WRITE)) {
if (isSubDir() || isReadOnly() || READ_ONLY) {
if (isSubDir() || isReadOnly() || EXFAT_READ_ONLY) {
DBG_FAIL_MACRO;
goto fail;
}
}
#if !READ_ONLY
#if !EXFAT_READ_ONLY
if (oflag & O_TRUNC) {
if (!(m_flags & FILE_FLAG_WRITE)) {
DBG_FAIL_MACRO;
@ -381,14 +381,14 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
DBG_FAIL_MACRO;
goto fail;
}
#endif // !READ_ONLY
#endif // !EXFAT_READ_ONLY
return true;
create:
#if READ_ONLY
#if EXFAT_READ_ONLY
DBG_FAIL_MACRO;
goto fail;
#else // READ_ONLY
#else // EXFAT_READ_ONLY
// don't create unless O_CREAT and write
if (!(oflag & O_CREAT) || !(modeFlags & FILE_FLAG_WRITE) || !fname) {
DBG_WARN_MACRO;
@ -471,7 +471,7 @@ bool ExFatFile::openPrivate(ExFatFile* dir, ExName_t* fname, oflag_t oflag) {
}
}
return sync();
#endif // READ_ONLY
#endif // EXFAT_READ_ONLY
fail:
// close file

View file

@ -250,7 +250,7 @@ class ExFatFile {
return isOpen() ? m_error & WRITE_ERROR : true;
}
/**
* Check for BlockDevice busy.
* Check for FsBlockDevice busy.
*
* \return true if busy else false.
*/

View file

@ -26,7 +26,7 @@
#include "../common/DebugMacros.h"
#include "ExFatLib.h"
//==============================================================================
#if READ_ONLY
#if EXFAT_READ_ONLY
bool ExFatFile::mkdir(ExFatFile* parent, const char* path, bool pFlag) {
(void) parent;
(void)path;
@ -58,7 +58,7 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) {
return false;
}
//==============================================================================
#else // READ_ONLY
#else // EXFAT_READ_ONLY
//------------------------------------------------------------------------------
static uint16_t exFatDirChecksum(const uint8_t* data, uint16_t checksum) {
bool skip = data[0] == EXFAT_TYPE_FILE;
@ -753,4 +753,4 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) {
m_error |= WRITE_ERROR;
return 0;
}
#endif // READ_ONLY
#endif // EXFAT_READ_ONLY

View file

@ -46,7 +46,7 @@ const uint32_t ROOT_CLUSTER = 4;
#define writeMsg(pr, str) if (pr) pr->write(str)
#endif // PRINT_FORMAT_PROGRESS
//------------------------------------------------------------------------------
bool ExFatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) {
bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
#if !PRINT_FORMAT_PROGRESS
(void)pr;
#endif // !PRINT_FORMAT_PROGRESS

View file

@ -24,7 +24,7 @@
*/
#ifndef ExFatFormatter_h
#define ExFatFormatter_h
#include "../common/BlockDevice.h"
#include "../common/FsBlockDevice.h"
/**
* \class ExFatFormatter
* \brief Format an exFAT volume.
@ -40,7 +40,7 @@ class ExFatFormatter {
*
* \return true for success or false for failure.
*/
bool format(BlockDevice* dev, uint8_t* secBuf, print_t* pr = nullptr);
bool format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr = nullptr);
private:
bool syncUpcase();
bool writeUpcase(uint32_t sector);
@ -49,7 +49,7 @@ class ExFatFormatter {
uint32_t m_upcaseSector;
uint32_t m_upcaseChecksum;
uint32_t m_upcaseSize;
BlockDevice* m_dev;
FsBlockDevice* m_dev;
uint8_t* m_secBuf;
};
#endif // ExFatFormatter_h

View file

@ -83,9 +83,13 @@ size_t ExFatFile::getName7(char* name, size_t count) {
}
for (uint8_t in = 0; in < 15; in++) {
uint16_t c = getLe16(dn->unicode + 2*in);
if (c == 0 || (n + 1) >= count) {
if (c == 0) {
goto done;
}
if ((n + 1) >= count) {
DBG_FAIL_MACRO;
goto fail;
}
name[n++] = c < 0X7F ? c : '?';
}
}
@ -140,8 +144,8 @@ size_t ExFatFile::getName8(char* name, size_t count) {
// Save space for zero byte.
ptr = FsUtf::cpToMb(cp, str, end - 1);
if (!ptr) {
// Truncate name. Could goto fail.
goto done;
DBG_FAIL_MACRO;
goto fail;
}
str = ptr;
}

View file

@ -266,7 +266,7 @@ uint32_t ExFatPartition::freeClusterCount() {
}
}
//------------------------------------------------------------------------------
bool ExFatPartition::init(BlockDevice* dev, uint8_t part) {
bool ExFatPartition::init(FsBlockDevice* dev, uint8_t part) {
uint32_t volStart = 0;
uint8_t* cache;
pbs_t* pbs;

View file

@ -29,10 +29,13 @@
* \brief ExFatPartition include file.
*/
#include "../common/SysCall.h"
#include "../common/BlockDevice.h"
#include "../common/FsBlockDevice.h"
#include "../common/FsCache.h"
#include "../common/FsStructs.h"
#include "ExFatConfig.h"
/** Set EXFAT_READ_ONLY non-zero for read only */
#ifndef EXFAT_READ_ONLY
#define EXFAT_READ_ONLY 0
#endif // EXFAT_READ_ONLY
/** Type for exFAT partition */
const uint8_t FAT_TYPE_EXFAT = 64;
@ -79,6 +82,13 @@ class ExFatPartition {
uint32_t clusterCount() const {return m_clusterCount;}
/** \return the cluster heap start sector. */
uint32_t clusterHeapStartSector() const {return m_clusterHeapStartSector;}
/** End access to volume
* \return pointer to sector size buffer for format.
*/
uint8_t* end() {
m_fatType = 0;
return cacheClear();
}
/** \return the FAT length in sectors */
uint32_t fatLength() const {return m_fatLength;}
/** \return the FAT start sector number. */
@ -96,9 +106,9 @@ class ExFatPartition {
*
* \return true for success or false for failure.
*/
bool init(BlockDevice* dev, uint8_t part);
bool init(FsBlockDevice* dev, uint8_t part);
/**
* Check for BlockDevice busy.
* Check for device busy.
*
* \return true if busy else false.
*/
@ -142,7 +152,7 @@ class ExFatPartition {
return m_dataCache.prepare(sector, option);
#endif // USE_EXFAT_BITMAP_CACHE
}
void cacheInit(BlockDevice* dev) {
void cacheInit(FsBlockDevice* dev) {
#if USE_EXFAT_BITMAP_CACHE
m_bitmapCache.init(dev);
#endif // USE_EXFAT_BITMAP_CACHE
@ -213,7 +223,7 @@ class ExFatPartition {
uint32_t m_rootDirectoryCluster;
uint32_t m_clusterMask;
uint32_t m_bytesPerCluster;
BlockDevice* m_blockDev;
FsBlockDevice* m_blockDev;
uint8_t m_fatType = 0;
uint8_t m_sectorsPerClusterShift;
};

View file

@ -40,7 +40,7 @@ class ExFatVolume : public ExFatPartition {
* \param[in] part partition to initialize.
* \return true for success or false for failure.
*/
bool begin(BlockDevice* dev, bool setCwv = true, uint8_t part = 1) {
bool begin(FsBlockDevice* dev, bool setCwv = true, uint8_t part = 1) {
if (!init(dev, part)) {
return false;
}

View file

@ -377,7 +377,7 @@ class FatFile {
return isOpen() ? m_error & WRITE_ERROR : true;
}
/**
* Check for BlockDevice busy.
* Check for device busy.
*
* \return true if busy else false.
*/
@ -442,14 +442,6 @@ class FatFile {
* \return true for success or false for failure.
*/
bool mkdir(FatFile* dir, const char* path, bool pFlag = true);
/** No longer implemented due to Long File Names.
*
* Use getName(char* name, size_t size).
* \return a pointer to replacement suggestion.
*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
const char* __attribute__((error("use getName(name, size)"))) name();
#endif // DOXYGEN_SHOULD_SKIP_THIS
/** Open a file in the volume root directory.
*
* \param[in] vol Volume where the file is located.

View file

@ -232,7 +232,7 @@ bool FatFile::makeUniqueSfn(FatLfn_t* fname) {
const uint8_t FIRST_HASH_SEQ = 2; // min value is 2
uint8_t pos = fname->seqPos;
DirFat_t* dir;
uint16_t hex;
uint16_t hex = 0;
DBG_HALT_IF(!(fname->flags & FNAME_FLAG_LOST_CHARS));
DBG_HALT_IF(fname->sfn[pos] != '~' && fname->sfn[pos + 1] != '1');
@ -242,7 +242,7 @@ bool FatFile::makeUniqueSfn(FatLfn_t* fname) {
#ifdef USE_LFN_HASH
hex = Bernstein(fname->begin, fname->end, seq);
#else
hex = micros();
hex += millis();
#endif
if (pos > 3) {
// Make space in name for ~HHHH.

View file

@ -37,7 +37,7 @@ bool FatFile::open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag) {
uint8_t checksum;
#endif // SFN_OPEN_USES_CHKSUM
uint8_t lfnOrd = 0;
uint16_t emptyIndex;
uint16_t emptyIndex = 0;
uint16_t index = 0;
DirFat_t* dir;
DirLfn_t* ldir;
@ -53,7 +53,7 @@ bool FatFile::open(FatFile* dirFile, FatSfn_t* fname, oflag_t oflag) {
// At EOF if no error.
break;
}
if (dir->name[0] == FAT_NAME_FREE || dir->name[0] == FAT_NAME_FREE) {
if (dir->name[0] == FAT_NAME_DELETED || dir->name[0] == FAT_NAME_FREE) {
if (!emptyFound) {
emptyIndex = index;
emptyFound = true;

View file

@ -45,7 +45,7 @@ const uint16_t FAT16_ROOT_SECTOR_COUNT =
#define writeMsg(str) if (m_pr) m_pr->write(str)
#endif // PRINT_FORMAT_PROGRESS
//------------------------------------------------------------------------------
bool FatFormatter::format(BlockDevice* dev, uint8_t* secBuf, print_t* pr) {
bool FatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
bool rtn;
m_dev = dev;
m_secBuf = secBuf;

View file

@ -25,7 +25,7 @@
#ifndef FatFormatter_h
#define FatFormatter_h
#include "../common/SysCall.h"
#include "../common/BlockDevice.h"
#include "../common/FsBlockDevice.h"
/**
* \class FatFormatter
* \brief Format a FAT volume.
@ -41,7 +41,7 @@ class FatFormatter {
*
* \return true for success or false for failure.
*/
bool format(BlockDevice* dev, uint8_t* secBuffer, print_t* pr = nullptr);
bool format(FsBlockDevice* dev, uint8_t* secBuffer, print_t* pr = nullptr);
private:
bool initFatDir(uint8_t fatType, uint32_t sectorCount);
@ -56,7 +56,7 @@ class FatFormatter {
uint32_t m_relativeSectors;
uint32_t m_sectorCount;
uint32_t m_totalSectors;
BlockDevice* m_dev;
FsBlockDevice* m_dev;
print_t* m_pr;
uint8_t* m_secBuf;
uint16_t m_reservedSectorCount;

View file

@ -52,8 +52,7 @@ size_t FatFile::getName(char* name, size_t size) {
size_t FatFile::getName7(char* name, size_t size) {
FatFile dir;
DirLfn_t* ldir;
char* ptr = name;
char* end = ptr + size;
size_t n = 0;
if (!isOpen()) {
DBG_FAIL_MACRO;
goto fail;
@ -78,15 +77,19 @@ size_t FatFile::getName7(char* name, size_t size) {
}
for (uint8_t i = 0; i < 13; i++) {
uint16_t c = getLfnChar(ldir, i);
if (c == 0 || (ptr + 1) == end) {
if (c == 0) {
goto done;
}
*ptr++ = c >= 0X7F ? '?' : c;
if ((n + 1) >= size) {
DBG_FAIL_MACRO;
goto fail;
}
name[n++] = c >= 0X7F ? '?' : c;
}
}
done:
*ptr = '\0';
return ptr - name;
name[n] = 0;
return n;
fail:
name[0] = '\0';
@ -147,8 +150,8 @@ size_t FatFile::getName8(char* name, size_t size) {
// Save space for zero byte.
ptr = FsUtf::cpToMb(cp, str, end - 1);
if (!ptr) {
// Truncate name. Could goto fail.
goto done;
DBG_FAIL_MACRO;
goto fail;
}
str = ptr;
}
@ -205,8 +208,9 @@ size_t FatFile::getSFN(char* name, size_t size) {
continue;
}
}
if ((j + 1u) == size) {
break;
if ((j + 1u) >= size) {
DBG_FAIL_MACRO;
goto fail;
}
name[j++] = c;
}

View file

@ -390,7 +390,7 @@ int32_t FatPartition::freeClusterCount() {
return -1;
}
//------------------------------------------------------------------------------
bool FatPartition::init(BlockDevice* dev, uint8_t part) {
bool FatPartition::init(FsBlockDevice* dev, uint8_t part) {
uint32_t clusterCount;
uint32_t totalSectors;
uint32_t volumeStartSector = 0;

View file

@ -30,7 +30,7 @@
*/
#include <stddef.h>
#include "../common/SysCall.h"
#include "../common/BlockDevice.h"
#include "../common/FsBlockDevice.h"
#include "../common/FsCache.h"
#include "../common/FsStructs.h"
@ -107,6 +107,13 @@ class FatPartition {
uint32_t dataStartSector() const {
return m_dataStartSector;
}
/** End access to volume
* \return pointer to sector size buffer for format.
*/
uint8_t* end() {
m_fatType = 0;
return cacheClear();
}
/** \return The number of File Allocation Tables. */
uint8_t fatCount() const {
return 2;
@ -126,7 +133,7 @@ class FatPartition {
int32_t freeClusterCount();
/** Initialize a FAT partition.
*
* \param[in] dev BlockDevice for this partition.
* \param[in] dev FsBlockDevice for this partition.
* \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
@ -134,7 +141,7 @@ class FatPartition {
*
* \return true for success or false for failure.
*/
bool init(BlockDevice* dev, uint8_t part = 1);
bool init(FsBlockDevice* dev, uint8_t part = 1);
/** \return The number of entries in the root directory for FAT16 volumes. */
uint16_t rootDirEntryCount() const {
return m_rootDirEntryCount;
@ -158,7 +165,7 @@ class FatPartition {
return fatGet(n, v);
}
/**
* Check for BlockDevice busy.
* Check for FsBlockDevice busy.
*
* \return true if busy else false.
*/
@ -179,7 +186,7 @@ class FatPartition {
static const uint16_t m_bytesPerSector = 1 << m_bytesPerSectorShift;
static const uint16_t m_sectorMask = m_bytesPerSector - 1;
//----------------------------------------------------------------------------
BlockDevice* m_blockDev; // sector device
FsBlockDevice* m_blockDev; // sector device
uint8_t m_sectorsPerCluster; // Cluster size in sectors.
uint8_t m_clusterSectorMask; // Mask to extract sector of cluster.
uint8_t m_sectorsPerClusterShift; // Cluster count to sector count shift.

View file

@ -43,7 +43,7 @@ class FatVolume : public FatPartition {
* \param[in] part partition to initialize.
* \return true for success or false for failure.
*/
bool begin(BlockDevice* dev, bool setCwv = true, uint8_t part = 1) {
bool begin(FsBlockDevice* dev, bool setCwv = true, uint8_t part = 1) {
if (!init(dev, part)) {
return false;
}
@ -72,7 +72,6 @@ class FatVolume : public FatPartition {
* \return true for success or false for failure.
*/
bool chdir(const char *path);
//----------------------------------------------------------------------------
/**
* Test for the existence of a file.

View file

@ -239,7 +239,7 @@ class FsBaseFile {
m_xFile ? m_xFile->getWriteError() : true;
}
/**
* Check for BlockDevice busy.
* Check for FsBlockDevice busy.
*
* \return true if busy else false.
*/
@ -355,14 +355,6 @@ class FsBaseFile {
* \return true for success or false for failure.
*/
bool mkdir(FsBaseFile* dir, const char* path, bool pFlag = true);
/** No longer implemented due to Long File Names.
*
* Use getName(char* name, size_t size).
* \return a pointer to replacement suggestion.
*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
const char* __attribute__((error("use getName(name, size)"))) name();
#endif // DOXYGEN_SHOULD_SKIP_THIS
/** Open a file or directory by name.
*
* \param[in] dir An open file instance for the directory containing
@ -761,6 +753,14 @@ class FsBaseFile {
return m_fFile ? length < (1ULL << 32) && m_fFile->truncate(length) :
m_xFile ? m_xFile->truncate(length) : false;
}
/** Write a string to a file. Used by the Arduino Print class.
* \param[in] str Pointer to the string.
* Use getWriteError to check for errors.
* \return count of characters written for success or -1 for failure.
*/
size_t write(const char* str) {
return write(str, strlen(str));
}
/** 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.

57
src/FsLib/FsFormatter.h Normal file
View file

@ -0,0 +1,57 @@
/**
* Copyright (c) 2011-2021 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 FsFormatter_h
#define FsFormatter_h
#include "FatLib/FatLib.h"
#include "ExFatLib/ExFatLib.h"
/**
* \class FsFormatter
* \brief Format a exFAT/FAT volume.
*/
class FsFormatter {
public:
/**
* Format a FAT volume.
*
* \param[in] dev Block device for volume.
* \param[in] secBuffer buffer for writing to volume.
* \param[in] pr Print device for progress output.
*
* \return true for success or false for failure.
*/
bool format(FsBlockDevice* dev, uint8_t* secBuffer, print_t* pr = nullptr) {
uint32_t sectorCount = dev->sectorCount();
if (sectorCount == 0) {
return false;
}
return sectorCount <= 67108864 ?
m_fFmt.format(dev, secBuffer, pr) :
m_xFmt.format(dev, secBuffer, pr);
}
private:
FatFormatter m_fFmt;
ExFatFormatter m_xFmt;
};
#endif // FsFormatter_h

View file

@ -30,4 +30,5 @@
*/
#include "FsVolume.h"
#include "FsFile.h"
#include "FsFormatter.h"
#endif // FsLib_h

View file

@ -25,16 +25,16 @@
#include "FsLib.h"
FsVolume* FsVolume::m_cwv = nullptr;
//------------------------------------------------------------------------------
bool FsVolume::begin(BlockDevice* blockDev) {
bool FsVolume::begin(FsBlockDevice* blockDev, bool setCwv, uint8_t part) {
m_blockDev = blockDev;
m_fVol = nullptr;
m_xVol = new (m_volMem) ExFatVolume;
if (m_xVol && m_xVol->begin(m_blockDev, false)) {
if (m_xVol && m_xVol->begin(m_blockDev, false, part)) {
goto done;
}
m_xVol = nullptr;
m_fVol = new (m_volMem) FatVolume;
if (m_fVol && m_fVol->begin(m_blockDev, false)) {
if (m_fVol && m_fVol->begin(m_blockDev, false, part)) {
goto done;
}
m_cwv = nullptr;
@ -42,7 +42,9 @@ bool FsVolume::begin(BlockDevice* blockDev) {
return false;
done:
m_cwv = this;
if (setCwv || !m_cwv) {
m_cwv = this;
}
return true;
}
//------------------------------------------------------------------------------

View file

@ -46,9 +46,11 @@ class FsVolume {
/**
* Initialize an FatVolume object.
* \param[in] blockDev Device block driver.
* \param[in] setCwv Set current working volume if true.
* \param[in] part partition to initialize.
* \return true for success or false for failure.
*/
bool begin(BlockDevice* blockDev);
bool begin(FsBlockDevice* blockDev, bool setCwv = true, uint8_t part = 1);
#ifndef DOXYGEN_SHOULD_SKIP_THIS
uint32_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster();
#endif // DOXYGEN_SHOULD_SKIP_THIS
@ -86,10 +88,14 @@ class FsVolume {
return m_fVol ? m_fVol->dataStartSector() :
m_xVol ? m_xVol->clusterHeapStartSector() : 0;
}
/** free dynamic memory and end access to volume */
void end() {
/** End access to volume
* \return pointer to sector size buffer for format.
*/
uint8_t* end() {
m_fVol = nullptr;
m_xVol = nullptr;
static_assert(sizeof(m_volMem) >= 512, "m_volMem too small");
return reinterpret_cast<uint8_t*>(m_volMem);
}
/** Test for the existence of a file in a directory
*
@ -119,7 +125,7 @@ class FsVolume {
m_xVol ? m_xVol->freeClusterCount() : 0;
}
/**
* Check for BlockDevice busy.
* Check for device busy.
*
* \return true if busy else false.
*/
@ -379,6 +385,6 @@ class FsVolume {
static FsVolume* m_cwv;
FatVolume* m_fVol = nullptr;
ExFatVolume* m_xVol = nullptr;
BlockDevice* m_blockDev;
FsBlockDevice* m_blockDev;
};
#endif // FsVolume_h

View file

@ -24,14 +24,16 @@
*/
#ifndef SdCardInterface_h
#define SdCardInterface_h
#include "../common/BlockDeviceInterface.h"
#include "../common/FsBlockDeviceInterface.h"
#include "SdCardInfo.h"
/**
* \class SdCardInterface
* \brief Abstract interface for an SD card.
*/
class SdCardInterface : public BlockDeviceInterface {
class SdCardInterface : public FsBlockDeviceInterface {
public:
/** end use of card */
virtual void end() = 0;
/** Erase a range of sectors.
*
* \param[in] firstSector The address of the first sector in the range.
@ -46,6 +48,18 @@ class SdCardInterface : public BlockDeviceInterface {
virtual uint32_t errorData() const = 0;
/** \return true if card is busy. */
virtual bool isBusy() = 0;
/** \return false by default */
virtual bool hasDedicatedSpi() {return false;}
/** \return false by default */
bool virtual isDedicatedSpi() {return false;}
/** Set SPI sharing state
* \param[in] value desired state.
* \return false by default.
*/
virtual bool setDedicatedSpi(bool value) {
(void)value;
return false;
}
/**
* Read a card's CID register.
*

View file

@ -665,7 +665,7 @@ bool DedicatedSpiCard::begin(SdSpiConfig spiConfig) {
if (!SharedSpiCard::begin(spiConfig)) {
return false;
}
m_sharedSpi = spiOptionShared(spiConfig.options);
m_dedicatedSpi = spiOptionDedicated(spiConfig.options);
return true;
}
//------------------------------------------------------------------------------
@ -687,18 +687,25 @@ bool DedicatedSpiCard::readSectors(
}
}
m_curSector += ns;
return m_sharedSpi ? readStop() : true;
return m_dedicatedSpi ? true : readStop();
fail:
return false;
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::setDedicatedSpi(bool value) {
if (!syncDevice()) {
return false;
}
m_dedicatedSpi = value;
return true;
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::writeSector(uint32_t sector, const uint8_t* src) {
if (m_sharedSpi) {
return SharedSpiCard::writeSector(sector, src);
} else {
if (m_dedicatedSpi) {
return writeSectors(sector, src, 1);
}
return SharedSpiCard::writeSector(sector, src);
}
//------------------------------------------------------------------------------
bool DedicatedSpiCard::writeSectors(
@ -715,7 +722,7 @@ bool DedicatedSpiCard::writeSectors(
}
}
m_curSector += ns;
return m_sharedSpi ? writeStop() : true;
return m_dedicatedSpi ? true : writeStop();
fail:
return false;

View file

@ -41,7 +41,7 @@
#if HAS_SDIO_CLASS
class SharedSpiCard : public SdCardInterface {
#elif USE_BLOCK_DEVICE_INTERFACE
class SharedSpiCard : public BlockDeviceInterface {
class SharedSpiCard : public FsBlockDeviceInterface {
#else // HAS_SDIO_CLASS
class SharedSpiCard {
#endif // HAS_SDIO_CLASS
@ -59,6 +59,10 @@ class SharedSpiCard {
* \return true for success or false for failure.
*/
bool begin(SdSpiConfig spiConfig);
/** End use of card */
void end() {
spiEnd();
}
/** Erase a range of sectors.
*
* \param[in] firstSector The address of the first sector in the range.
@ -96,12 +100,16 @@ class SharedSpiCard {
uint32_t errorData() const {
return m_status;
}
/** \return false for shared class. */
bool hasDedicatedSpi() {return false;}
/**
* Check for busy. MISO low indicates the card is busy.
*
* \return true if busy else false.
*/
bool isBusy();
/** \return false, can't be in dedicated state. */
bool isDedicatedSpi() {return false;}
/**
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
@ -189,6 +197,14 @@ class SharedSpiCard {
// Use sectorCount(). cardSize() will be removed in the future.
uint32_t __attribute__((error("use sectorCount()"))) cardSize();
#endif // DOXYGEN_SHOULD_SKIP_THIS
/** Set SPI sharing state
* \param[in] value desired state.
* \return false for shared card
*/
bool setDedicatedSpi(bool value) {
(void)value;
return false;
}
/** end a mult-sector transfer.
*
* \return true for success or false for failure.
@ -263,7 +279,6 @@ class SharedSpiCard {
}
bool waitReady(uint16_t ms);
bool writeData(uint8_t token, const uint8_t* src);
#if SPI_DRIVER_SELECT < 2
void spiActivate() {
m_spiDriver.activate();
@ -274,6 +289,9 @@ class SharedSpiCard {
void spiDeactivate() {
m_spiDriver.deactivate();
}
void spiEnd() {
m_spiDriver.end();
}
uint8_t spiReceive() {
return m_spiDriver.receive();
}
@ -300,6 +318,9 @@ class SharedSpiCard {
void spiDeactivate() {
m_spiDriverPtr->deactivate();
}
void spiEnd() {
m_spiDriverPtr->end();
}
uint8_t spiReceive() {
return m_spiDriverPtr->receive();
}
@ -317,7 +338,6 @@ class SharedSpiCard {
}
SdSpiDriver* m_spiDriverPtr;
#endif // SPI_DRIVER_SELECT < 2
SdCsPin_t m_csPin;
uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
bool m_spiActive;
@ -340,6 +360,10 @@ class DedicatedSpiCard : public SharedSpiCard {
* \return true for success or false for failure.
*/
bool begin(SdSpiConfig spiConfig);
/** \return true, can be in dedicaded state. */
bool hasDedicatedSpi() {return true;}
/** \return true if in dedicated SPI state. */
bool isDedicatedSpi() {return m_dedicatedSpi;}
/**
* Read a 512 byte sector from an SD card.
*
@ -357,6 +381,11 @@ class DedicatedSpiCard : public SharedSpiCard {
* \return true for success or false for failure.
*/
bool readSectors(uint32_t sector, uint8_t* dst, size_t ns);
/** Set SPI sharing state
* \param[in] value desired state.
* \return true for success else false;
*/
bool setDedicatedSpi(bool value);
/**
* Write a 512 byte sector to an SD card.
*
@ -377,7 +406,7 @@ class DedicatedSpiCard : public SharedSpiCard {
private:
uint32_t m_curSector;
bool m_sharedSpi = true;
bool m_dedicatedSpi = false;
};
//==============================================================================
#if ENABLE_DEDICATED_SPI

View file

@ -61,9 +61,9 @@ class SdioCard : public SdCardInterface {
*/
bool begin(SdioConfig sdioConfig);
/** Disable an SDIO card.
* \return false - not implemented.
* not implemented.
*/
bool end() {return false;}
void end() {}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
uint32_t __attribute__((error("use sectorCount()"))) cardSize();

View file

@ -572,7 +572,6 @@ static bool transferStop() {
if (!cardCommand(CMD12_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD12);
}
// if (yieldTimeout(isBusyCMD13)) {
if (yieldTimeout(isBusyDat)) {
return sdError(SD_CARD_ERROR_CMD13);
}
@ -599,7 +598,7 @@ static bool yieldTimeout(bool (*fcn)()) {
m_busyFcn = 0;
return true;
}
SysCall::yield();
yield();
}
m_busyFcn = 0;
return false; // Caller will set errorCode.

View file

@ -38,15 +38,15 @@
#endif // INCLUDE_SDIOS
//------------------------------------------------------------------------------
/** SdFat version for cpp use. */
#define SD_FAT_VERSION 20101
#define SD_FAT_VERSION 20102
/** SdFat version as string. */
#define SD_FAT_VERSION_STR "2.1.1"
#define SD_FAT_VERSION_STR "2.1.2"
//==============================================================================
/**
* \class SdBase
* \brief base SD file system template class.
*/
template <class Vol>
template <class Vol, class Fmt>
class SdBase : public Vol {
public:
//----------------------------------------------------------------------------
@ -115,6 +115,14 @@ class SdBase : public Vol {
return m_card && !m_card->errorCode();
}
//----------------------------------------------------------------------------
/** End use of card. */
void end() {
Vol::end();
if (m_card) {
m_card->end();
}
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
@ -128,7 +136,7 @@ class SdBase : public Vol {
} else if (!Vol::fatType()) {
pr->println(F("Check SD format."));
}
SysCall::halt();
while (true) {}
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
@ -153,13 +161,51 @@ class SdBase : public Vol {
errorHalt(pr);
}
//----------------------------------------------------------------------------
/** Format SD card
*
* \param[in] pr Print destination.
* \return true for success else false.
*/
bool format(print_t* pr = nullptr) {
Fmt fmt;
uint8_t* mem = Vol::end();
if (!mem) {
return false;
}
bool switchSpi = hasDedicatedSpi() && !isDedicatedSpi();
if (switchSpi && !setDedicatedSpi(true)) {
return 0;
}
bool rtn = fmt.format(card(), mem, pr);
if (switchSpi && !setDedicatedSpi(false)) {
return 0;
}
return rtn;
}
//----------------------------------------------------------------------------
/** \return the free cluster count. */
uint32_t freeClusterCount() {
bool switchSpi = hasDedicatedSpi() && !isDedicatedSpi();
if (switchSpi && !setDedicatedSpi(true)) {
return 0;
}
uint32_t rtn = Vol::freeClusterCount();
if (switchSpi && !setDedicatedSpi(false)) {
return 0;
}
return rtn;
}
//----------------------------------------------------------------------------
/** \return true if can be in dedicated SPI state */
bool hasDedicatedSpi() {return m_card ? m_card->hasDedicatedSpi() : false;}
//----------------------------------------------------------------------------
/** %Print error info and halt.
*
* \param[in] pr Print destination.
*/
void initErrorHalt(print_t* pr) {
initErrorPrint(pr);
SysCall::halt();
while (true) {}
}
//----------------------------------------------------------------------------
/** %Print error info and halt.
@ -177,7 +223,7 @@ class SdBase : public Vol {
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorHalt(Print* pr, const __FlashStringHelper* msg) {
void initErrorHalt(print_t* pr, const __FlashStringHelper* msg) {
pr->println(msg);
initErrorHalt(pr);
}
@ -186,7 +232,7 @@ class SdBase : public Vol {
*
* \param[in] pr Print destination.
*/
void initErrorPrint(Print* pr) {
void initErrorPrint(print_t* pr) {
pr->println(F("begin() failed"));
if (sdErrorCode()) {
pr->println(F("Do not reformat the SD."));
@ -197,6 +243,9 @@ class SdBase : public Vol {
errorPrint(pr);
}
//----------------------------------------------------------------------------
/** \return true if in dedicated SPI state. */
bool isDedicatedSpi() {return m_card ? m_card->isDedicatedSpi() : false;}
//----------------------------------------------------------------------------
/** %Print volume FAT/exFAT type.
*
* \param[in] pr Print destination.
@ -241,7 +290,7 @@ class SdBase : public Vol {
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorPrint(Print* pr, const __FlashStringHelper* msg) {
void errorPrint(print_t* pr, const __FlashStringHelper* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
@ -278,6 +327,17 @@ class SdBase : public Vol {
/** \return SD card error data. */
uint8_t sdErrorData() {return m_card ? m_card->errorData() : 0;}
//----------------------------------------------------------------------------
/** Set SPI sharing state
* \param[in] value desired state.
* \return true for success else false;
*/
bool setDedicatedSpi(bool value) {
if (m_card) {
return m_card->setDedicatedSpi(value);
}
return false;
}
//----------------------------------------------------------------------------
/** \return pointer to base volume */
Vol* vol() {return reinterpret_cast<Vol*>(this);}
//----------------------------------------------------------------------------
@ -341,7 +401,7 @@ class SdBase : public Vol {
#endif // ENABLE_ARDUINO_SERIAL
//----------------------------------------------------------------------------
private:
SdCard* m_card;
SdCard* m_card = nullptr;
SdCardFactory m_cardFactory;
};
//------------------------------------------------------------------------------
@ -349,73 +409,27 @@ class SdBase : public Vol {
* \class SdFat32
* \brief SD file system class for FAT volumes.
*/
class SdFat32 : public SdBase<FatVolume> {
class SdFat32 : public SdBase<FatVolume, FatFormatter> {
public:
/** Format a SD card FAT32/FAT16.
*
* \param[in] pr Optional Print information.
* \return true for success or false for failure.
*/
bool format(print_t* pr = nullptr) {
FatFormatter fmt;
uint8_t* cache = cacheClear();
if (!cache) {
return false;
}
return fmt.format(card(), cache, pr);
}
};
//------------------------------------------------------------------------------
/**
* \class SdExFat
* \brief SD file system class for exFAT volumes.
*/
class SdExFat : public SdBase<ExFatVolume> {
class SdExFat : public SdBase<ExFatVolume, ExFatFormatter> {
public:
/** Format a SD card exFAT.
*
* \param[in] pr Optional Print information.
* \return true for success or false for failure.
*/
bool format(print_t* pr = nullptr) {
ExFatFormatter fmt;
uint8_t* cache = cacheClear();
if (!cache) {
return false;
}
return fmt.format(card(), cache, pr);
}
};
//------------------------------------------------------------------------------
/**
* \class SdFs
* \brief SD file system class for FAT16, FAT32, and exFAT volumes.
*/
class SdFs : public SdBase<FsVolume> {
class SdFs : public SdBase<FsVolume, FsFormatter> {
public:
/** Format a SD card FAT or exFAT.
*
* \param[in] pr Optional Print information.
* \return true for success or false for failure.
*/
bool format(print_t* pr = nullptr) {
static_assert(sizeof(m_volMem) >= 512, "m_volMem too small");
uint32_t sectorCount = card()->sectorCount();
if (sectorCount == 0) {
return false;
}
end();
if (sectorCount > 67108864) {
ExFatFormatter fmt;
return fmt.format(card(), reinterpret_cast<uint8_t*>(m_volMem), pr);
} else {
FatFormatter fmt;
return fmt.format(card(), reinterpret_cast<uint8_t*>(m_volMem), pr);
}
}
};
//------------------------------------------------------------------------------
#if SDFAT_FILE_TYPE == 1
#if SDFAT_FILE_TYPE == 1 || defined(DOXYGEN)
/** Select type for SdFat. */
typedef SdFat32 SdFat;
/** Select type for SdBaseFile. */
@ -435,11 +449,11 @@ typedef FsBaseFile SdBaseFile;
#if defined __has_include
#if __has_include(<FS.h>)
#define HAS_INCLUDE_FS_H
#warning File not defined because __has__include(FS.h)
#warning File not defined because __has_include(FS.h)
#endif // __has_include(<FS.h>)
#endif // defined __has_include
#ifndef HAS_INCLUDE_FS_H
#if SDFAT_FILE_TYPE == 1
#if SDFAT_FILE_TYPE == 1 || defined(DOXYGEN)
/** Select type for File. */
typedef File32 File;
#elif SDFAT_FILE_TYPE == 2

View file

@ -137,10 +137,10 @@
#endif // SD_MAX_INIT_RATE_KHZ
/**
* Set USE_BLOCK_DEVICE_INTERFACE nonzero to use a generic block device.
* This allow use of an external BlockDevice driver that is derived from
* the BlockDeviceInterface like this:
* This allow use of an external FsBlockDevice driver that is derived from
* the FsBlockDeviceInterface like this:
*
* class UsbMscDriver : public BlockDeviceInterface {
* class UsbMscDriver : public FsBlockDeviceInterface {
* ... code for USB mass storage class driver.
* };
*
@ -341,19 +341,6 @@ typedef uint8_t SdCsPin_t;
#define ENDL_CALLS_FLUSH 0
#endif // ENDL_CALLS_FLUSH
//------------------------------------------------------------------------------
/**
* Handle Watchdog Timer for WiFi modules.
*
* Yield will be called before accessing the SPI bus if it has been more
* than WDT_YIELD_TIME_MILLIS milliseconds since the last yield call by SdFat.
*/
#if defined(PLATFORM_ID) || defined(ESP8266)
// If Particle device or ESP8266 call yield.
#define WDT_YIELD_TIME_MILLIS 100
#else // defined(PLATFORM_ID) || defined(ESP8266)
#define WDT_YIELD_TIME_MILLIS 0
#endif // defined(PLATFORM_ID) || defined(ESP8266)
//------------------------------------------------------------------------------
/**
* Set USE_SIMPLE_LITTLE_ENDIAN nonzero for little endian processors
* with no memory alignment restrictions.

View file

@ -42,6 +42,10 @@ void SdSpiArduinoDriver::deactivate() {
m_spi->endTransaction();
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::end() {
m_spi->end();
}
//------------------------------------------------------------------------------
uint8_t SdSpiArduinoDriver::receive() {
return m_spi->transfer(0XFF);
}

View file

@ -27,19 +27,23 @@
// Use of in-line for AVR to save flash.
#define nop asm volatile ("nop\n\t")
//------------------------------------------------------------------------------
inline void SdSpiArduinoDriver::activate() {
SPI.beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
inline void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
(void)spiConfig;
SPI.begin();
}
//------------------------------------------------------------------------------
inline void SdSpiArduinoDriver::activate() {
SPI.beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
inline void SdSpiArduinoDriver::deactivate() {
SPI.endTransaction();
}
//------------------------------------------------------------------------------
inline void SdSpiArduinoDriver::end() {
SPI.end();
}
//------------------------------------------------------------------------------
inline uint8_t SdSpiArduinoDriver::receive() {
return SPI.transfer(0XFF);
}

View file

@ -92,10 +92,6 @@ class SdSpiDriverBareUno {
public:
/** Activate SPI hardware. */
void activate() {}
/** deactivate SPI driver. */
void end() {}
/** Deactivate SPI hardware. */
void deactivate() {}
/** Initialize the SPI bus.
*
* \param[in] spiConfig SD card configuration.
@ -112,6 +108,10 @@ class SdSpiDriverBareUno {
unoPinMode(UNO_SCK, OUTPUT);
unoPinMode(UNO_MOSI, OUTPUT);
}
/** Deactivate SPI hardware. */
void deactivate() {}
/** deactivate SPI driver. */
void end() {}
/** Receive a byte.
*
* \return The byte.

View file

@ -43,6 +43,8 @@ class SdSpiBaseClass {
virtual void begin(SdSpiConfig config) = 0;
/** Deactivate SPI hardware. */
virtual void deactivate() {}
/** deactivate SPI driver. */
virtual void end() {}
/** Receive a byte.
*
* \return The byte.

View file

@ -50,16 +50,15 @@ const uint8_t SHARED_SPI = 0;
const uint8_t DEDICATED_SPI = 1;
/**
* \param[in] opt option field of SdSpiConfig.
* \return true for shared SPI.
* \return true for dedicated SPI.
*/
inline bool spiOptionShared(uint8_t opt) {return !(opt & DEDICATED_SPI);}
inline bool spiOptionDedicated(uint8_t opt) {return opt & DEDICATED_SPI;}
#else // ENABLE_DEDICATED_SPI
/**
* \param[in] opt option field of SdSpiConfig.
* \return true for shared SPI.
* \return true for dedicated SPI.
*/
inline bool spiOptionShared(uint8_t opt) {(void)opt; return true;}
inline bool spiOptionDedicated(uint8_t opt) {(void)opt; return false;}
#endif // ENABLE_DEDICATED_SPI
//------------------------------------------------------------------------------
/** SPISettings for SCK frequency in Hz. */

View file

@ -62,25 +62,6 @@ static bool dmac_channel_transfer_done(uint32_t ul_num) {
return (DMAC->DMAC_CHSR & (DMAC_CHSR_ENA0 << ul_num)) ? false : true;
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
(void)spiConfig;
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);
@ -141,10 +122,33 @@ void SdSpiArduinoDriver::activate() {
pSpi->SPI_CR |= SPI_CR_SPIEN;
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
(void)spiConfig;
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
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::deactivate() {
SPI.endTransaction();
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::end() {
SPI.end();
}
//------------------------------------------------------------------------------
static inline uint8_t spiTransfer(uint8_t b) {
Spi* pSpi = SPI0;

View file

@ -48,6 +48,10 @@ void SdSpiArduinoDriver::deactivate() {
m_spi->endTransaction();
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::end() {
m_spi->end();
}
//------------------------------------------------------------------------------
uint8_t SdSpiArduinoDriver::receive() {
return m_spi->transfer(0XFF);
}

View file

@ -46,6 +46,10 @@ inline void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
m_spi->begin();
}
//------------------------------------------------------------------------------
inline void SdSpiArduinoDriver::end() {
m_spi->end();
}
//------------------------------------------------------------------------------
inline void SdSpiArduinoDriver::deactivate() {
m_spi->endTransaction();
}

View file

@ -47,6 +47,10 @@ void SdSpiArduinoDriver::deactivate() {
m_spi->endTransaction();
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::end() {
m_spi->end();
}
//------------------------------------------------------------------------------
uint8_t SdSpiArduinoDriver::receive() {
return m_spi->transfer(0XFF);
}

View file

@ -51,6 +51,10 @@ void SdSpiArduinoDriver::deactivate() {
m_spi->endTransaction();
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::end() {
m_spi->end();
}
//------------------------------------------------------------------------------
uint8_t SdSpiArduinoDriver::receive() {
return m_spi->transfer(0XFF);
}

View file

@ -43,6 +43,10 @@ void SdSpiArduinoDriver::deactivate() {
m_spi->endTransaction();
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::end() {
m_spi->end();
}
//------------------------------------------------------------------------------
uint8_t SdSpiArduinoDriver::receive() {
return m_spi->transfer(0XFF);
}

View file

@ -49,6 +49,8 @@ class SdSpiSoftDriver {
}
/** Deactivate SPI hardware. */
void deactivate() {}
/** deactivate SPI driver. */
void end() {}
/** Receive a byte.
*
* \return The byte.

View file

@ -50,6 +50,10 @@ void SdSpiArduinoDriver::deactivate() {
m_spi->endTransaction();
}
//------------------------------------------------------------------------------
void SdSpiArduinoDriver::end() {
m_spi->end();
}
//------------------------------------------------------------------------------
uint8_t SdSpiArduinoDriver::receive() {
return m_spi->transfer(0XFF);
}

View file

@ -24,7 +24,7 @@
*/
#ifndef ArduinoFiles_h
#define ArduinoFiles_h
#include "SdFatConfig.h"
#include "SysCall.h"
//------------------------------------------------------------------------------
/** Arduino SD.h style flag for open for read. */
#ifndef FILE_READ
@ -91,9 +91,8 @@ class StreamFile : public stream_t, public BaseFile {
* \return a pointer to replacement suggestion.
*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
const char* __attribute__((error("use getName(name, size)"))) name();
char* __attribute__((error("use getName(name, size)"))) name();
#endif // DOXYGEN_SHOULD_SKIP_THIS
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;

View file

@ -24,7 +24,7 @@
*/
#ifndef DebugMacros_h
#define DebugMacros_h
#include "SdFatConfig.h"
#include "SysCall.h"
// 0 - disable, 1 - fail, halt 2 - fail, halt, warn
#define USE_DBG_MACROS 0

View file

@ -139,8 +139,7 @@ void divmod10(uint32_t in, uint32_t &div, uint32_t &mod)
if (r > 9) mod = r - 10;
else mod = r;
}
// Hackers delight function is here:
// http://www.hackersdelight.org/hdcodetxt/divuc.c.txt
// See: https://github.com/hcs0/Hackers-Delight
// 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) {

View file

@ -24,8 +24,7 @@
*/
#ifndef FsApiConstants_h
#define FsApiConstants_h
#include "SdFatConfig.h"
#include "SysCall.h"
#if USE_FCNTL_H
#include <fcntl.h>
/* values for GNU Arm Embedded Toolchain.

View file

@ -22,12 +22,12 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef BlockDevice_h
#define BlockDevice_h
#ifndef FsBlockDevice_h
#define FsBlockDevice_h
#include "SdCard/SdCard.h"
#if HAS_SDIO_CLASS || USE_BLOCK_DEVICE_INTERFACE
typedef BlockDeviceInterface BlockDevice;
typedef FsBlockDeviceInterface FsBlockDevice;
#else
typedef SdCard BlockDevice;
typedef SdCard FsBlockDevice;
#endif
#endif // BlockDevice_h
#endif // FsBlockDevice_h

View file

@ -24,22 +24,24 @@
*/
/**
* \file
* \brief BlockDeviceInterface include file.
* \brief FsBlockDeviceInterface include file.
*/
#ifndef BlockDeviceInterface_h
#define BlockDeviceInterface_h
#ifndef FsBlockDeviceInterface_h
#define FsBlockDeviceInterface_h
#include <stdint.h>
#include <stddef.h>
#include "SdFatConfig.h"
/**
* \class BlockDeviceInterface
* \brief BlockDeviceInterface class.
* \class FsBlockDeviceInterface
* \brief FsBlockDeviceInterface class.
*/
class BlockDeviceInterface {
class FsBlockDeviceInterface {
public:
virtual ~BlockDeviceInterface() {}
virtual ~FsBlockDeviceInterface() {}
/** end use of device */
virtual void end() {}
/**
* Check for BlockDevice busy.
* Check for FsBlockDevice busy.
*
* \return true if busy else false.
*/
@ -90,4 +92,4 @@ class BlockDeviceInterface {
*/
virtual bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns) = 0;
};
#endif // BlockDeviceInterface_h
#endif // FsBlockDeviceInterface_h

View file

@ -29,7 +29,7 @@
* \brief Common cache code for exFAT and FAT.
*/
#include "SysCall.h"
#include "BlockDevice.h"
#include "FsBlockDevice.h"
/**
* \class FsCache
* \brief Sector cache.
@ -127,7 +127,7 @@ class FsCache {
/** Initialize the cache.
* \param[in] blockDev Block device for this cache.
*/
void init(BlockDevice* blockDev) {
void init(FsBlockDevice* blockDev) {
m_blockDev = blockDev;
invalidate();
}
@ -153,6 +153,12 @@ class FsCache {
bool isDirty() {
return m_status & CACHE_STATUS_DIRTY;
}
/** Prepare cache to access sector.
* \param[in] sector Sector to read.
* \param[in] option mode for cached sector.
* \return Address of cached sector.
*/
uint8_t* prepare(uint32_t sector, uint8_t option);
/** \return Logical sector number for cached sector. */
uint32_t sector() {
return m_sector;
@ -163,12 +169,6 @@ class FsCache {
void setMirrorOffset(uint32_t offset) {
m_mirrorOffset = offset;
}
/** Prepare cache to access sector.
* \param[in] sector Sector to read.
* \param[in] option mode for cached sector.
* \return Address of cached sector.
*/
uint8_t* prepare(uint32_t sector, uint8_t option);
/** Write current sector if dirty.
* \return true for success or false for failure.
*/
@ -176,7 +176,7 @@ class FsCache {
private:
uint8_t m_status;
BlockDevice* m_blockDev;
FsBlockDevice* m_blockDev;
uint32_t m_mirrorOffset;
uint32_t m_sector;
uint8_t m_buffer[512];

View file

@ -24,7 +24,7 @@
*/
#ifndef FsName_h
#define FsName_h
#include "SdFatConfig.h"
#include "SysCall.h"
#include <stdint.h>
/**
* \file

91
src/common/PrintBasic.cpp Normal file
View file

@ -0,0 +1,91 @@
/**
* Copyright (c) 2011-2020 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "PrintBasic.h"
#if ENABLE_ARDUINO_FEATURES == 0
#include <math.h>
size_t PrintBasic::print(long n, uint8_t base) {
if (n < 0 && base == 10) {
return print('-') + printNum(-n, base);
}
return printNum(n, base);
}
size_t PrintBasic::printNum(unsigned long n, uint8_t base) {
const uint8_t DIM = 8*sizeof(long);
char buf[DIM];
char *str = &buf[DIM];
if (base < 2) return 0;
do {
char c = n%base;
n /= base;
*--str = c + (c < 10 ? '0' : 'A' - 10);
} while (n);
return write(str, &buf[DIM] - str);
}
size_t PrintBasic::printDouble(double n, uint8_t prec) {
// Max printable 32-bit floating point number. AVR uses 32-bit double.
const double maxfp = static_cast<double>(0XFFFFFF00UL);
size_t rtn = 0;
if (isnan(n)) {
return write("NaN");
}
if (n < 0) {
n = -n;
rtn += print('-');
}
if (isinf(n)) {
return rtn + write("Inf");
}
if (n > maxfp) {
return rtn + write("Ovf");
}
double round = 0.5;
for (uint8_t i = 0; i < prec; ++i) {
round *= 0.1;
}
n += round;
uint32_t whole = (uint32_t)n;
rtn += print(whole);
if (prec) {
rtn += print('.');
double fraction = n - static_cast<double>(whole);
for (uint8_t i = 0; i < prec; i++) {
fraction *= 10.0;
uint8_t digit = fraction;
rtn += print(digit);
fraction -= digit;
}
}
return rtn;
}
#endif // ENABLE_ARDUINO_FEATURES == 0

169
src/common/PrintBasic.h Normal file
View file

@ -0,0 +1,169 @@
/**
* Copyright (c) 2011-2020 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef PrintBasic_h
#define PrintBasic_h
/**
* \file
* \brief Stream/Print like replacement for non-Arduino systems.
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "../SdFatConfig.h"
#ifndef F
#if defined(__AVR__)
#include <avr/pgmspace.h>
class __FlashStringHelper;
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
#else // defined(__AVR__)
#define F(str) (str)
#endif // defined(__AVR__)
#endif // F
#ifdef BIN
#undef BIN
#endif // BIN
#define BIN 2
#define OCT 8
#define DEC 10
#define HEX 16
class PrintBasic {
public:
PrintBasic() : m_error(0) {}
void clearWriteError() {
setWriteError(0);
}
int getWriteError() {
return m_error;
}
size_t print(char c) {
return write(c);
}
size_t print(const char* str) {
return write(str);
}
size_t print(const __FlashStringHelper *str) {
#ifdef __AVR__
PGM_P p = reinterpret_cast<PGM_P>(str);
size_t n = 0;
for (uint8_t c; (c = pgm_read_byte(p + n)) && write(c); n++) {}
return n;
#else // __AVR__
return print(reinterpret_cast<const char *>(str));
#endif // __AVR__
}
size_t println(const __FlashStringHelper *str) {
#ifdef __AVR__
return print(str) + println();
#else // __AVR__
return println(reinterpret_cast<const char *>(str));
#endif // __AVR__
}
size_t print(double n, uint8_t prec = 2) {
return printDouble(n, prec);
}
size_t print(signed char n, uint8_t base = 10) {
return print((long)n, base);
}
size_t print(unsigned char n, uint8_t base = 10) {
return print((unsigned long)n, base);
}
size_t print(int n, uint8_t base = 10) {
return print((long)n, base);
}
size_t print(unsigned int n, uint8_t base = 10) {
return print((unsigned long)n, base);
}
size_t print(long n, uint8_t base = 10);
size_t print(unsigned long n, uint8_t base = 10) {
return printNum(n, base);
}
size_t println() {
return write("\r\n");
}
size_t println(char c) {
return write(c) + println();
}
size_t println(const char* str) {
return print(str) + println();
}
size_t println(double n, uint8_t prec = 2) {
return print(n, prec) + println();
}
size_t println(signed char n, uint8_t base = 10) {
return print(n, base) + println();
}
size_t println(unsigned char n, uint8_t base = 10) {
return print(n, base) + println();
}
size_t println(int n, uint8_t base = 10) {
return print(n, base) + println();
}
size_t println(unsigned int n, uint8_t base = 10) {
return print(n, base) + println();
}
size_t println(long n, uint8_t base = 10) {
return print(n, base) + println();
}
size_t println(unsigned long n, uint8_t base = 10) {
return print(n, base) + println();
}
size_t write(const char *str) {
return write(str, strlen(str));
}
virtual size_t write(uint8_t b) = 0;
virtual size_t write(const uint8_t* buffer, size_t size) {
size_t i;
for (i = 0; i < size; i++) {
if (!write(buffer[i])) break;
}
return i;
}
size_t write(const char *buffer, size_t size) {
return write((const uint8_t*)buffer, size);
}
protected:
void setWriteError(int err = 1) {
m_error = err;
}
private:
size_t printDouble(double n, uint8_t prec);
size_t printNum(unsigned long n, uint8_t base);
int m_error;
};
//------------------------------------------------------------------------------
class StreamBasic : public PrintBasic {
public:
virtual int available() = 0;
virtual int peek() = 0;
virtual int read() = 0;
};
#endif // PrintBasic_h

View file

@ -30,30 +30,13 @@
#define SysCall_h
#include <stdint.h>
#include <stddef.h>
#include "SdFatConfig.h"
#include "../SdFatConfig.h"
#if __cplusplus < 201103
#warning nullptr defined
/** Define nullptr if not C++11 */
#define nullptr NULL
#endif // __cplusplus < 201103
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/**
* \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 ENABLE_ARDUINO_FEATURES
#if defined(ARDUINO)
/** Use Arduino Print. */
@ -69,28 +52,11 @@ typedef Stream stream_t;
#define F(str) (str)
#endif // F
//------------------------------------------------------------------------------
#if defined(PLATFORM_ID) // Only defined if a Particle device
inline void SysCall::yield() {
// Recommended to only call Particle.process() if system threading is disabled
if (system_thread_get_state(NULL) == spark::feature::DISABLED) {
Particle.process();
}
}
#elif defined(ARDUINO)
inline void SysCall::yield() {
// Use the external Arduino yield() function.
::yield();
}
#else // defined(PLATFORM_ID)
inline void SysCall::yield() {}
#endif // defined(PLATFORM_ID)
//------------------------------------------------------------------------------
#else // ENABLE_ARDUINO_FEATURES
#include "PrintBasic.h"
/** If not Arduino */
typedef PrintBasic print_t;
/** If not Arduino */
typedef PrintBasic stream_t;
inline void SysCall::yield() {}
#endif // ENABLE_ARDUINO_FEATURES
#endif // SysCall_h

View file

@ -28,7 +28,6 @@
* \file
* \brief ArduinoInStream and ArduinoOutStream classes
*/
#include "SdFatConfig.h"
#include "bufstream.h"
//==============================================================================
/**
@ -54,7 +53,7 @@ class ArduinoInStream : public ibufstream {
uint32_t t;
m_line[0] = '\0';
while (!m_hw->available()) {
SysCall::yield();
yield();
}
while (1) {
@ -111,7 +110,7 @@ class ArduinoOutStream : public ostream {
*
* \param[in] pr Print object for this ArduinoOutStream.
*/
explicit ArduinoOutStream(Print& pr) : m_pr(&pr) {}
explicit ArduinoOutStream(print_t& pr) : m_pr(&pr) {}
protected:
/// @cond SHOW_PROTECTED
@ -146,6 +145,6 @@ class ArduinoOutStream : public ostream {
/// @endcond
private:
ArduinoOutStream() {}
Print* m_pr;
print_t* m_pr;
};
#endif // ArduinoStream_h

View file

@ -440,7 +440,7 @@ class StdioStream : private StreamBaseFile {
return n > 0 ? n : 0;
}
//----------------------------------------------------------------------------
/** Print a number.
/** Print a number.
*
* \param[in] val the number to be printed.
*

View file

@ -33,7 +33,7 @@
/** For internal use in c++ streams */
typedef fspos_t pos_t;
//==============================================================================
#if SDFAT_FILE_TYPE == 1
#if SDFAT_FILE_TYPE == 1 || defined(DOXYGEN)
/** Set File type for iostreams. */
typedef FatFile StreamBaseFile;
#elif SDFAT_FILE_TYPE == 2