summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Plasa <dplasa@gmail.com>2020-05-31 14:43:26 +0200
committerDaniel Plasa <dplasa@gmail.com>2020-05-31 14:43:26 +0200
commit5094cb3c168ed5c08dbdaa982fe1c096482c5ecc (patch)
tree618593e64517b17b3e2876c12a71e11c6f76d855
parentdescribe limited use of FuseFS clients (diff)
downloadFTPCLientServer-5094cb3c168ed5c08dbdaa982fe1c096482c5ecc.tar
FTPCLientServer-5094cb3c168ed5c08dbdaa982fe1c096482c5ecc.tar.gz
FTPCLientServer-5094cb3c168ed5c08dbdaa982fe1c096482c5ecc.tar.bz2
FTPCLientServer-5094cb3c168ed5c08dbdaa982fe1c096482c5ecc.tar.lz
FTPCLientServer-5094cb3c168ed5c08dbdaa982fe1c096482c5ecc.tar.xz
FTPCLientServer-5094cb3c168ed5c08dbdaa982fe1c096482c5ecc.tar.zst
FTPCLientServer-5094cb3c168ed5c08dbdaa982fe1c096482c5ecc.zip
-rw-r--r--FTPClient.cpp9
-rw-r--r--FTPClient.h1
-rw-r--r--FTPCommon.cpp16
-rw-r--r--FTPCommon.h15
-rw-r--r--FTPServer.cpp151
-rw-r--r--esp32compat/PolledTimeout.h254
-rw-r--r--examples/FTPServerSample/LittleFSSample/LittleFSSample.ino9
-rw-r--r--examples/FTPServerSample/SPIFFSSample/SPIFFSSample.ino77
8 files changed, 379 insertions, 153 deletions
diff --git a/FTPClient.cpp b/FTPClient.cpp
index ef4db15..d385c43 100644
--- a/FTPClient.cpp
+++ b/FTPClient.cpp
@@ -155,7 +155,12 @@ void FTPClient::handleFTP()
millisBeginTrans = millis();
bytesTransfered = 0;
ftpState = cTransfer;
- allocateBuffer(TCP_MSS);
+ if (allocateBuffer() == 0)
+ {
+ _serverStatus.code = errorMemory;
+ _serverStatus.desc = F("No memory for transfer buffer");
+ ftpState = cError;
+ }
if (_direction & FTP_PUT_NONBLOCKING)
{
FTP_DEBUG_MSG(">>> STOR %s", _remoteFileName.c_str());
@@ -208,7 +213,7 @@ int8_t FTPClient::controlConnect()
{
FTP_DEBUG_MSG("Ignoring CA verification - FTP only");
}
- control.connect(_server->servername, _server->port);
+ control.connect(_server->servername.c_str(), _server->port);
FTP_DEBUG_MSG("Connection to %s:%d ... %S", _server->servername.c_str(), _server->port, control.connected() ? PSTR("OK") : PSTR("failed"));
if (control.connected())
return 1;
diff --git a/FTPClient.h b/FTPClient.h
index ca5cd78..05a1bf3 100644
--- a/FTPClient.h
+++ b/FTPClient.h
@@ -51,6 +51,7 @@ public:
static constexpr int16_t errorDataConnectionFailed = -5;
static constexpr int16_t errorUninitialized = -6;
static constexpr int16_t errorTimeout = -7;
+ static constexpr int16_t errorMemory = -8;
typedef struct
{
diff --git a/FTPCommon.cpp b/FTPCommon.cpp
index 4b8af4c..0651022 100644
--- a/FTPCommon.cpp
+++ b/FTPCommon.cpp
@@ -1,7 +1,6 @@
#include "FTPCommon.h"
-FTPCommon::FTPCommon(FS &_FSImplementation) :
- THEFS(_FSImplementation), sTimeOutMs(FTP_TIME_OUT*60*1000), aTimeout(FTP_TIME_OUT*60*1000)
+FTPCommon::FTPCommon(FS &_FSImplementation) : THEFS(_FSImplementation), sTimeOutMs(FTP_TIME_OUT * 60 * 1000), aTimeout(FTP_TIME_OUT * 60 * 1000)
{
}
@@ -23,14 +22,17 @@ void FTPCommon::setTimeout(uint32_t timeoutMs)
sTimeOutMs = timeoutMs;
}
+//
+// allocate a big buffer for file transfers
+//
uint16_t FTPCommon::allocateBuffer(uint16_t desiredBytes)
{
- // allocate a big buffer for file transfers
+#if (defined ESP8266)
uint16_t maxBlock = ESP.getMaxFreeBlockSize() / 2;
if (desiredBytes > maxBlock)
desiredBytes = maxBlock;
-
+#endif
while (fileBuffer == NULL && desiredBytes > 0)
{
fileBuffer = (uint8_t *)malloc(desiredBytes);
@@ -141,7 +143,7 @@ bool FTPCommon::doNetworkToFile()
void FTPCommon::closeTransfer()
{
- freeBuffer();
- file.close();
- data.stop();
+ freeBuffer();
+ file.close();
+ data.stop();
}
diff --git a/FTPCommon.h b/FTPCommon.h
index edb9d8b..a88dd8d 100644
--- a/FTPCommon.h
+++ b/FTPCommon.h
@@ -5,7 +5,18 @@
#include <FS.h>
#include <WiFiClient.h>
#include <WString.h>
+
+#ifdef ESP8266
#include <PolledTimeout.h>
+using esp8266::polledTimeout::oneShotMs; // import the type to the local namespace
+#define BUFFERSIZE TCP_MSS
+#define PRINTu32 "lu"
+#elif defined ESP32
+#include "esp32compat/PolledTimeout.h"
+using esp32::polledTimeout::oneShotMs;
+#define BUFFERSIZE CONFIG_TCP_MSS
+#define PRINTu32 "u"
+#endif
#define FTP_SERVER_VERSION "0.9.7-20200529"
@@ -84,8 +95,6 @@
#define FTP_CMD_LE_SYST 0x54535953 // "SYST" as uint32_t (little endian)
#define FTP_CMD_BE_SYST 0x53595354 // "SYST" as uint32_t (big endian)
-using esp8266::polledTimeout::oneShotMs; // import the type to the local namespace
-
class FTPCommon
{
public:
@@ -124,7 +133,7 @@ protected:
bool doNetworkToFile();
virtual void closeTransfer();
- uint16_t allocateBuffer(uint16_t desiredBytes); // allocate buffer for transfer
+ uint16_t allocateBuffer(uint16_t desiredBytes = BUFFERSIZE); // allocate buffer for transfer
void freeBuffer();
uint8_t *fileBuffer = NULL; // pointer to buffer for file transfer (by allocateBuffer)
uint16_t fileBufferSize; // size of buffer
diff --git a/FTPServer.cpp b/FTPServer.cpp
index c521691..bad2fb2 100644
--- a/FTPServer.cpp
+++ b/FTPServer.cpp
@@ -546,31 +546,37 @@ int8_t FTPServer::processCommand()
path.remove(dashPos);
}
FTP_DEBUG_MSG("Listing content of '%s'", path.c_str());
+#if (defined ESP8266)
Dir dir = THEFS.openDir(path);
while (dir.next())
{
- ++dirCount;
- bool isDir = false;
- String fn = dir.fileName();
- if (cwd == FPSTR(aSlash) && fn[0] == '/')
- fn.remove(0, 1);
- isDir = dir.isDirectory();
file = dir.openFile("r");
+#elif (defined ESP32)
+ File dir = THEFS.open(path);
+ file = dir.openNextFile();
+ while (file)
+ {
+#endif
+ bool isDir = file.isDirectory();
+ String fn = file.name();
+ uint32_t fs = file.size();
String fileTime = makeDateTimeStr(file.getLastWrite());
file.close();
+ if (cwd == FPSTR(aSlash) && fn[0] == '/')
+ fn.remove(0, 1);
if (FTP_CMD(LIST) == command)
{
// unixperms type userid groupid size time & date name
// drwxrwsr-x 2 111 117 4096 Apr 01 12:45 aDirectory
// -rw-rw-r-- 1 111 117 875315 Mar 23 17:29 aFile
- data.printf_P(PSTR("%crw%cr-%cr-%c %c 0 0 %8lu %s %s\r\n"),
+ data.printf_P(PSTR("%crw%cr-%cr-%c %c 0 0 %8" PRINTu32 " %s %s\r\n"),
isDir ? 'd' : '-',
isDir ? 'x' : '-',
isDir ? 'x' : '-',
isDir ? 'x' : '-',
isDir ? '2' : '1',
- isDir ? 0 : (uint32_t)dir.fileSize(),
+ isDir ? 0 : fs,
fileTime.c_str(),
fn.c_str());
//data.printf_P(PSTR("+r,s%lu\r\n,\t%s\r\n"), (uint32_t)dir.fileSize(), fn.c_str());
@@ -586,7 +592,7 @@ int8_t FTPServer::processCommand()
}
else
{
- data.printf_P(PSTR("0644;size=%lu;type=file; "), (uint32_t)dir.fileSize());
+ data.printf_P(PSTR("0644;size=%" PRINTu32 ";type=file; "), fs);
}
data.printf_P(PSTR("%s\r\n"), fn.c_str());
}
@@ -594,124 +600,21 @@ int8_t FTPServer::processCommand()
{
data.println(fn);
}
+ ++dirCount;
+#if (defined ESP32)
+ file = dir.openNextFile();
+#endif
}
-
+
if (FTP_CMD(MLSD) == command)
{
control.println(F("226-options: -a -l\r\n"));
}
sendMessage_P(226, PSTR("%d matches total"), dirCount);
}
-#if defined ESP32
- File root = THEFS.open(cwd);
- if (!root)
- {
- sendMessage_P(550, PSTR("Can't open directory \"%s\""), cwd.c_str());
- // return;
- }
- else
- {
- // if(!root.isDirectory()){
- // FTP_DEBUG_MSG("Not a directory: '%s'", cwd.c_str());
- // return;
- // }
-
- File file = root.openNextFile();
- while (file)
- {
- if (file.isDirectory())
- {
- data.println("+r,s <DIR> " + String(file.name()));
- // Serial.print(" DIR : ");
- // Serial.println(file.name());
- // if(levels){
- // listDir(fs, file.name(), levels -1);
- // }
- }
- else
- {
- String fn, fs;
- fn = file.name();
- // fn.remove(0, 1);
- fs = String(file.size());
- data.println("+r,s" + fs);
- data.println(",\t" + fn);
- nm++;
- }
- file = root.openNextFile();
- }
- sendMessage_P(226, PSTR("%d matches total"), nm);
- }
-#endif
data.stop();
}
-#if defined ESP32
- //
- // FIXME MLSD ESP32
- //
- else if (!strcmp(command, "MLSD"))
- {
- File root = THEFS.open(cwd);
- // if(!root){
- // control.println( "550, "Can't open directory " + cwd );
- // // return;
- // } else {
- // if(!root.isDirectory()){
- // Serial.println("Not a directory");
- // return;
- // }
-
- File file = root.openNextFile();
- while (file)
- {
- // if(file.isDirectory()){
- // data.println( "+r,s <DIR> " + String(file.name()));
- // // Serial.print(" DIR : ");
- // // Serial.println(file.name());
- // // if(levels){
- // // listDir(fs, file.name(), levels -1);
- // // }
- // } else {
- String fn, fs;
- fn = file.name();
- fn.remove(0, 1);
- fs = String(file.size());
- data.println("Type=file;Size=" + fs + ";" + "modify=20000101160656;" + " " + fn);
- nm++;
- // }
- file = root.openNextFile();
- }
- sendMessage_P(226, PSTR("-options: -a -l"));
- sendMessage_P(226, PSTR("%d matches total"), nm);
- // }
- data.stop();
- }
- //
- // NLST
- //
- else if (!strcmp(command, "NLST"))
- {
- File root = THEFS.open(cwd);
- if (!root)
- {
- sendMessage_P(550, "Can't open directory %s\n"), cwd.c_str());
- }
- else
- {
- File file = root.openNextFile();
- while (file)
- {
- data.println(file.name());
- nm++;
- file = root.openNextFile();
- }
- sendMessage_P(226, "%d matches total", nm);
- }
- data.stop();
- }
-#endif
-
//
// RETR - Retrieve
//
@@ -730,7 +633,7 @@ int8_t FTPServer::processCommand()
{
sendMessage_P(550, PSTR("File \"%s\" not found."), parameters.c_str());
}
- else if (!file.isFile())
+ else if (file.isDirectory())
{
sendMessage_P(450, PSTR("Cannot open file \"%s\"."), parameters.c_str());
}
@@ -748,7 +651,7 @@ int8_t FTPServer::processCommand()
millisBeginTrans = millis();
bytesTransfered = 0;
uint32_t fs = file.size();
- if (allocateBuffer(TCP_MSS))
+ if (allocateBuffer())
{
FTP_DEBUG_MSG("Sending file '%s' (%lu bytes)", path.c_str(), fs);
sendMessage_P(150, PSTR("%lu bytes to download"), fs);
@@ -795,7 +698,7 @@ int8_t FTPServer::processCommand()
transferState = tStore;
millisBeginTrans = millis();
bytesTransfered = 0;
- if (allocateBuffer(TCP_MSS))
+ if (allocateBuffer())
{
FTP_DEBUG_MSG("Receiving file '%s' => %s", parameters.c_str(), path.c_str());
sendMessage_P(150, PSTR("Connected to port %d"), dataPort);
@@ -839,9 +742,17 @@ int8_t FTPServer::processCommand()
sendMessage_P(550, "Remove directory operation failed."); //not support on SPIFFS
#else
// check directory for files
+#if (defined ESP8266)
Dir dir = THEFS.openDir(path);
if (dir.next())
{
+#elif (defined ESP32)
+ File dir = THEFS.open(path);
+ file = dir.openNextFile();
+ if (file)
+ {
+ file.close();
+#endif
//only delete if dir is empty!
sendMessage_P(550, PSTR("Remove directory operation failed, directory is not empty."));
}
diff --git a/esp32compat/PolledTimeout.h b/esp32compat/PolledTimeout.h
new file mode 100644
index 0000000..64677b7
--- /dev/null
+++ b/esp32compat/PolledTimeout.h
@@ -0,0 +1,254 @@
+#ifndef __POLLEDTIMING_H__
+#define __POLLEDTIMING_H__
+
+
+/*
+ PolledTimeout.h - Encapsulation of a polled Timeout
+
+ Copyright (c) 2018 Daniel Salazar. All rights reserved.
+ This file is part of the esp8266 core for Arduino environment.
+
+ 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 <limits>
+
+#include <Arduino.h>
+
+namespace esp32
+{
+
+
+namespace polledTimeout
+{
+
+namespace YieldPolicy
+{
+
+struct DoNothing
+{
+ static void execute() {}
+};
+
+struct YieldOrSkip
+{
+ static void execute() {delay(0);}
+};
+
+template <unsigned long delayMs>
+struct YieldAndDelayMs
+{
+ static void execute() {delay(delayMs);}
+};
+
+} //YieldPolicy
+
+namespace TimePolicy
+{
+
+struct TimeSourceMillis
+{
+ // time policy in milli-seconds based on millis()
+
+ using timeType = decltype(millis());
+ static timeType time() {return millis();}
+ static constexpr timeType ticksPerSecond = 1000;
+ static constexpr timeType ticksPerSecondMax = 1000;
+};
+
+template <typename TimeSourceType, unsigned long long second_th>
+ // "second_th" units of timeType for one second
+struct TimeUnit
+{
+ using timeType = typename TimeSourceType::timeType;
+
+#if __GNUC__ < 5
+ // gcc-4.8 cannot compile the constexpr-only version of this function
+ // using #defines instead luckily works
+ static constexpr timeType computeRangeCompensation ()
+ {
+ #define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond)
+ #define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick)
+
+ return ({
+ fractional == 0?
+ 1: // no need for compensation
+ (number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
+ });
+
+ #undef number_of_secondTh_in_one_tick
+ #undef fractional
+ }
+#else
+ static constexpr timeType computeRangeCompensation ()
+ {
+ return ({
+ constexpr double number_of_secondTh_in_one_tick = (1.0 * second_th) / ticksPerSecond;
+ constexpr double fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick;
+ fractional == 0?
+ 1: // no need for compensation
+ (number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
+ });
+ }
+#endif
+
+ static constexpr timeType ticksPerSecond = TimeSourceType::ticksPerSecond;
+ static constexpr timeType ticksPerSecondMax = TimeSourceType::ticksPerSecondMax;
+ static constexpr timeType rangeCompensate = computeRangeCompensation();
+ static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th;
+ static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th;
+ static constexpr timeType user2UnitDivider = rangeCompensate;
+ // std::numeric_limits<timeType>::max() is reserved
+ static constexpr timeType timeMax = (std::numeric_limits<timeType>::max() - 1) / user2UnitMultiplierMax;
+
+ static timeType toTimeTypeUnit (const timeType userUnit) {return (userUnit * user2UnitMultiplier) / user2UnitDivider;}
+ static timeType toUserUnit (const timeType internalUnit) {return (internalUnit * user2UnitDivider) / user2UnitMultiplier;}
+ static timeType time () {return TimeSourceType::time();}
+};
+
+using TimeMillis = TimeUnit< TimeSourceMillis, 1000 >;
+
+} //TimePolicy
+
+template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing, typename TimePolicyT = TimePolicy::TimeMillis>
+class timeoutTemplate
+{
+public:
+ using timeType = typename TimePolicyT::timeType;
+ static_assert(std::is_unsigned<timeType>::value == true, "timeType must be unsigned");
+
+ static constexpr timeType alwaysExpired = 0;
+ static constexpr timeType neverExpires = std::numeric_limits<timeType>::max();
+ static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug
+
+ timeoutTemplate(const timeType userTimeout)
+ {
+ reset(userTimeout);
+ }
+
+ IRAM_ATTR // fast
+ bool expired()
+ {
+ YieldPolicyT::execute(); //in case of DoNothing: gets optimized away
+ if(PeriodicT) //in case of false: gets optimized away
+ return expiredRetrigger();
+ return expiredOneShot();
+ }
+
+ IRAM_ATTR // fast
+ operator bool()
+ {
+ return expired();
+ }
+
+ bool canExpire () const
+ {
+ return !_neverExpires;
+ }
+
+ bool canWait () const
+ {
+ return _timeout != alwaysExpired;
+ }
+
+ IRAM_ATTR // called from ISR
+ void reset(const timeType newUserTimeout)
+ {
+ reset();
+ _timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout);
+ _neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax());
+ }
+
+ IRAM_ATTR // called from ISR
+ void reset()
+ {
+ _start = TimePolicyT::time();
+ }
+
+ void resetToNeverExpires ()
+ {
+ _timeout = alwaysExpired + 1; // because canWait() has precedence
+ _neverExpires = true;
+ }
+
+ timeType getTimeout() const
+ {
+ return TimePolicyT::toUserUnit(_timeout);
+ }
+
+ static constexpr timeType timeMax()
+ {
+ return TimePolicyT::timeMax;
+ }
+
+private:
+
+ IRAM_ATTR // fast
+ bool checkExpired(const timeType internalUnit) const
+ {
+ // canWait() is not checked here
+ // returns "can expire" and "time expired"
+ return (!_neverExpires) && ((internalUnit - _start) >= _timeout);
+ }
+
+protected:
+
+ IRAM_ATTR // fast
+ bool expiredRetrigger()
+ {
+ if (!canWait())
+ return true;
+
+ timeType current = TimePolicyT::time();
+ if(checkExpired(current))
+ {
+ unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout)
+ _start += n * _timeout;
+ return true;
+ }
+ return false;
+ }
+
+ IRAM_ATTR // fast
+ bool expiredOneShot() const
+ {
+ // returns "always expired" or "has expired"
+ return !canWait() || checkExpired(TimePolicyT::time());
+ }
+
+ timeType _timeout;
+ timeType _start;
+ bool _neverExpires;
+};
+
+// standard versions (based on millis())
+// timeMax() is 49.7 days ((2^32)-2 ms)
+
+using oneShotMs = polledTimeout::timeoutTemplate<false>;
+using periodicMs = polledTimeout::timeoutTemplate<true>;
+
+
+} //polledTimeout
+
+
+/* A 1-shot timeout that auto-yields when in CONT can be built as follows:
+ * using oneShotYieldMs = esp32::polledTimeout::timeoutTemplate<false, esp32::polledTimeout::YieldPolicy::YieldOrSkip>;
+ *
+ * Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file.
+ */
+
+}//esp32
+
+#endif
diff --git a/examples/FTPServerSample/LittleFSSample/LittleFSSample.ino b/examples/FTPServerSample/LittleFSSample/LittleFSSample.ino
index 197c730..d30120b 100644
--- a/examples/FTPServerSample/LittleFSSample/LittleFSSample.ino
+++ b/examples/FTPServerSample/LittleFSSample/LittleFSSample.ino
@@ -15,12 +15,11 @@
Daniel Plasa <dplasa@gmail.com>
*/
-#ifdef ESP8266
-#include <ESP8266WiFi.h>
-#elif defined ESP32
-#include <WiFi.h>
+#if (defined ESP32)
+#error "No LittlFS on the ESP32"
#endif
+#include <ESP8266WiFi.h>
#include <LittleFS.h>
#include <FTPServer.h>
@@ -47,7 +46,7 @@ void setup(void)
Serial.printf_P(PSTR("\nConnected to %S, IP address is %s\n"), ssid, WiFi.localIP().toString().c_str());
// setup the ftp server with username and password
- // ports are defined in esFTP.h, default is
+ // ports are defined in FTPCommon.h, default is
// 21 for the control connection
// 50009 for the data connection (passive mode by default)
ftpSrv.begin(F("ftp"), F("ftp")); //username, password for ftp. set ports in ESP8266FtpServer.h (default 21, 50009 for PASV)
diff --git a/examples/FTPServerSample/SPIFFSSample/SPIFFSSample.ino b/examples/FTPServerSample/SPIFFSSample/SPIFFSSample.ino
index 358404c..b15bd98 100644
--- a/examples/FTPServerSample/SPIFFSSample/SPIFFSSample.ino
+++ b/examples/FTPServerSample/SPIFFSSample/SPIFFSSample.ino
@@ -15,18 +15,18 @@
Daniel Plasa <dplasa@gmail.com>
*/
-#ifdef ESP8266
-#include <FS.h>
-#include <ESP8266WiFi.h>
-#elif defined ESP32
+#if (defined ESP32)
#include <WiFi.h>
#include <SPIFFS.h>
+#elif (defined ESP8266)
+#include <ESP8266WiFi.h>
+#include <FS.h>
#endif
#include <FTPServer.h>
-const char *ssid PROGMEM = "YOUR_SSID";
-const char *password PROGMEM = "YOUR_PASS";
+const char *ssid = "YOUR_SSID";
+const char *password = "YOUR_PASS";
// Since SPIFFS is becoming deprecated but might still be in
// use in your Projects, tell the FtpServer to use SPIFFS
@@ -38,7 +38,7 @@ void setup(void)
WiFi.begin(ssid, password);
bool fsok = SPIFFS.begin();
- Serial.printf_P(PSTR("FS init: %S\n"), fsok ? PSTR("ok") : PSTR("fail!"));
+ Serial.printf_P(PSTR("FS init: %s\n"), fsok ? PSTR("ok") : PSTR("fail!"));
// Wait for connection
while (WiFi.status() != WL_CONNECTED)
@@ -46,10 +46,10 @@ void setup(void)
delay(500);
Serial.printf_P(PSTR("."));
}
- Serial.printf_P(PSTR("\nConnected to %S, IP address is %s\n"), ssid, WiFi.localIP().toString().c_str());
+ Serial.printf_P(PSTR("\nConnected to %s, IP address is %s\n"), ssid, WiFi.localIP().toString().c_str());
// setup the ftp server with username and password
- // ports are defined in esFTP.h, default is
+ // ports are defined in FTPCommon.h, default is
// 21 for the control connection
// 50009 for the data connection (passive mode by default)
ftpSrv.begin(F("ftp"), F("ftp"));
@@ -102,14 +102,59 @@ void loop(void)
else if (action == list)
{
Serial.printf_P(PSTR("Listing contents...\n"));
- uint16_t dirCount = 0;
- Dir dir = SPIFFS.openDir(F("/"));
- while (dir.next())
- {
- ++dirCount;
- Serial.printf_P(PSTR("%6ld %s\n"), (uint32_t)dir.fileSize(), dir.fileName().c_str());
- }
+ uint16_t dirCount = ListDir("/");
Serial.printf_P(PSTR("%d files total\n"), dirCount);
action = show;
}
}
+
+#if (defined ESP8266)
+uint16_t ListDir(const char *path)
+{
+ uint16_t dirCount = 0;
+ Dir dir = SPIFFS.openDir(path);
+ while (dir.next())
+ {
+ ++dirCount;
+ Serial.printf_P(PSTR("%6ld %s\n"), (uint32_t)dir.fileSize(), dir.fileName().c_str());
+ }
+ return dirCount;
+}
+#elif (defined ESP32)
+uint16_t ListDir(const char *path)
+{
+ uint16_t dirCount = 0;
+ File root = SPIFFS.open(path);
+ if (!root)
+ {
+ Serial.println(F("failed to open root"));
+ return 0;
+ }
+ if (!root.isDirectory())
+ {
+ Serial.println(F("/ not a directory"));
+ return 0;
+ }
+
+ File file = root.openNextFile();
+ while (file)
+ {
+ ++dirCount;
+ if (file.isDirectory())
+ {
+ Serial.print(F(" DIR : "));
+ Serial.println(file.name());
+ dirCount += ListDir(file.name());
+ }
+ else
+ {
+ Serial.print(F(" FILE: "));
+ Serial.print(file.name());
+ Serial.print(F("\tSIZE: "));
+ Serial.println(file.size());
+ }
+ file = root.openNextFile();
+ }
+ return dirCount;
+}
+#endif \ No newline at end of file