Simple FTP Server library now with support for Wio Terminal and SD

Spread the love

I receive this device from SeeedStudio, and I find It very usefully. The first thing I thought about doing with this device was porting my SimpleFTPServer library.

Wio Terminal FTP Server with TFT monitor main
Wio Terminal FTP Server with TFT monitor main

About Seeed Studio

Seeed is the IoT hardware enabler providing services over 10 years that empower makers to realize their projects and products. Seeed offers a wide array of hardware platforms and sensor modules ready to be integrated with existing IoT platforms and one-stop PCB manufacturing and Prototype PCB Assembly. Seeed Studio provides a wide selection of electronic parts including Arduino, Raspberry Pi and many different development board platforms. Especially the Grove Sytsem help engineers and makers to avoid jumper wires problems. Seeed Studio has developed more than 280 Grove modules covering a wide range of applications that can fulfill a variety of needs. 

Wio Terminal

I recommend that you also read the introductory article on this device “Wio Terminal: pinout, specs and Arduino IDE configurations“.

Wio Terminal is a complete system, compared to a normal development board it is equipped with screen + development board + input / output interface + container, which makes it an efficient product and ready for the final product.

You can find the device here on SeeedStudio Aliexpress

Wio Terminal pinout mischianti low resolution
Wio Terminal pinout mischianti low resolution

Link to high resolution pinout image

Library

You can find the library here on GitHub. I don’t already integrate It on Arduino IDE Library manger, but I think I do that soon.

I already write something about that on this article “FTP server on esp8266 and esp32” when I integrate esp32 and esp8266.

Click the DOWNLOADS button in the top right corner, rename the uncompressed folder SimpleFTPServer.

Check that the SimpleFTPServer contains FtpServer.cpp, FtpServer.h, FtpServerKey.h e SimpleFTPServer.h .

Place the SimpleFTPServer library folder your /libraries/ folder.

You may need to create the libraries subfolder if its your first library.

Restart the IDE.

You must set the correct environment by editing the lines in the FtpServerKey.h file.

#define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_SEEED_RTL8720DN
#define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SDFAT2

As you can see I don’t use the Seeed library to manage SD because exist an unresolved bug on It that generate a lot of scope problem.

Update 21/07/2021: the bug is solved, now you can use also this configuration

#define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_SEEED_RTL8720DN
#define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SEEED_SD

But with this configuration, and the library SdFat, works properly.

How to

Create minimal FTP server

After download properly the library you can create a simple FTP server with few line of code.

You need to import all these libraries:

  • Adafruit_ZeroDMA
  • SdFat
  • Seeed_Arduino_FreeRTOS
  • Seeed_Arduino_FS
  • Seeed_Arduino_mbedtls
  • Seeed_Arduino_rpcUnified
  • Seeed_Arduino_rpcWiFi
  • Seeed_Arduino_SFUD
  • SimpleFTPServer
  • SPI

Here the complete sketch.

/*
 * FtpServer Wio Terminal with SdFat library
 *
 * AUTHOR:  Renzo Mischianti
 *
 * https://mischianti.org/
 *
 */
#include "SdFat.h"

#include <rpcWiFi.h>

#include <FtpServer.h>


#define SD_CONFIG SdSpiConfig(SDCARD_SS_PIN, 2)
SdFs sd;

FtpServer ftpSrv;

const char *ssid = "<YOUR-SSID>";
const char *password = "<YOUR-PASSWD>";

void setup()
{
    Serial.begin(115200);
    delay(1000);

    pinMode(5, OUTPUT);
    digitalWrite(5, HIGH);

    Serial.print("Starting SD.");
    // Initialize the SD.
    if (!sd.begin(SD_CONFIG)) {
      sd.initErrorHalt(&Serial);
    }
    FsFile dir;
    FsFile file;

    // Open root directory
    if (!dir.open("/")){
      Serial.println("dir.open failed");
    }

    Serial.println("finish!");

    // We start by connecting to a WiFi network

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.print(ssid);

    WiFi.mode(WIFI_STA);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED)
    {
        Serial.print("Connecting to ");
        Serial.println(ssid);
        WiFi.begin(ssid, password);
        Serial.print(".");
        delay(500);
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    delay(1000);

    ftpSrv.begin("wioterminal","wioterminal");    //username, password for ftp.
  }

  void loop(void) {
  	  ftpSrv.handleFTP();        //make sure in loop you call handleFTP()!!
  }

