From c02e922aa42b01f1b0f65b90e2c6838c76d6a3b3 Mon Sep 17 00:00:00 2001 From: Luc Date: Mon, 7 Oct 2019 17:54:57 +0800 Subject: [PATCH] SD wrapper backbone --- esp3d/src/include/defines.h | 5 + esp3d/src/modules/sd/esp_sd.cpp | 188 +++++++++++++++++++ esp3d/src/modules/sd/esp_sd.h | 100 ++++++++++ esp3d/src/modules/sd/sd_esp32.cpp | 295 ++++++++++++++++++++++++++++++ 4 files changed, 588 insertions(+) create mode 100644 esp3d/src/modules/sd/esp_sd.cpp create mode 100644 esp3d/src/modules/sd/esp_sd.h create mode 100644 esp3d/src/modules/sd/sd_esp32.cpp diff --git a/esp3d/src/include/defines.h b/esp3d/src/include/defines.h index 06d1d5bd..2d984c39 100644 --- a/esp3d/src/include/defines.h +++ b/esp3d/src/include/defines.h @@ -62,6 +62,11 @@ #define ESP_FAT_FILESYSTEM 2 #define ESP_LITTLEFS_FILESYSTEM 3 +//SD +#define ESP_SD_NATIVE 1 +#define ESP_SDIO 2 +#define ESP_SDFAT 3 + //Notifications #define ESP_PUSHOVER_NOTIFICATION 1 #define ESP_EMAIL_NOTIFICATION 2 diff --git a/esp3d/src/modules/sd/esp_sd.cpp b/esp3d/src/modules/sd/esp_sd.cpp new file mode 100644 index 00000000..b86a58f6 --- /dev/null +++ b/esp3d/src/modules/sd/esp_sd.cpp @@ -0,0 +1,188 @@ +/* + esp_sd.cpp - ESP3D SD support class + + Copyright (c) 2014 Luc Lebosse. All rights reserved. + + 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 +*/ +#include "../../include/esp3d_config.h" +#ifdef SD_FEATURE +#include "esp_sd.h" +#include "../../core/genLinkedList.h" +#ifdef SD_TIMESTAMP_FEATURE +#include +#endif //SD_TIMESTAMP_FEATURE +#include + + +#define ESP_MAX_SD_OPENHANDLE 4 +File tSDFile_handle[ESP_MAX_SD_OPENHANDLE]; + +bool ESP_SD::_started = false; + +//constructor +ESP_SD::ESP_SD() +{ +} + +//destructor +ESP_SD::~ESP_SD() +{ +} + +//helper to format size to readable string +String & ESP_SD::formatBytes (uint64_t bytes) +{ + static String res; + if (bytes < 1024) { + res = String ((uint16_t)bytes) + " B"; + } else if (bytes < (1024 * 1024) ) { + res = String ((float)(bytes / 1024.0),2) + " KB"; + } else if (bytes < (1024 * 1024 * 1024) ) { + res = String ((float)(bytes / 1024.0 / 1024.0),2) + " MB"; + } else { + res = String ((float)(bytes / 1024.0 / 1024.0 / 1024.0),2) + " GB"; + } + return res; +} + +ESP_SDFile::ESP_SDFile(const char * name, const char * filename, bool isdir, size_t size) +{ + _isdir = isdir; + _dirlist = ""; + _isfakedir = isdir; + _index = -1; + _filename = filename; + _name = name; +#ifdef SD_TIMESTAMP_FEATURE + memset (&_lastwrite,0,sizeof(time_t)); +#endif //SD_TIMESTAMP_FEATURE + _iswritemode = false; + _size = size; +} + +ESP_SDFile::~ESP_SDFile() +{ + //log_esp3d("Destructor %s index %d",(_isdir)?"Dir":"File", _index); +} + +ESP_SDFile::operator bool() const +{ + if ((_index != -1) || (_filename.length() > 0)) { + //log_esp3d("Bool yes %d %d",_index, _filename.length()); + return true; + } else { + return false; + } +} + +bool ESP_SDFile::isOpen() +{ + return !(_index == -1); +} + +const char* ESP_SDFile::name() const +{ + return _name.c_str(); +} + +const char* ESP_SDFile::filename() const +{ + return _filename.c_str(); +} + +bool ESP_SDFile::isDirectory() +{ + return _isdir; +} + +size_t ESP_SDFile::size() +{ + return _size; +} + +#ifdef SD_TIMESTAMP_FEATURE +time_t ESP_SDFile::getLastWrite() +{ + return _lastwrite; +} +#endif //SD_TIMESTAMP_FEATURE + +int ESP_SDFile::available() +{ + if (_index == -1 || _isdir) { + return 0; + } + return tSDFile_handle[_index].available(); +} + +size_t ESP_SDFile::write(uint8_t i) +{ + if ((_index == -1) || _isdir) { + return 0; + } + return tSDFile_handle[_index].write (i); +} + +size_t ESP_SDFile::write(const uint8_t *buf, size_t size) +{ + if ((_index == -1) || _isdir) { + return 0; + } + return tSDFile_handle[_index].write (buf, size); +} + +int ESP_SDFile::read() +{ + if ((_index == -1) || _isdir) { + return -1; + } + return tSDFile_handle[_index].read(); +} + +size_t ESP_SDFile::read(uint8_t* buf, size_t size) +{ + if ((_index == -1) || _isdir) { + return -1; + } + return tSDFile_handle[_index].read(buf, size); +} + +void ESP_SDFile::flush() +{ + if ((_index == -1) || _isdir) { + return; + } + tSDFile_handle[_index].flush(); +} + +ESP_SDFile& ESP_SDFile::operator=(const ESP_SDFile & other) +{ + //log_esp3d("Copy %s", other._filename.c_str()); + _isdir = other._isdir; + _isfakedir = other._isfakedir; + _index = other._index; + _filename = other._filename; + _name = other._name; + _size = other._size; + _iswritemode = other._iswritemode; + _dirlist = other._dirlist; +#ifdef SD_TIMESTAMP_FEATURE + memcpy(&_lastwrite, &(other._lastwrite), sizeof (time_t)); +#endif //SD_TIMESTAMP_FEATURE + return *this; +} + +#endif //SD_FEATURE diff --git a/esp3d/src/modules/sd/esp_sd.h b/esp3d/src/modules/sd/esp_sd.h new file mode 100644 index 00000000..5bcf9cf0 --- /dev/null +++ b/esp3d/src/modules/sd/esp_sd.h @@ -0,0 +1,100 @@ +/* + esp_sd.h - ESP3D SD support class + + Copyright (c) 2014 Luc Lebosse. All rights reserved. + + 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 _ESP_SD_H +#define _ESP_SD_H +#include "../../include/esp3d_config.h" +#ifdef SD_TIMESTAMP_FEATURE +#include +#endif //SD_TIMESTAMP_FEATURE +#define ESP_SD_FILE_READ 0 +#define ESP_SD_FILE_WRITE 1 +#define ESP_SD_FILE_APPEND 2 + +#define ESP_SD_HEADER "/SD:" + +#define ESP_MAX_SD_OPENHANDLE 4 + +class ESP_SDFile +{ +public: + ESP_SDFile(void * handle = nullptr, bool isdir =false, bool iswritemode = false, const char * path = nullptr); + ESP_SDFile(const char * name, const char * filename, bool isdir = true, size_t size =0); + ~ESP_SDFile(); + operator bool() const; + bool isDirectory(); + const char* name() const; + const char* filename() const; + void close(); + bool isOpen(); + ESP_SDFile & operator=(const ESP_SDFile & other); + size_t size(); +#ifdef SD_TIMESTAMP_FEATURE + time_t getLastWrite(); +#endif //SD_TIMESTAMP_FEATURE + int available(); + size_t write(uint8_t i); + size_t write(const uint8_t *buf, size_t size); + int read(); + size_t read(uint8_t* buf, size_t size); + void flush(); + ESP_SDFile openNextFile(); +private: + String _dirlist; + bool _isdir; + bool _isfakedir; + bool _iswritemode; + int8_t _index; + String _filename; + String _name; + size_t _size; +#ifdef SD_TIMESTAMP_FEATURE + time_t _lastwrite; +#endif //SD_TIMESTAMP_FEATURE +}; + +class ESP_SD +{ +public: + static String & formatBytes (uint64_t bytes); + ESP_SD(); + ~ESP_SD(); + static bool begin(); + static void end(); + static size_t totalBytes(); + static size_t usedBytes(); + static size_t freeBytes() + { + return totalBytes()-usedBytes(); + }; + static const char * FilesystemName(); + static bool format(); + static ESP_File open(const char* path, uint8_t mode = ESP_SD_FILE_READ); + static bool exists(const char* path); + static bool remove(const char *path); + static bool mkdir(const char *path); + static bool rmdir(const char *path); + static void closeAll(); +private: + static bool _started; +}; + + +#endif //_ESP_SD_H diff --git a/esp3d/src/modules/sd/sd_esp32.cpp b/esp3d/src/modules/sd/sd_esp32.cpp new file mode 100644 index 00000000..eb4162b7 --- /dev/null +++ b/esp3d/src/modules/sd/sd_esp32.cpp @@ -0,0 +1,295 @@ +/* +sd_native_esp32.cpp - ESP3D sd support class + + Copyright (c) 2014 Luc Lebosse. All rights reserved. + + 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 +*/ +#include "../../include/esp3d_config.h" +#if defined (ARCH_ESP32) && defined(SD_FEATURE) +#if (SD_FEATURE == ESP_SD_NATIVE) +#include "esp_sd.h" +#include "FS.h" +#include "SD.h" + +extern File tSDFile_handle[ESP_MAX_SD_OPENHANDLE]; + +bool ESP_SDFileSystem::begin() +{ + _started = SD.begin(); + return _started; +} + +void ESP_SDFileSystem::end() +{ + SD.end(); + _started = false; +} + +size_t ESP_SDFileSystem::totalBytes() +{ + return SD.totalBytes(); +} + +size_t ESP_SDFileSystem::usedBytes() +{ + return (SD.totalBytes() - SD.freeBytes()); +} + + +const char * ESP_SDFileSystem::FilesystemName() +{ + return "FAT"; +} + +bool ESP_SDFileSystem::format() +{ + return SD.format(); +} + +ESP_SDFile ESP_SDFileSystem::open(const char* path, uint8_t mode) +{ + //do some check + if(((strcmp(path,"/") == 0) && ((mode == ESP_FILE_WRITE) || (mode == ESP_FILE_APPEND))) || (strlen(path) == 0)) { + return ESP_SDFile(); + } + // path must start by '/' + if (path[0] != '/') { + return ESP_SDFile(); + } + if (mode != ESP_FILE_READ) { + //check container exists + String p = path; + p.remove(p.lastIndexOf('/') +1); + if (!exists(p.c_str())) { + log_esp3d("Error opening: %s", path); + return ESP_SDFile(); + } + } + File tmp = SD.open(path, (mode == ESP_FILE_READ)?FILE_READ:(mode == ESP_FILE_WRITE)?FILE_WRITE:FILE_APPEND); + ESP_SDFile esptmp(&tmp, tmp.isDirectory(),(mode == ESP_FILE_READ)?false:true, path); + return esptmp; +} + +bool ESP_SDFileSystem::exists(const char* path) +{ + bool res = false; + //root should always be there if started + if (strcmp(path, "/") == 0) { + return _started; + } + res = SD.exists(path); + if (!res) { + ESP_SDFile root = ESP_SDFileSystem::open(path, ESP_FILE_READ); + if (root) { + res = root.isDirectory(); + } + } + return res; +} + +bool ESP_SDFileSystem::remove(const char *path) +{ + return SD.remove(path); +} + +bool ESP_SDFileSystem::mkdir(const char *path) +{ + return SD.mkdir(path); +} + +bool ESP_SDFileSystem::rmdir(const char *path) +{ + if (!exists(path)) { + return false; + } + bool res = true; + GenLinkedList pathlist; + String p = path; + pathlist.push(p); + while (pathlist.count() > 0) { + File dir = SD.open(pathlist.getLast().c_str()); + File f = dir.openNextFile(); + bool candelete = true; + while (f) { + if (f.isDirectory()) { + candelete = false; + String newdir = f.name(); + pathlist.push(newdir); + f.close(); + f = File(); + } else { + SD.remove(f.name()); + f.close(); + f = dir.openNextFile(); + } + } + if (candelete) { + if (pathlist.getLast() !="/") { + res = SD.rmdir(pathlist.getLast().c_str()); + } + pathlist.pop(); + } + dir.close(); + } + p = String(); + log_esp3d("count %d", pathlist.count()); + return res; +} + +void ESP_SDFileSystem::closeAll() +{ + for (uint8_t i = 0; i < ESP_MAX_OPENHANDLE; i++) { + tSDFile_handle[i].close(); + tSDFile_handle[i] = File(); + } +} + +ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * path) +{ + _isdir = isdir; + _dirlist = ""; + _isfakedir = false; + _index = -1; + _filename = ""; + _name = ""; +#ifdef FILESYSTEM_TIMESTAMP_FEATURE + memset (&_lastwrite,0,sizeof(time_t)); +#endif //FILESYSTEM_TIMESTAMP_FEATURE + _iswritemode = iswritemode; + _size = 0; + if (!handle) { + return ; + } + bool set =false; + for (uint8_t i=0; (i < ESP_MAX_OPENHANDLE) && !set; i++) { + if (!tSDFile_handle[i]) { + tSDFile_handle[i] = *((File*)handle); + //filename + _filename = tSDFile_handle[i].name(); + + //if root + if (_filename == "/") { + _filename = "/."; + } + if (_isdir) { + if (_filename[_filename.length()-1] != '.') { + if (_filename[_filename.length()-2] != '/') { + _filename+="/"; + } + _filename+="."; + } + } + //name + if (_filename == "/.") { + _name = "/"; + } else { + _name = _filename; + if (_name.endsWith("/.")) { + _name.remove( _name.length() - 2,2); + _isfakedir = true; + _isdir = true; + } + if (_name[0] == '/') { + _name.remove( 0, 1); + } + int pos = _name.lastIndexOf('/'); + if (pos != -1) { + _name.remove( 0, pos+1); + } + } + //size + _size = tSDFile_handle[i].size(); + //time +#ifdef FILESYSTEM_TIMESTAMP_FEATURE + _lastwrite = tSDFile_handle[i].getLastWrite(); +#endif //FILESYSTEM_TIMESTAMP_FEATURE + _index = i; + //log_esp3d("Opening File at index %d",_index); + set = true; + } + } +} + +void ESP_SDFile::close() +{ + if (_index != -1) { + //log_esp3d("Closing File at index %d", _index); + tSDFile_handle[_index].close(); + //reopen if mode = write + //udate size + date + if (_iswritemode && !_isdir) { + File ftmp = SD.open(_filename.c_str()); + if (ftmp) { + _size = ftmp.size(); +#ifdef FILESYSTEM_TIMESTAMP_FEATURE + _lastwrite = ftmp.getLastWrite(); +#endif //FILESYSTEM_TIMESTAMP_FEATURE + ftmp.close(); + } + } + tSDFile_handle[_index] = File(); + //log_esp3d("Closing File at index %d",_index); + _index = -1; + } +} + +ESP_SDFile ESP_SDFile::openNextFile() +{ + if ((_index == -1) || !_isdir) { + log_esp3d("openNextFile failed"); + return ESP_SDFile(); + } + File tmp = tSDFile_handle[_index].openNextFile(); + while (tmp) { + log_esp3d("tmp name :%s %s", tmp.name(), (tmp.isDirectory())?"isDir":"isFile"); + ESP_SDFile esptmp(&tmp, tmp.isDirectory()); + esptmp.close(); + String sub = esptmp.filename(); + sub.remove(0,_filename.length()-1); + int pos = sub.indexOf("/"); + if (pos!=-1) { + //is subdir + sub = sub.substring(0,pos); + //log_esp3d("file name:%s name: %s %s sub:%s root:%s", esptmp.filename(), esptmp.name(), (esptmp.isDirectory())?"isDir":"isFile", sub.c_str(), _filename.c_str()); + String tag = "*" + sub + "*"; + //test if already in directory list + if (_dirlist.indexOf(tag) == -1) {//not in list so add it and return the info + _dirlist+= tag; + String fname = _filename.substring(0,_filename.length()-1) + sub + "/."; + //log_esp3d("Found dir name: %s filename:%s", sub.c_str(), fname.c_str()); + esptmp = ESP_SDFile(sub.c_str(), fname.c_str()); + return esptmp; + } else { //already in list so ignore it + //log_esp3d("Dir name: %s already in list", sub.c_str()); + tmp = tSDFile_handle[_index].openNextFile(); + } + } else { //is file + //log_esp3d("file name:%s name: %s %s sub:%s root:%s", esptmp.filename(), esptmp.name(), (esptmp.isDirectory())?"isDir":"isFile", sub.c_str(), _filename.c_str()); + if (sub == ".") { + //log_esp3d("Dir tag, ignore it"); + tmp = tSDFile_handle[_index].openNextFile(); + } else { + return esptmp; + } + } + + } + return ESP_SDFile(); +} + + +#endif //SD_FEATURE == ESP_SD_NATIVE +#endif //ARCH_ESP32 && SD_FEATURE