Site icon Renzo Mischianti

Libreria Simple FTP Server ora con supporto a WioTerminal con SD

Wio Terminal Server FTP Server con monitor dello stato su display TFT

Wio Terminal Server FTP Server con monitor dello stato su display TFT

Spread the love

Ho ricevuto questo dispositivo da SeeedStudio e lo trovo molto utile. La prima cosa che ho pensato di fare con questo dispositivo è stato il porting della mia libreria SimpleFTPServer .

Wio Terminal FTP Server with TFT monitor main

Spero che tu voglia leggere l’articolo introduttivo su questo dispositivo qui “Wio Terminal: pinout, specifiche e configurazioni Arduino IDE“.

Wio Terminal

Wio Terminal è un sistema completo, rispetto a una normale scheda di sviluppo è dotata di schermo + scheda di sviluppo + interfaccia di input/output + contenitore, che lo rende un prodotto efficiente e pronto per il prodotto finale.

Puoi trovare il dispositivo su SeeedStudio Aliexpress

Wio Terminal pinout mischianti low resolution

Link to high resolution pinout image

Libreria

Puoi trovare la libreria qui su GitHub. Non l’ho integrato ancora sul gestore delle librerie dell’IDE di Arduino, ma penso che lo farò presto.

Ho già scritto qualcosa a riguardo in questo articolo “Server FTP su esp8266 ed esp32” per l’integrazione dell’esp32 e esp8266.

Fare clic sul pulsante DOWNLOAD nell’angolo in alto a destra, rinominare la cartella non compressa SimpleFTPServer.

Verificare che SimpleFTPServer contenga FtpServer.cpp, FtpServer.h, FtpServerKey.he SimpleFTPServer.h .

Posiziona la cartella della libreria SimpleFTPServer nella tua cartella /libraries/.

Potrebbe essere necessario creare la sottocartella delle librerie se è la tua prima libreria.

Riavvia l’IDE.

È necessario impostare l’ambiente corretto modificando le righe nel file FtpServerKey.h.

#define DEFAULT_FTP_SERVER_NETWORK_TYPE_SAMD NETWORK_SEEED_RTL8720DN
#define DEFAULT_STORAGE_TYPE_SAMD STORAGE_SDFAT2

Come puoi vedere non uso la libreria Seeed per gestire l’SD perché esiste un bug irrisolto che genera molti problemi di scope.

Ma con questa configurazione, e l’uso della libreria SdFat, funziona correttamente.

How to

Creare un server FTP minimo

Dopo aver scaricato correttamente la libreria puoi create un semplice server FTP con poche righe di codice.

Devi importare tutte queste librerie:

Qui lo sketch completo.

/*
 * 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()!!
  }

Ora puoi connetterti al terminale via FTP, verifica la configurazione del client FTP nel relativo capitolo.

Qui l’output seriale.

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

Aggiungere una callback di stato al tuo Server FTP

La libreria offre la possibilità di aggiungere qualche callback per verificare lo stato della connessione o del trasferimento.

Le firme delle funzioni sono:

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

Callback principale

La prima callback viene richiamata quando viene eseguita una di queste operazioni:

Gli altri parametri sono:

Callback di trasferimento

La seconda quando vengono eseguite queste operazioni:

Gli altri parametri sono:

Sketch di esempio con callback

Il codice con callback risultante può essere:

/*
 * 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()!!
  }

Qui l’output seriale:

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

Analizziamo l’output:

Aggiungere l’interfaccia grafica per monitorare il server FTP

Ora se vogliamo aggiungere alcune informazioni sul server FTP, possiamo utilizzare il display TFT del dispositivo.

Il codice diventa più complesso con la gestione del TFT, ma non è così difficile da leggere.

Stato di visualizzazione

All’inizio avrai questa schermata sul WioTerminal.

Wio Terminal FTP server WiFi connecting

In questa schermata puoi vedere che il terminale wio prova a connettersi al mio SSID reef-casa-sopra. Quindi quando il WiFi è connesso puoi vedere la potenza del segnale e lo spazio libero.

Wio Terminal FTP server WiFi connected and RSSI

Quindi con l’IP, che puoi vedere sullo schermo, puoi provare a connetterti con il tuo client FTP. Una volta connesso, il display cambia di nuovo.

Wio Terminal FTP server Client connected and free space

Ora puoi trasferire i tuoi files. Ora carico una piccola foto, e nella schermata appare lo stato di trasferimento Upload (e la dimensione trasferita che cambia costantemente).

Wio Terminal FTP server upload a file

Quando il trasferimento è andato a buon fine, puoi controllare lo stato cambiato in OK sullo schermo.

Wio Terminal FTP server upload completed successfully

Sketch con server completo e visualizzazione dello stato

Qui lo sketch completo.

/*
 * 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;
}

Potete trovare l’esempio anche sulla libreria.

Configurazione del client FTP

Questa libreria supporta solo la modalità passiva ed è necessario forzare una sola connessione alla volta.

Uso FileZilla come client, puoi scaricarlo qui, è abbastanza semplice sia da usare che configurare.

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

Per prima cosa devi andare su Manage site --> New site e ora imposta questo parametro:

Filezilla configuration for access esp8266, select max num connections

Se vuoi trasferire file di grandi dimensioni, devi estendere il tempo di timeout.

Grazie

  1. Libreria SimpleFTPServer library: guida esp32 e esp8266
  2. Libreria SimpleFTPServer: guida WioTerminal
  3. Server FTP su STM32 con W5500, ENC28J60, scheda SD e memoria flash SPI

Spread the love
Exit mobile version