Now you can connect to the terminal via FTP, check the configuration of the FTP client in the relative chapter.

Here the serial output.

Connecting to <YOUR-SSID>
WiFi connected
IP address: 
192.168.1.176

Add a status callback to your FTP Server

The library offer the opportunity to add some callback to check the state of connection or transfer.

The signs of the functions are:

  void (*_callback)(FtpOperation ftpOperation, unsigned int freeSpace, unsigned int totalSpace){};
  void (*_transferCallback)(FtpTransferOperation ftpOperation, const char* name, unsigned int transferredSize){};

Main callback

The first is called when one of these operation is executed:

  • FTP_CONNECT: a connection is established;
  • FTP_DISCONNECT: client is disconnected;
  • FTP_FREE_SPACE_CHANGE: free space is changed.

The other parameters are:

  • freeSpace: space available on SD;
  • totalSpace: total space of SD.

Transfer callback

The second one when these operation are executed:

  • FTP_UPLOAD_START: when an upload is started;
  • FTP_UPLOAD: when an upload is in course;
  • FTP_DOWNLOAD_START: when download is started;
  • FTP_DOWNLOAD: when a download is in course;
  • FTP_DOWNLOAD_STOP or FTP_TRANSFER_STOP: when download is finished;
  • FTP_UPLOAD_STOP or FTP_TRANSFER_STOP: when upload is finished;
  • FTP_DOWNLOAD_ERROR or FTP_TRANSFER_ERROR: when a download error is occured;
  • FTP_UPLOAD_ERROR or FTP_TRANSFER_ERROR: when an upload error is occured.

The other parameters are:

  • name: the name of the file;
  • transferredSize: the size transferred.

Example sketch with callback

The resulting code with callbacks can be:

/*
 * FtpServer Wio Terminal with SdFat library
 * and with callbacks to the main actions of FTP server 
 *
 * AUTHOR:  Renzo Mischianti
 *
 * https://mischianti.org/
 *
 */
#include "SdFat.h"

#include <rpcWiFi.h>

#include <FtpServer.h>


#define SD_CONFIG SdSpiConfig(SDCARD_SS_PIN, 2)
SdFs sd;

FtpServer ftpSrv;

const char *ssid = "<YOUR-SSID>";
const char *password = "<YOUR PASSWD>";

void _callback(FtpOperation ftpOperation, unsigned int freeSpace, unsigned int totalSpace){
	Serial.print(">>>>>>>>>>>>>>> _callback " );
	Serial.print(ftpOperation);
	/* FTP_CONNECT,
	 * FTP_DISCONNECT,
	 * FTP_FREE_SPACE_CHANGE
	 */
	Serial.print(" ");
	Serial.print(freeSpace);
	Serial.print(" ");
	Serial.println(totalSpace);
};

void _transferCallback(FtpTransferOperation ftpOperation, const char* name, unsigned int transferredSize){
	Serial.print(">>>>>>>>>>>>>>> _transferCallback " );
	Serial.print(ftpOperation);
	/* FTP_UPLOAD_START = 0,
	 * FTP_UPLOAD = 1,
	 *
	 * FTP_DOWNLOAD_START = 2,
	 * FTP_DOWNLOAD = 3,
	 *
	 * FTP_TRANSFER_STOP = 4,
	 * FTP_DOWNLOAD_STOP = 4,
	 * FTP_UPLOAD_STOP = 4,
	 *
	 * FTP_TRANSFER_ERROR = 5,
	 * FTP_DOWNLOAD_ERROR = 5,
	 * FTP_UPLOAD_ERROR = 5
	 */
	Serial.print(" ");
	Serial.print(name);
	Serial.print(" ");
	Serial.println(transferredSize);
};

