mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-13 13:01:55 +03:00
committed by
david gauchard
parent
98125f8860
commit
eea9999dc5
@ -1,29 +1,29 @@
|
||||
/*
|
||||
SDFS.cpp - file system wrapper for SdFat
|
||||
Copyright (c) 2019 Earle F. Philhower, III. All rights reserved.
|
||||
SDFS.cpp - file system wrapper for SdFat
|
||||
Copyright (c) 2019 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
Based on spiffs_api.cpp which is:
|
||||
| Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
Based on spiffs_api.cpp which is:
|
||||
| Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
|
||||
This code was influenced by NodeMCU and Sming libraries, and first version of
|
||||
Arduino wrapper written by Hristo Gochkov.
|
||||
This code was influenced by NodeMCU and Sming libraries, and first version of
|
||||
Arduino wrapper written by Hristo Gochkov.
|
||||
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
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 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.
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
#include "SDFS.h"
|
||||
#include "SDFSFormatter.h"
|
||||
#include <FS.h>
|
||||
@ -35,34 +35,28 @@ using namespace fs;
|
||||
FS SDFS = FS(FSImplPtr(new sdfs::SDFSImpl()));
|
||||
#endif
|
||||
|
||||
namespace sdfs
|
||||
{
|
||||
namespace sdfs {
|
||||
|
||||
|
||||
FileImplPtr SDFSImpl::open(const char* path, OpenMode openMode, AccessMode accessMode)
|
||||
{
|
||||
if (!_mounted)
|
||||
{
|
||||
if (!_mounted) {
|
||||
DEBUGV("SDFSImpl::open() called on unmounted FS\n");
|
||||
return FileImplPtr();
|
||||
}
|
||||
if (!path || !path[0])
|
||||
{
|
||||
if (!path || !path[0]) {
|
||||
DEBUGV("SDFSImpl::open() called with invalid filename\n");
|
||||
return FileImplPtr();
|
||||
}
|
||||
int flags = _getFlags(openMode, accessMode);
|
||||
if ((openMode && OM_CREATE) && strchr(path, '/'))
|
||||
{
|
||||
if ((openMode && OM_CREATE) && strchr(path, '/')) {
|
||||
// For file creation, silently make subdirs as needed. If any fail,
|
||||
// it will be caught by the real file open later on
|
||||
char *pathStr = strdup(path);
|
||||
if (pathStr)
|
||||
{
|
||||
if (pathStr) {
|
||||
// Make dirs up to the final fnamepart
|
||||
char *ptr = strrchr(pathStr, '/');
|
||||
if (ptr && ptr != pathStr) // Don't try to make root dir!
|
||||
{
|
||||
if (ptr && ptr != pathStr) { // Don't try to make root dir!
|
||||
*ptr = 0;
|
||||
_fs.mkdir(pathStr, true);
|
||||
}
|
||||
@ -70,8 +64,7 @@ FileImplPtr SDFSImpl::open(const char* path, OpenMode openMode, AccessMode acces
|
||||
free(pathStr);
|
||||
}
|
||||
sdfat::File fd = _fs.open(path, flags);
|
||||
if (!fd)
|
||||
{
|
||||
if (!fd) {
|
||||
DEBUGV("SDFSImpl::openFile: fd=%p path=`%s` openMode=%d accessMode=%d",
|
||||
&fd, path, openMode, accessMode);
|
||||
return FileImplPtr();
|
||||
@ -82,80 +75,62 @@ FileImplPtr SDFSImpl::open(const char* path, OpenMode openMode, AccessMode acces
|
||||
|
||||
DirImplPtr SDFSImpl::openDir(const char* path)
|
||||
{
|
||||
if (!_mounted)
|
||||
{
|
||||
if (!_mounted) {
|
||||
return DirImplPtr();
|
||||
}
|
||||
char *pathStr = strdup(path); // Allow edits on our scratch copy
|
||||
if (!pathStr)
|
||||
{
|
||||
if (!pathStr) {
|
||||
// OOM
|
||||
return DirImplPtr();
|
||||
}
|
||||
// Get rid of any trailing slashes
|
||||
while (strlen(pathStr) && (pathStr[strlen(pathStr) - 1] == '/'))
|
||||
{
|
||||
pathStr[strlen(pathStr) - 1] = 0;
|
||||
while (strlen(pathStr) && (pathStr[strlen(pathStr)-1]=='/')) {
|
||||
pathStr[strlen(pathStr)-1] = 0;
|
||||
}
|
||||
// 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.
|
||||
sdfat::File dirFile;
|
||||
const char *filter = "";
|
||||
if (!pathStr[0])
|
||||
{
|
||||
if (!pathStr[0]) {
|
||||
// openDir("") === openDir("/")
|
||||
dirFile = _fs.open("/", sdfat::O_RDONLY);
|
||||
filter = "";
|
||||
}
|
||||
else if (_fs.exists(pathStr))
|
||||
{
|
||||
} else if (_fs.exists(pathStr)) {
|
||||
dirFile = _fs.open(pathStr, sdfat::O_RDONLY);
|
||||
if (dirFile.isDir())
|
||||
{
|
||||
if (dirFile.isDir()) {
|
||||
// Easy peasy, path specifies an existing dir!
|
||||
filter = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
dirFile.close();
|
||||
// This is a file, so open the containing dir
|
||||
char *ptr = strrchr(pathStr, '/');
|
||||
if (!ptr)
|
||||
{
|
||||
if (!ptr) {
|
||||
// No slashes, open the root dir
|
||||
dirFile = _fs.open("/", sdfat::O_RDONLY);
|
||||
filter = pathStr;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// We've got slashes, open the dir one up
|
||||
*ptr = 0; // Remove slash, truncare string
|
||||
dirFile = _fs.open(pathStr, sdfat::O_RDONLY);
|
||||
filter = ptr + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Name doesn't exist, so use the parent dir of whatever was sent in
|
||||
// This is a file, so open the containing dir
|
||||
char *ptr = strrchr(pathStr, '/');
|
||||
if (!ptr)
|
||||
{
|
||||
if (!ptr) {
|
||||
// No slashes, open the root dir
|
||||
dirFile = _fs.open("/", sdfat::O_RDONLY);
|
||||
filter = pathStr;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// We've got slashes, open the dir one up
|
||||
*ptr = 0; // Remove slash, truncare string
|
||||
dirFile = _fs.open(pathStr, sdfat::O_RDONLY);
|
||||
filter = ptr + 1;
|
||||
}
|
||||
}
|
||||
if (!dirFile)
|
||||
{
|
||||
if (!dirFile) {
|
||||
DEBUGV("SDFSImpl::openDir: path=`%s`\n", path);
|
||||
return DirImplPtr();
|
||||
}
|
||||
@ -165,10 +140,8 @@ DirImplPtr SDFSImpl::openDir(const char* path)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool SDFSImpl::format()
|
||||
{
|
||||
if (_mounted)
|
||||
{
|
||||
bool SDFSImpl::format() {
|
||||
if (_mounted) {
|
||||
return false;
|
||||
}
|
||||
SDFSFormatter formatter;
|
||||
|
@ -2,31 +2,31 @@
|
||||
#define SDFS_H
|
||||
|
||||
/*
|
||||
SDFS.h - file system wrapper for SdLib
|
||||
Copyright (c) 2019 Earle F. Philhower, III. All rights reserved.
|
||||
SDFS.h - file system wrapper for SdLib
|
||||
Copyright (c) 2019 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
Based on spiffs_api.h, which is:
|
||||
| Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
Based on spiffs_api.h, which is:
|
||||
| Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
|
||||
This code was influenced by NodeMCU and Sming libraries, and first version of
|
||||
Arduino wrapper written by Hristo Gochkov.
|
||||
This code was influenced by NodeMCU and Sming libraries, and first version of
|
||||
Arduino wrapper written by Hristo Gochkov.
|
||||
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
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 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.
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
#include <limits>
|
||||
#include <assert.h>
|
||||
#include "FS.h"
|
||||
@ -38,50 +38,43 @@
|
||||
|
||||
using namespace fs;
|
||||
|
||||
namespace sdfs
|
||||
{
|
||||
namespace sdfs {
|
||||
|
||||
class SDFSFileImpl;
|
||||
class SDFSDirImpl;
|
||||
class SDFSConfig : public FSConfig
|
||||
{
|
||||
public:
|
||||
SDFSConfig()
|
||||
{
|
||||
SDFSConfig() {
|
||||
_type = SDFSConfig::fsid::FSId;
|
||||
_autoFormat = false;
|
||||
_csPin = 4;
|
||||
_spiSettings = SD_SCK_MHZ(10);
|
||||
_part = 0;
|
||||
_part = 0;
|
||||
}
|
||||
SDFSConfig(uint8_t csPin, SPISettings spi)
|
||||
{
|
||||
SDFSConfig(uint8_t csPin, SPISettings spi) {
|
||||
_type = SDFSConfig::fsid::FSId;
|
||||
_autoFormat = false;
|
||||
_csPin = csPin;
|
||||
_spiSettings = spi;
|
||||
_part = 0;
|
||||
_part = 0;
|
||||
}
|
||||
|
||||
enum fsid { FSId = 0x53444653 };
|
||||
|
||||
SDFSConfig setAutoFormat(bool val = true)
|
||||
{
|
||||
SDFSConfig setAutoFormat(bool val = true) {
|
||||
_autoFormat = val;
|
||||
return *this;
|
||||
}
|
||||
SDFSConfig setCSPin(uint8_t pin)
|
||||
{
|
||||
SDFSConfig setCSPin(uint8_t pin) {
|
||||
_csPin = pin;
|
||||
return *this;
|
||||
}
|
||||
SDFSConfig setSPI(SPISettings spi)
|
||||
{
|
||||
SDFSConfig setSPI(SPISettings spi) {
|
||||
_spiSettings = spi;
|
||||
return *this;
|
||||
}
|
||||
SDFSConfig setPart(uint8_t part)
|
||||
{
|
||||
SDFSConfig setPart(uint8_t part) {
|
||||
_part = part;
|
||||
return *this;
|
||||
}
|
||||
@ -101,22 +94,18 @@ public:
|
||||
|
||||
FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) override;
|
||||
|
||||
bool exists(const char* path)
|
||||
{
|
||||
bool exists(const char* path) {
|
||||
return _mounted ? _fs.exists(path) : false;
|
||||
}
|
||||
|
||||
DirImplPtr openDir(const char* path) override;
|
||||
|
||||
bool rename(const char* pathFrom, const char* pathTo) override
|
||||
{
|
||||
bool rename(const char* pathFrom, const char* pathTo) override {
|
||||
return _mounted ? _fs.rename(pathFrom, pathTo) : false;
|
||||
}
|
||||
|
||||
bool info(FSInfo& info) override
|
||||
{
|
||||
if (!_mounted)
|
||||
{
|
||||
bool info(FSInfo& info) override {
|
||||
if (!_mounted) {
|
||||
DEBUGV("SDFS::info: FS not mounted\n");
|
||||
return false;
|
||||
}
|
||||
@ -124,54 +113,46 @@ public:
|
||||
info.blockSize = _fs.vol()->blocksPerCluster() * 512;
|
||||
info.pageSize = 0; // TODO ?
|
||||
info.maxPathLength = 255; // TODO ?
|
||||
info.totalBytes = _fs.vol()->volumeBlockCount() * 512;
|
||||
info.totalBytes =_fs.vol()->volumeBlockCount() * 512;
|
||||
info.usedBytes = info.totalBytes - (_fs.vol()->freeClusterCount() * _fs.vol()->blocksPerCluster() * 512);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remove(const char* path) override
|
||||
{
|
||||
bool remove(const char* path) override {
|
||||
return _mounted ? _fs.remove(path) : false;
|
||||
}
|
||||
|
||||
bool mkdir(const char* path) override
|
||||
{
|
||||
bool mkdir(const char* path) override {
|
||||
return _mounted ? _fs.mkdir(path) : false;
|
||||
}
|
||||
|
||||
bool rmdir(const char* path) override
|
||||
{
|
||||
return _mounted ? _fs.rmdir(path) : false;
|
||||
bool rmdir(const char* path) override {
|
||||
return _mounted ?_fs.rmdir(path) : false;
|
||||
}
|
||||
|
||||
bool setConfig(const FSConfig &cfg) override
|
||||
{
|
||||
if ((cfg._type != SDFSConfig::fsid::FSId) || _mounted)
|
||||
{
|
||||
if ((cfg._type != SDFSConfig::fsid::FSId) || _mounted) {
|
||||
DEBUGV("SDFS::setConfig: invalid config or already mounted\n");
|
||||
return false;
|
||||
}
|
||||
_cfg = *static_cast<const SDFSConfig *>(&cfg);
|
||||
_cfg = *static_cast<const SDFSConfig *>(&cfg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool begin() override
|
||||
{
|
||||
if (_mounted)
|
||||
{
|
||||
bool begin() override {
|
||||
if (_mounted) {
|
||||
end();
|
||||
}
|
||||
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
|
||||
if (!_mounted && _cfg._autoFormat)
|
||||
{
|
||||
if (!_mounted && _cfg._autoFormat) {
|
||||
format();
|
||||
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
|
||||
}
|
||||
return _mounted;
|
||||
}
|
||||
|
||||
void end() override
|
||||
{
|
||||
void end() override {
|
||||
_mounted = false;
|
||||
// TODO
|
||||
}
|
||||
@ -187,27 +168,21 @@ protected:
|
||||
return &_fs;
|
||||
}
|
||||
|
||||
static uint8_t _getFlags(OpenMode openMode, AccessMode accessMode)
|
||||
{
|
||||
static uint8_t _getFlags(OpenMode openMode, AccessMode accessMode) {
|
||||
uint8_t mode = 0;
|
||||
if (openMode & OM_CREATE)
|
||||
{
|
||||
if (openMode & OM_CREATE) {
|
||||
mode |= sdfat::O_CREAT;
|
||||
}
|
||||
if (openMode & OM_APPEND)
|
||||
{
|
||||
if (openMode & OM_APPEND) {
|
||||
mode |= sdfat::O_AT_END;
|
||||
}
|
||||
if (openMode & OM_TRUNCATE)
|
||||
{
|
||||
if (openMode & OM_TRUNCATE) {
|
||||
mode |= sdfat::O_TRUNC;
|
||||
}
|
||||
if (accessMode & AM_READ)
|
||||
{
|
||||
if (accessMode & AM_READ) {
|
||||
mode |= sdfat::O_READ;
|
||||
}
|
||||
if (accessMode & AM_WRITE)
|
||||
{
|
||||
if (accessMode & AM_WRITE) {
|
||||
mode |= sdfat::O_WRITE;
|
||||
}
|
||||
return mode;
|
||||
@ -247,8 +222,7 @@ public:
|
||||
|
||||
void flush() override
|
||||
{
|
||||
if (_opened)
|
||||
{
|
||||
if (_opened) {
|
||||
_fd->flush();
|
||||
_fd->sync();
|
||||
}
|
||||
@ -256,23 +230,21 @@ public:
|
||||
|
||||
bool seek(uint32_t pos, SeekMode mode) override
|
||||
{
|
||||
if (!_opened)
|
||||
{
|
||||
if (!_opened) {
|
||||
return false;
|
||||
}
|
||||
switch (mode)
|
||||
{
|
||||
case SeekSet:
|
||||
return _fd->seekSet(pos);
|
||||
case SeekEnd:
|
||||
return _fd->seekEnd(-pos); // TODO again, odd from POSIX
|
||||
case SeekCur:
|
||||
return _fd->seekCur(pos);
|
||||
default:
|
||||
// Should not be hit, we've got an invalid seek mode
|
||||
DEBUGV("SDFSFileImpl::seek: invalid seek mode %d\n", mode);
|
||||
assert((mode == SeekSet) || (mode == SeekEnd) || (mode == SeekCur)); // Will fail and give meaningful assert message
|
||||
return false;
|
||||
switch (mode) {
|
||||
case SeekSet:
|
||||
return _fd->seekSet(pos);
|
||||
case SeekEnd:
|
||||
return _fd->seekEnd(-pos); // TODO again, odd from POSIX
|
||||
case SeekCur:
|
||||
return _fd->seekCur(pos);
|
||||
default:
|
||||
// Should not be hit, we've got an invalid seek mode
|
||||
DEBUGV("SDFSFileImpl::seek: invalid seek mode %d\n", mode);
|
||||
assert((mode==SeekSet) || (mode==SeekEnd) || (mode==SeekCur)); // Will fail and give meaningful assert message
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,8 +260,7 @@ public:
|
||||
|
||||
bool truncate(uint32_t size) override
|
||||
{
|
||||
if (!_opened)
|
||||
{
|
||||
if (!_opened) {
|
||||
DEBUGV("SDFSFileImpl::truncate: file not opened\n");
|
||||
return false;
|
||||
}
|
||||
@ -298,8 +269,7 @@ public:
|
||||
|
||||
void close() override
|
||||
{
|
||||
if (_opened)
|
||||
{
|
||||
if (_opened) {
|
||||
_fd->close();
|
||||
_opened = false;
|
||||
}
|
||||
@ -307,13 +277,10 @@ public:
|
||||
|
||||
const char* name() const override
|
||||
{
|
||||
if (!_opened)
|
||||
{
|
||||
if (!_opened) {
|
||||
DEBUGV("SDFSFileImpl::name: file not opened\n");
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
const char *p = _name.get();
|
||||
const char *slash = strrchr(p, '/');
|
||||
// For names w/o any path elements, return directly
|
||||
@ -353,8 +320,7 @@ public:
|
||||
SDFSDirImpl(const String& pattern, SDFSImpl* fs, std::shared_ptr<sdfat::File> dir, const char *dirPath = nullptr)
|
||||
: _pattern(pattern), _fs(fs), _dir(dir), _valid(false), _dirPath(nullptr)
|
||||
{
|
||||
if (dirPath)
|
||||
{
|
||||
if (dirPath) {
|
||||
_dirPath = std::shared_ptr<char>(new char[strlen(dirPath) + 1], std::default_delete<char[]>());
|
||||
strcpy(_dirPath.get(), dirPath);
|
||||
}
|
||||
@ -367,20 +333,18 @@ public:
|
||||
|
||||
FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) override
|
||||
{
|
||||
if (!_valid)
|
||||
{
|
||||
if (!_valid) {
|
||||
return FileImplPtr();
|
||||
}
|
||||
// MAX_PATH on FAT32 is potentially 260 bytes per most implementations
|
||||
char tmpName[260];
|
||||
snprintf(tmpName, sizeof(tmpName), "%s%s%s", _dirPath.get() ? _dirPath.get() : "", _dirPath.get() && _dirPath.get()[0] ? "/" : "", _lfn);
|
||||
snprintf(tmpName, sizeof(tmpName), "%s%s%s", _dirPath.get() ? _dirPath.get() : "", _dirPath.get()&&_dirPath.get()[0]?"/":"", _lfn);
|
||||
return _fs->open((const char *)tmpName, openMode, accessMode);
|
||||
}
|
||||
|
||||
const char* fileName() override
|
||||
{
|
||||
if (!_valid)
|
||||
{
|
||||
if (!_valid) {
|
||||
DEBUGV("SDFSDirImpl::fileName: directory not valid\n");
|
||||
return nullptr;
|
||||
}
|
||||
@ -389,8 +353,7 @@ public:
|
||||
|
||||
size_t fileSize() override
|
||||
{
|
||||
if (!_valid)
|
||||
{
|
||||
if (!_valid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -410,24 +373,20 @@ public:
|
||||
bool next() override
|
||||
{
|
||||
const int n = _pattern.length();
|
||||
do
|
||||
{
|
||||
do {
|
||||
sdfat::File file;
|
||||
file.openNext(_dir.get(), sdfat::O_READ);
|
||||
if (file)
|
||||
{
|
||||
if (file) {
|
||||
_valid = 1;
|
||||
_size = file.fileSize();
|
||||
_isFile = file.isFile();
|
||||
_isDirectory = file.isDirectory();
|
||||
file.getName(_lfn, sizeof(_lfn));
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_valid = 0;
|
||||
}
|
||||
} while (_valid && strncmp((const char*) _lfn, _pattern.c_str(), n) != 0);
|
||||
} while(_valid && strncmp((const char*) _lfn, _pattern.c_str(), n) != 0);
|
||||
return _valid;
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,24 @@
|
||||
/*
|
||||
SDFSFormatter.cpp - Formatter for SdFat SD cards
|
||||
Copyright (c) 2019 Earle F. Philhower, III. All rights reserved.
|
||||
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
|
||||
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 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.
|
||||
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
|
||||
*/
|
||||
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
|
||||
@ -27,11 +27,9 @@
|
||||
#include <FS.h>
|
||||
#include <PolledTimeout.h>
|
||||
|
||||
namespace sdfs
|
||||
{
|
||||
namespace sdfs {
|
||||
|
||||
class SDFSFormatter
|
||||
{
|
||||
class SDFSFormatter {
|
||||
private:
|
||||
// Taken from main FS object
|
||||
sdfat::Sd2Card *card;
|
||||
@ -57,73 +55,59 @@ private:
|
||||
uint32_t fatSize;
|
||||
uint32_t dataStart;
|
||||
|
||||
uint8_t writeCache(uint32_t lbn)
|
||||
{
|
||||
uint8_t writeCache(uint32_t lbn) {
|
||||
return card->writeBlock(lbn, cache->data);
|
||||
}
|
||||
|
||||
void clearCache(uint8_t addSig)
|
||||
{
|
||||
void clearCache(uint8_t addSig) {
|
||||
memset(cache, 0, sizeof(*cache));
|
||||
if (addSig)
|
||||
{
|
||||
if (addSig) {
|
||||
cache->mbr.mbrSig0 = sdfat::BOOTSIG0;
|
||||
cache->mbr.mbrSig1 = sdfat::BOOTSIG1;
|
||||
}
|
||||
}
|
||||
|
||||
bool clearFatDir(uint32_t bgn, uint32_t count)
|
||||
{
|
||||
bool clearFatDir(uint32_t bgn, uint32_t count) {
|
||||
clearCache(false);
|
||||
if (!card->writeStart(bgn, count))
|
||||
{
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (!card->writeData(cache->data)) {
|
||||
DEBUGV("SDFS: Clear FAT/DIR writeData failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!card->writeStop())
|
||||
{
|
||||
if (!card->writeStop()) {
|
||||
DEBUGV("SDFS: Clear FAT/DIR writeStop failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t lbnToCylinder(uint32_t lbn)
|
||||
{
|
||||
uint16_t lbnToCylinder(uint32_t lbn) {
|
||||
return lbn / (numberOfHeads * sectorsPerTrack);
|
||||
}
|
||||
|
||||
uint8_t lbnToHead(uint32_t lbn)
|
||||
{
|
||||
uint8_t lbnToHead(uint32_t lbn) {
|
||||
return (lbn % (numberOfHeads * sectorsPerTrack)) / sectorsPerTrack;
|
||||
}
|
||||
|
||||
uint8_t lbnToSector(uint32_t lbn)
|
||||
{
|
||||
uint8_t lbnToSector(uint32_t lbn) {
|
||||
return (lbn % sectorsPerTrack) + 1;
|
||||
}
|
||||
|
||||
bool writeMbr()
|
||||
{
|
||||
bool writeMbr() {
|
||||
clearCache(true);
|
||||
sdfat::part_t* p = cache->mbr.part;
|
||||
p->boot = 0;
|
||||
uint16_t c = lbnToCylinder(relSector);
|
||||
if (c > 1023)
|
||||
{
|
||||
if (c > 1023) {
|
||||
DEBUGV("SDFS: MBR CHS");
|
||||
return false;
|
||||
}
|
||||
@ -134,15 +118,12 @@ private:
|
||||
p->type = partType;
|
||||
uint32_t endLbn = relSector + partSize - 1;
|
||||
c = lbnToCylinder(endLbn);
|
||||
if (c <= 1023)
|
||||
{
|
||||
if (c <= 1023) {
|
||||
p->endCylinderHigh = c >> 8;
|
||||
p->endCylinderLow = c & 0XFF;
|
||||
p->endHead = lbnToHead(endLbn);
|
||||
p->endSector = lbnToSector(endLbn);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Too big flag, c = 1023, h = 254, s = 63
|
||||
p->endCylinderHigh = 3;
|
||||
p->endCylinderLow = 255;
|
||||
@ -151,58 +132,46 @@ private:
|
||||
}
|
||||
p->firstSector = relSector;
|
||||
p->totalSectors = partSize;
|
||||
if (!writeCache(0))
|
||||
{
|
||||
if (!writeCache(0)) {
|
||||
DEBUGV("SDFS: write MBR");
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t volSerialNumber()
|
||||
{
|
||||
uint32_t volSerialNumber() {
|
||||
return (cardSizeBlocks << 8) + micros();
|
||||
}
|
||||
|
||||
bool makeFat16()
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if (dataStart < r) {
|
||||
continue;
|
||||
}
|
||||
relSector = dataStart - r + BU16;
|
||||
break;
|
||||
}
|
||||
// check valid cluster count for FAT16 volume
|
||||
if (nc < 4085 || nc >= 65525)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (partSize < 32680) {
|
||||
partType = 0X01;
|
||||
}
|
||||
else if (partSize < 65536)
|
||||
{
|
||||
} else if (partSize < 65536) {
|
||||
partType = 0X04;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
partType = 0X06;
|
||||
}
|
||||
// write MBR
|
||||
if (!writeMbr())
|
||||
{
|
||||
if (!writeMbr()) {
|
||||
DEBUGV("SDFS: writembr failed");
|
||||
return false;
|
||||
}
|
||||
@ -212,8 +181,7 @@ private:
|
||||
pb->jump[0] = 0XEB;
|
||||
pb->jump[1] = 0X00;
|
||||
pb->jump[2] = 0X90;
|
||||
for (uint8_t i = 0; i < sizeof(pb->oemId); i++)
|
||||
{
|
||||
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
|
||||
pb->oemId[i] = ' ';
|
||||
}
|
||||
pb->bytesPerSector = 512;
|
||||
@ -233,14 +201,12 @@ private:
|
||||
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))
|
||||
{
|
||||
if (!writeCache(relSector)) {
|
||||
DEBUGV("SDFS: FAT16 write PBS failed");
|
||||
return false;
|
||||
}
|
||||
// clear FAT and root directory
|
||||
if (!clearFatDir(fatStart, dataStart - fatStart))
|
||||
{
|
||||
if (!clearFatDir(fatStart, dataStart - fatStart)) {
|
||||
DEBUGV("SDFS: FAT16 clear root failed\n");
|
||||
return false;
|
||||
}
|
||||
@ -248,32 +214,27 @@ private:
|
||||
cache->fat16[0] = 0XFFF8;
|
||||
cache->fat16[1] = 0XFFFF;
|
||||
// write first block of FAT and backup for reserved clusters
|
||||
if (!writeCache(fatStart) || !writeCache(fatStart + fatSize))
|
||||
{
|
||||
if (!writeCache(fatStart) || !writeCache(fatStart + fatSize)) {
|
||||
DEBUGV("FAT16 reserve failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool makeFat32()
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if (dataStart >= r) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// error if too few clusters in FAT32 volume
|
||||
if (nc < 65525)
|
||||
{
|
||||
if (nc < 65525) {
|
||||
DEBUGV("SDFS: Bad cluster count");
|
||||
return false;
|
||||
}
|
||||
@ -282,18 +243,14 @@ private:
|
||||
partSize = nc * sectorsPerCluster + dataStart - relSector;
|
||||
// type depends on address of end sector
|
||||
// max CHS has lbn = 16450560 = 1024*255*63
|
||||
if ((relSector + partSize) <= 16450560)
|
||||
{
|
||||
if ((relSector + partSize) <= 16450560) {
|
||||
// FAT32
|
||||
partType = 0X0B;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// FAT32 with INT 13
|
||||
partType = 0X0C;
|
||||
}
|
||||
if (!writeMbr())
|
||||
{
|
||||
if (!writeMbr()) {
|
||||
DEBUGV("SDFS: writembr failed");
|
||||
return false;
|
||||
}
|
||||
@ -304,8 +261,7 @@ private:
|
||||
pb->jump[0] = 0XEB;
|
||||
pb->jump[1] = 0X00;
|
||||
pb->jump[2] = 0X90;
|
||||
for (uint8_t i = 0; i < sizeof(pb->oemId); i++)
|
||||
{
|
||||
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
|
||||
pb->oemId[i] = ' ';
|
||||
}
|
||||
pb->bytesPerSector = 512;
|
||||
@ -327,15 +283,13 @@ private:
|
||||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (!writeCache(relSector + 2) || !writeCache(relSector + 8)) {
|
||||
DEBUGV("SDFS: FAT32 PBS ext failed");
|
||||
return false;
|
||||
}
|
||||
@ -345,8 +299,7 @@ private:
|
||||
pf->freeCount = 0XFFFFFFFF;
|
||||
pf->nextFree = 0XFFFFFFFF;
|
||||
// write FSINFO sector and backup
|
||||
if (!writeCache(relSector + 1) || !writeCache(relSector + 7))
|
||||
{
|
||||
if (!writeCache(relSector + 1) || !writeCache(relSector + 7)) {
|
||||
DEBUGV("SDFS: FAT32 FSINFO failed");
|
||||
return false;
|
||||
}
|
||||
@ -356,62 +309,43 @@ private:
|
||||
cache->fat32[1] = 0x0FFFFFFF;
|
||||
cache->fat32[2] = 0x0FFFFFFF;
|
||||
// write first block of FAT and backup for reserved clusters
|
||||
if (!writeCache(fatStart) || !writeCache(fatStart + fatSize))
|
||||
{
|
||||
if (!writeCache(fatStart) || !writeCache(fatStart + fatSize)) {
|
||||
DEBUGV("SDFS: FAT32 reserve failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
bool format(sdfat::SdFat *_fs, int8_t _csPin, SPISettings _spiSettings)
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (!card->begin(_csPin, _spiSettings)) {
|
||||
return false;
|
||||
}
|
||||
cardSizeBlocks = card->cardSize();
|
||||
if (cardSizeBlocks == 0)
|
||||
{
|
||||
if (cardSizeBlocks == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cardCapacityMB = (cardSizeBlocks + 2047) / 2048;
|
||||
cardCapacityMB = (cardSizeBlocks + 2047)/2048;
|
||||
|
||||
if (cardCapacityMB <= 6)
|
||||
{
|
||||
if (cardCapacityMB <= 6) {
|
||||
return false; // Card is too small
|
||||
}
|
||||
else if (cardCapacityMB <= 16)
|
||||
{
|
||||
} else if (cardCapacityMB <= 16) {
|
||||
sectorsPerCluster = 2;
|
||||
}
|
||||
else if (cardCapacityMB <= 32)
|
||||
{
|
||||
} else if (cardCapacityMB <= 32) {
|
||||
sectorsPerCluster = 4;
|
||||
}
|
||||
else if (cardCapacityMB <= 64)
|
||||
{
|
||||
} else if (cardCapacityMB <= 64) {
|
||||
sectorsPerCluster = 8;
|
||||
}
|
||||
else if (cardCapacityMB <= 128)
|
||||
{
|
||||
} else if (cardCapacityMB <= 128) {
|
||||
sectorsPerCluster = 16;
|
||||
}
|
||||
else if (cardCapacityMB <= 1024)
|
||||
{
|
||||
} else if (cardCapacityMB <= 1024) {
|
||||
sectorsPerCluster = 32;
|
||||
}
|
||||
else if (cardCapacityMB <= 32768)
|
||||
{
|
||||
} else if (cardCapacityMB <= 32768) {
|
||||
sectorsPerCluster = 64;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// SDXC cards
|
||||
sectorsPerCluster = 128;
|
||||
}
|
||||
@ -419,36 +353,21 @@ public:
|
||||
// set fake disk geometry
|
||||
sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63;
|
||||
|
||||
if (cardCapacityMB <= 16)
|
||||
{
|
||||
if (cardCapacityMB <= 16) {
|
||||
numberOfHeads = 2;
|
||||
}
|
||||
else if (cardCapacityMB <= 32)
|
||||
{
|
||||
} else if (cardCapacityMB <= 32) {
|
||||
numberOfHeads = 4;
|
||||
}
|
||||
else if (cardCapacityMB <= 128)
|
||||
{
|
||||
} else if (cardCapacityMB <= 128) {
|
||||
numberOfHeads = 8;
|
||||
}
|
||||
else if (cardCapacityMB <= 504)
|
||||
{
|
||||
} else if (cardCapacityMB <= 504) {
|
||||
numberOfHeads = 16;
|
||||
}
|
||||
else if (cardCapacityMB <= 1008)
|
||||
{
|
||||
} else if (cardCapacityMB <= 1008) {
|
||||
numberOfHeads = 32;
|
||||
}
|
||||
else if (cardCapacityMB <= 2016)
|
||||
{
|
||||
} else if (cardCapacityMB <= 2016) {
|
||||
numberOfHeads = 64;
|
||||
}
|
||||
else if (cardCapacityMB <= 4032)
|
||||
{
|
||||
} else if (cardCapacityMB <= 4032) {
|
||||
numberOfHeads = 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
numberOfHeads = 255;
|
||||
}
|
||||
|
||||
@ -456,32 +375,25 @@ public:
|
||||
uint32_t const ERASE_SIZE = 262144L;
|
||||
uint32_t firstBlock = 0;
|
||||
uint32_t lastBlock;
|
||||
do
|
||||
{
|
||||
do {
|
||||
lastBlock = firstBlock + ERASE_SIZE - 1;
|
||||
if (lastBlock >= cardSizeBlocks)
|
||||
{
|
||||
if (lastBlock >= cardSizeBlocks) {
|
||||
lastBlock = cardSizeBlocks - 1;
|
||||
}
|
||||
if (!card->erase(firstBlock, lastBlock))
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (!card->readBlock(0, cache->data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (card->type() != sdfat::SD_CARD_TYPE_SDHC)
|
||||
{
|
||||
if (card->type() != sdfat::SD_CARD_TYPE_SDHC) {
|
||||
return makeFat16();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return makeFat32();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user