Integrate filesystem in core

Integrate filesystem in core
This commit is contained in:
Theo Arends 2021-01-08 15:00:40 +01:00
parent 4390fe03fe
commit 8a269c8902
3 changed files with 169 additions and 163 deletions

View File

@ -229,6 +229,10 @@ void setup(void) {
// Serial.setRxBufferSize(INPUT_BUFFER_SIZE); // Default is 256 chars // Serial.setRxBufferSize(INPUT_BUFFER_SIZE); // Default is 256 chars
TasmotaGlobal.seriallog_level = LOG_LEVEL_INFO; // Allow specific serial messages until config loaded TasmotaGlobal.seriallog_level = LOG_LEVEL_INFO; // Allow specific serial messages until config loaded
#ifdef USE_UFILESYS
UfsInit(); // xdrv_50_filesystem.ino
#endif
SettingsLoad(); SettingsLoad();
SettingsDelta(); SettingsDelta();

View File

@ -523,7 +523,7 @@ char *GetNumericArgument(char *lp,uint8_t lastop,float *fp, JsonParserObject *jo
char *GetStringArgument(char *lp,uint8_t lastop,char *cp, JsonParserObject *jo); char *GetStringArgument(char *lp,uint8_t lastop,char *cp, JsonParserObject *jo);
char *ForceStringVar(char *lp,char *dstr); char *ForceStringVar(char *lp,char *dstr);
void send_download(void); void send_download(void);
uint8_t ufs_reject(char *name); uint8_t UfsReject(char *name);
void ScriptEverySecond(void) { void ScriptEverySecond(void) {
@ -2120,7 +2120,7 @@ chknext:
while (true) { while (true) {
File entry = glob_script_mem.files[find].openNextFile(); File entry = glob_script_mem.files[find].openNextFile();
if (entry) { if (entry) {
if (!ufs_reject((char*)entry.name())) { if (!UfsReject((char*)entry.name())) {
char *ep = (char*)entry.name(); char *ep = (char*)entry.name();
if (*ep=='/') ep++; if (*ep=='/') ep++;
char *lcp = strrchr(ep,'/'); char *lcp = strrchr(ep,'/');
@ -2248,7 +2248,7 @@ chknext:
if (!strncmp(vname, "fsi(", 4)) { if (!strncmp(vname, "fsi(", 4)) {
lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0); lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0);
fvar = ufs_fsinfo(fvar, 0); fvar = UfsInfo(fvar, 0);
lp++; lp++;
len = 0; len = 0;
goto exit; goto exit;

View File

@ -27,19 +27,16 @@ This driver adds universal file system support for
The sd card chip select is the standard SDCARD_CS or when not found SDCARD_CS_PIN and initializes The sd card chip select is the standard SDCARD_CS or when not found SDCARD_CS_PIN and initializes
the FS System Pointer ufsp which can be used by all standard file system calls. the FS System Pointer ufsp which can be used by all standard file system calls.
The only specific call is ufs_fsinfo() which gets the total size (0) and free size (1). The only specific call is UfsInfo() which gets the total size (0) and free size (1).
A button is created in the setup section to show up the file directory to download and upload files A button is created in the setup section to show up the file directory to download and upload files
subdirectories are supported. subdirectories are supported.
console calls : Supported commands:
ufs fs info ufs fs info
ufstype get filesytem type 0=none 1=SD 2=Flashfile ufstype get filesytem type 0=none 1=SD 2=Flashfile
ufssize total size in kB ufssize total size in kB
ufsfree free size in kB ufsfree free size in kB
The driver enabled by #define USE_UFILESYS
\*********************************************************************************************/ \*********************************************************************************************/
#define XDRV_50 50 #define XDRV_50 50
@ -48,9 +45,13 @@ The driver enabled by #define USE_UFILESYS
#define SDCARD_CS_PIN 4 #define SDCARD_CS_PIN 4
#endif #endif
#ifdef ESP32 #define UFS_TNONE 0
#define FFS_2 #define UFS_TSDC 1
#endif #define UFS_TFAT 2
#define UFS_TLFS 3
#define UFS_FILE_WRITE "w"
#define UFS_FILE_READ "r"
#ifdef ESP8266 #ifdef ESP8266
#include <LittleFS.h> #include <LittleFS.h>
@ -62,6 +63,7 @@ The driver enabled by #define USE_UFILESYS
#endif // ESP8266 #endif // ESP8266
#ifdef ESP32 #ifdef ESP32
#define FFS_2
#include <LITTLEFS.h> #include <LITTLEFS.h>
#ifdef USE_SDCARD #ifdef USE_SDCARD
#include <SD.h> #include <SD.h>
@ -70,9 +72,6 @@ The driver enabled by #define USE_UFILESYS
#include "FS.h" #include "FS.h"
#endif // ESP32 #endif // ESP32
#define UFS_FILE_WRITE "w"
#define UFS_FILE_READ "r"
// global file system pointer // global file system pointer
FS *ufsp; FS *ufsp;
// flash file system pointer on esp32 // flash file system pointer on esp32
@ -83,14 +82,11 @@ FS *dfsp;
char ufs_path[48]; char ufs_path[48];
File ufs_upload_file; File ufs_upload_file;
uint8_t ufs_dir; uint8_t ufs_dir;
// 0 = none, 1 = SD, 2 = ffat, 3 = littlefs // 0 = none, 1 = SD, 2 = ffat, 3 = littlefs
uint8_t ufs_type; uint8_t ufs_type;
uint8_t ffs_type; uint8_t ffs_type;
#define UFS_TNONE 0
#define UFS_TSDC 1 /*********************************************************************************************/
#define UFS_TFAT 2
#define UFS_TLFS 3
void UfsInit(void) { void UfsInit(void) {
ufs_type = 0; ufs_type = 0;
@ -100,7 +96,6 @@ void UfsInit(void) {
// 1. check for SD card // 1. check for SD card
// 2. check for littlefs or FAT // 2. check for littlefs or FAT
#ifdef USE_SDCARD #ifdef USE_SDCARD
if (TasmotaGlobal.spi_enabled) { if (TasmotaGlobal.spi_enabled) {
// if (1) { // if (1) {
@ -165,9 +160,130 @@ void UfsInit(void) {
ufs_type = UFS_TLFS; ufs_type = UFS_TLFS;
ffsp = ufsp; ffsp = ufsp;
dfsp = ufsp; dfsp = ufsp;
return;
} }
uint32_t UfsInfo(uint32_t sel, uint32_t type) {
uint32_t result = 0;
FS *ifsp = ufsp;
uint8_t itype = ufs_type;
if (type) {
ifsp = ffsp;
itype = ffs_type;
}
#ifdef ESP8266
FSInfo64 fsinfo;
#endif // ESP8266
switch (itype) {
case UFS_TSDC:
#ifdef USE_SDCARD
#ifdef ESP8266
ifsp->info64(fsinfo);
if (sel == 0) {
result = fsinfo.totalBytes;
} else {
result = (fsinfo.totalBytes - fsinfo.usedBytes);
}
#endif // ESP8266
#ifdef ESP32
if (sel == 0) {
result = SD.totalBytes();
} else {
result = (SD.totalBytes() - SD.usedBytes());
}
#endif // ESP32
#endif // USE_SDCARD
break;
case UFS_TLFS:
#ifdef ESP8266
ifsp->info64(fsinfo);
if (sel == 0) {
result = fsinfo.totalBytes;
} else {
result = (fsinfo.totalBytes - fsinfo.usedBytes);
}
#endif // ESP8266
#ifdef ESP32
if (sel == 0) {
result = LITTLEFS.totalBytes();
} else {
result = LITTLEFS.totalBytes() - LITTLEFS.usedBytes();
}
#endif // ESP32
break;
case UFS_TFAT:
#ifdef ESP32
if (sel == 0) {
result = FFat.totalBytes();
} else {
result = FFat.freeBytes();
}
#endif // ESP32
break;
}
return result / 1024;
}
#if USE_LONG_FILE_NAMES>0
#undef REJCMPL
#define REJCMPL 6
#else
#undef REJCMPL
#define REJCMPL 8
#endif
uint8_t UfsReject(char *name) {
char *lcp = strrchr(name,'/');
if (lcp) {
name = lcp + 1;
}
while (*name=='/') { name++; }
if (*name=='_') { return 1; }
if (*name=='.') { return 1; }
if (!strncasecmp(name, "SPOTLI~1", REJCMPL)) { return 1; }
if (!strncasecmp(name, "TRASHE~1", REJCMPL)) { return 1; }
if (!strncasecmp(name, "FSEVEN~1", REJCMPL)) { return 1; }
if (!strncasecmp(name, "SYSTEM~1", REJCMPL)) { return 1; }
if (!strncasecmp(name, "System Volume", 13)) { return 1; }
return 0;
}
// Format number with thousand marker - Not international as '.' is decimal on most countries
void UfsForm1000(uint32_t number, char *dp, char sc) {
char str[32];
sprintf(str, "%d", number);
char *sp = str;
uint32_t inum = strlen(sp)/3;
uint32_t fnum = strlen(sp)%3;
if (!fnum) { inum--; }
for (uint32_t count = 0; count <= inum; count++) {
if (fnum) {
memcpy(dp, sp, fnum);
dp += fnum;
sp += fnum;
fnum = 0;
} else {
memcpy(dp, sp, 3);
dp += 3;
sp += 3;
}
if (count != inum) {
*dp++ = sc;
}
}
*dp = 0;
}
/*********************************************************************************************\
* Tfs low level functions
\*********************************************************************************************/
bool TfsFileExists(const char *fname){ bool TfsFileExists(const char *fname){
if (!ufs_type) { return false; } if (!ufs_type) { return false; }
@ -223,144 +339,34 @@ bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) {
return true; return true;
} }
uint32_t ufs_fsinfo(uint32_t sel, uint32_t type) { /*********************************************************************************************\
uint32_t result = 0; * Commands
FS *ifsp = ufsp; \*********************************************************************************************/
uint8_t itype = ufs_type;
if (type) {
ifsp = ffsp;
itype = ffs_type;
}
#ifdef ESP8266
FSInfo64 fsinfo;
#endif // ESP8266
switch (itype) {
case UFS_TSDC:
#ifdef USE_SDCARD
#ifdef ESP8266
ifsp->info64(fsinfo);
if (sel == 0) {
result = fsinfo.totalBytes;
} else {
result = (fsinfo.totalBytes - fsinfo.usedBytes);
}
#endif // ESP8266
#ifdef ESP32
if (sel == 0) {
result = SD.totalBytes();
} else {
result = (SD.totalBytes() - SD.usedBytes());
}
#endif
#endif //USE_SDCARD
break;
case UFS_TLFS:
#ifdef ESP8266
ifsp->info64(fsinfo);
if (sel == 0) {
result = fsinfo.totalBytes;
} else {
result = (fsinfo.totalBytes - fsinfo.usedBytes);
}
#endif // ESP8266
#ifdef ESP32
if (sel == 0) {
result = LITTLEFS.totalBytes();
} else {
result = LITTLEFS.totalBytes() - LITTLEFS.usedBytes();
}
#endif // ESP32
break;
case UFS_TFAT:
#ifdef ESP32
if (sel == 0) {
result = FFat.totalBytes();
} else {
result = FFat.freeBytes();
}
#endif // ESP32
break;
}
return result / 1000;
}
#if USE_LONG_FILE_NAMES>0
#undef REJCMPL
#define REJCMPL 6
#else
#undef REJCMPL
#define REJCMPL 8
#endif
uint8_t ufs_reject(char *name) {
char *lcp = strrchr(name,'/');
if (lcp) {
name = lcp + 1;
}
while (*name=='/') { name++; }
if (*name=='_') { return 1; }
if (*name=='.') { return 1; }
if (!strncasecmp(name, "SPOTLI~1", REJCMPL)) { return 1; }
if (!strncasecmp(name, "TRASHE~1", REJCMPL)) { return 1; }
if (!strncasecmp(name, "FSEVEN~1", REJCMPL)) { return 1; }
if (!strncasecmp(name, "SYSTEM~1", REJCMPL)) { return 1; }
if (!strncasecmp(name, "System Volume", 13)) { return 1; }
return 0;
}
// format number with thousand marker
void UFS_form1000(uint32_t number, char *dp, char sc) {
char str[32];
sprintf(str, "%d", number);
char *sp = str;
uint32_t inum = strlen(sp)/3;
uint32_t fnum = strlen(sp)%3;
if (!fnum) { inum--; }
for (uint32_t count = 0; count <= inum; count++) {
if (fnum) {
memcpy(dp, sp, fnum);
dp += fnum;
sp += fnum;
fnum = 0;
} else {
memcpy(dp, sp, 3);
dp += 3;
sp += 3;
}
if (count != inum) {
*dp++ = sc;
}
}
*dp = 0;
}
const char kUFSCommands[] PROGMEM = "Ufs" "|" // Prefix const char kUFSCommands[] PROGMEM = "Ufs" "|" // Prefix
"|" "Type" "|" "Size" "|" "Free"; "|" "Type" "|" "Size" "|" "Free";
void (* const kUFSCommand[])(void) PROGMEM = { void (* const kUFSCommand[])(void) PROGMEM = {
&UFS_info, &UFS_type, &UFS_size, &UFS_free}; &UFSInfo, &UFSType, &UFSSize, &UFSFree};
void UFS_info(void) { void UFSInfo(void) {
Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}}"), ufs_type, ufs_fsinfo(0, 0), ufs_fsinfo(1, 0)); Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}}"), ufs_type, UfsInfo(0, 0), UfsInfo(1, 0));
} }
void UFS_type(void) { void UFSType(void) {
ResponseCmndNumber(ufs_type); ResponseCmndNumber(ufs_type);
} }
void UFS_size(void) { void UFSSize(void) {
ResponseCmndNumber(ufs_fsinfo(0, 0)); ResponseCmndNumber(UfsInfo(0, 0));
} }
void UFS_free(void) { void UFSFree(void) {
ResponseCmndNumber(ufs_fsinfo(1, 0)); ResponseCmndNumber(UfsInfo(1, 0));
} }
/*********************************************************************************************\
* Web support
\*********************************************************************************************/
const char UFS_WEB_DIR[] PROGMEM = const char UFS_WEB_DIR[] PROGMEM =
"<p><form action='" "ufsd" "' method='get'><button>" "%s" "</button></form></p>"; "<p><form action='" "ufsd" "' method='get'><button>" "%s" "</button></form></p>";
@ -376,7 +382,6 @@ const char UFS_FORM_FILE_UPGc1[] PROGMEM =
const char UFS_FORM_FILE_UPGc2[] PROGMEM = const char UFS_FORM_FILE_UPGc2[] PROGMEM =
"</div>"; "</div>";
const char UFS_FORM_FILE_UPG[] PROGMEM = const char UFS_FORM_FILE_UPG[] PROGMEM =
"<form method='post' action='ufsu' enctype='multipart/form-data'>" "<form method='post' action='ufsu' enctype='multipart/form-data'>"
"<br><input type='file' name='ufsu'><br>" "<br><input type='file' name='ufsu'><br>"
@ -397,7 +402,7 @@ const char UFS_FORM_SDC_DIRb[] PROGMEM =
const char UFS_FORM_SDC_HREF[] PROGMEM = const char UFS_FORM_SDC_HREF[] PROGMEM =
"http://%s/ufsd?download=%s/%s"; "http://%s/ufsd?download=%s/%s";
void UFSdirectory(void) { void UfsDirectory(void) {
uint8_t depth = 0; uint8_t depth = 0;
strcpy(ufs_path, "/"); strcpy(ufs_path, "/");
@ -406,7 +411,7 @@ void UFSdirectory(void) {
if (Webserver->hasArg("download")) { if (Webserver->hasArg("download")) {
String stmp = Webserver->arg("download"); String stmp = Webserver->arg("download");
char *cp = (char*)stmp.c_str(); char *cp = (char*)stmp.c_str();
if (UFS_DownloadFile(cp)) { if (UfsDownloadFile(cp)) {
// is directory // is directory
strcpy(ufs_path, cp); strcpy(ufs_path, cp);
} }
@ -430,8 +435,8 @@ void UFSdirectory(void) {
char ts[16]; char ts[16];
char fs[16]; char fs[16];
UFS_form1000(ufs_fsinfo(0, ufs_dir == 2 ? 1:0), ts, '.'); UfsForm1000(UfsInfo(0, ufs_dir == 2 ? 1:0), ts, '.');
UFS_form1000(ufs_fsinfo(1, ufs_dir == 2 ? 1:0), fs, '.'); UfsForm1000(UfsInfo(1, ufs_dir == 2 ? 1:0), fs, '.');
WSContentSend_P(UFS_FORM_FILE_UPGc, WebColor(COL_TEXT), ts, fs); WSContentSend_P(UFS_FORM_FILE_UPGc, WebColor(COL_TEXT), ts, fs);
@ -444,7 +449,7 @@ void UFSdirectory(void) {
WSContentSend_P(UFS_FORM_SDC_DIRa); WSContentSend_P(UFS_FORM_SDC_DIRa);
if (ufs_type) { if (ufs_type) {
UFS_ListDir(ufs_path, depth); UfsListDir(ufs_path, depth);
} }
WSContentSend_P(UFS_FORM_SDC_DIRc); WSContentSend_P(UFS_FORM_SDC_DIRc);
WSContentSend_P(UFS_FORM_FILE_UPGb); WSContentSend_P(UFS_FORM_FILE_UPGb);
@ -453,7 +458,7 @@ void UFSdirectory(void) {
Web.upload_error = 0; Web.upload_error = 0;
} }
void UFS_ListDir(char *path, uint8_t depth) { void UfsListDir(char *path, uint8_t depth) {
char name[32]; char name[32];
char npath[128]; char npath[128];
char format[12]; char format[12];
@ -497,7 +502,7 @@ void UFS_ListDir(char *path, uint8_t depth) {
if (!*(pp + 1)) { pp++; } if (!*(pp + 1)) { pp++; }
char *cp = name; char *cp = name;
// osx formatted disks contain a lot of stuff we dont want // osx formatted disks contain a lot of stuff we dont want
if (!ufs_reject((char*)ep)) { if (!UfsReject((char*)ep)) {
for (uint8_t cnt = 0; cnt<depth; cnt++) { for (uint8_t cnt = 0; cnt<depth; cnt++) {
*cp++ = '-'; *cp++ = '-';
@ -512,7 +517,7 @@ void UFS_ListDir(char *path, uint8_t depth) {
strcat(path, "/"); strcat(path, "/");
} }
strcat(path, ep); strcat(path, ep);
UFS_ListDir(path, depth + 4); UfsListDir(path, depth + 4);
path[plen] = 0; path[plen] = 0;
} else { } else {
snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, WiFi.localIP().toString().c_str(), pp, ep); snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, WiFi.localIP().toString().c_str(), pp, ep);
@ -525,7 +530,7 @@ void UFS_ListDir(char *path, uint8_t depth) {
} }
} }
uint8_t UFS_DownloadFile(char *file) { uint8_t UfsDownloadFile(char *file) {
File download_file; File download_file;
WiFiClient download_Client; WiFiClient download_Client;
@ -586,7 +591,7 @@ uint8_t UFS_DownloadFile(char *file) {
return 0; return 0;
} }
void UFS_Upload(void) { void UfsUpload(void) {
HTTPUpload& upload = Webserver->upload(); HTTPUpload& upload = Webserver->upload();
if (upload.status == UPLOAD_FILE_START) { if (upload.status == UPLOAD_FILE_START) {
char npath[48]; char npath[48];
@ -619,9 +624,6 @@ bool Xdrv50(uint8_t function) {
bool result = false; bool result = false;
switch (function) { switch (function) {
case FUNC_PRE_INIT:
UfsInit();
break;
case FUNC_COMMAND: case FUNC_COMMAND:
result = DecodeCommand(kUFSCommands, kUFSCommand); result = DecodeCommand(kUFSCommands, kUFSCommand);
break; break;
@ -632,12 +634,12 @@ bool Xdrv50(uint8_t function) {
} }
break; break;
case FUNC_WEB_ADD_HANDLER: case FUNC_WEB_ADD_HANDLER:
Webserver->on("/ufsd", UFSdirectory); Webserver->on("/ufsd", UfsDirectory);
Webserver->on("/ufsu", HTTP_GET, UFSdirectory); Webserver->on("/ufsu", HTTP_GET, UfsDirectory);
Webserver->on("/ufsu", HTTP_POST,[]() { Webserver->on("/ufsu", HTTP_POST,[]() {
Webserver->sendHeader("Location","/ufsu"); Webserver->sendHeader("Location","/ufsu");
Webserver->send(303); Webserver->send(303);
}, UFS_Upload); }, UfsUpload);
break; break;
#endif // USE_WEBSERVER #endif // USE_WEBSERVER
} }