void setup()
{
    Serial.begin(115200);
    delay(1000);

    pinMode(5, OUTPUT);
    digitalWrite(5, HIGH);

    Serial.print("Starting SD.");
    // Initialize the SD.
    if (!sd.begin(SD_CONFIG)) {
      sd.initErrorHalt(&Serial);
    }
    FsFile dir;
    FsFile file;

    // Open root directory
    if (!dir.open("/")){
      Serial.println("dir.open failed");
    }

    Serial.println("finish!");

    // We start by connecting to a WiFi network

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.print(ssid);

    WiFi.mode(WIFI_STA);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED)
    {
        Serial.print("Connecting to ");
        Serial.println(ssid);
        WiFi.begin(ssid, password);
        Serial.print(".");
        delay(500);
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    delay(1000);

	ftpSrv.setCallback(_callback);
	ftpSrv.setTransferCallback(_transferCallback);

    ftpSrv.begin("wioterminal","wioterminal");    //username, password for ftp.
  }

  void loop(void) {
  	  ftpSrv.handleFTP();        //make sure in loop you call handleFTP()!!
  }

Here the serial output:

Connecting to <YOUR-SSID>
WiFi connected
IP address: 
192.168.1.176
>>>>>>>>>>>>>>> _callback 0 1470368 1927168

>>>>>>>>>>>>>>> _transferCallback 0 tappo.stl 0
>>>>>>>>>>>>>>> _transferCallback 1 tappo.stl 1024
>>>>>>>>>>>>>>> _transferCallback 1 tappo.stl 2048
[...]
>>>>>>>>>>>>>>> _transferCallback 1 tappo.stl 58368
>>>>>>>>>>>>>>> _transferCallback 1 tappo.stl 58550
>>>>>>>>>>>>>>> _transferCallback 4 tappo.stl 58550

>>>>>>>>>>>>>>> _callback 2 1470304 1927168

>>>>>>>>>>>>>>> _transferCallback 2 test.gif 46160
>>>>>>>>>>>>>>> _transferCallback 3 test.gif 2048
>>>>>>>>>>>>>>> _transferCallback 3 test.gif 4096
[...]
>>>>>>>>>>>>>>> _transferCallback 3 test.gif 45056
>>>>>>>>>>>>>>> _transferCallback 3 test.gif 46160
>>>>>>>>>>>>>>> _transferCallback 4 test.gif 46160

We are going to analize the output:

  • line 5: identify the connection of the client;
  • from 7 to 13: at line 7 start upload transfer from 8 to 12 transfer in course at line 13 finish transfer;
  • line 15: free space changed;
  • from 17 to 23: at line 17 start download transfer from 18 to 22 transfer in course at line 23 finish transfer.

Add graphical interface to monitor the FTP Server

Now if we want to add some information about the FTP server, we can use the device’s TFT display.

The code become more complex with the management of TFT, but It isn’t so difficult to read.

Display status

At first you will have this screen on the WioTerminal.

Wio Terminal FTP server WiFi connecting
Wio Terminal FTP server WiFi connecting

In this screen you can see that the wio terminal try to connect to my SSID reef-casa-sopra. Than when WiFi is connected you can see the strenght of the signal and free space.

Wio Terminal FTP server WiFi connected and RSSI
Wio Terminal FTP server WiFi connected and RSSI

Then with the IP, that you can see in the screen, you can try to connect with your FTP client. When connected the display change again.

Wio Terminal FTP server Client connected and free space
Wio Terminal FTP server Client connected and free space

Now you can transfer your files. Now i upload a small photo, and in the screen appear the transfer state Upload (and the stranferred size that change constantely).

Wio Terminal FTP server upload a file
Wio Terminal FTP server upload a file

When the transfer is successful, you can check the status changed to OK on the screen.

Wio Terminal FTP server upload completed succesfully
Wio Terminal FTP server upload completed successfully

Sketch with complete server and display of the status

Here the complete sketch.

/*
 * FtpServer Wio Terminal with SdFat library
 * and with callbacks to the main actions of FTP server
 * and a monitor on TFT
 *
 * AUTHOR:  Renzo Mischianti
 *
 * https://mischianti.org/
 *
 */

#include "SdFat.h"

#include <rpcWiFi.h>


#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>

#include <FtpServer.h>

TFT_eSPI tft = TFT_eSPI(); // Invoke custom library

