Updated the SDFS librarie because it was updated in the sdk.
This commit is contained in:
parent
ae72a34a80
commit
8d305ec4da
@ -25,7 +25,6 @@
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#include "SDFS.h"
|
#include "SDFS.h"
|
||||||
#include "SDFSFormatter.h"
|
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
|
|
||||||
using namespace fs;
|
using namespace fs;
|
||||||
@ -37,6 +36,9 @@ FS SDFS = FS(FSImplPtr(new sdfs::SDFSImpl()));
|
|||||||
|
|
||||||
namespace sdfs {
|
namespace sdfs {
|
||||||
|
|
||||||
|
// Required to be global because SDFAT doesn't allow a this pointer in it's own time call
|
||||||
|
time_t (*__sdfs_timeCallback)(void) = nullptr;
|
||||||
|
|
||||||
FileImplPtr SDFSImpl::open(const char* path, OpenMode openMode, AccessMode accessMode)
|
FileImplPtr SDFSImpl::open(const char* path, OpenMode openMode, AccessMode accessMode)
|
||||||
{
|
{
|
||||||
if (!_mounted) {
|
if (!_mounted) {
|
||||||
@ -62,13 +64,13 @@ FileImplPtr SDFSImpl::open(const char* path, OpenMode openMode, AccessMode acces
|
|||||||
}
|
}
|
||||||
free(pathStr);
|
free(pathStr);
|
||||||
}
|
}
|
||||||
sdfat::File fd = _fs.open(path, flags);
|
sdfat::File32 fd = _fs.open(path, flags);
|
||||||
if (!fd) {
|
if (!fd) {
|
||||||
DEBUGV("SDFSImpl::openFile: fd=%p path=`%s` openMode=%d accessMode=%d",
|
DEBUGV("SDFSImpl::openFile: fd=%p path=`%s` openMode=%d accessMode=%d",
|
||||||
&fd, path, openMode, accessMode);
|
&fd, path, openMode, accessMode);
|
||||||
return FileImplPtr();
|
return FileImplPtr();
|
||||||
}
|
}
|
||||||
auto sharedFd = std::make_shared<sdfat::File>(fd);
|
auto sharedFd = std::make_shared<sdfat::File32>(fd);
|
||||||
return std::make_shared<SDFSFileImpl>(this, sharedFd, path);
|
return std::make_shared<SDFSFileImpl>(this, sharedFd, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +90,7 @@ DirImplPtr SDFSImpl::openDir(const char* path)
|
|||||||
}
|
}
|
||||||
// At this point we have a name of "/blah/blah/blah" or "blah" or ""
|
// At this point we have a name of "/blah/blah/blah" or "blah" or ""
|
||||||
// If that references a directory, just open it and we're done.
|
// If that references a directory, just open it and we're done.
|
||||||
sdfat::File dirFile;
|
sdfat::File32 dirFile;
|
||||||
const char *filter = "";
|
const char *filter = "";
|
||||||
if (!pathStr[0]) {
|
if (!pathStr[0]) {
|
||||||
// openDir("") === openDir("/")
|
// openDir("") === openDir("/")
|
||||||
@ -133,7 +135,7 @@ DirImplPtr SDFSImpl::openDir(const char* path)
|
|||||||
DEBUGV("SDFSImpl::openDir: path=`%s`\n", path);
|
DEBUGV("SDFSImpl::openDir: path=`%s`\n", path);
|
||||||
return DirImplPtr();
|
return DirImplPtr();
|
||||||
}
|
}
|
||||||
auto sharedDir = std::make_shared<sdfat::File>(dirFile);
|
auto sharedDir = std::make_shared<sdfat::File32>(dirFile);
|
||||||
auto ret = std::make_shared<SDFSDirImpl>(filter, this, sharedDir, pathStr);
|
auto ret = std::make_shared<SDFSDirImpl>(filter, this, sharedDir, pathStr);
|
||||||
free(pathStr);
|
free(pathStr);
|
||||||
return ret;
|
return ret;
|
||||||
@ -143,12 +145,18 @@ bool SDFSImpl::format() {
|
|||||||
if (_mounted) {
|
if (_mounted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SDFSFormatter formatter;
|
sdfat::SdCardFactory cardFactory;
|
||||||
bool ret = formatter.format(&_fs, _cfg._csPin, _cfg._spiSettings);
|
sdfat::SdCard* card = cardFactory.newCard(sdfat::SdSpiConfig(_cfg._csPin, DEDICATED_SPI, _cfg._spiSettings));
|
||||||
|
if (!card || card->errorCode()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sdfat::FatFormatter fatFormatter;
|
||||||
|
uint8_t *sectorBuffer = new uint8_t[512];
|
||||||
|
bool ret = fatFormatter.format(card, sectorBuffer, nullptr);
|
||||||
|
delete[] sectorBuffer;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t (*SDFSImpl::timeCallback)(void) = nullptr;
|
|
||||||
|
|
||||||
}; // namespace sdfs
|
}; // namespace sdfs
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class SDFSConfig : public FSConfig
|
|||||||
public:
|
public:
|
||||||
static constexpr uint32_t FSId = 0x53444653;
|
static constexpr uint32_t FSId = 0x53444653;
|
||||||
|
|
||||||
SDFSConfig(uint8_t csPin = 4, SPISettings spi = SD_SCK_MHZ(10)) : FSConfig(FSId, false), _csPin(csPin), _part(0), _spiSettings(spi) { }
|
SDFSConfig(uint8_t csPin = 4, uint32_t spi = SD_SCK_MHZ(10)) : FSConfig(FSId, false), _csPin(csPin), _part(0), _spiSettings(spi) { }
|
||||||
|
|
||||||
SDFSConfig setAutoFormat(bool val = true) {
|
SDFSConfig setAutoFormat(bool val = true) {
|
||||||
_autoFormat = val;
|
_autoFormat = val;
|
||||||
@ -57,7 +57,7 @@ public:
|
|||||||
_csPin = pin;
|
_csPin = pin;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
SDFSConfig setSPI(SPISettings spi) {
|
SDFSConfig setSPI(uint32_t spi) {
|
||||||
_spiSettings = spi;
|
_spiSettings = spi;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -67,9 +67,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inherit _type and _autoFormat
|
// Inherit _type and _autoFormat
|
||||||
uint8_t _csPin;
|
uint8_t _csPin;
|
||||||
uint8_t _part;
|
uint8_t _part;
|
||||||
SPISettings _spiSettings;
|
uint32_t _spiSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDFSImpl : public FSImpl
|
class SDFSImpl : public FSImpl
|
||||||
@ -97,11 +97,11 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
info.maxOpenFiles = 999; // TODO - not valid
|
info.maxOpenFiles = 999; // TODO - not valid
|
||||||
info.blockSize = _fs.vol()->blocksPerCluster() * 512;
|
info.blockSize = _fs.vol()->sectorsPerCluster() * _fs.vol()->bytesPerSector();
|
||||||
info.pageSize = 0; // TODO ?
|
info.pageSize = 0; // TODO ?
|
||||||
info.maxPathLength = 255; // TODO ?
|
info.maxPathLength = 255; // TODO ?
|
||||||
info.totalBytes =_fs.vol()->volumeBlockCount() * 512LL;
|
info.totalBytes =_fs.vol()->clusterCount() * info.blockSize;
|
||||||
info.usedBytes = info.totalBytes - (_fs.vol()->freeClusterCount() * _fs.vol()->blocksPerCluster() * 512LL);
|
info.usedBytes = info.totalBytes - (_fs.vol()->freeClusterCount() * _fs.vol()->sectorsPerCluster() * _fs.vol()->bytesPerSector());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,14 +149,14 @@ public:
|
|||||||
|
|
||||||
bool begin() override {
|
bool begin() override {
|
||||||
if (_mounted) {
|
if (_mounted) {
|
||||||
end();
|
return true;
|
||||||
}
|
}
|
||||||
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
|
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
|
||||||
if (!_mounted && _cfg._autoFormat) {
|
if (!_mounted && _cfg._autoFormat) {
|
||||||
format();
|
format();
|
||||||
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
|
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
|
||||||
}
|
}
|
||||||
sdfat::SdFile::dateTimeCallback(dateTimeCB);
|
sdfat::FsDateTime::setCallback(dateTimeCB);
|
||||||
return _mounted;
|
return _mounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ public:
|
|||||||
return _fs.vol()->fatType();
|
return _fs.vol()->fatType();
|
||||||
}
|
}
|
||||||
size_t blocksPerCluster() {
|
size_t blocksPerCluster() {
|
||||||
return _fs.vol()->blocksPerCluster();
|
return _fs.vol()->sectorsPerCluster();
|
||||||
}
|
}
|
||||||
size_t totalClusters() {
|
size_t totalClusters() {
|
||||||
return _fs.vol()->clusterCount();
|
return _fs.vol()->clusterCount();
|
||||||
@ -185,7 +185,7 @@ public:
|
|||||||
return (totalClusters() / blocksPerCluster());
|
return (totalClusters() / blocksPerCluster());
|
||||||
}
|
}
|
||||||
size_t clusterSize() {
|
size_t clusterSize() {
|
||||||
return blocksPerCluster() * 512; // 512b block size
|
return blocksPerCluster() * _fs.vol()->bytesPerSector();
|
||||||
}
|
}
|
||||||
size_t size() {
|
size_t size() {
|
||||||
return (clusterSize() * totalClusters());
|
return (clusterSize() * totalClusters());
|
||||||
@ -205,24 +205,26 @@ public:
|
|||||||
return mktime(&tiempo);
|
return mktime(&tiempo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void setTimeCallback(time_t (*cb)(void)) override {
|
||||||
|
extern time_t (*__sdfs_timeCallback)(void);
|
||||||
|
__sdfs_timeCallback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
// Because SdFat has a single, global setting for this we can only use a
|
// Because SdFat has a single, global setting for this we can only use a
|
||||||
// static member of our class to return the time/date. However, since
|
// static member of our class to return the time/date.
|
||||||
// this is static, we can't see the time callback variable. Punt for now,
|
|
||||||
// using time(NULL) as the best we can do.
|
|
||||||
static void dateTimeCB(uint16_t *dosYear, uint16_t *dosTime) {
|
static void dateTimeCB(uint16_t *dosYear, uint16_t *dosTime) {
|
||||||
|
time_t now;
|
||||||
time_t now = (timeCallback == nullptr) ? time(nullptr) : (*timeCallback)();
|
extern time_t (*__sdfs_timeCallback)(void);
|
||||||
//time_t now = time(nullptr);
|
if (__sdfs_timeCallback) {
|
||||||
|
now = __sdfs_timeCallback();
|
||||||
|
} else {
|
||||||
|
now = time(nullptr);
|
||||||
|
}
|
||||||
struct tm *tiempo = localtime(&now);
|
struct tm *tiempo = localtime(&now);
|
||||||
*dosYear = ((tiempo->tm_year - 80) << 9) | ((tiempo->tm_mon + 1) << 5) | tiempo->tm_mday;
|
*dosYear = ((tiempo->tm_year - 80) << 9) | ((tiempo->tm_mon + 1) << 5) | tiempo->tm_mday;
|
||||||
*dosTime = (tiempo->tm_hour << 11) | (tiempo->tm_min << 5) | tiempo->tm_sec;
|
*dosTime = (tiempo->tm_hour << 11) | (tiempo->tm_min << 5) | tiempo->tm_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setTimeCallback(time_t (*cb)(void))
|
|
||||||
{
|
|
||||||
timeCallback = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class SDFileImpl;
|
friend class SDFileImpl;
|
||||||
friend class SDFSDirImpl;
|
friend class SDFSDirImpl;
|
||||||
@ -232,6 +234,7 @@ protected:
|
|||||||
return &_fs;
|
return &_fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint8_t _getFlags(OpenMode openMode, AccessMode accessMode) {
|
static uint8_t _getFlags(OpenMode openMode, AccessMode accessMode) {
|
||||||
uint8_t mode = 0;
|
uint8_t mode = 0;
|
||||||
if (openMode & OM_CREATE) {
|
if (openMode & OM_CREATE) {
|
||||||
@ -255,16 +258,13 @@ protected:
|
|||||||
sdfat::SdFat _fs;
|
sdfat::SdFat _fs;
|
||||||
SDFSConfig _cfg;
|
SDFSConfig _cfg;
|
||||||
bool _mounted;
|
bool _mounted;
|
||||||
|
|
||||||
private:
|
|
||||||
static time_t (*timeCallback)(void);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class SDFSFileImpl : public FileImpl
|
class SDFSFileImpl : public FileImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SDFSFileImpl(SDFSImpl *fs, std::shared_ptr<sdfat::File> fd, const char *name)
|
SDFSFileImpl(SDFSImpl *fs, std::shared_ptr<sdfat::File32> fd, const char *name)
|
||||||
: _fs(fs), _fd(fd), _opened(true)
|
: _fs(fs), _fd(fd), _opened(true)
|
||||||
{
|
{
|
||||||
_name = std::shared_ptr<char>(new char[strlen(name) + 1], std::default_delete<char[]>());
|
_name = std::shared_ptr<char>(new char[strlen(name) + 1], std::default_delete<char[]>());
|
||||||
@ -277,12 +277,17 @@ public:
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int availableForWrite() override
|
||||||
|
{
|
||||||
|
return _opened ? _fd->availableSpaceForWrite() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t write(const uint8_t *buf, size_t size) override
|
size_t write(const uint8_t *buf, size_t size) override
|
||||||
{
|
{
|
||||||
return _opened ? _fd->write(buf, size) : -1;
|
return _opened ? _fd->write(buf, size) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t read(uint8_t* buf, size_t size) override
|
int read(uint8_t* buf, size_t size) override
|
||||||
{
|
{
|
||||||
return _opened ? _fd->read(buf, size) : -1;
|
return _opened ? _fd->read(buf, size) : -1;
|
||||||
}
|
}
|
||||||
@ -290,7 +295,6 @@ public:
|
|||||||
void flush() override
|
void flush() override
|
||||||
{
|
{
|
||||||
if (_opened) {
|
if (_opened) {
|
||||||
_fd->flush();
|
|
||||||
_fd->sync();
|
_fd->sync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -370,15 +374,15 @@ public:
|
|||||||
|
|
||||||
bool isDirectory() const override
|
bool isDirectory() const override
|
||||||
{
|
{
|
||||||
return _opened ? _fd->isDirectory() : false;
|
return _opened ? _fd->isDir() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t getLastWrite() override {
|
time_t getLastWrite() override {
|
||||||
time_t ftime = 0;
|
time_t ftime = 0;
|
||||||
if (_opened && _fd) {
|
if (_opened && _fd) {
|
||||||
sdfat::dir_t tmp;
|
sdfat::DirFat_t tmp;
|
||||||
if (_fd.get()->dirEntry(&tmp)) {
|
if (_fd.get()->dirEntry(&tmp)) {
|
||||||
ftime = SDFSImpl::FatToTimeT(tmp.lastWriteDate, tmp.lastWriteTime);
|
ftime = SDFSImpl::FatToTimeT(*(uint16_t*)tmp.modifyDate, *(uint16_t*)tmp.modifyTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ftime;
|
return ftime;
|
||||||
@ -387,19 +391,17 @@ public:
|
|||||||
time_t getCreationTime() override {
|
time_t getCreationTime() override {
|
||||||
time_t ftime = 0;
|
time_t ftime = 0;
|
||||||
if (_opened && _fd) {
|
if (_opened && _fd) {
|
||||||
sdfat::dir_t tmp;
|
sdfat::DirFat_t tmp;
|
||||||
if (_fd.get()->dirEntry(&tmp)) {
|
if (_fd.get()->dirEntry(&tmp)) {
|
||||||
ftime = SDFSImpl::FatToTimeT(tmp.creationDate, tmp.creationTime);
|
ftime = SDFSImpl::FatToTimeT(*(uint16_t*)tmp.createDate, *(uint16_t*)tmp.createTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ftime;
|
return ftime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SDFSImpl* _fs;
|
SDFSImpl* _fs;
|
||||||
std::shared_ptr<sdfat::File> _fd;
|
std::shared_ptr<sdfat::File32> _fd;
|
||||||
std::shared_ptr<char> _name;
|
std::shared_ptr<char> _name;
|
||||||
bool _opened;
|
bool _opened;
|
||||||
};
|
};
|
||||||
@ -407,7 +409,7 @@ protected:
|
|||||||
class SDFSDirImpl : public DirImpl
|
class SDFSDirImpl : public DirImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SDFSDirImpl(const String& pattern, SDFSImpl* fs, std::shared_ptr<sdfat::File> dir, const char *dirPath = nullptr)
|
SDFSDirImpl(const String& pattern, SDFSImpl* fs, std::shared_ptr<sdfat::File32> dir, const char *dirPath = nullptr)
|
||||||
: _pattern(pattern), _fs(fs), _dir(dir), _valid(false), _dirPath(nullptr)
|
: _pattern(pattern), _fs(fs), _dir(dir), _valid(false), _dirPath(nullptr)
|
||||||
{
|
{
|
||||||
if (dirPath) {
|
if (dirPath) {
|
||||||
@ -482,17 +484,17 @@ public:
|
|||||||
{
|
{
|
||||||
const int n = _pattern.length();
|
const int n = _pattern.length();
|
||||||
do {
|
do {
|
||||||
sdfat::File file;
|
sdfat::File32 file;
|
||||||
file.openNext(_dir.get(), sdfat::O_READ);
|
file.openNext(_dir.get(), sdfat::O_READ);
|
||||||
if (file) {
|
if (file) {
|
||||||
_valid = 1;
|
_valid = 1;
|
||||||
_size = file.fileSize();
|
_size = file.fileSize();
|
||||||
_isFile = file.isFile();
|
_isFile = file.isFile();
|
||||||
_isDirectory = file.isDirectory();
|
_isDirectory = file.isDir();
|
||||||
sdfat::dir_t tmp;
|
sdfat::DirFat_t tmp;
|
||||||
if (file.dirEntry(&tmp)) {
|
if (file.dirEntry(&tmp)) {
|
||||||
_time = SDFSImpl::FatToTimeT(tmp.lastWriteDate, tmp.lastWriteTime);
|
_time = SDFSImpl::FatToTimeT(*(uint16_t*)tmp.modifyDate, *(uint16_t*)tmp.modifyTime);
|
||||||
_creation = SDFSImpl::FatToTimeT(tmp.creationDate, tmp.creationTime);
|
_creation = SDFSImpl::FatToTimeT(*(uint16_t*)tmp.createDate, *(uint16_t*)tmp.createTime);
|
||||||
} else {
|
} else {
|
||||||
_time = 0;
|
_time = 0;
|
||||||
_creation = 0;
|
_creation = 0;
|
||||||
@ -516,7 +518,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
String _pattern;
|
String _pattern;
|
||||||
SDFSImpl* _fs;
|
SDFSImpl* _fs;
|
||||||
std::shared_ptr<sdfat::File> _dir;
|
std::shared_ptr<sdfat::File32> _dir;
|
||||||
bool _valid;
|
bool _valid;
|
||||||
char _lfn[64];
|
char _lfn[64];
|
||||||
time_t _time;
|
time_t _time;
|
||||||
|
@ -1,405 +0,0 @@
|
|||||||
/*
|
|
||||||
SDFSFormatter.cpp - Formatter for SdFat SD cards
|
|
||||||
Copyright (c) 2019 Earle F. Philhower, III. All rights reserved.
|
|
||||||
|
|
||||||
A C++ implementation of the SdFat/examples/SdFormatter sketch:
|
|
||||||
| Copyright (c) 2011-2018 Bill Greiman
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _SDFSFORMATTER_H
|
|
||||||
#define _SDFSFORMATTER_H
|
|
||||||
|
|
||||||
#include "SDFS.h"
|
|
||||||
#include <FS.h>
|
|
||||||
#include <PolledTimeout.h>
|
|
||||||
|
|
||||||
namespace sdfs {
|
|
||||||
|
|
||||||
class SDFSFormatter {
|
|
||||||
private:
|
|
||||||
// Taken from main FS object
|
|
||||||
sdfat::Sd2Card *card;
|
|
||||||
sdfat::cache_t *cache;
|
|
||||||
|
|
||||||
uint32_t cardSizeBlocks;
|
|
||||||
uint32_t cardCapacityMB;
|
|
||||||
|
|
||||||
|
|
||||||
// MBR information
|
|
||||||
uint8_t partType;
|
|
||||||
uint32_t relSector;
|
|
||||||
uint32_t partSize;
|
|
||||||
|
|
||||||
// Fake disk geometry
|
|
||||||
uint8_t numberOfHeads;
|
|
||||||
uint8_t sectorsPerTrack;
|
|
||||||
|
|
||||||
// FAT parameters
|
|
||||||
uint16_t reservedSectors;
|
|
||||||
uint8_t sectorsPerCluster;
|
|
||||||
uint32_t fatStart;
|
|
||||||
uint32_t fatSize;
|
|
||||||
uint32_t dataStart;
|
|
||||||
|
|
||||||
uint8_t writeCache(uint32_t lbn) {
|
|
||||||
return card->writeBlock(lbn, cache->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearCache(uint8_t addSig) {
|
|
||||||
memset(cache, 0, sizeof(*cache));
|
|
||||||
if (addSig) {
|
|
||||||
cache->mbr.mbrSig0 = sdfat::BOOTSIG0;
|
|
||||||
cache->mbr.mbrSig1 = sdfat::BOOTSIG1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool clearFatDir(uint32_t bgn, uint32_t count) {
|
|
||||||
clearCache(false);
|
|
||||||
if (!card->writeStart(bgn, count)) {
|
|
||||||
DEBUGV("SDFS: Clear FAT/DIR writeStart failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
esp8266::polledTimeout::periodicFastMs timeToYield(5); // Yield every 5ms of runtime
|
|
||||||
for (uint32_t i = 0; i < count; i++) {
|
|
||||||
if (timeToYield) {
|
|
||||||
delay(0); // WDT feed
|
|
||||||
}
|
|
||||||
if (!card->writeData(cache->data)) {
|
|
||||||
DEBUGV("SDFS: Clear FAT/DIR writeData failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!card->writeStop()) {
|
|
||||||
DEBUGV("SDFS: Clear FAT/DIR writeStop failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t lbnToCylinder(uint32_t lbn) {
|
|
||||||
return lbn / (numberOfHeads * sectorsPerTrack);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t lbnToHead(uint32_t lbn) {
|
|
||||||
return (lbn % (numberOfHeads * sectorsPerTrack)) / sectorsPerTrack;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t lbnToSector(uint32_t lbn) {
|
|
||||||
return (lbn % sectorsPerTrack) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool writeMbr() {
|
|
||||||
clearCache(true);
|
|
||||||
sdfat::part_t* p = cache->mbr.part;
|
|
||||||
p->boot = 0;
|
|
||||||
uint16_t c = lbnToCylinder(relSector);
|
|
||||||
if (c > 1023) {
|
|
||||||
DEBUGV("SDFS: MBR CHS");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
p->beginCylinderHigh = c >> 8;
|
|
||||||
p->beginCylinderLow = c & 0XFF;
|
|
||||||
p->beginHead = lbnToHead(relSector);
|
|
||||||
p->beginSector = lbnToSector(relSector);
|
|
||||||
p->type = partType;
|
|
||||||
uint32_t endLbn = relSector + partSize - 1;
|
|
||||||
c = lbnToCylinder(endLbn);
|
|
||||||
if (c <= 1023) {
|
|
||||||
p->endCylinderHigh = c >> 8;
|
|
||||||
p->endCylinderLow = c & 0XFF;
|
|
||||||
p->endHead = lbnToHead(endLbn);
|
|
||||||
p->endSector = lbnToSector(endLbn);
|
|
||||||
} else {
|
|
||||||
// Too big flag, c = 1023, h = 254, s = 63
|
|
||||||
p->endCylinderHigh = 3;
|
|
||||||
p->endCylinderLow = 255;
|
|
||||||
p->endHead = 254;
|
|
||||||
p->endSector = 63;
|
|
||||||
}
|
|
||||||
p->firstSector = relSector;
|
|
||||||
p->totalSectors = partSize;
|
|
||||||
if (!writeCache(0)) {
|
|
||||||
DEBUGV("SDFS: write MBR");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t volSerialNumber() {
|
|
||||||
return (cardSizeBlocks << 8) + micros();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool makeFat16() {
|
|
||||||
uint16_t const BU16 = 128;
|
|
||||||
uint32_t nc;
|
|
||||||
for (dataStart = 2 * BU16;; dataStart += BU16) {
|
|
||||||
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
|
|
||||||
fatSize = (nc + 2 + 255)/256;
|
|
||||||
uint32_t r = BU16 + 1 + 2 * fatSize + 32;
|
|
||||||
if (dataStart < r) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
relSector = dataStart - r + BU16;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// check valid cluster count for FAT16 volume
|
|
||||||
if (nc < 4085 || nc >= 65525) {
|
|
||||||
DEBUGV("SDFS: Bad cluster count");
|
|
||||||
}
|
|
||||||
reservedSectors = 1;
|
|
||||||
fatStart = relSector + reservedSectors;
|
|
||||||
partSize = nc * sectorsPerCluster + 2 * fatSize + reservedSectors + 32;
|
|
||||||
if (partSize < 32680) {
|
|
||||||
partType = 0X01;
|
|
||||||
} else if (partSize < 65536) {
|
|
||||||
partType = 0X04;
|
|
||||||
} else {
|
|
||||||
partType = 0X06;
|
|
||||||
}
|
|
||||||
// write MBR
|
|
||||||
if (!writeMbr()) {
|
|
||||||
DEBUGV("SDFS: writembr failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearCache(true);
|
|
||||||
sdfat::fat_boot_t* pb = &cache->fbs;
|
|
||||||
pb->jump[0] = 0XEB;
|
|
||||||
pb->jump[1] = 0X00;
|
|
||||||
pb->jump[2] = 0X90;
|
|
||||||
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
|
|
||||||
pb->oemId[i] = ' ';
|
|
||||||
}
|
|
||||||
pb->bytesPerSector = 512;
|
|
||||||
pb->sectorsPerCluster = sectorsPerCluster;
|
|
||||||
pb->reservedSectorCount = reservedSectors;
|
|
||||||
pb->fatCount = 2;
|
|
||||||
pb->rootDirEntryCount = 512;
|
|
||||||
pb->mediaType = 0XF8;
|
|
||||||
pb->sectorsPerFat16 = fatSize;
|
|
||||||
pb->sectorsPerTrack = sectorsPerTrack;
|
|
||||||
pb->headCount = numberOfHeads;
|
|
||||||
pb->hidddenSectors = relSector;
|
|
||||||
pb->totalSectors32 = partSize;
|
|
||||||
pb->driveNumber = 0X80;
|
|
||||||
pb->bootSignature = sdfat::EXTENDED_BOOT_SIG;
|
|
||||||
pb->volumeSerialNumber = volSerialNumber();
|
|
||||||
memcpy_P(pb->volumeLabel, PSTR("NO NAME "), sizeof(pb->volumeLabel));
|
|
||||||
memcpy_P(pb->fileSystemType, PSTR("FAT16 "), sizeof(pb->fileSystemType));
|
|
||||||
// write partition boot sector
|
|
||||||
if (!writeCache(relSector)) {
|
|
||||||
DEBUGV("SDFS: FAT16 write PBS failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// clear FAT and root directory
|
|
||||||
if (!clearFatDir(fatStart, dataStart - fatStart)) {
|
|
||||||
DEBUGV("SDFS: FAT16 clear root failed\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
clearCache(false);
|
|
||||||
cache->fat16[0] = 0XFFF8;
|
|
||||||
cache->fat16[1] = 0XFFFF;
|
|
||||||
// write first block of FAT and backup for reserved clusters
|
|
||||||
if (!writeCache(fatStart) || !writeCache(fatStart + fatSize)) {
|
|
||||||
DEBUGV("FAT16 reserve failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool makeFat32() {
|
|
||||||
uint16_t const BU32 = 8192;
|
|
||||||
uint32_t nc;
|
|
||||||
relSector = BU32;
|
|
||||||
for (dataStart = 2 * BU32;; dataStart += BU32) {
|
|
||||||
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
|
|
||||||
fatSize = (nc + 2 + 127)/128;
|
|
||||||
uint32_t r = relSector + 9 + 2 * fatSize;
|
|
||||||
if (dataStart >= r) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// error if too few clusters in FAT32 volume
|
|
||||||
if (nc < 65525) {
|
|
||||||
DEBUGV("SDFS: Bad cluster count");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
reservedSectors = dataStart - relSector - 2 * fatSize;
|
|
||||||
fatStart = relSector + reservedSectors;
|
|
||||||
partSize = nc * sectorsPerCluster + dataStart - relSector;
|
|
||||||
// type depends on address of end sector
|
|
||||||
// max CHS has lbn = 16450560 = 1024*255*63
|
|
||||||
if ((relSector + partSize) <= 16450560) {
|
|
||||||
// FAT32
|
|
||||||
partType = 0X0B;
|
|
||||||
} else {
|
|
||||||
// FAT32 with INT 13
|
|
||||||
partType = 0X0C;
|
|
||||||
}
|
|
||||||
if (!writeMbr()) {
|
|
||||||
DEBUGV("SDFS: writembr failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearCache(true);
|
|
||||||
|
|
||||||
sdfat::fat32_boot_t* pb = &cache->fbs32;
|
|
||||||
pb->jump[0] = 0XEB;
|
|
||||||
pb->jump[1] = 0X00;
|
|
||||||
pb->jump[2] = 0X90;
|
|
||||||
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
|
|
||||||
pb->oemId[i] = ' ';
|
|
||||||
}
|
|
||||||
pb->bytesPerSector = 512;
|
|
||||||
pb->sectorsPerCluster = sectorsPerCluster;
|
|
||||||
pb->reservedSectorCount = reservedSectors;
|
|
||||||
pb->fatCount = 2;
|
|
||||||
pb->mediaType = 0XF8;
|
|
||||||
pb->sectorsPerTrack = sectorsPerTrack;
|
|
||||||
pb->headCount = numberOfHeads;
|
|
||||||
pb->hidddenSectors = relSector;
|
|
||||||
pb->totalSectors32 = partSize;
|
|
||||||
pb->sectorsPerFat32 = fatSize;
|
|
||||||
pb->fat32RootCluster = 2;
|
|
||||||
pb->fat32FSInfo = 1;
|
|
||||||
pb->fat32BackBootBlock = 6;
|
|
||||||
pb->driveNumber = 0X80;
|
|
||||||
pb->bootSignature = sdfat::EXTENDED_BOOT_SIG;
|
|
||||||
pb->volumeSerialNumber = volSerialNumber();
|
|
||||||
memcpy_P(pb->volumeLabel, PSTR("NO NAME "), sizeof(pb->volumeLabel));
|
|
||||||
memcpy_P(pb->fileSystemType, PSTR("FAT32 "), sizeof(pb->fileSystemType));
|
|
||||||
// write partition boot sector and backup
|
|
||||||
if (!writeCache(relSector) || !writeCache(relSector + 6)) {
|
|
||||||
DEBUGV("SDFS: FAT32 write PBS failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
clearCache(true);
|
|
||||||
// write extra boot area and backup
|
|
||||||
if (!writeCache(relSector + 2) || !writeCache(relSector + 8)) {
|
|
||||||
DEBUGV("SDFS: FAT32 PBS ext failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sdfat::fat32_fsinfo_t* pf = &cache->fsinfo;
|
|
||||||
pf->leadSignature = sdfat::FSINFO_LEAD_SIG;
|
|
||||||
pf->structSignature = sdfat::FSINFO_STRUCT_SIG;
|
|
||||||
pf->freeCount = 0XFFFFFFFF;
|
|
||||||
pf->nextFree = 0XFFFFFFFF;
|
|
||||||
// write FSINFO sector and backup
|
|
||||||
if (!writeCache(relSector + 1) || !writeCache(relSector + 7)) {
|
|
||||||
DEBUGV("SDFS: FAT32 FSINFO failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
clearFatDir(fatStart, 2 * fatSize + sectorsPerCluster);
|
|
||||||
clearCache(false);
|
|
||||||
cache->fat32[0] = 0x0FFFFFF8;
|
|
||||||
cache->fat32[1] = 0x0FFFFFFF;
|
|
||||||
cache->fat32[2] = 0x0FFFFFFF;
|
|
||||||
// write first block of FAT and backup for reserved clusters
|
|
||||||
if (!writeCache(fatStart) || !writeCache(fatStart + fatSize)) {
|
|
||||||
DEBUGV("SDFS: FAT32 reserve failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool format(sdfat::SdFat *_fs, int8_t _csPin, SPISettings _spiSettings) {
|
|
||||||
card = static_cast<sdfat::Sd2Card*>(_fs->card());
|
|
||||||
cache = _fs->cacheClear();
|
|
||||||
|
|
||||||
if (!card->begin(_csPin, _spiSettings)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cardSizeBlocks = card->cardSize();
|
|
||||||
if (cardSizeBlocks == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cardCapacityMB = (cardSizeBlocks + 2047)/2048;
|
|
||||||
|
|
||||||
if (cardCapacityMB <= 6) {
|
|
||||||
return false; // Card is too small
|
|
||||||
} else if (cardCapacityMB <= 16) {
|
|
||||||
sectorsPerCluster = 2;
|
|
||||||
} else if (cardCapacityMB <= 32) {
|
|
||||||
sectorsPerCluster = 4;
|
|
||||||
} else if (cardCapacityMB <= 64) {
|
|
||||||
sectorsPerCluster = 8;
|
|
||||||
} else if (cardCapacityMB <= 128) {
|
|
||||||
sectorsPerCluster = 16;
|
|
||||||
} else if (cardCapacityMB <= 1024) {
|
|
||||||
sectorsPerCluster = 32;
|
|
||||||
} else if (cardCapacityMB <= 32768) {
|
|
||||||
sectorsPerCluster = 64;
|
|
||||||
} else {
|
|
||||||
// SDXC cards
|
|
||||||
sectorsPerCluster = 128;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set fake disk geometry
|
|
||||||
sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63;
|
|
||||||
|
|
||||||
if (cardCapacityMB <= 16) {
|
|
||||||
numberOfHeads = 2;
|
|
||||||
} else if (cardCapacityMB <= 32) {
|
|
||||||
numberOfHeads = 4;
|
|
||||||
} else if (cardCapacityMB <= 128) {
|
|
||||||
numberOfHeads = 8;
|
|
||||||
} else if (cardCapacityMB <= 504) {
|
|
||||||
numberOfHeads = 16;
|
|
||||||
} else if (cardCapacityMB <= 1008) {
|
|
||||||
numberOfHeads = 32;
|
|
||||||
} else if (cardCapacityMB <= 2016) {
|
|
||||||
numberOfHeads = 64;
|
|
||||||
} else if (cardCapacityMB <= 4032) {
|
|
||||||
numberOfHeads = 128;
|
|
||||||
} else {
|
|
||||||
numberOfHeads = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Erase all data on card (TRIM)
|
|
||||||
uint32_t const ERASE_SIZE = 262144L;
|
|
||||||
uint32_t firstBlock = 0;
|
|
||||||
uint32_t lastBlock;
|
|
||||||
do {
|
|
||||||
lastBlock = firstBlock + ERASE_SIZE - 1;
|
|
||||||
if (lastBlock >= cardSizeBlocks) {
|
|
||||||
lastBlock = cardSizeBlocks - 1;
|
|
||||||
}
|
|
||||||
if (!card->erase(firstBlock, lastBlock)) {
|
|
||||||
return false; // Erase fail
|
|
||||||
}
|
|
||||||
delay(0); // yield to the OS to avoid WDT
|
|
||||||
firstBlock += ERASE_SIZE;
|
|
||||||
} while (firstBlock < cardSizeBlocks);
|
|
||||||
|
|
||||||
if (!card->readBlock(0, cache->data)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (card->type() != sdfat::SD_CARD_TYPE_SDHC) {
|
|
||||||
return makeFat16();
|
|
||||||
} else {
|
|
||||||
return makeFat32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}; // class SDFSFormatter
|
|
||||||
|
|
||||||
}; // namespace sdfs
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _SDFSFORMATTER_H
|
|
Loading…
Reference in New Issue
Block a user