Tasmota/tasmota/xdrv_50_filesystem.ino

649 lines
17 KiB
Arduino
Raw Normal View History

2020-12-31 13:19:50 +00:00
/*
2021-01-06 13:41:23 +00:00
xdrv_50_filesystem.ino - unified file system for Tasmota
2020-12-31 13:19:50 +00:00
Copyright (C) 2020 Gerhard Mutz and Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2021-01-04 14:52:32 +00:00
#ifdef USE_UFILESYS
/*********************************************************************************************\
This driver adds universal file system support for
- ESP8266 (sd card or littlefs on > 1 M devices with special linker file e.g. eagle.flash.4m2m.ld)
(makes no sense on 1M devices without sd card)
- ESP32 (sd card or littlefs or sfatfile system).
2021-01-04 14:52:32 +00:00
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 UfsInfo() which gets the total size (0) and free size (1).
2021-01-04 14:52:32 +00:00
A button is created in the setup section to show up the file directory to download and upload files
subdirectories are supported.
2020-12-31 13:19:50 +00:00
Supported commands:
2020-12-31 13:19:50 +00:00
ufs fs info
ufstype get filesytem type 0=none 1=SD 2=Flashfile
ufssize total size in kB
ufsfree free size in kB
2021-01-04 14:52:32 +00:00
\*********************************************************************************************/
2020-12-31 13:19:50 +00:00
2021-01-06 13:41:23 +00:00
#define XDRV_50 50
2020-12-31 13:19:50 +00:00
2021-01-04 14:52:32 +00:00
#ifndef SDCARD_CS_PIN
#define SDCARD_CS_PIN 4
#endif
2020-12-31 13:19:50 +00:00
#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"
2021-01-07 09:57:24 +00:00
2020-12-31 13:19:50 +00:00
#ifdef ESP8266
#include <LittleFS.h>
#include <SPI.h>
#ifdef USE_SDCARD
2020-12-31 13:19:50 +00:00
#include <SD.h>
#include <SDFAT.h>
2021-01-04 14:52:32 +00:00
#endif // USE_SDCARD
#endif // ESP8266
#ifdef ESP32
#define FFS_2
2020-12-31 17:05:42 +00:00
#include <LITTLEFS.h>
#ifdef USE_SDCARD
2020-12-31 13:19:50 +00:00
#include <SD.h>
2021-01-04 14:52:32 +00:00
#endif // USE_SDCARD
2020-12-31 13:19:50 +00:00
#include "FFat.h"
#include "FS.h"
2021-01-04 14:52:32 +00:00
#endif // ESP32
2020-12-31 13:19:50 +00:00
// global file system pointer
FS *ufsp;
2021-01-06 09:51:22 +00:00
// flash file system pointer on esp32
FS *ffsp;
2021-01-07 09:57:24 +00:00
// local pointer for file managment
FS *dfsp;
2020-12-31 13:19:50 +00:00
char ufs_path[48];
File ufs_upload_file;
2021-01-07 09:57:24 +00:00
uint8_t ufs_dir;
2021-01-01 15:48:52 +00:00
// 0 = none, 1 = SD, 2 = ffat, 3 = littlefs
2020-12-31 13:19:50 +00:00
uint8_t ufs_type;
2021-01-07 09:57:24 +00:00
uint8_t ffs_type;
/*********************************************************************************************/
2020-12-31 13:19:50 +00:00
void UfsInit(void) {
2020-12-31 13:19:50 +00:00
ufs_type = 0;
2021-01-06 09:51:22 +00:00
ffsp = 0;
2021-01-07 09:57:24 +00:00
ufs_dir = 0;
2020-12-31 13:19:50 +00:00
// check for fs options,
// 1. check for SD card
// 2. check for littlefs or FAT
2021-01-01 10:38:01 +00:00
#ifdef USE_SDCARD
2021-01-07 10:01:04 +00:00
if (TasmotaGlobal.spi_enabled) {
// if (1) {
2021-01-01 15:48:52 +00:00
int8_t cs = SDCARD_CS_PIN;
2021-01-04 14:52:32 +00:00
if (PinUsed(GPIO_SDCARD_CS)) {
cs = Pin(GPIO_SDCARD_CS);
2020-12-31 13:19:50 +00:00
}
if (SD.begin(cs)) {
#ifdef ESP8266
2021-01-05 15:36:45 +00:00
ufsp = &SDFS;
2021-01-04 14:52:32 +00:00
#endif // ESP8266
#ifdef ESP32
2020-12-31 13:19:50 +00:00
ufsp = &SD;
2021-01-04 14:52:32 +00:00
#endif // ESP32
2020-12-31 15:41:58 +00:00
ufs_type = UFS_TSDC;
2021-01-07 09:57:24 +00:00
dfsp = ufsp;
#ifdef FFS_2
2021-01-06 09:51:22 +00:00
// now detect ffs
ffsp = &LITTLEFS;
if (!LITTLEFS.begin()) {
// ffat is second
ffsp = &FFat;
if (!FFat.begin(true)) {
ffsp = 0;
return;
}
2021-01-07 09:57:24 +00:00
ffs_type = UFS_TFAT;
ufs_dir = 1;
return;
2021-01-06 09:51:22 +00:00
}
2021-01-07 09:57:24 +00:00
ffs_type = UFS_TLFS;
ufs_dir = 1;
#endif // FFS_2
2020-12-31 13:19:50 +00:00
return;
}
}
2021-01-01 10:38:01 +00:00
#endif // USE_SDCARD
2020-12-31 13:19:50 +00:00
// if no success with sd card try flash fs
#ifdef ESP8266
ufsp = &LittleFS;
2020-12-31 17:05:42 +00:00
if (!LittleFS.begin()) {
2020-12-31 13:19:50 +00:00
return;
}
2021-01-04 14:52:32 +00:00
#endif // ESP8266
#ifdef ESP32
2020-12-31 19:22:54 +00:00
// try lfs first
ufsp = &LITTLEFS;
if (!LITTLEFS.begin(true)) {
// ffat is second
ufsp = &FFat;
if (!FFat.begin(true)) {
2020-12-31 15:41:58 +00:00
return;
}
2020-12-31 19:22:54 +00:00
ufs_type = UFS_TFAT;
2021-01-06 09:51:22 +00:00
ffsp = ufsp;
2021-01-07 10:03:02 +00:00
dfsp = ufsp;
2020-12-31 13:19:50 +00:00
return;
}
2021-01-04 14:52:32 +00:00
#endif // ESP32
2020-12-31 19:22:54 +00:00
ufs_type = UFS_TLFS;
2021-01-06 09:51:22 +00:00
ffsp = ufsp;
2021-01-07 09:57:24 +00:00
dfsp = ufsp;
}
uint32_t UfsInfo(uint32_t sel, uint32_t type) {
2021-01-04 14:52:32 +00:00
uint32_t result = 0;
2021-01-07 09:57:24 +00:00
FS *ifsp = ufsp;
uint8_t itype = ufs_type;
if (type) {
ifsp = ffsp;
itype = ffs_type;
}
2021-01-04 14:52:32 +00:00
2021-01-01 15:48:52 +00:00
#ifdef ESP8266
2021-01-04 14:52:32 +00:00
FSInfo64 fsinfo;
#endif // ESP8266
2020-12-31 13:19:50 +00:00
2021-01-07 09:57:24 +00:00
switch (itype) {
2020-12-31 13:19:50 +00:00
case UFS_TSDC:
#ifdef USE_SDCARD
2021-01-04 14:52:32 +00:00
#ifdef ESP8266
2021-01-07 09:57:24 +00:00
ifsp->info64(fsinfo);
2021-01-01 15:48:52 +00:00
if (sel == 0) {
result = fsinfo.totalBytes;
} else {
result = (fsinfo.totalBytes - fsinfo.usedBytes);
}
2021-01-04 14:52:32 +00:00
#endif // ESP8266
#ifdef ESP32
if (sel == 0) {
result = SD.totalBytes();
} else {
result = (SD.totalBytes() - SD.usedBytes());
}
#endif // ESP32
#endif // USE_SDCARD
2020-12-31 13:19:50 +00:00
break;
2020-12-31 17:05:42 +00:00
case UFS_TLFS:
2020-12-31 13:19:50 +00:00
#ifdef ESP8266
2021-01-07 09:57:24 +00:00
ifsp->info64(fsinfo);
2020-12-31 13:19:50 +00:00
if (sel == 0) {
result = fsinfo.totalBytes;
} else {
result = (fsinfo.totalBytes - fsinfo.usedBytes);
}
2021-01-04 14:52:32 +00:00
#endif // ESP8266
#ifdef ESP32
2020-12-31 17:05:42 +00:00
if (sel == 0) {
result = LITTLEFS.totalBytes();
} else {
result = LITTLEFS.totalBytes() - LITTLEFS.usedBytes();
}
#endif // ESP32
2020-12-31 17:05:42 +00:00
break;
case UFS_TFAT:
#ifdef ESP32
2020-12-31 13:19:50 +00:00
if (sel == 0) {
result = FFat.totalBytes();
} else {
result = FFat.freeBytes();
}
#endif // ESP32
2020-12-31 13:19:50 +00:00
break;
2020-12-31 17:05:42 +00:00
2020-12-31 13:19:50 +00:00
}
return result / 1024;
2020-12-31 13:19:50 +00:00
}
#if USE_LONG_FILE_NAMES>0
#undef REJCMPL
#define REJCMPL 6
#else
#undef REJCMPL
#define REJCMPL 8
#endif
uint8_t UfsReject(char *name) {
2020-12-31 13:19:50 +00:00
char *lcp = strrchr(name,'/');
if (lcp) {
name = lcp + 1;
}
2021-01-04 14:52:32 +00:00
while (*name=='/') { name++; }
if (*name=='_') { return 1; }
if (*name=='.') { return 1; }
2020-12-31 13:19:50 +00:00
2021-01-04 14:52:32 +00:00
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; }
2020-12-31 13:19:50 +00:00
return 0;
}
// Format number with thousand marker - Not international as '.' is decimal on most countries
void UfsForm1000(uint32_t number, char *dp, char sc) {
2020-12-31 13:19:50 +00:00
char str[32];
sprintf(str, "%d", number);
char *sp = str;
uint32_t inum = strlen(sp)/3;
uint32_t fnum = strlen(sp)%3;
2021-01-04 14:52:32 +00:00
if (!fnum) { inum--; }
for (uint32_t count = 0; count <= inum; count++) {
if (fnum) {
memcpy(dp, sp, fnum);
dp += fnum;
sp += fnum;
fnum = 0;
2020-12-31 13:19:50 +00:00
} else {
2021-01-04 14:52:32 +00:00
memcpy(dp, sp, 3);
dp += 3;
sp += 3;
2020-12-31 13:19:50 +00:00
}
2021-01-04 14:52:32 +00:00
if (count != inum) {
*dp++ = sc;
2020-12-31 13:19:50 +00:00
}
}
2021-01-04 14:52:32 +00:00
*dp = 0;
2020-12-31 13:19:50 +00:00
}
/*********************************************************************************************\
* Tfs low level functions
\*********************************************************************************************/
bool TfsFileExists(const char *fname){
if (!ufs_type) { return false; }
bool yes = ffsp->exists(fname);
if (!yes) {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: File not found"));
}
return yes;
}
bool TfsSaveFile(const char *fname, const uint8_t *buf, uint32_t len) {
if (!ufs_type) { return false; }
File file = ffsp->open(fname, "w");
if (!file) {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Save failed"));
return false;
}
file.write(buf, len);
file.close();
return true;
}
bool TfsInitFile(const char *fname, uint32_t len, uint8_t init_value) {
if (!ufs_type) { return false; }
File file = ffsp->open(fname, "w");
if (!file) {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: Erase failed"));
return false;
}
for (uint32_t i = 0; i < len; i++) {
file.write(&init_value, 1);
}
file.close();
return true;
}
bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) {
if (!ufs_type) { return false; }
if (!TfsFileExists(fname)) { return false; }
File file = ffsp->open(fname, "r");
if (!file) {
AddLog_P(LOG_LEVEL_INFO, PSTR("TFS: File not found"));
return false;
}
file.read(buf, len);
file.close();
return true;
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
2021-01-04 14:52:32 +00:00
const char kUFSCommands[] PROGMEM = "Ufs" "|" // Prefix
"|" "Type" "|" "Size" "|" "Free";
2020-12-31 13:19:50 +00:00
void (* const kUFSCommand[])(void) PROGMEM = {
&UFSInfo, &UFSType, &UFSSize, &UFSFree};
2020-12-31 13:19:50 +00:00
void UFSInfo(void) {
Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}}"), ufs_type, UfsInfo(0, 0), UfsInfo(1, 0));
2020-12-31 13:19:50 +00:00
}
2021-01-04 14:52:32 +00:00
void UFSType(void) {
2020-12-31 13:19:50 +00:00
ResponseCmndNumber(ufs_type);
}
void UFSSize(void) {
ResponseCmndNumber(UfsInfo(0, 0));
2020-12-31 13:19:50 +00:00
}
void UFSFree(void) {
ResponseCmndNumber(UfsInfo(1, 0));
2020-12-31 13:19:50 +00:00
}
/*********************************************************************************************\
* Web support
\*********************************************************************************************/
2020-12-31 13:19:50 +00:00
const char UFS_WEB_DIR[] PROGMEM =
"<p><form action='" "ufsd" "' method='get'><button>" "%s" "</button></form></p>";
2021-01-06 16:54:03 +00:00
2020-12-31 13:19:50 +00:00
const char UFS_FORM_FILE_UPLOAD[] PROGMEM =
2021-01-04 14:52:32 +00:00
"<div id='f1' name='f1' style='display:block;'>"
2021-01-06 16:54:03 +00:00
"<fieldset><legend><b>&nbsp;" D_MANAGE_FILE_SYSTEM "&nbsp;</b></legend>";
const char UFS_FORM_FILE_UPGc[] PROGMEM =
2021-01-07 09:57:24 +00:00
"<div style='text-align:left;color:#%06x;'>" D_FS_SIZE " %s kB - " D_FS_FREE " %s kB";
const char UFS_FORM_FILE_UPGc1[] PROGMEM =
" &nbsp;&nbsp;<a href='http://%s/ufsd?dir=%d'>%s</a>";
const char UFS_FORM_FILE_UPGc2[] PROGMEM =
"</div>";
2020-12-31 13:19:50 +00:00
const char UFS_FORM_FILE_UPG[] PROGMEM =
2021-01-04 14:52:32 +00:00
"<form method='post' action='ufsu' enctype='multipart/form-data'>"
2021-01-06 16:54:03 +00:00
"<br><input type='file' name='ufsu'><br>"
"<br><button type='submit' onclick='eb(\"f1\").style.display=\"none\";eb(\"f2\").style.display=\"block\";this.form.submit();'>" D_START " %s</button></form>"
"<br>";
2020-12-31 13:19:50 +00:00
const char UFS_FORM_SDC_DIRa[] PROGMEM =
2021-01-06 16:54:03 +00:00
"<div style='text-align:left;overflow:auto;height:250px;'>";
2020-12-31 13:19:50 +00:00
const char UFS_FORM_SDC_DIRc[] PROGMEM =
2021-01-04 14:52:32 +00:00
"</div>";
2020-12-31 13:19:50 +00:00
const char UFS_FORM_FILE_UPGb[] PROGMEM =
2021-01-04 14:52:32 +00:00
"</fieldset>"
"</div>"
"<div id='f2' name='f2' style='display:none;text-align:center;'><b>" D_UPLOAD_STARTED " ...</b></div>";
2020-12-31 13:19:50 +00:00
const char UFS_FORM_SDC_DIRd[] PROGMEM =
2021-01-04 14:52:32 +00:00
"<pre><a href='%s' file='%s'>%s</a></pre>";
2020-12-31 13:19:50 +00:00
const char UFS_FORM_SDC_DIRb[] PROGMEM =
2021-01-06 16:54:03 +00:00
"<pre><a href='%s' file='%s'>%s</a> %s %8d</pre>";
2020-12-31 13:19:50 +00:00
const char UFS_FORM_SDC_HREF[] PROGMEM =
2021-01-04 14:52:32 +00:00
"http://%s/ufsd?download=%s/%s";
2020-12-31 13:19:50 +00:00
void UfsDirectory(void) {
2020-12-31 13:19:50 +00:00
uint8_t depth = 0;
strcpy(ufs_path, "/");
if (!HttpCheckPriviledgedAccess()) { return; }
if (Webserver->hasArg("download")) {
String stmp = Webserver->arg("download");
char *cp = (char*)stmp.c_str();
if (UfsDownloadFile(cp)) {
2020-12-31 13:19:50 +00:00
// is directory
strcpy(ufs_path, cp);
}
}
2021-01-07 09:57:24 +00:00
if (Webserver->hasArg("dir")) {
String stmp = Webserver->arg("dir");
ufs_dir = atoi(stmp.c_str());
if (ufs_dir == 1) {
dfsp = ufsp;
} else {
if (ffsp) {
dfsp = ffsp;
}
}
}
2021-01-06 16:54:03 +00:00
WSContentStart_P(PSTR(D_MANAGE_FILE_SYSTEM));
2020-12-31 13:19:50 +00:00
WSContentSendStyle();
2021-01-06 16:54:03 +00:00
WSContentSend_P(UFS_FORM_FILE_UPLOAD);
2020-12-31 13:19:50 +00:00
char ts[16];
char fs[16];
UfsForm1000(UfsInfo(0, ufs_dir == 2 ? 1:0), ts, '.');
UfsForm1000(UfsInfo(1, ufs_dir == 2 ? 1:0), fs, '.');
2021-01-07 09:57:24 +00:00
2021-01-06 16:54:03 +00:00
WSContentSend_P(UFS_FORM_FILE_UPGc, WebColor(COL_TEXT), ts, fs);
2021-01-07 09:57:24 +00:00
if (ufs_dir) {
WSContentSend_P(UFS_FORM_FILE_UPGc1, WiFi.localIP().toString().c_str(),ufs_dir == 1 ? 2:1, ufs_dir == 1 ? "UFS":"FFS");
}
WSContentSend_P(UFS_FORM_FILE_UPGc2);
2021-01-06 16:54:03 +00:00
WSContentSend_P(UFS_FORM_FILE_UPG, D_SCRIPT_UPLOAD);
2020-12-31 13:19:50 +00:00
WSContentSend_P(UFS_FORM_SDC_DIRa);
if (ufs_type) {
UfsListDir(ufs_path, depth);
2020-12-31 13:19:50 +00:00
}
WSContentSend_P(UFS_FORM_SDC_DIRc);
WSContentSend_P(UFS_FORM_FILE_UPGb);
WSContentSpaceButton(BUTTON_CONFIGURATION);
WSContentStop();
Web.upload_error = 0;
}
void UfsListDir(char *path, uint8_t depth) {
2020-12-31 13:19:50 +00:00
char name[32];
char npath[128];
char format[12];
sprintf(format, "%%-%ds", 24 - depth);
2021-01-07 09:57:24 +00:00
File dir = dfsp->open(path, UFS_FILE_READ);
2020-12-31 13:19:50 +00:00
if (dir) {
dir.rewindDirectory();
if (strlen(path)>1) {
2021-01-04 14:52:32 +00:00
snprintf_P(npath, sizeof(npath), PSTR("http://%s/ufsd?download=%s"), WiFi.localIP().toString().c_str(), path);
for (uint32_t cnt = strlen(npath) - 1; cnt > 0; cnt--) {
if (npath[cnt] == '/') {
if (npath[cnt - 1] == '=') {
npath[cnt + 1] = 0;
} else {
npath[cnt] = 0;
}
2020-12-31 13:19:50 +00:00
break;
}
}
2021-01-04 14:52:32 +00:00
WSContentSend_P(UFS_FORM_SDC_DIRd, npath, path, "..");
2020-12-31 13:19:50 +00:00
}
char *ep;
while (true) {
File entry = dir.openNextFile();
if (!entry) {
break;
}
// esp32 returns path here, shorten to filename
ep = (char*)entry.name();
2021-01-04 14:52:32 +00:00
if (*ep == '/') { ep++; }
2020-12-31 13:19:50 +00:00
char *lcp = strrchr(ep,'/');
if (lcp) {
ep = lcp + 1;
}
2021-01-06 16:54:03 +00:00
uint32_t tm = entry.getLastWrite();
String tstr = GetDT(tm);
2020-12-31 13:19:50 +00:00
char *pp = path;
2021-01-04 14:52:32 +00:00
if (!*(pp + 1)) { pp++; }
2020-12-31 13:19:50 +00:00
char *cp = name;
// osx formatted disks contain a lot of stuff we dont want
if (!UfsReject((char*)ep)) {
2020-12-31 13:19:50 +00:00
2021-01-01 07:41:36 +00:00
for (uint8_t cnt = 0; cnt<depth; cnt++) {
*cp++ = '-';
2020-12-31 13:19:50 +00:00
}
2021-01-01 07:41:36 +00:00
sprintf(cp, format, ep);
if (entry.isDirectory()) {
2021-01-04 14:52:32 +00:00
snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, WiFi.localIP().toString().c_str(), pp, ep);
WSContentSend_P(UFS_FORM_SDC_DIRd, npath, ep, name);
2021-01-01 07:41:36 +00:00
uint8_t plen = strlen(path);
2021-01-04 14:52:32 +00:00
if (plen > 1) {
2021-01-01 07:41:36 +00:00
strcat(path, "/");
}
strcat(path, ep);
UfsListDir(path, depth + 4);
2021-01-01 07:41:36 +00:00
path[plen] = 0;
} else {
2021-01-04 14:52:32 +00:00
snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, WiFi.localIP().toString().c_str(), pp, ep);
2021-01-06 16:54:03 +00:00
WSContentSend_P(UFS_FORM_SDC_DIRb, npath, ep, name, tstr.c_str(), entry.size());
2021-01-01 07:41:36 +00:00
}
2020-12-31 13:19:50 +00:00
}
entry.close();
}
dir.close();
}
}
uint8_t UfsDownloadFile(char *file) {
2020-12-31 13:19:50 +00:00
File download_file;
WiFiClient download_Client;
2021-01-07 09:57:24 +00:00
if (!dfsp->exists(file)) {
2021-01-04 14:52:32 +00:00
AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: File not found"));
return 0;
}
2020-12-31 13:19:50 +00:00
2021-01-07 09:57:24 +00:00
download_file = dfsp->open(file, UFS_FILE_READ);
2021-01-04 14:52:32 +00:00
if (!download_file) {
AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: Could not open file"));
return 0;
}
2020-12-31 13:19:50 +00:00
2021-01-04 14:52:32 +00:00
if (download_file.isDirectory()) {
download_file.close();
return 1;
}
2020-12-31 13:19:50 +00:00
2021-01-04 14:52:32 +00:00
uint32_t flen = download_file.size();
2020-12-31 13:19:50 +00:00
2021-01-04 14:52:32 +00:00
download_Client = Webserver->client();
Webserver->setContentLength(flen);
2020-12-31 13:19:50 +00:00
2021-01-04 14:52:32 +00:00
char attachment[100];
char *cp;
for (uint32_t cnt = strlen(file); cnt >= 0; cnt--) {
if (file[cnt] == '/') {
cp = &file[cnt + 1];
break;
2020-12-31 13:19:50 +00:00
}
2021-01-04 14:52:32 +00:00
}
snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=%s"), cp);
Webserver->sendHeader(F("Content-Disposition"), attachment);
WSSend(200, CT_STREAM, "");
uint8_t buff[512];
uint32_t bread;
// transfer is about 150kb/s
uint32_t cnt = 0;
while (download_file.available()) {
bread = download_file.read(buff, sizeof(buff));
uint32_t bw = download_Client.write((const char*)buff, bread);
if (!bw) { break; }
cnt++;
if (cnt > 7) {
cnt = 0;
//if (glob_script_mem.script_loglevel & 0x80) {
// this indeed multitasks, but is slower 50 kB/s
// loop();
//}
2020-12-31 13:19:50 +00:00
}
2021-01-04 14:52:32 +00:00
delay(0);
}
download_file.close();
download_Client.stop();
return 0;
2020-12-31 13:19:50 +00:00
}
void UfsUpload(void) {
2020-12-31 13:19:50 +00:00
HTTPUpload& upload = Webserver->upload();
if (upload.status == UPLOAD_FILE_START) {
char npath[48];
sprintf(npath, "%s/%s", ufs_path, upload.filename.c_str());
2021-01-07 09:57:24 +00:00
dfsp->remove(npath);
ufs_upload_file = dfsp->open(npath, UFS_FILE_WRITE);
2021-01-04 14:52:32 +00:00
if (!ufs_upload_file) { Web.upload_error = 1; }
}
else if (upload.status == UPLOAD_FILE_WRITE) {
if (ufs_upload_file) {
ufs_upload_file.write(upload.buf, upload.currentSize);
}
}
else if (upload.status == UPLOAD_FILE_END) {
if (ufs_upload_file) { ufs_upload_file.close(); }
2020-12-31 13:19:50 +00:00
if (Web.upload_error) {
AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: upload error"));
}
} else {
2021-01-04 14:52:32 +00:00
Web.upload_error = 1;
2021-01-01 10:38:01 +00:00
WSSend(500, CT_PLAIN, F("500: couldn't create file"));
2020-12-31 13:19:50 +00:00
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
2021-01-06 13:41:23 +00:00
bool Xdrv50(uint8_t function) {
2020-12-31 13:19:50 +00:00
bool result = false;
switch (function) {
case FUNC_COMMAND:
result = DecodeCommand(kUFSCommands, kUFSCommand);
break;
#ifdef USE_WEBSERVER
2021-01-06 16:54:03 +00:00
case FUNC_WEB_ADD_MANAGEMENT_BUTTON:
2020-12-31 13:19:50 +00:00
if (ufs_type) {
2021-01-06 16:54:03 +00:00
WSContentSend_PD(UFS_WEB_DIR, D_MANAGE_FILE_SYSTEM);
2020-12-31 13:19:50 +00:00
}
break;
case FUNC_WEB_ADD_HANDLER:
Webserver->on("/ufsd", UfsDirectory);
Webserver->on("/ufsu", HTTP_GET, UfsDirectory);
2021-01-04 14:52:32 +00:00
Webserver->on("/ufsu", HTTP_POST,[]() {
Webserver->sendHeader("Location","/ufsu");
Webserver->send(303);
}, UfsUpload);
2020-12-31 13:19:50 +00:00
break;
#endif // USE_WEBSERVER
}
return result;
}
#endif // USE_UFILESYS