#define DEG2RAD 0.0174532925

byte inc = 0;
unsigned int col = 0;

#define SD_CONFIG SdSpiConfig(SDCARD_SS_PIN, 2)
SdFs sd;

FtpServer ftpSrv;

const char *ssid = "<YOUR-SSID>";
const char *password = "<YOUR-PASSWD>";

#define MAIN_TOP 110

#define FREE_SPACE_PIE_X 80
#define FREE_SPACE_PIE_Y MAIN_TOP+40
#define FREE_SPACE_PIE_RADIUS 50

void freeSpacePieData(unsigned int freeSpace, unsigned int totalSpace) {
	int pieFree = 360 - (freeSpace * 360 / totalSpace);

    fillSegment(FREE_SPACE_PIE_X, FREE_SPACE_PIE_Y, 0, pieFree, FREE_SPACE_PIE_RADIUS, TFT_RED);
    fillSegment(FREE_SPACE_PIE_X, FREE_SPACE_PIE_Y, pieFree, 360 - pieFree, FREE_SPACE_PIE_RADIUS, TFT_BLUE);

    // Set "cursor" at top left corner of display (0,0) and select font 2
    // (cursor will move to next line automatically during printing with 'tft.println'
    //  or stay on the line is there is room for the text with tft.print)
    tft.setCursor(FREE_SPACE_PIE_X + 80, MAIN_TOP, 2);
    // Set the font colour to be white with a black background, set text size multiplier to 1
    tft.setTextColor(TFT_WHITE, TFT_BLACK);  tft.setTextSize(1);
    // We can now plot text on screen using the "print" class
    Serial.print(freeSpace/1000);Serial.print("Mb/");Serial.print(String(totalSpace/1000));Serial.println("Mb");
    tft.print(freeSpace/1000);tft.print("Mb/");tft.print(String(totalSpace/1000));tft.println("Mb");
}

void connectedDisconnected(bool connected) {
    tft.fillCircle(FREE_SPACE_PIE_X + 80 + 10, MAIN_TOP+25+7, 10, (connected)?TFT_GREEN:TFT_RED);

    tft.setCursor(FREE_SPACE_PIE_X + 80 + 25, MAIN_TOP+25, 2);
    tft.println("              ");

    tft.setCursor(FREE_SPACE_PIE_X + 80 + 25, MAIN_TOP+25, 2);
    (connected)?tft.println("Connected!"):tft.println("Disconnected!");
}

void transfer(bool transfer, bool upload) {
    tft.fillCircle(FREE_SPACE_PIE_X + 80 + 10, MAIN_TOP+25+25+7, 10, (transfer)?(upload)?TFT_GREEN:TFT_BLUE:TFT_RED);

    tft.setCursor(FREE_SPACE_PIE_X + 80 + 25, MAIN_TOP+25+25, 2);
    tft.println("              ");

    tft.setCursor(FREE_SPACE_PIE_X + 80 + 25, MAIN_TOP+25+25, 2);
    (transfer)?tft.println((upload)?"Upload!":"Download!"):tft.println("Idle!");
}

//index - starting at, n- how many chars
char* subString(const char *s, int index, int n){
	char* b = (char*) malloc((strlen(s) + 1) * sizeof(char));
	strcpy(b,s);

	Serial.println("--------------------------------------");
	Serial.println(s);
	Serial.println(index);
	Serial.println(n);
    char *res = new char[n + 1];
    Serial.println(res);
    sprintf(res, "%.*s", n, b + index);
    Serial.println(res);
    free(b);
    return res;
}


