diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index e060853ea..42567082e 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -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(); diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index 339aab26d..46075bbe5 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -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; diff --git a/tasmota/xdrv_50_filesystem.ino b/tasmota/xdrv_50_filesystem.ino index a1694620e..14992eb9d 100644 --- a/tasmota/xdrv_50_filesystem.ino +++ b/tasmota/xdrv_50_filesystem.ino @@ -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 @@ -62,6 +63,7 @@ The driver enabled by #define USE_UFILESYS #endif // ESP8266 #ifdef ESP32 +#define FFS_2 #include #ifdef USE_SDCARD #include @@ -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 = "

"; @@ -376,7 +382,6 @@ const char UFS_FORM_FILE_UPGc1[] PROGMEM = const char UFS_FORM_FILE_UPGc2[] PROGMEM = ""; - const char UFS_FORM_FILE_UPG[] PROGMEM = "
" "

" @@ -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; cntupload(); 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 }