Compare commits
7 Commits
4a1fc5b712
...
66fdc24a3e
Author | SHA1 | Date | |
---|---|---|---|
|
66fdc24a3e | ||
|
5a75603f6e | ||
|
e699b89faf | ||
|
36f87a27a8 | ||
|
34769ac251 | ||
|
28103022cd | ||
|
f7fc5abad5 |
@ -12,6 +12,7 @@ _fileRecvBytes(0),
|
|||||||
_waitingForDataConnection(false),
|
_waitingForDataConnection(false),
|
||||||
_fileIsBeeingReceived(false),
|
_fileIsBeeingReceived(false),
|
||||||
_actionTimeout(0),
|
_actionTimeout(0),
|
||||||
|
_dataClientConnected(false),
|
||||||
_ftpClientState(FTPServer<FTPClient>::FTPClientState::INIT),
|
_ftpClientState(FTPServer<FTPClient>::FTPClientState::INIT),
|
||||||
_binaryFlag(FTPServer<FTPClient>::BinaryFlag::OFF),
|
_binaryFlag(FTPServer<FTPClient>::BinaryFlag::OFF),
|
||||||
_dataTransferPending(FTPServer<FTPClient>::FTPClientDataTransfer::NONE)
|
_dataTransferPending(FTPServer<FTPClient>::FTPClientDataTransfer::NONE)
|
||||||
@ -30,6 +31,7 @@ FTPClient::~FTPClient()
|
|||||||
|
|
||||||
void FTPClient::setDataClient(WiFiClient dataClient)
|
void FTPClient::setDataClient(WiFiClient dataClient)
|
||||||
{
|
{
|
||||||
|
_dataClientConnected = true;
|
||||||
_dataClient = dataClient;
|
_dataClient = dataClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,32 +43,42 @@ boolean FTPClient::parseCommandAndParameters()
|
|||||||
if(cr != NULL)
|
if(cr != NULL)
|
||||||
{
|
{
|
||||||
*cr = '\0';
|
*cr = '\0';
|
||||||
|
//Serial.println("got r");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cr = strchr((char *)_data,'\n');
|
cr = strchr((char *)_data,'\n');
|
||||||
if(cr != NULL)
|
if(cr != NULL)
|
||||||
|
{
|
||||||
*cr = '\0';
|
*cr = '\0';
|
||||||
|
//Serial.println("got n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Serial.printf("Data : #%s#\n", (char *)_data);
|
||||||
char *cmdDelimiter = strchr((char *)_data,' ');
|
char *cmdDelimiter = strchr((char *)_data,' ');
|
||||||
|
|
||||||
if(cmdDelimiter == NULL) //It means that we do not have any parameters
|
if(cmdDelimiter == NULL) //It means that we do not have any parameters
|
||||||
{
|
{
|
||||||
cmdDelimiter = (char *)_data + strlen((char *)_data) - 1;
|
uint16_t dataSize = strlen((char *)_data);
|
||||||
strcpy(_ftpCommand, (char *)_data);
|
cmdDelimiter = (char *)_data + dataSize - 1;
|
||||||
|
strncpy(_ftpCommand, (char *)_data, dataSize <= 4 ? dataSize : 4);
|
||||||
|
_ftpCommand[dataSize <= 4 ? dataSize : 4] = '\0';
|
||||||
|
//Serial.printf("Got no space : size %d\n", dataSize);
|
||||||
}
|
}
|
||||||
else //we do
|
else //we do
|
||||||
{
|
{
|
||||||
strncpy(_ftpCommand, (char *)_data, cmdDelimiter - (char *)_data);
|
uint16_t dataSize = cmdDelimiter - (char *)_data;
|
||||||
_ftpCommand[cmdDelimiter - (char *)_data] = '\0'; // /!\ strncpy does not append the terminating string character
|
|
||||||
|
strncpy(_ftpCommand, (char *)_data, dataSize <= 4 ? dataSize : 4);
|
||||||
|
_ftpCommand[dataSize <= 4 ? dataSize : 4] = '\0'; // /!\ strncpy does not append the terminating string character
|
||||||
|
//Serial.printf("Got a space : size %d\n", dataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
//We get the parameters :
|
//We get the parameters :
|
||||||
DictionaryHelper::StringEntity params(cmdDelimiter+1); //+1 to skip the first space
|
DictionaryHelper::StringEntity params(cmdDelimiter+1); //+1 to skip the first space
|
||||||
delete _cmdParameters;
|
delete _cmdParameters;
|
||||||
_cmdParameters = params.split(' ');
|
_cmdParameters = params.split(' ');
|
||||||
|
|
||||||
//At the end, we flush the buffer:
|
//At the end, we flush the buffer:
|
||||||
freeDataBuffer(_dataSize);
|
freeDataBuffer(_dataSize);
|
||||||
|
|
||||||
@ -103,6 +115,12 @@ void FTPClient::setCurrentFile(const char *file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FTPClient::closeDataConnection()
|
||||||
|
{
|
||||||
|
_dataClientConnected = false;
|
||||||
|
_dataClient.stop();
|
||||||
|
}
|
||||||
|
|
||||||
void FTPClient::startTimeout()
|
void FTPClient::startTimeout()
|
||||||
{
|
{
|
||||||
_actionTimeout = millis();
|
_actionTimeout = millis();
|
||||||
|
@ -21,6 +21,7 @@ class FTPClient : public TCPClient
|
|||||||
void setCurrentDirectory(const char *dir);
|
void setCurrentDirectory(const char *dir);
|
||||||
void setCurrentFile(const char *file);
|
void setCurrentFile(const char *file);
|
||||||
void startTimeout();
|
void startTimeout();
|
||||||
|
void closeDataConnection();
|
||||||
|
|
||||||
char _ftpCommand[5];
|
char _ftpCommand[5];
|
||||||
Dictionary<DictionaryHelper::StringEntity> *_cmdParameters;
|
Dictionary<DictionaryHelper::StringEntity> *_cmdParameters;
|
||||||
@ -33,6 +34,7 @@ class FTPClient : public TCPClient
|
|||||||
boolean _waitingForDataConnection;
|
boolean _waitingForDataConnection;
|
||||||
boolean _fileIsBeeingReceived;
|
boolean _fileIsBeeingReceived;
|
||||||
uint64_t _actionTimeout;
|
uint64_t _actionTimeout;
|
||||||
|
boolean _dataClientConnected;
|
||||||
|
|
||||||
FTPServer<FTPClient>::FTPClientState _ftpClientState;
|
FTPServer<FTPClient>::FTPClientState _ftpClientState;
|
||||||
FTPServer<FTPClient>::BinaryFlag _binaryFlag;
|
FTPServer<FTPClient>::BinaryFlag _binaryFlag;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include "SDCardManager.h"
|
#include "SDCardManager.h"
|
||||||
#include "definition.h"
|
#include "definition.h"
|
||||||
#include "Dictionary.h"
|
#include "Dictionary.h"
|
||||||
#define DEBUG_FTPS
|
//#define DEBUG_FTPS
|
||||||
#define READ_BUFFER_SIZE 2500 //2500 is max to read sd card, more will crash
|
#define READ_BUFFER_SIZE 2500 //2500 is max to read sd card, more will crash
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -13,9 +13,10 @@ class FTPServer : public TCPServer<T>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum FTPClientState {INIT, WAITING_FOR_COMMANDS};
|
enum FTPClientState {INIT, WAITING_FOR_COMMANDS};
|
||||||
enum FTPClientDataTransfer {NONE, LIST_DF, NLST_DF, RETR_DF, STOR_DF};
|
enum FTPClientDataTransfer {NONE = 0, LIST_DF, NLST_DF, RETR_DF, STOR_DF, APPE_DF};
|
||||||
enum FileTransferStatus {OK, NOT_FOUND, NO_FILE_NAME};
|
enum FileTransferStatus {OK, NOT_FOUND, NO_FILE_NAME};
|
||||||
enum BinaryFlag {OFF = 0, ON};
|
enum BinaryFlag {OFF = 0, ON};
|
||||||
|
enum FtpMsgCode {_150, _200, _215, _220, _221, _230, _226, _227, _250, _257, _331, _350, _451, _5_502, _504, _530, _550 };
|
||||||
|
|
||||||
FTPServer(unsigned int port = 21, SDCardManager *sdCardManager = NULL, const char *login = NULL, const char *password = NULL, uint8_t maxClient = MAX_CLIENT, uint16_t clientCommandDataBufferSize = 255) : TCPServer<T>(port, maxClient, clientCommandDataBufferSize),
|
FTPServer(unsigned int port = 21, SDCardManager *sdCardManager = NULL, const char *login = NULL, const char *password = NULL, uint8_t maxClient = MAX_CLIENT, uint16_t clientCommandDataBufferSize = 255) : TCPServer<T>(port, maxClient, clientCommandDataBufferSize),
|
||||||
_login(NULL),
|
_login(NULL),
|
||||||
@ -41,7 +42,6 @@ class FTPServer : public TCPServer<T>
|
|||||||
strcpy(_password, password);
|
strcpy(_password, password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_dataServer.begin(_dataPort);
|
_dataServer.begin(_dataPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,17 +68,20 @@ class FTPServer : public TCPServer<T>
|
|||||||
client->_clientState = TCPClient::HANDLED;
|
client->_clientState = TCPClient::HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void processClientData(T *client)
|
ICACHE_RAM_ATTR virtual void processClientData(T *client)
|
||||||
{
|
{
|
||||||
if (client->_waitingForDataConnection)
|
/*if (client->_waitingForDataConnection)
|
||||||
{
|
{
|
||||||
//#ifdef DEBUG_FTPS
|
//#ifdef DEBUG_FTPS
|
||||||
//Serial.println("Listening for new data client");
|
//Serial.println("Listening for new data client");
|
||||||
//#endif
|
//#endif
|
||||||
WiFiClient dataClient = _dataServer.available();
|
WiFiClient dataClient = _dataServer.available();
|
||||||
|
|
||||||
if (dataClient)
|
if(dataClient)
|
||||||
{
|
{
|
||||||
|
#ifdef DEBUG_FTPS
|
||||||
|
Serial.println("Data client returns true");
|
||||||
|
#endif
|
||||||
if (dataClient.connected())
|
if (dataClient.connected())
|
||||||
{
|
{
|
||||||
client->_waitingForDataConnection = false;
|
client->_waitingForDataConnection = false;
|
||||||
@ -90,72 +93,68 @@ class FTPServer : public TCPServer<T>
|
|||||||
else
|
else
|
||||||
dataClient.stop();
|
dataClient.stop();
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
switch(client->_dataTransferPending)
|
switch(client->_dataTransferPending)
|
||||||
{
|
{
|
||||||
case LIST_DF: //We list the files of the current directory
|
case LIST_DF:
|
||||||
//We check if the dataConnection is established:
|
if (client->_dataClient.connected())
|
||||||
if (client->_dataClient.connected())
|
|
||||||
{
|
|
||||||
client->_client.println("150 File status okay;");
|
|
||||||
if(sendFSTree(client))
|
|
||||||
{
|
{
|
||||||
client->_client.println("226 Closing data connection.");
|
#ifdef DEBUG_FTPS
|
||||||
|
Serial.println("Listing started");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
client->_client.println("150 File status okay.");
|
||||||
|
if(sendFSTree(client))
|
||||||
|
{
|
||||||
|
client->_client.println("226 Closing data connection.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
client->_client.println("451 Requested action aborted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
client->closeDataConnection();
|
||||||
|
client->_dataTransferPending = NONE;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
client->_client.println("451 Requested action aborted.");
|
|
||||||
}
|
|
||||||
|
|
||||||
client->_dataClient.stop();
|
|
||||||
client->_dataTransferPending = NONE;
|
|
||||||
}
|
|
||||||
//A timeout should be added
|
|
||||||
/*else
|
|
||||||
{
|
|
||||||
client->_client.println("425 Can't open data connection.");
|
|
||||||
}*/
|
|
||||||
break;
|
break;
|
||||||
case RETR_DF:
|
case RETR_DF:
|
||||||
if (client->_dataClient.connected())
|
if (client->_dataClient.connected())
|
||||||
{
|
{
|
||||||
if(client->_fileSentBytes == 0)
|
if(client->_fileSentBytes == 0)
|
||||||
client->_client.println("150 File status okay;");
|
client->_client.println("150 File status okay.");
|
||||||
|
|
||||||
FileTransferStatus fts;
|
FileTransferStatus fts;
|
||||||
if(!sendFile(client,&fts))//File was sent or error occured
|
if(!sendFile(client,&fts))//File was sent or error occured
|
||||||
{
|
{
|
||||||
//we check the return code
|
//we check the return code
|
||||||
switch(fts)
|
if(fts == OK)
|
||||||
{
|
{
|
||||||
case OK:
|
client->_client.println("226 Closing data connection.");
|
||||||
client->_client.println("226 Closing data connection.");
|
client->closeDataConnection();
|
||||||
client->_dataClient.stop();
|
client->_dataTransferPending = NONE;
|
||||||
client->_dataTransferPending = NONE;
|
}
|
||||||
break;
|
else if(fts == NOT_FOUND)
|
||||||
case NOT_FOUND:
|
{
|
||||||
client->_client.println("451 File not found.");
|
client->_client.println("451 File not found.");
|
||||||
client->_dataClient.stop();
|
client->closeDataConnection();
|
||||||
client->_dataTransferPending = NONE;
|
client->_dataTransferPending = NONE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//A timeout should be added
|
else if(client->_fileSentBytes != 0)
|
||||||
/*else
|
{
|
||||||
|
client->_client.println("426 Connection closed; transfer aborted.");
|
||||||
|
client->closeDataConnection();
|
||||||
|
client->_dataTransferPending = NONE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STOR_DF:
|
||||||
|
if (client->_dataClient.connected() || client->_dataClient.available())//Here we need to check if client has some data available for reading. IMPORTANT
|
||||||
{
|
{
|
||||||
client->_client.println("425 Can't open data connection.");
|
|
||||||
}*/
|
|
||||||
break;
|
|
||||||
case STOR_DF :
|
|
||||||
if (client->_dataClient.connected() || client->_dataClient.available())
|
|
||||||
{
|
|
||||||
if(client->_dataClient.connected())
|
|
||||||
client->_fileIsBeeingReceived = true;
|
|
||||||
|
|
||||||
if(client->_dataClient.available())
|
if(client->_dataClient.available())
|
||||||
{
|
{
|
||||||
|
client->_fileIsBeeingReceived = true;
|
||||||
#ifdef DEBUG_FTPS
|
#ifdef DEBUG_FTPS
|
||||||
Serial.printf("receiving file %s\n", client->_currentFile);
|
Serial.printf("receiving file %s\n", client->_currentFile);
|
||||||
#endif
|
#endif
|
||||||
@ -171,18 +170,19 @@ class FTPServer : public TCPServer<T>
|
|||||||
{
|
{
|
||||||
client->_client.println("451 Requested action aborted: local error in processing.");
|
client->_client.println("451 Requested action aborted: local error in processing.");
|
||||||
}
|
}
|
||||||
client->_dataClient.stop();
|
client->closeDataConnection();
|
||||||
client->_fileIsBeeingReceived = false;
|
client->_fileIsBeeingReceived = false;
|
||||||
client->_dataTransferPending = NONE;
|
client->_dataTransferPending = NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(client->_fileIsBeeingReceived)
|
//If no data connection exists and no error was raised during writting, then it could be just a file creation with no data connection opened
|
||||||
|
else if(client->_fileIsBeeingReceived || (client->_dataClientConnected || millis() - client->_actionTimeout > 5000))
|
||||||
{
|
{
|
||||||
if(client->_fileRecvBytes == 0) //File was just created empty
|
if(client->_fileRecvBytes == 0) //File was just created empty
|
||||||
{
|
{
|
||||||
if(_sdCardManager->exists(client->_currentFile))
|
if(_sdCardManager->exists(client->_currentFile))
|
||||||
_sdCardManager->remove(client->_currentFile);
|
_sdCardManager->remove(client->_currentFile);
|
||||||
|
|
||||||
File file2create = _sdCardManager->open(client->_currentFile, FILE_WRITE);
|
File file2create = _sdCardManager->open(client->_currentFile, FILE_WRITE);
|
||||||
|
|
||||||
@ -201,13 +201,55 @@ class FTPServer : public TCPServer<T>
|
|||||||
client->_client.println("226 Closing data connection.");
|
client->_client.println("226 Closing data connection.");
|
||||||
|
|
||||||
client->_fileIsBeeingReceived = false;
|
client->_fileIsBeeingReceived = false;
|
||||||
client->_dataClient.stop();
|
client->closeDataConnection();
|
||||||
client->_dataTransferPending = NONE;
|
client->_dataTransferPending = NONE;
|
||||||
client->_fileRecvBytes = 0;
|
client->_fileRecvBytes = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case APPE_DF:
|
||||||
|
if (client->_dataClient.connected() || client->_dataClient.available())//Here we need to check if client has some data for reading. IMPORTANT
|
||||||
|
{
|
||||||
|
if(client->_dataClient.available())
|
||||||
|
{
|
||||||
|
client->_fileIsBeeingReceived = true;
|
||||||
|
#ifdef DEBUG_FTPS
|
||||||
|
Serial.printf("appending to file %s\n", client->_currentFile);
|
||||||
|
#endif
|
||||||
|
FileTransferStatus fts = OK;
|
||||||
|
|
||||||
|
if(!writeToSdCard(client, &fts, true)) //An error occured
|
||||||
|
{
|
||||||
|
if(fts == NO_FILE_NAME)
|
||||||
|
{
|
||||||
|
client->_client.println("501 No file name given.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
client->_client.println("451 Requested action aborted: local error in processing.");
|
||||||
|
}
|
||||||
|
client->closeDataConnection();
|
||||||
|
client->_fileIsBeeingReceived = false;
|
||||||
|
client->_dataTransferPending = NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//If the connection is closed and data has been received, then we got the whole file
|
||||||
|
else if(client->_fileIsBeeingReceived)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_FTPS
|
||||||
|
Serial.println("Whole file received");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
client->_client.println("226 Closing data connection.");
|
||||||
|
|
||||||
|
client->_fileIsBeeingReceived = false;
|
||||||
|
client->closeDataConnection();
|
||||||
|
client->_dataTransferPending = NONE;
|
||||||
|
client->_fileRecvBytes = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_FTPS
|
#ifdef DEBUG_FTPS
|
||||||
if (client->_newDataAvailable)
|
if (client->_newDataAvailable)
|
||||||
{
|
{
|
||||||
@ -215,17 +257,17 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (client->_dataSize > 0)
|
if(client->_dataSize > 0)
|
||||||
{
|
{
|
||||||
switch (client->_ftpClientState)
|
switch (client->_ftpClientState)
|
||||||
{
|
{
|
||||||
|
case WAITING_FOR_COMMANDS:
|
||||||
|
processCommands(client);
|
||||||
|
break;
|
||||||
case INIT:
|
case INIT:
|
||||||
client->setCurrentDirectory(FTP_DIR);
|
client->setCurrentDirectory(FTP_DIR);
|
||||||
client->_ftpClientState = WAITING_FOR_COMMANDS;
|
client->_ftpClientState = WAITING_FOR_COMMANDS;
|
||||||
break;
|
break;
|
||||||
case WAITING_FOR_COMMANDS:
|
|
||||||
processCommands(client);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,7 +301,7 @@ class FTPServer : public TCPServer<T>
|
|||||||
client->setUsername(client->_cmdParameters->getAt(0)->getString());
|
client->setUsername(client->_cmdParameters->getAt(0)->getString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
client->_client.println("530 Username required.");
|
sendInfoResponse(_530, client);//client->_client.println("530 Username required.");
|
||||||
}
|
}
|
||||||
else //The ftp access is open
|
else //The ftp access is open
|
||||||
{
|
{
|
||||||
@ -279,35 +321,47 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->_client.println("530 Wrong username or password !.");
|
sendInfoResponse(_530, client, "Wrong username or password !");//client->_client.println("530 Wrong username or password !.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->_client.println("530 Password required.");
|
sendInfoResponse(_530, client,"");//client->_client.println("530 Password required.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(client->_ftpCommand, "PWD") == 0) //We set the default directory
|
else if (strcmp(client->_ftpCommand, "PWD") == 0) //We set the default directory
|
||||||
{
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
client->_client.printf("257 \"%s\"\r\n", client->_currentDirectory);
|
client->_client.printf("257 \"%s\"\r\n", client->_currentDirectory);
|
||||||
}
|
}
|
||||||
else if (strcmp(client->_ftpCommand, "TYPE") == 0)
|
else if (strcmp(client->_ftpCommand, "TYPE") == 0)
|
||||||
{
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->_cmdParameters->count() > 0)
|
if (client->_cmdParameters->count() > 0)
|
||||||
{
|
{
|
||||||
switch (client->_cmdParameters->getAt(0)->getString()[0])
|
switch (client->_cmdParameters->getAt(0)->getString()[0])
|
||||||
{
|
{
|
||||||
case 'I':
|
case 'I':
|
||||||
client->_binaryFlag = ON;
|
client->_binaryFlag = ON;
|
||||||
client->_client.println("200 Command okay.");
|
sendInfoResponse(_200, client,"");//client->_client.println("200 Command okay.");
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
client->_binaryFlag = ON;
|
client->_binaryFlag = ON;
|
||||||
client->_client.println("200 Command okay.");
|
sendInfoResponse(_200, client,"");//client->_client.println("200 Command okay.");
|
||||||
break;
|
break;
|
||||||
case 'A':
|
case 'A':
|
||||||
client->_binaryFlag = OFF;
|
client->_binaryFlag = OFF;
|
||||||
client->_client.println("200 Command okay.");
|
sendInfoResponse(_200, client,"");//client->_client.println("200 Command okay.");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
client->_client.println("504 Command not implemented for TYPE.");
|
client->_client.println("504 Command not implemented for TYPE.");
|
||||||
@ -320,19 +374,80 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
else if (strcmp(client->_ftpCommand, "PASV") == 0)
|
else if (strcmp(client->_ftpCommand, "PASV") == 0)
|
||||||
{
|
{
|
||||||
client->_client.printf("227 Entering Passive Mode (%u,%u,%u,%u,%d,%d).\r\n", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3], _dataPort / 256, _dataPort % 256);
|
if(!client->_loggedIn)
|
||||||
client->_waitingForDataConnection = true;
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//We need to test if we are in softAP or STA to chose the right IP
|
||||||
|
uint8_t addr[4] = {0};
|
||||||
|
if(WiFi.status() == WL_CONNECTED)
|
||||||
|
{
|
||||||
|
addr[0] = WiFi.localIP()[0];
|
||||||
|
addr[1] = WiFi.localIP()[1];
|
||||||
|
addr[2] = WiFi.localIP()[2];
|
||||||
|
addr[3] = WiFi.localIP()[3];
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
addr[0] = WiFi.softAPIP()[0];
|
||||||
|
addr[1] = WiFi.softAPIP()[1];
|
||||||
|
addr[2] = WiFi.softAPIP()[2];
|
||||||
|
addr[3] = WiFi.softAPIP()[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
client->_client.printf("227 Entering Passive Mode (%u,%u,%u,%u,%d,%d).\r\n", addr[0], addr[1], addr[2], addr[3], _dataPort / 256, _dataPort % 256);
|
||||||
#ifdef DEBUG_FTPS
|
#ifdef DEBUG_FTPS
|
||||||
Serial.println("Opening data server for new data client");
|
Serial.println("Opening data server for new data client");
|
||||||
#endif
|
#endif
|
||||||
|
//We listen for 100 ms directly to accept the client
|
||||||
|
uint64_t timeOut(millis());
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
WiFiClient dataClient = _dataServer.available();
|
||||||
|
//Serial.printf("Client state : %d\n", dataClient.status());
|
||||||
|
if (dataClient)
|
||||||
|
{
|
||||||
|
//Serial.printf("Data client is true , available : %d\n", dataClient.available());
|
||||||
|
if (dataClient.connected())//Connected returns true if the status() is ESTABLISHED or available() returns true
|
||||||
|
{
|
||||||
|
client->setDataClient(dataClient);
|
||||||
|
#ifdef DEBUG_FTPS
|
||||||
|
Serial.println("Data client accepted from loop");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dataClient.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(millis() - timeOut > 100)
|
||||||
|
{
|
||||||
|
client->_waitingForDataConnection = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(client->_ftpCommand, "LIST") == 0)
|
else if (strcmp(client->_ftpCommand, "LIST") == 0)
|
||||||
{
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//We inform that a data transfer is pending
|
//We inform that a data transfer is pending
|
||||||
client->_dataTransferPending = LIST_DF;
|
client->_dataTransferPending = LIST_DF;
|
||||||
}
|
}
|
||||||
else if (strcmp(client->_ftpCommand, "CWD") == 0)
|
else if (strcmp(client->_ftpCommand, "CWD") == 0)
|
||||||
{
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->_cmdParameters->count() > 0)
|
if (client->_cmdParameters->count() > 0)
|
||||||
{
|
{
|
||||||
//Go back one level
|
//Go back one level
|
||||||
@ -389,6 +504,12 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
else if(strcmp(client->_ftpCommand, "RETR") == 0)
|
else if(strcmp(client->_ftpCommand, "RETR") == 0)
|
||||||
{
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->_cmdParameters->count() > 0)
|
if (client->_cmdParameters->count() > 0)
|
||||||
{
|
{
|
||||||
//We save the file path to be sent
|
//We save the file path to be sent
|
||||||
@ -408,6 +529,12 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
else if(strcmp(client->_ftpCommand, "MKD") == 0)
|
else if(strcmp(client->_ftpCommand, "MKD") == 0)
|
||||||
{
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->_cmdParameters->count() > 0)
|
if (client->_cmdParameters->count() > 0)
|
||||||
{
|
{
|
||||||
char *dirNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
char *dirNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||||
@ -429,16 +556,22 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->_client.println("550 Requested action not taken.");
|
sendInfoResponse(_550, client,"");//client->_client.println("550 Requested action not taken.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->_client.println("550 Requested action not taken.");
|
sendInfoResponse(_550, client,"");//client->_client.println("550 Requested action not taken.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(strcmp(client->_ftpCommand, "RMD") == 0)
|
else if(strcmp(client->_ftpCommand, "RMD") == 0)
|
||||||
{
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->_cmdParameters->count() > 0)
|
if (client->_cmdParameters->count() > 0)
|
||||||
{
|
{
|
||||||
//We have the dir name, we need to append the current directory...
|
//We have the dir name, we need to append the current directory...
|
||||||
@ -454,27 +587,36 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->_client.println("550 Requested action not taken.");
|
sendInfoResponse(_550, client,"");//client->_client.println("550 Requested action not taken.");
|
||||||
}
|
}
|
||||||
|
|
||||||
free(dirNameWithPath);
|
free(dirNameWithPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->_client.println("550 Requested action not taken.");
|
sendInfoResponse(_550, client,"");//client->_client.println("550 Requested action not taken.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(strcmp(client->_ftpCommand, "STOR") == 0)
|
else if(strcmp(client->_ftpCommand, "STOR") == 0)
|
||||||
{
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->_cmdParameters->count() > 0)
|
if (client->_cmdParameters->count() > 0)
|
||||||
{
|
{
|
||||||
|
client->_client.printf_P(PSTR("150 File status okay; about to open data connection.\r\n"));
|
||||||
//We save the file path to be sent
|
//We save the file path to be sent
|
||||||
char *fileNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
char *fileNameWithPath(NULL);
|
||||||
|
|
||||||
client->_client.println("150 File status okay; about to open data connection.");
|
if(client->_cmdParameters->getAt(0)->getString()[0] == '/')
|
||||||
|
fileNameWithPath = constructFileNameWithPath("", client->_cmdParameters);
|
||||||
|
else
|
||||||
|
fileNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||||
|
|
||||||
client->setCurrentFile(fileNameWithPath);
|
client->setCurrentFile(fileNameWithPath);
|
||||||
|
|
||||||
#ifdef DEBUG_FTPS
|
#ifdef DEBUG_FTPS
|
||||||
Serial.printf("File to store : #%s#\n", client->_currentFile);
|
Serial.printf("File to store : #%s#\n", client->_currentFile);
|
||||||
#endif
|
#endif
|
||||||
@ -483,12 +625,39 @@ class FTPServer : public TCPServer<T>
|
|||||||
client->startTimeout();
|
client->startTimeout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(strcmp(client->_ftpCommand, "APPE") == 0)
|
||||||
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->_cmdParameters->count() > 0)
|
||||||
|
{
|
||||||
|
client->_client.printf_P(PSTR("150 File status okay; about to open data connection.\r\n"));
|
||||||
|
//We save the file path to be sent
|
||||||
|
char *fileNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||||
|
client->setCurrentFile(fileNameWithPath);
|
||||||
|
#ifdef DEBUG_FTPS
|
||||||
|
Serial.printf("File to append : #%s#\n", client->_currentFile);
|
||||||
|
#endif
|
||||||
|
free(fileNameWithPath);
|
||||||
|
client->_dataTransferPending = APPE_DF;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if(strcmp(client->_ftpCommand, "SYST") == 0)
|
else if(strcmp(client->_ftpCommand, "SYST") == 0)
|
||||||
{
|
{
|
||||||
client->_client.println("215 UNIX Type: L8");
|
client->_client.println("215 UNIX Type: L8");
|
||||||
}
|
}
|
||||||
else if(strcmp(client->_ftpCommand, "DELE") == 0)
|
else if(strcmp(client->_ftpCommand, "DELE") == 0)
|
||||||
{
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->_cmdParameters->count() > 0)
|
if (client->_cmdParameters->count() > 0)
|
||||||
{
|
{
|
||||||
//We have the file name, we need to append the current directory...
|
//We have the file name, we need to append the current directory...
|
||||||
@ -504,22 +673,33 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->_client.println("550 Requested action not taken.");
|
sendInfoResponse(_550, client,"");//client->_client.println("550 Requested action not taken.");
|
||||||
}
|
}
|
||||||
|
|
||||||
free(file2deleteNameWithPath);
|
free(file2deleteNameWithPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->_client.println("550 Requested action not taken.");
|
sendInfoResponse(_550, client,"");//client->_client.println("550 Requested action not taken.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(strcmp(client->_ftpCommand, "RNFR") == 0)
|
else if(strcmp(client->_ftpCommand, "RNFR") == 0)
|
||||||
{
|
{
|
||||||
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->_cmdParameters->count() > 0)
|
if (client->_cmdParameters->count() > 0)
|
||||||
{
|
{
|
||||||
//We have the file name, we need to append the current directory...
|
//We have the file name, we need to append the current directory...
|
||||||
char *fileNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
char *fileNameWithPath(NULL);
|
||||||
|
|
||||||
|
if(client->_cmdParameters->getAt(0)->getString()[0] == '/')
|
||||||
|
fileNameWithPath = constructFileNameWithPath("", client->_cmdParameters);
|
||||||
|
else
|
||||||
|
fileNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||||
|
|
||||||
#ifdef DEBUG_FTPS
|
#ifdef DEBUG_FTPS
|
||||||
Serial.printf("file to rename : #%s#\n",fileNameWithPath);
|
Serial.printf("file to rename : #%s#\n",fileNameWithPath);
|
||||||
@ -532,15 +712,26 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->_client.println("550 Requested action not taken.");
|
sendInfoResponse(_550, client,"");//client->_client.println("550 Requested action not taken.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(strcmp(client->_ftpCommand, "RNTO") == 0)
|
else if(strcmp(client->_ftpCommand, "RNTO") == 0)
|
||||||
{
|
{
|
||||||
if (client->_cmdParameters->count() > 0)
|
if(!client->_loggedIn)
|
||||||
|
{
|
||||||
|
sendInfoResponse(_530, client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->_cmdParameters->count() > 0) //If the name starts with a /, we do not need to prepend the directory
|
||||||
{
|
{
|
||||||
//Here we rename the file
|
//Here we rename the file
|
||||||
char *file2RenameNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
char *file2RenameNameWithPath(NULL);
|
||||||
|
if(client->_cmdParameters->getAt(0)->getString()[0] == '/')
|
||||||
|
file2RenameNameWithPath = constructFileNameWithPath("", client->_cmdParameters);
|
||||||
|
else
|
||||||
|
file2RenameNameWithPath = constructFileNameWithPath(client->_currentDirectory, client->_cmdParameters);
|
||||||
|
|
||||||
#ifdef DEBUG_FTPS
|
#ifdef DEBUG_FTPS
|
||||||
Serial.printf("file to rename to : #%s#\n",file2RenameNameWithPath);
|
Serial.printf("file to rename to : #%s#\n",file2RenameNameWithPath);
|
||||||
Serial.printf("Old name : %s --> %s\n",client->_currentFile,file2RenameNameWithPath);
|
Serial.printf("Old name : %s --> %s\n",client->_currentFile,file2RenameNameWithPath);
|
||||||
@ -550,21 +741,45 @@ class FTPServer : public TCPServer<T>
|
|||||||
{
|
{
|
||||||
client->_client.println("250 Requested file action okay.");
|
client->_client.println("250 Requested file action okay.");
|
||||||
}else
|
}else
|
||||||
client->_client.println("550 Requested action not taken.");
|
sendInfoResponse(_550, client,"");//client->_client.println("550 Requested action not taken.");
|
||||||
|
|
||||||
free(file2RenameNameWithPath);
|
free(file2RenameNameWithPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(strcmp(client->_ftpCommand, "QUIT") == 0)
|
||||||
|
{
|
||||||
|
if(client->_dataTransferPending == NONE)//If no transfers are in progress
|
||||||
|
{
|
||||||
|
sendInfoResponse(_221, client);
|
||||||
|
|
||||||
|
client->_client.stop();
|
||||||
|
client->_clientState = TCPClient::ClientState::DISCARDED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sendInfoResponse(_221, client);
|
||||||
|
}
|
||||||
|
/*else if(strcmp(client->_ftpCommand, "SIZE") == 0)
|
||||||
|
{
|
||||||
|
if (client->_cmdParameters->count() > 0)
|
||||||
|
{
|
||||||
|
client->_client.println("213 15224");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
else
|
else
|
||||||
|
{
|
||||||
client->_client.println("502 Command not implemented.");
|
client->_client.println("502 Command not implemented.");
|
||||||
|
#ifdef DEBUG_FTPS
|
||||||
|
Serial.println("Command not implemented");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Here we write the received file to the sd card
|
//Here we write the received file to the sd card
|
||||||
boolean writeToSdCard(T *client, FileTransferStatus *fts)
|
ICACHE_RAM_ATTR inline boolean writeToSdCard(T *client, FileTransferStatus *fts, boolean append = false)
|
||||||
{
|
{
|
||||||
if (client->_currentFile != NULL)
|
if (client->_currentFile != NULL)
|
||||||
{
|
{
|
||||||
if(_sdCardManager->exists(client->_currentFile) && client->_fileRecvBytes == 0)
|
if(_sdCardManager->exists(client->_currentFile) && client->_fileRecvBytes == 0 && !append)
|
||||||
_sdCardManager->remove(client->_currentFile);
|
_sdCardManager->remove(client->_currentFile);
|
||||||
|
|
||||||
File fileBeeingReceived = _sdCardManager->open(client->_currentFile, FILE_WRITE);
|
File fileBeeingReceived = _sdCardManager->open(client->_currentFile, FILE_WRITE);
|
||||||
@ -598,7 +813,7 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Here we send the fs tree to the ftp client
|
//Here we send the fs tree to the ftp client
|
||||||
boolean sendFSTree(T *client)
|
ICACHE_RAM_ATTR inline boolean sendFSTree(T *client)
|
||||||
{
|
{
|
||||||
if (client->_currentDirectory != NULL)
|
if (client->_currentDirectory != NULL)
|
||||||
{
|
{
|
||||||
@ -642,7 +857,7 @@ class FTPServer : public TCPServer<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
//The binary flag needs to be taken into consideration
|
//The binary flag needs to be taken into consideration
|
||||||
boolean sendFile(T *client, FileTransferStatus *fts)
|
ICACHE_RAM_ATTR inline boolean sendFile(T *client, FileTransferStatus *fts)
|
||||||
{
|
{
|
||||||
if (client->_currentFile != NULL)
|
if (client->_currentFile != NULL)
|
||||||
{
|
{
|
||||||
@ -690,39 +905,7 @@ class FTPServer : public TCPServer<T>
|
|||||||
*fts = NOT_FOUND;
|
*fts = NOT_FOUND;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *_83FileNameFormat(char *filename)
|
|
||||||
{
|
|
||||||
char *buffer = (char *)malloc((sizeof(char) * strlen(filename)) + 1);
|
|
||||||
strcpy(buffer, filename);
|
|
||||||
char *delimiter = strchr(buffer, '.');
|
|
||||||
if(delimiter != NULL)
|
|
||||||
{
|
|
||||||
*delimiter = '\0';
|
|
||||||
|
|
||||||
if(strlen(buffer) > 8)
|
|
||||||
buffer[8] = '\0';
|
|
||||||
|
|
||||||
strcpy(filename, buffer);
|
|
||||||
|
|
||||||
if(strlen(delimiter + 1) > 3)
|
|
||||||
*(delimiter + 1 + 3) = '\0';
|
|
||||||
|
|
||||||
strcat(filename, ".");
|
|
||||||
strcat(filename, delimiter + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(strlen(buffer) > 8)
|
|
||||||
{
|
|
||||||
buffer[8] = '\0';
|
|
||||||
}
|
|
||||||
strcpy(filename, buffer);
|
|
||||||
}
|
|
||||||
free(buffer);
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
//This functions construct the full file path.
|
//This functions construct the full file path.
|
||||||
//ie : if the current directory is : "/somedir/subdir" and the received file name is : "my file .txt"
|
//ie : if the current directory is : "/somedir/subdir" and the received file name is : "my file .txt"
|
||||||
//then it will return : "/somedir/subdir/my file .txt"
|
//then it will return : "/somedir/subdir/my file .txt"
|
||||||
@ -763,10 +946,30 @@ class FTPServer : public TCPServer<T>
|
|||||||
return fileNameWithPath;
|
return fileNameWithPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Error code functions
|
||||||
|
void sendInfoResponse(FtpMsgCode code, T *client, const char *msg = "")
|
||||||
|
{
|
||||||
|
switch(code)
|
||||||
|
{
|
||||||
|
case _200:
|
||||||
|
client->_client.printf_P(PSTR("200 Command okay. %s\r\n"), msg);
|
||||||
|
break;
|
||||||
|
case _221:
|
||||||
|
client->_client.printf_P(PSTR("221 Service closing control connection. %s\r\n"));
|
||||||
|
break;
|
||||||
|
case _530:
|
||||||
|
client->_client.printf_P(PSTR("530 Password required. %s\r\n"), msg);
|
||||||
|
break;
|
||||||
|
case _550:
|
||||||
|
client->_client.printf_P(PSTR("550 Requested action not taken. %s\r\n"), msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char *_login;
|
char *_login;
|
||||||
char *_password;
|
char *_password;
|
||||||
unsigned int _dataPort;
|
unsigned int _dataPort;
|
||||||
|
|
||||||
WiFiServer _dataServer; //In passive mode, the FTP server opens two different ports (one for the commands and the other for the data stream)
|
WiFiServer _dataServer; //In passive mode, the FTP server opens two different ports (one for the commands and the other for the data stream)
|
||||||
SDCardManager *_sdCardManager;
|
SDCardManager *_sdCardManager;
|
||||||
};
|
};
|
||||||
|
@ -31,3 +31,7 @@ boolean RtcManager::hasLostPower() const
|
|||||||
return _rtcRef.lostPower();
|
return _rtcRef.lostPower();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float RtcManager::getTemperature() const
|
||||||
|
{
|
||||||
|
return _rtcRef.getTemperature();
|
||||||
|
}
|
||||||
|
@ -11,6 +11,7 @@ class RtcManager
|
|||||||
void setTime(const DateTime dateTime);
|
void setTime(const DateTime dateTime);
|
||||||
void setDateTime(const DateTime dateTime);
|
void setDateTime(const DateTime dateTime);
|
||||||
boolean hasLostPower() const;
|
boolean hasLostPower() const;
|
||||||
|
float getTemperature() const;
|
||||||
protected:
|
protected:
|
||||||
RtcManager(RTC_DS3231 &rtc);
|
RtcManager(RTC_DS3231 &rtc);
|
||||||
private:
|
private:
|
||||||
|
@ -37,14 +37,15 @@ void setup()
|
|||||||
|
|
||||||
delete cfgDictionary;
|
delete cfgDictionary;
|
||||||
|
|
||||||
sab.getScreenManager().addView(&(view_1), &v1p, 0);
|
sab.getScreenManager().addView(&(homeInfo), &v1p, 0);
|
||||||
sab.getScreenManager().addView(&(view_2), &vap, 1);
|
sab.getScreenManager().addView(&(rtcInfo), &sab, 1);
|
||||||
sab.getScreenManager().addView(&(view_3), &vstap, 2);
|
sab.getScreenManager().addView(&(apInfo), &vap, 2);
|
||||||
sab.getScreenManager().addView(&(memInfo), NULL, 3);
|
sab.getScreenManager().addView(&(staInfo), &vstap, 3);
|
||||||
sab.getScreenManager().addView(&(ioInfo), &vio, 4);
|
sab.getScreenManager().addView(&(memInfo), NULL, 4);
|
||||||
sab.getScreenManager().addView(&(sysErrorInfo), &sab, 5);
|
sab.getScreenManager().addView(&(ioInfo), &vio, 5);
|
||||||
sab.getScreenManager().addView(NULL, NULL, 6); //for testing purposes
|
sab.getScreenManager().addView(&(sysErrorInfo), &sab, 6);
|
||||||
sab.getScreenManager().addView(&(dummy), NULL, 7); //for testing purposes
|
sab.getScreenManager().addView(NULL, NULL, 7); //for testing purposes
|
||||||
|
sab.getScreenManager().addView(&(dummy), NULL, 8); //for testing purposes
|
||||||
|
|
||||||
sab.getScreenManager().displayView(0);
|
sab.getScreenManager().displayView(0);
|
||||||
if(sab.getRtcManager().hasLostPower())
|
if(sab.getRtcManager().hasLostPower())
|
||||||
|
@ -20,5 +20,9 @@
|
|||||||
#define SOFT_VERSION "1.3.2" //Modified TCPServer and WEBServer core logic
|
#define SOFT_VERSION "1.3.2" //Modified TCPServer and WEBServer core logic
|
||||||
#define SOFT_VERSION "1.4.0" //Added the new FTPServer
|
#define SOFT_VERSION "1.4.0" //Added the new FTPServer
|
||||||
#define SOFT_VERSION "1.4.1" //Updated FTP server to use the new SD library for the ESP8266
|
#define SOFT_VERSION "1.4.1" //Updated FTP server to use the new SD library for the ESP8266
|
||||||
|
#define SOFT_VERSION "1.4.2" //Added new functionalities as well as login check
|
||||||
|
#define SOFT_VERSION "1.4.3" //Added ICACHE_RAM_ATTR because of a strange performance hit
|
||||||
|
#define SOFT_VERSION "1.5.0" //Added new rtcInfo view + DS3231 internal temperature
|
||||||
|
|
||||||
|
|
||||||
#endif //VERSIONS_H
|
#endif //VERSIONS_H
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "views.h"
|
#include "views.h"
|
||||||
|
|
||||||
boolean view_1(Adafruit_SSD1306 &display, void *pData)
|
boolean homeInfo(Adafruit_SSD1306 &display, void *pData)
|
||||||
{
|
{
|
||||||
char time_str[300] = "", power_str[15] = "", sdCard[10] = "", pageTitle[22] = "", zero_prepended[5][3] = {"","","","",""};
|
char time_str[300] = "", power_str[15] = "", sdCard[10] = "", pageTitle[22] = "", zero_prepended[5][3] = {"","","","",""};
|
||||||
View1Packet *p = (View1Packet *) pData;
|
View1Packet *p = (View1Packet *) pData;
|
||||||
@ -19,14 +19,14 @@ boolean view_1(Adafruit_SSD1306 &display, void *pData)
|
|||||||
else
|
else
|
||||||
sprintf(sdCard,"NO CARD");
|
sprintf(sdCard,"NO CARD");
|
||||||
|
|
||||||
sprintf(time_str,"Time : %s:%s:%s\nDate : %s/%s/%d\nFree RAM : %d\nSdCard : %s\nPower : %s\nViews : %u\n"
|
sprintf_P(time_str, F("Time : %s:%s:%s\nDate : %s/%s/%d\nFree RAM : %d\nSdCard : %s\nPower : %s\nViews : %u\n")
|
||||||
, dateTimeFormater(zero_prepended[0],p->dateTime.hour(),'0')
|
, dateTimeFormater(zero_prepended[0],p->dateTime.hour(),'0')
|
||||||
, dateTimeFormater(zero_prepended[1],p->dateTime.minute(),'0')
|
, dateTimeFormater(zero_prepended[1],p->dateTime.minute(),'0')
|
||||||
, dateTimeFormater(zero_prepended[2],p->dateTime.second(),'0')
|
, dateTimeFormater(zero_prepended[2],p->dateTime.second(),'0')
|
||||||
, dateTimeFormater(zero_prepended[3],p->dateTime.day(),'0')
|
, dateTimeFormater(zero_prepended[3],p->dateTime.day(),'0')
|
||||||
, dateTimeFormater(zero_prepended[4],p->dateTime.month(),'0')
|
, dateTimeFormater(zero_prepended[4],p->dateTime.month(),'0')
|
||||||
, p->dateTime.year(),ESP.getFreeHeap(),sdCard,power_str, p->nbViews);
|
, p->dateTime.year(),ESP.getFreeHeap(),sdCard,power_str, p->nbViews);
|
||||||
sprintf(pageTitle, "GLOBAL INFO v %s",p->version);
|
sprintf_P(pageTitle, F("GLOBAL INFO v %s"),p->version);
|
||||||
display.println(time_str);
|
display.println(time_str);
|
||||||
display.setCursor(0,56);
|
display.setCursor(0,56);
|
||||||
display.println(pageTitle);
|
display.println(pageTitle);
|
||||||
@ -34,16 +34,30 @@ boolean view_1(Adafruit_SSD1306 &display, void *pData)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean view_2(Adafruit_SSD1306 &display, void *pData)
|
boolean rtcInfo(Adafruit_SSD1306 &display, void *pData)
|
||||||
|
{
|
||||||
|
char buffer[300] = "";
|
||||||
|
SAB *p = (SAB *) pData;
|
||||||
|
|
||||||
|
sprintf_P(buffer, F("Rtc temp : %.2f C"), p->getRtcManager().getTemperature());
|
||||||
|
|
||||||
|
display.println(buffer);
|
||||||
|
|
||||||
|
display.setCursor(0,56);
|
||||||
|
display.println(F("RTC INFO"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean apInfo(Adafruit_SSD1306 &display, void *pData)
|
||||||
{
|
{
|
||||||
char conn_str[300];
|
char conn_str[300];
|
||||||
|
|
||||||
ViewAPPacket *p = (ViewAPPacket *) pData;
|
ViewAPPacket *p = (ViewAPPacket *) pData;
|
||||||
|
|
||||||
if(p->enabled)
|
if(p->enabled)
|
||||||
sprintf(conn_str,"Ip addr : %u.%u.%u.%u\nMac addr : \n%s\nConns : %u\nSSID : %s\n" ,p->ipAddr[0], p->ipAddr[1], p->ipAddr[2], p->ipAddr[3], p->macAddr.c_str(), p->nbOfCon, p->ssid.c_str());
|
sprintf_P(conn_str,F("Ip addr : %u.%u.%u.%u\nMac addr : \n%s\nConns : %u\nSSID : %s\n") ,p->ipAddr[0], p->ipAddr[1], p->ipAddr[2], p->ipAddr[3], p->macAddr.c_str(), p->nbOfCon, p->ssid.c_str());
|
||||||
else
|
else
|
||||||
sprintf(conn_str,"AP connectivity\nis not enabled\nCheck the cfg file\n");
|
sprintf_P(conn_str,F("AP connectivity\nis not enabled\nCheck the cfg file\n"));
|
||||||
|
|
||||||
display.println(conn_str);
|
display.println(conn_str);
|
||||||
|
|
||||||
@ -53,16 +67,16 @@ boolean view_2(Adafruit_SSD1306 &display, void *pData)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean view_3(Adafruit_SSD1306 &display, void *pData)
|
boolean staInfo(Adafruit_SSD1306 &display, void *pData)
|
||||||
{
|
{
|
||||||
char conn_str[300];
|
char conn_str[300];
|
||||||
|
|
||||||
ViewSTAPacket *p = (ViewSTAPacket *) pData;
|
ViewSTAPacket *p = (ViewSTAPacket *) pData;
|
||||||
|
|
||||||
if(p->enabled)
|
if(p->enabled)
|
||||||
sprintf(conn_str,"Ip addr : %u.%u.%u.%u\nMac addr : \n%s\nSignal : %d dBm\n", p->ipAddr[0], p->ipAddr[1], p->ipAddr[2], p->ipAddr[3], p->macAddr.c_str(), p->sigStrength);
|
sprintf_P(conn_str, F("Ip addr : %u.%u.%u.%u\nMac addr : \n%s\nSignal : %d dBm\n"), p->ipAddr[0], p->ipAddr[1], p->ipAddr[2], p->ipAddr[3], p->macAddr.c_str(), p->sigStrength);
|
||||||
else
|
else
|
||||||
sprintf(conn_str,"STA connectivity\nis not enabled\nCheck the cfg file\n");
|
sprintf_P(conn_str,F("STA connectivity\nis not enabled\nCheck the cfg file\n"));
|
||||||
|
|
||||||
display.println(conn_str);
|
display.println(conn_str);
|
||||||
|
|
||||||
@ -79,7 +93,7 @@ boolean memInfo(Adafruit_SSD1306 &display, void *pData)
|
|||||||
uint16_t biggestContigMemBlock;
|
uint16_t biggestContigMemBlock;
|
||||||
uint8_t frag;
|
uint8_t frag;
|
||||||
ESP.getHeapStats(&freeMem, &biggestContigMemBlock, &frag);
|
ESP.getHeapStats(&freeMem, &biggestContigMemBlock, &frag);
|
||||||
sprintf(dispBuffer, "Free RAM : %u\nHeap frag : %u\nMax block : %u\nFree Flash : %u\nProg size : %u\nCPU Freq : %u MHz\n", freeMem, frag, biggestContigMemBlock, ESP.getFreeSketchSpace(), ESP.getSketchSize(), ESP.getCpuFreqMHz());
|
sprintf_P(dispBuffer, F("Free RAM : %u\nHeap frag : %u\nMax block : %u\nFree Flash : %u\nProg size : %u\nCPU Freq : %u MHz\n"), freeMem, frag, biggestContigMemBlock, ESP.getFreeSketchSpace(), ESP.getSketchSize(), ESP.getCpuFreqMHz());
|
||||||
display.println(dispBuffer);
|
display.println(dispBuffer);
|
||||||
|
|
||||||
display.setCursor(0,56);
|
display.setCursor(0,56);
|
||||||
|
@ -14,7 +14,7 @@ typedef struct view1Packet
|
|||||||
} View1Packet;
|
} View1Packet;
|
||||||
|
|
||||||
//Global info
|
//Global info
|
||||||
boolean view_1(Adafruit_SSD1306 &display, void *pData);
|
boolean homeInfo(Adafruit_SSD1306 &display, void *pData);
|
||||||
|
|
||||||
typedef struct viewAPPacket
|
typedef struct viewAPPacket
|
||||||
{
|
{
|
||||||
@ -25,8 +25,11 @@ typedef struct viewAPPacket
|
|||||||
boolean enabled;
|
boolean enabled;
|
||||||
} ViewAPPacket;
|
} ViewAPPacket;
|
||||||
|
|
||||||
|
//Rtc infos
|
||||||
|
boolean rtcInfo(Adafruit_SSD1306 &display, void *pData);
|
||||||
|
|
||||||
//AP info
|
//AP info
|
||||||
boolean view_2(Adafruit_SSD1306 &display, void *pData);
|
boolean apInfo(Adafruit_SSD1306 &display, void *pData);
|
||||||
|
|
||||||
typedef struct viewSTAPacket
|
typedef struct viewSTAPacket
|
||||||
{
|
{
|
||||||
@ -37,7 +40,7 @@ typedef struct viewSTAPacket
|
|||||||
} ViewSTAPacket;
|
} ViewSTAPacket;
|
||||||
|
|
||||||
//STA info
|
//STA info
|
||||||
boolean view_3(Adafruit_SSD1306 &display, void *pData);
|
boolean staInfo(Adafruit_SSD1306 &display, void *pData);
|
||||||
|
|
||||||
//Memory INFO
|
//Memory INFO
|
||||||
boolean memInfo(Adafruit_SSD1306 &display, void *pData);
|
boolean memInfo(Adafruit_SSD1306 &display, void *pData);
|
||||||
|
@ -506,3 +506,16 @@ void RTC_DS3231::writeSqwPinMode(Ds3231SqwPinMode mode) {
|
|||||||
|
|
||||||
//Serial.println( read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), HEX);
|
//Serial.println( read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), HEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float RTC_DS3231::getTemperature()
|
||||||
|
{
|
||||||
|
//Lets tell which register we want to read
|
||||||
|
Wire.beginTransmission(DS3231_ADDRESS);
|
||||||
|
Wire._I2C_WRITE((byte)DS3231_TEMPREG);
|
||||||
|
Wire.endTransmission();
|
||||||
|
//Lets read it :
|
||||||
|
Wire.requestFrom((uint8_t)DS3231_ADDRESS, (uint8_t)2);
|
||||||
|
uint8_t upper = Wire._I2C_READ(), lower = Wire._I2C_READ();
|
||||||
|
|
||||||
|
return (float) upper + (lower >> 6) * 0.25;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Code by JeeLabs http://news.jeelabs.org/code/
|
// Code by JeeLabs http://news.jeelabs.org/code/
|
||||||
// Released to the public domain! Enjoy!
|
// Released to the public domain! Enjoy!
|
||||||
// Added a real begin verification for the ds3231 01/05/2019 Th3maz1ng
|
// Added a real begin verification for the ds3231 01/05/2019 Th3maz1ng
|
||||||
|
// Adding DS3231 internal temp sensor reading
|
||||||
|
|
||||||
#ifndef _RTCLIB_H_
|
#ifndef _RTCLIB_H_
|
||||||
#define _RTCLIB_H_
|
#define _RTCLIB_H_
|
||||||
@ -20,6 +21,7 @@ class TimeSpan;
|
|||||||
#define DS3231_ADDRESS 0x68
|
#define DS3231_ADDRESS 0x68
|
||||||
#define DS3231_CONTROL 0x0E
|
#define DS3231_CONTROL 0x0E
|
||||||
#define DS3231_STATUSREG 0x0F
|
#define DS3231_STATUSREG 0x0F
|
||||||
|
#define DS3231_TEMPREG 0x11
|
||||||
|
|
||||||
#define SECONDS_PER_DAY 86400L
|
#define SECONDS_PER_DAY 86400L
|
||||||
|
|
||||||
@ -104,6 +106,7 @@ public:
|
|||||||
static DateTime now();
|
static DateTime now();
|
||||||
static Ds3231SqwPinMode readSqwPinMode();
|
static Ds3231SqwPinMode readSqwPinMode();
|
||||||
static void writeSqwPinMode(Ds3231SqwPinMode mode);
|
static void writeSqwPinMode(Ds3231SqwPinMode mode);
|
||||||
|
float getTemperature();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user