void fileTransfer(FtpTransferOperation ftpOperation, const char* filename, unsigned int transferredSize) {
	int yoffset = 2;

    tft.setCursor(20, MAIN_TOP+(FREE_SPACE_PIE_RADIUS*2)+yoffset, 2);
    tft.println(F("                          "));

	tft.setCursor(20, MAIN_TOP+(FREE_SPACE_PIE_RADIUS*2)+yoffset, 2);
	int lenfile = strlen(filename);
	Serial.println(lenfile);
    if (lenfile>22) {

		tft.print(subString(filename, 0, 16));tft.print(F("~"));
		tft.print( subString(filename, (lenfile-4), 4) );
    } else {
		tft.print(filename);
    }
	tft.setCursor(20+160, MAIN_TOP+(FREE_SPACE_PIE_RADIUS*2)+yoffset, 2);
	tft.print(F("                         "));
	tft.setCursor(20+160, MAIN_TOP+(FREE_SPACE_PIE_RADIUS*2)+yoffset, 2);
	tft.print(transferredSize);tft.print("Kb");

	tft.setCursor(320-55, MAIN_TOP+(FREE_SPACE_PIE_RADIUS*2)+yoffset, 2);
	switch (ftpOperation) {
	case FTP_UPLOAD:
	    		tft.setTextColor(TFT_GREEN, TFT_BLACK);
				tft.print(F("Upload"));
				tft.setTextColor(TFT_WHITE, TFT_BLACK);
				break;
	case FTP_DOWNLOAD:
				tft.setTextColor(TFT_BLUE, TFT_BLACK);
				tft.print(F("Down"));
				tft.setTextColor(TFT_WHITE, TFT_BLACK);

				break;
	case FTP_TRANSFER_STOP:
				tft.setTextColor(TFT_GREEN, TFT_BLACK);
				tft.print(F("OK"));
				tft.setTextColor(TFT_WHITE, TFT_BLACK);

				break;
	case FTP_TRANSFER_ERROR:
				tft.setTextColor(TFT_RED, TFT_BLACK);
				tft.print(F("Error"));
				tft.setTextColor(TFT_WHITE, TFT_BLACK);

				break;

		default:
			break;
	}

}

void wifiStrenght (int8_t RSSI, bool connection = false) {
	Serial.print("RSSI --> ");Serial.println(RSSI);
	int marginX = 30;

	int startX = 90;
	int widthW = 320-(startX+marginX);

	int startY = 60;
	int heightY = 10;

	tft.setCursor(marginX, startY - 5, 2);
	tft.print(F("                                         "));
	tft.setCursor(marginX, startY - 5, 2);

	if (connection) {
		tft.print(F("Connectint to: "));
		tft.print(ssid);
	}else{
		tft.println("WiFi str: ");

		// 120 : 120-RSSI = 300 : x

		tft.drawRoundRect(startX, startY, widthW, heightY, 5, TFT_WHITE);

		uint32_t colorRSSI = TFT_GREEN;
		if (abs(RSSI)<55) {
			colorRSSI = TFT_GREEN;
		} else if (abs(RSSI)<75) {
			colorRSSI = TFT_YELLOW;
		} else if (abs(RSSI)<75) {
			colorRSSI = TFT_RED;
		}

		tft.fillRoundRect(startX+1, startY+1, (120+RSSI)*widthW/120, heightY-2, 5, colorRSSI);

		tft.setCursor(marginX, startY + 15, 2);

		tft.print("IP: ");
		tft.println(WiFi.localIP());
	}
}

void _callback(FtpOperation ftpOperation, unsigned int freeSpace, unsigned int totalSpace){
	Serial.print(">>>>>>>>>>>>>>> _callback " );
	Serial.print(ftpOperation);
	/* FTP_CONNECT,
	 * FTP_DISCONNECT,
	 * FTP_FREE_SPACE_CHANGE
	 */
	Serial.print(" ");
	Serial.print(freeSpace);
	Serial.print(" ");
	Serial.println(totalSpace);

	// freeSpace : totalSpace = x : 360

	freeSpacePieData(freeSpace, totalSpace);

	if (ftpOperation == FTP_CONNECT) connectedDisconnected(true);
	if (ftpOperation == FTP_DISCONNECT) connectedDisconnected(false);
};
void _transferCallback(FtpTransferOperation ftpOperation, const char* name, unsigned int transferredSize){
	Serial.print(">>>>>>>>>>>>>>> _transferCallback " );
	Serial.print(ftpOperation);
	/* FTP_UPLOAD_START = 0,
	 * FTP_UPLOAD = 1,
	 *
	 * FTP_DOWNLOAD_START = 2,
	 * FTP_DOWNLOAD = 3,
	 *
	 * FTP_TRANSFER_STOP = 4,
	 * FTP_DOWNLOAD_STOP = 4,
	 * FTP_UPLOAD_STOP = 4,
	 *
	 * FTP_TRANSFER_ERROR = 5,
	 * FTP_DOWNLOAD_ERROR = 5,
	 * FTP_UPLOAD_ERROR = 5
	 */
	Serial.print(" ");
	Serial.print(name);
	Serial.print(" ");
	Serial.println(transferredSize);

	(ftpOperation==FTP_UPLOAD || ftpOperation==FTP_DOWNLOAD)?transfer(true, ftpOperation==FTP_UPLOAD):transfer(false, false);

	fileTransfer(ftpOperation, name, transferredSize);
};


