mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-29 13:46:37 +00:00
Integrate filesystem in core
Integrate filesystem in core
This commit is contained in:
parent
4390fe03fe
commit
8a269c8902
@ -229,6 +229,10 @@ void setup(void) {
|
||||
// Serial.setRxBufferSize(INPUT_BUFFER_SIZE); // Default is 256 chars
|
||||
TasmotaGlobal.seriallog_level = LOG_LEVEL_INFO; // Allow specific serial messages until config loaded
|
||||
|
||||
#ifdef USE_UFILESYS
|
||||
UfsInit(); // xdrv_50_filesystem.ino
|
||||
#endif
|
||||
|
||||
SettingsLoad();
|
||||
SettingsDelta();
|
||||
|
||||
|
@ -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 *ForceStringVar(char *lp,char *dstr);
|
||||
void send_download(void);
|
||||
uint8_t ufs_reject(char *name);
|
||||
uint8_t UfsReject(char *name);
|
||||
|
||||
void ScriptEverySecond(void) {
|
||||
|
||||
@ -2120,7 +2120,7 @@ chknext:
|
||||
while (true) {
|
||||
File entry = glob_script_mem.files[find].openNextFile();
|
||||
if (entry) {
|
||||
if (!ufs_reject((char*)entry.name())) {
|
||||
if (!UfsReject((char*)entry.name())) {
|
||||
char *ep = (char*)entry.name();
|
||||
if (*ep=='/') ep++;
|
||||
char *lcp = strrchr(ep,'/');
|
||||
@ -2248,7 +2248,7 @@ chknext:
|
||||
|
||||
if (!strncmp(vname, "fsi(", 4)) {
|
||||
lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0);
|
||||
fvar = ufs_fsinfo(fvar, 0);
|
||||
fvar = UfsInfo(fvar, 0);
|
||||
lp++;
|
||||
len = 0;
|
||||
goto exit;
|
||||
|
@ -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 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
|
||||
subdirectories are supported.
|
||||
|
||||
console calls :
|
||||
|
||||
Supported commands:
|
||||
ufs fs info
|
||||
ufstype get filesytem type 0=none 1=SD 2=Flashfile
|
||||
ufssize total size in kB
|
||||
ufsfree free size in kB
|
||||
|
||||
The driver enabled by #define USE_UFILESYS
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_50 50
|
||||
@ -48,9 +45,13 @@ The driver enabled by #define USE_UFILESYS
|
||||
#define SDCARD_CS_PIN 4
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
#define FFS_2
|
||||
#endif
|
||||
#define UFS_TNONE 0
|
||||
#define UFS_TSDC 1
|
||||
#define UFS_TFAT 2
|
||||
#define UFS_TLFS 3
|
||||
|
||||
#define UFS_FILE_WRITE "w"
|
||||
#define UFS_FILE_READ "r"
|
||||
|
||||
#ifdef ESP8266
|
||||
#include <LittleFS.h>
|
||||
@ -62,6 +63,7 @@ The driver enabled by #define USE_UFILESYS
|
||||
#endif // ESP8266
|
||||
|
||||
#ifdef ESP32
|
||||
#define FFS_2
|
||||
#include <LITTLEFS.h>
|
||||
#ifdef USE_SDCARD
|
||||
#include <SD.h>
|
||||
@ -70,9 +72,6 @@ The driver enabled by #define USE_UFILESYS
|
||||
#include "FS.h"
|
||||
#endif // ESP32
|
||||
|
||||
#define UFS_FILE_WRITE "w"
|
||||
#define UFS_FILE_READ "r"
|
||||
|
||||
// global file system pointer
|
||||
FS *ufsp;
|
||||
// flash file system pointer on esp32
|
||||
@ -83,14 +82,11 @@ FS *dfsp;
|
||||
char ufs_path[48];
|
||||
File ufs_upload_file;
|
||||
uint8_t ufs_dir;
|
||||
|
||||
// 0 = none, 1 = SD, 2 = ffat, 3 = littlefs
|
||||
uint8_t ufs_type;
|
||||
uint8_t ffs_type;
|
||||
#define UFS_TNONE 0
|
||||
#define UFS_TSDC 1
|
||||
#define UFS_TFAT 2
|
||||
#define UFS_TLFS 3
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void UfsInit(void) {
|
||||
ufs_type = 0;
|
||||
@ -100,7 +96,6 @@ void UfsInit(void) {
|
||||
// 1. check for SD card
|
||||
// 2. check for littlefs or FAT
|
||||
|
||||
|
||||
#ifdef USE_SDCARD
|
||||
if (TasmotaGlobal.spi_enabled) {
|
||||
// if (1) {
|
||||
@ -165,9 +160,130 @@ void UfsInit(void) {
|
||||
ufs_type = UFS_TLFS;
|
||||
ffsp = 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){
|
||||
if (!ufs_type) { return false; }
|
||||
|
||||
@ -223,144 +339,34 @@ bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t ufs_fsinfo(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
|
||||
#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;
|
||||
}
|
||||
/*********************************************************************************************\
|
||||
* Commands
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char kUFSCommands[] PROGMEM = "Ufs" "|" // Prefix
|
||||
"|" "Type" "|" "Size" "|" "Free";
|
||||
|
||||
void (* const kUFSCommand[])(void) PROGMEM = {
|
||||
&UFS_info, &UFS_type, &UFS_size, &UFS_free};
|
||||
&UFSInfo, &UFSType, &UFSSize, &UFSFree};
|
||||
|
||||
void UFS_info(void) {
|
||||
Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}}"), ufs_type, ufs_fsinfo(0, 0), ufs_fsinfo(1, 0));
|
||||
void UFSInfo(void) {
|
||||
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);
|
||||
}
|
||||
void UFS_size(void) {
|
||||
ResponseCmndNumber(ufs_fsinfo(0, 0));
|
||||
void UFSSize(void) {
|
||||
ResponseCmndNumber(UfsInfo(0, 0));
|
||||
}
|
||||
void UFS_free(void) {
|
||||
ResponseCmndNumber(ufs_fsinfo(1, 0));
|
||||
void UFSFree(void) {
|
||||
ResponseCmndNumber(UfsInfo(1, 0));
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Web support
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char UFS_WEB_DIR[] PROGMEM =
|
||||
"<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 =
|
||||
"</div>";
|
||||
|
||||
|
||||
const char UFS_FORM_FILE_UPG[] PROGMEM =
|
||||
"<form method='post' action='ufsu' enctype='multipart/form-data'>"
|
||||
"<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 =
|
||||
"http://%s/ufsd?download=%s/%s";
|
||||
|
||||
void UFSdirectory(void) {
|
||||
void UfsDirectory(void) {
|
||||
uint8_t depth = 0;
|
||||
|
||||
strcpy(ufs_path, "/");
|
||||
@ -406,7 +411,7 @@ void UFSdirectory(void) {
|
||||
if (Webserver->hasArg("download")) {
|
||||
String stmp = Webserver->arg("download");
|
||||
char *cp = (char*)stmp.c_str();
|
||||
if (UFS_DownloadFile(cp)) {
|
||||
if (UfsDownloadFile(cp)) {
|
||||
// is directory
|
||||
strcpy(ufs_path, cp);
|
||||
}
|
||||
@ -430,8 +435,8 @@ void UFSdirectory(void) {
|
||||
|
||||
char ts[16];
|
||||
char fs[16];
|
||||
UFS_form1000(ufs_fsinfo(0, ufs_dir == 2 ? 1:0), ts, '.');
|
||||
UFS_form1000(ufs_fsinfo(1, ufs_dir == 2 ? 1:0), fs, '.');
|
||||
UfsForm1000(UfsInfo(0, ufs_dir == 2 ? 1:0), ts, '.');
|
||||
UfsForm1000(UfsInfo(1, ufs_dir == 2 ? 1:0), 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);
|
||||
if (ufs_type) {
|
||||
UFS_ListDir(ufs_path, depth);
|
||||
UfsListDir(ufs_path, depth);
|
||||
}
|
||||
WSContentSend_P(UFS_FORM_SDC_DIRc);
|
||||
WSContentSend_P(UFS_FORM_FILE_UPGb);
|
||||
@ -453,7 +458,7 @@ void UFSdirectory(void) {
|
||||
Web.upload_error = 0;
|
||||
}
|
||||
|
||||
void UFS_ListDir(char *path, uint8_t depth) {
|
||||
void UfsListDir(char *path, uint8_t depth) {
|
||||
char name[32];
|
||||
char npath[128];
|
||||
char format[12];
|
||||
@ -497,7 +502,7 @@ void UFS_ListDir(char *path, uint8_t depth) {
|
||||
if (!*(pp + 1)) { pp++; }
|
||||
char *cp = name;
|
||||
// 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++) {
|
||||
*cp++ = '-';
|
||||
@ -512,7 +517,7 @@ void UFS_ListDir(char *path, uint8_t depth) {
|
||||
strcat(path, "/");
|
||||
}
|
||||
strcat(path, ep);
|
||||
UFS_ListDir(path, depth + 4);
|
||||
UfsListDir(path, depth + 4);
|
||||
path[plen] = 0;
|
||||
} else {
|
||||
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;
|
||||
WiFiClient download_Client;
|
||||
|
||||
@ -586,7 +591,7 @@ uint8_t UFS_DownloadFile(char *file) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UFS_Upload(void) {
|
||||
void UfsUpload(void) {
|
||||
HTTPUpload& upload = Webserver->upload();
|
||||
if (upload.status == UPLOAD_FILE_START) {
|
||||
char npath[48];
|
||||
@ -619,9 +624,6 @@ bool Xdrv50(uint8_t function) {
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
case FUNC_PRE_INIT:
|
||||
UfsInit();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kUFSCommands, kUFSCommand);
|
||||
break;
|
||||
@ -632,12 +634,12 @@ bool Xdrv50(uint8_t function) {
|
||||
}
|
||||
break;
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
Webserver->on("/ufsd", UFSdirectory);
|
||||
Webserver->on("/ufsu", HTTP_GET, UFSdirectory);
|
||||
Webserver->on("/ufsd", UfsDirectory);
|
||||
Webserver->on("/ufsu", HTTP_GET, UfsDirectory);
|
||||
Webserver->on("/ufsu", HTTP_POST,[]() {
|
||||
Webserver->sendHeader("Location","/ufsu");
|
||||
Webserver->send(303);
|
||||
}, UFS_Upload);
|
||||
}, UfsUpload);
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user