void setup()
{
	ftpSrv.setCallback(_callback);
	ftpSrv.setTransferCallback(_transferCallback);

	Serial.begin(115200);
    delay(1000);

    tft.init();

    tft.begin();

    tft.setRotation(3);

    tft.fillScreen(TFT_BLACK);

	tft.setCursor(0, 0);

    tft.setTextColor(TFT_BLACK, TFT_WHITE);  tft.setTextSize(2);

    tft.fillRoundRect(3, 3, 320-6, 40, 5, TFT_WHITE);

    tft.drawCentreString("www.mischianti.org", 160, 14,1);
    tft.setTextColor(TFT_WHITE, TFT_BLACK);


	freeSpacePieData(0, 0);
	connectedDisconnected(false);
	transfer(false, false);

	wifiStrenght(0, true);

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.print(ssid);

    WiFi.mode(WIFI_STA);


    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED)
    {
        Serial.print(".");
        WiFi.begin(ssid, password);
        Serial.print(".");
        tft.print(F("."));
        delay(500);
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());

    wifiStrenght(WiFi.RSSI());

    delay(1000);

    if (!sd.begin(SD_CONFIG)) {
      sd.initErrorHalt(&Serial);
    }
    FsFile dir;
    FsFile file;

    // Open root directory
    if (!dir.open("/")){
      Serial.println("dir.open failed");
    }

	ftpSrv.begin("wioterminal","wioterminal");    //username, password for ftp.

}

void loop() {
    ftpSrv.handleFTP();        //make sure in loop you call handleFTP()!!
}


// #########################################################################
// Draw circle segments
// #########################################################################

// x,y == coords of centre of circle
// start_angle = 0 - 359
// sub_angle   = 0 - 360 = subtended angle
// r = radius
// colour = 16 bit colour value

int fillSegment(int x, int y, int start_angle, int sub_angle, int r, unsigned int colour) {
    // Calculate first pair of coordinates for segment start
    float sx = cos((start_angle - 90) * DEG2RAD);
    float sy = sin((start_angle - 90) * DEG2RAD);
    uint16_t x1 = sx * r + x;
    uint16_t y1 = sy * r + y;

    // Draw colour blocks every inc degrees
    for (int i = start_angle; i < start_angle + sub_angle; i++) {

        // Calculate pair of coordinates for segment end
        int x2 = cos((i + 1 - 90) * DEG2RAD) * r + x;
        int y2 = sin((i + 1 - 90) * DEG2RAD) * r + y;

        tft.fillTriangle(x1, y1, x2, y2, x, y, colour);

        // Copy segment end to sgement start for next segment
        x1 = x2;
        y1 = y2;
    }
}


// #########################################################################
// Return the 16 bit colour with brightness 0-100%
// #########################################################################
unsigned int brightness(unsigned int colour, int brightness) {
    byte red   = colour >> 11;
    byte green = (colour & 0x7E0) >> 5;
    byte blue  = colour & 0x1F;

    blue = (blue * brightness) / 100;
    green = (green * brightness) / 100;
    red = (red * brightness) / 100;

    return (red << 11) + (green << 5) + blue;
}

You can find the example also in the library.

Configure client

This library support only passive mode and you must force only one connection at time.

I use FileZilla as client, you can download It here, It quite simple to use and configure.

Filezilla configuration for access esp8266, select plain FTP on Manage Site

First you must go on Manage site --> New site and now set this parameter:

  • Select FTP as protocol;
  • Select Use plain FTP (insecure);
  • Set you login and password (you choice that in sketch);
  • Than on Trasfer settings select Maximun number of connection equal 1;
  • Now connect to your device.
Filezilla configuration for access esp8266, select max num connections

If you want to transfer big file, you must extend timeout time.

Thanks

  1. SimpleFTPServer library: esp32 and esp8266 how to
  2. SimpleFTPServer library: WioTerminal how to
  3. FTP server on STM32 with w5500, enc28j60, SD Card, and SPI Flash

Spread the love

16 Responses

  1. JanKoder says:

    Dear Renzo,

    Thank you for your efforts in creating this great library and for making it available to the world!

    I would like to integrate your FTP Server library into an ESP32 project that is programmed using the Arduino Framework.
    The ESP32 device’s onboard flash is formatted as a FAT partition which I’m accessing using the FFat.h library.
    It is not entirely clear to me how I can connect the FTP server’s file access methods to this FAT partition. Could you point me in the right direction?

    Many thanks!

    Jan

    • Hi Jan,
      now for ESP32 native filesystem I only add SPIFFS.
      I’m going to add It in the next few days.

      Bye Renzo

    • Hi Jan,
      I add support for ESP32 LITTLEFS and FFAT.

      For FFAT you must go to FtpServerKey.h file and set this configuration for ESP32

      #ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP32
      	#define DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP32 	NETWORK_ESP32
      	#define DEFAULT_STORAGE_TYPE_ESP32 STORAGE_FFAT
      #endif
      

      Than in the ino file begin the filesystem and start the ftp server

        	  Serial.println(F("Inizializing FS..."));
            if (FFat.begin(true)){
                Serial.println(F("done."));
            }else{
                Serial.println(F("fail."));
            }
      
            ftpSrv.setCallback(_callback);
      	  ftpSrv.setTransferCallback(_transferCallback);
      
            ftpSrv.begin("esp32","esp32");    //username, password for ftp.   (default 21, 50009 for PASV)
      

      Give me a feedback Bye Renzo

  2. Jan says:

    Hi Renzo,

    Sorry for my late response! I was expecting to receive a notification email when you posted a reply, but that didn’t come so I just saw your replies today when I came back to your blog. My mistake!

    Anyway, I downloaded the updated version and made adjustments as you suggested. Everything looks fine (Fat is accessible, FTP server is running) right up to the point where it is expecting the password: then the FTP server returns a “530” response.

    These are the log’s from the FileZilla client and the output from the serial console:

    [=== Serial output ===]
    >>>>>>>>>>>>>>> _callback 0 802816 1454080
    CONNECTED
    >>>>>>>>>>>>>>> _callback 1 802816 1454080
    DISCONNECTED
    >>>>>>>>>>>>>>> _callback 0 802816 1454080
    CONNECTED
    >>>>>>>>>>>>>>> _callback 1 802816 1454080
    DISCONNECTED
    
    [=== Filezilla log ===]
    Status: Connecting to 192.168.250.108:21…
    Status: Connection established, waiting for welcome message…
    Status: Plain FTP is insecure. Please switch to FTP over TLS.
    Command: USER ftp
    Response: 530
    Error: Could not connect to server
    Status: Waiting to retry…
    Status: Connecting to 192.168.250.108:21…
    Status: Connection established, waiting for welcome message…
    Response: 220— Welcome to FTP for Arduino —
    Response: 220— By Renzo Mischianti —
    Response: 220 — Version 2021-06-13 —
    Status: Plain FTP is insecure. Please switch to FTP over TLS.
    Command: USER ftp
    Response: 530
    Error: Could not connect to server
    [=== end ===]
    

    I hope you can help me out here!

    Again, thank you for your great work and amazing support!

    Bye, Jan

  3. Jan says:

    Hi Renzo,

    I found the cause of the “530” response:

    After changing my code from:

      #define FTP_USER "ftp"
      #define FTP_PASSWORD "ftp"
      ftpSrv.begin(FTP_USER, FTP_PASSWORD);
      ...
    

    to:

      ftpSrv.begin("ftp", "ftp");   
    

    the 530-response was no longer thrown and everything works like a charm!

    Once I noticed the declaration of the ftp login as “char user[ FTP_CRED_SIZE ]” in your code things got clear to me. I hope I didn’t waste too much of your time…

    THANKS!

    Br, Jan

  4. Daniel says:

    Hi Renzo,
    Tryed to port the library to a SamD21 with W5500 and SD card.
    But ran into a lot of Macro expansion issues.
    So i guess that i’m not doing a config right. But have a hard time setting up FTPserverKey config to set it up for another processor and get the correct setup to run / compile FtpServer

    Regards, Daniel

    • Hi Daniel,
      teolically SAMD21 and w5xxx already supported (but not tested).
      Try with this configuration

      #ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_ARDUINO_SAMD
      	#define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_W5100 
      	#define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SD
      #endif
      

      But remember for now w5xxx devices do not support SSL, exist a branch on GitHub that try to add that support.

      Bye Renzo

  5. Pierre-Yves says:

    Hello Renzo,
    I have installed your SimpleFTPServer library on an ESP32.
    At the beginning I got 530 Timeout because I have an e-Paper display that I have to update. But now when I stop display updating after a FTP client connection it’s run well. Except that FileZilla doesn’t show the files in / directory. These files are there, the sketch shows them in the monitor. Which default directory your FTP server should shows?
    Regards

  6. DR-DNK says:

    Hey Renzo !!!,
    I am using SEEED SAMD Board v1.8.5 (Seeeduino wio terminal ) and I want to run example code from Arduino IDE(Wio_Terminal_SdFat) SimpleFTPServer . But I am not able to compile it .
    My library version for SimpleFTPServer is v2.1.6 .
    Below are the errors that I am enocuntering with other File related ones.

    error: ‘Sd2Card’ does not name a type; did you mean ‘SdCard’?
    Sd2Card card;

    error: ‘SdVolume’ does not name a type; did you mean ‘FsVolume’?
    SdVolume volume;

    Please help me to run the SimpleFTPServer example code of Arduino on Wio Terminal .

    • Hi DR-DNK,
      I try to build the TFT example, and standard SD library example and It’s work correctly without errors.

      Check the FTP key configuration and retry.

      Bye Renzo

  7. DR-DNK says:

    Hey Renzo ,
    I am using the configurations listed above for FtpServerKey file .

    // wio terminal
    #define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_SEEED_RTL8720DN
    #define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SEEED_SD

    And I also performed the fresh installation of Arduino IDE with above listed libraries .
    Still my code is not able to compile .

  8. Gianfranco Ricci says:

    Ciao Renzo, sto provando ad usre il tuo server FTP su Wio Terminal.
    Ho impostato FileZilla come da tue indicazioni ma ottengo sempre questa risposta e non riesco a trasferire nulla:

    Stato: Connessione a 192.168.0.193:21…
    Stato: Connessione stabilita, in attesa del messaggio di benvenuto…
    Stato: L’FTP in chiaro non è sicuro. Passa a FTP su TLS.
    Stato: Il server non supporta caratteri non ASCII.
    Stato: Accesso effettuato
    Stato: Lettura elenco cartelle…
    Comando: PWD
    Risposta: 221 Goodbye
    Errore: Impossibile analizzare il percorso ritornato.
    Errore: Non è stato possibile leggere il contenuto della cartella
    Stato: Connessione chiusa dal server
    Puoi aiutarmi a capire casa è che non va?
    Grazie

    • Ciao Gianfranco,
      hai impostato correttamente il file FtpServerKey.h?
      Ciao Renzo

      • Gianfranco Ricci says:

        Ciao Renzo,
        Si come da te indicato ho cambiato così le seguenti stringhe;

        // Arduino SAMD21 like Arduino MKR Nano 33 IoT or Wio Terminal
        #ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_ARDUINO_SAMD
        // Wio Terminal
        #define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_SEEED_RTL8720DN
        #define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SEEED_SD

        // Arduino SAMD
        // #define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_WiFiNINA
        // #define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SD
        #endif

        e nella intestazione del file ino di esempio TFT_monitor ho cambiato con:

        #include
        #include “SD/Seeed_SD.h”

Leave a Reply

Your email address will not be published. Required fields are marked *