Compare commits

..

13 Commits

Author SHA1 Message Date
e68ab04195 Added the persistent constructor parameter, as well as added the connect method to ease the class's instantiation 2022-04-17 21:58:10 +02:00
285c9ef20b Removed the use of the lastIndexOf function which was replaced by the builtin strrchr function 2022-04-17 21:54:41 +02:00
f981c06fc3 Corrected a spelling mistake 2022-04-17 21:53:17 +02:00
16f917a0b2 Changed the way the ConnectivityManager is instantiated, it is no more newed and deleted 2022-04-17 21:52:02 +02:00
1e453eb5d8 Added the display auto power off functionality 2022-04-17 21:50:05 +02:00
453f4cdd6e Replaced NULL with nullptr, removed constant value attribute initialization from the initializer list 2022-04-17 21:48:56 +02:00
365b7764a2 Added some comments, removed _httpRequestData.getParamsDataPointer which isn't used anymore 2022-04-17 21:43:17 +02:00
ec7c608dfe Renamed the HttpParserStatus enum members for the sake of consistency, added the 414 http error : URI too long, reworked the parsing of http resource queries, removedd the use of lastIndexOf, replaced useless strstr with strchr where needed 2022-04-17 21:41:50 +02:00
5d05bdb144 Officially retiring the WEBServerManager class which is superseded by the WEBServer class that have more features 2022-04-17 21:38:30 +02:00
fb9ad7d95e Renamed task_batt_sensing to task_sys_info as well as added the display auto off and wake up feature 2022-04-17 21:36:44 +02:00
62b5957895 Renamed the task_batt_sensing task to task_sys_info and added displayed information like IP address or RAM consumption 2022-04-17 21:35:32 +02:00
4a7765fc35 Removed the lastIndexOf function returning the last occurence of a character in a string, using builtin strrchr instead 2022-04-17 21:33:27 +02:00
df4159668c Updated version history 2022-04-17 21:26:02 +02:00
20 changed files with 300 additions and 208 deletions

View File

@ -1,20 +1,29 @@
#include "ConnectivityManager.h"
ConnectivityManager::ConnectivityManager() : _error(0), _sdCardManager(NULL)
ConnectivityManager::ConnectivityManager(bool persistent)
{
persistent(false);
ConnectivityManager::persistent(persistent);
}
ConnectivityManager::ConnectivityManager(SDCardManager &sdCardManager, bool persistent) : _sdCardManager(&sdCardManager)
{
ConnectivityManager::persistent(persistent);
}
boolean ConnectivityManager::connect()
{
if(!_sdCardManager) // ie _sdCardManager was not provided in contructor
{
if(!WiFi.disconnect(true))_error |= STA_ENABLED_DISABLE_ERR;
if(!WiFi.softAPdisconnect(true))_error |= AP_ENABLED_DISABLE_ERR;
if(!softAP("ESP8266SwissArmyBoard", NULL, 1, false, 8))_error |= AP_SETUP_ERR;
return _error == NO_ERROR;
}
ConnectivityManager::ConnectivityManager(SDCardManager &sdCardManager) : _error(0), _sdCardManager(&sdCardManager)
else
{
persistent(false);
startAP();
connectToSTA();
return connectToSTA() && startAP();
}
}
boolean ConnectivityManager::connectToSTA()

View File

@ -20,6 +20,7 @@ class ConnectivityManager : public ESP8266WiFiClass
{
friend class SAB;
public:
boolean connect();
boolean enableSTAAndAP(boolean enable);
boolean isSTAEnabled();
boolean isAPEnabled();
@ -27,14 +28,14 @@ class ConnectivityManager : public ESP8266WiFiClass
unsigned char RSSIPercent();
unsigned char getError() const;
protected:
ConnectivityManager();
ConnectivityManager(SDCardManager &sdCardManager);
ConnectivityManager(bool persistent = false);
ConnectivityManager(SDCardManager &sdCardManager, bool persistent = false);
boolean connectToSTA();
boolean startAP();
private:
unsigned char _error;
SDCardManager *_sdCardManager;
unsigned char _error = NO_ERROR;
SDCardManager *_sdCardManager = nullptr;
};
#endif //CONNECTIVITYMANAGER_H

View File

@ -473,7 +473,7 @@ class FTPServer : public TCPServer<T>
char *dirCopy = (char *)malloc((sizeof(char) * strlen(client->_currentDirectory)) + 1);
strcpy(dirCopy, client->_currentDirectory);
char *p = lastIndexOf(dirCopy, '/');
char *p = strrchr(dirCopy, '/');
if (dirCopy == p)
{
*(p + 1) = '\0';

View File

@ -25,7 +25,7 @@ class HttpClient : public WiFiClient, public HttpConstants
HttpClient(const HttpClient &object);
virtual ~HttpClient();
int sendHttpQuery(const char *ressource,
int sendHttpQuery(const char *resource,
HttpRequestMethod method = HttpRequestMethod::GET,
Dictionary<DictionaryHelper::StringEntity> *getData = NULL,
Dictionary<DictionaryHelper::StringEntity> *postData = NULL,

View File

@ -10,15 +10,13 @@ _display(_boardConfig.getScreenWidth(),_boardConfig.getScreenHeight(), &Wire),
_screenManager(_display, &_sdCardManager),
_rtc(),
_rtcManager(_rtc),
_connectivityManager(NULL),
//_webServerManager(80, &_sdCardManager),
_connectivityManager(_sdCardManager),
_webServer(80, &_sdCardManager, 10),
_ftpServer(21, &_sdCardManager, "ESP8266", "12345678", 10),
_dbWSServer(81),
_pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire),
_ioManager(_pcf),
_taskSchedulerManager(_rtcManager),
_error(0)
_taskSchedulerManager(_rtcManager)
{
initCommonConfig();
}
@ -29,15 +27,13 @@ _display(_boardConfig.getScreenWidth(), _boardConfig.getScreenHeight(), &Wire),
_screenManager(_display, &_sdCardManager),
_rtc(),
_rtcManager(_rtc),
_connectivityManager(NULL),
//_webServerManager(webServerPort, &_sdCardManager),
_connectivityManager(_sdCardManager),
_webServer(webServerPort, &_sdCardManager, 10),
_ftpServer(ftpServerPort, &_sdCardManager, "ESP8266", "12345678", 10),
_dbWSServer(81),
_pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire),
_ioManager(_pcf),
_taskSchedulerManager(_rtcManager),
_error(0)
_taskSchedulerManager(_rtcManager)
{
initCommonConfig();
}
@ -58,13 +54,19 @@ void SAB::initCommonConfig()
SAB::_rtcManagerP = &_rtcManager;
}
if(!_display.begin(SSD1306_SWITCHCAPVCC, _boardConfig.getI2C_screenAddress())){ _error |= DISP_BEGIN_ERR;}
if(!_sdCardManager.mountSD()){ _error |= SDCARD_INIT_ERR; Serial.print("Failed to init SDCard : SPI_SPEED : "); Serial.print(8000000); Serial.print(" CS PIN : "); Serial.println(_boardConfig.getSPI_SDCard_cs());}
if(!_sdCardManager.mountSD())
{
_error |= SDCARD_INIT_ERR;
Serial.printf_P(PSTR("Failed to init SDCard :\n\tSpeed -> %u\n\tCS Pin -> %u\n"),
_boardConfig.getSPISpeed(),
_boardConfig.getSPI_SDCard_cs());
}
else
{
_sdCardManager.setTimeCallback(&(SAB::myTimeCallback));
}
_screenManager.init();
_connectivityManager = new ConnectivityManager(_sdCardManager);
if(!_connectivityManager.connect()){ _error |= CONNECT_ERR;}
if(!_pcf.begin()){_error |= IO_INIT_ERR;}
_powerUpTime = _rtcManager.getDateTime();
@ -107,14 +109,9 @@ SDCardManager& SAB::getSdCardManager()
ConnectivityManager& SAB::getConnectivityManager()
{
return *_connectivityManager;
return _connectivityManager;
}
/*WEBServerManager& SAB::getWebServerManager()
{
return _webServerManager;
}*/
WEBServer<WEBClient>& SAB::getWebServer()
{
return _webServer;
@ -155,7 +152,7 @@ const char *SAB::getSoftVersion() const
return SOFT_VERSION;
}
unsigned char SAB::getError() const
uint8_t SAB::getError() const
{
return _error;
}

View File

@ -6,7 +6,6 @@
#include "ScreenManager.h"
#include "SDCardManager.h"
#include "ConnectivityManager.h"
//#include "WEBServerManager.h"
#include "WEBClient.h" //includes WEBServer internally
#include "FTPClient.h" //includes FTPServer internally
#include "DashboardWSServer.h"
@ -21,13 +20,12 @@
class SAB
{
public:
enum Error {RTC_BEGIN_ERR = 1, DISP_BEGIN_ERR = 2, SDCARD_INIT_ERR = 4, IO_INIT_ERR = 8};
enum Error {RTC_BEGIN_ERR = 1, DISP_BEGIN_ERR = 2, SDCARD_INIT_ERR = 4, IO_INIT_ERR = 8, CONNECT_ERR = 16};
SAB();
SAB(const BoardConfig boardConfig, const unsigned int webServerPort = 80, const unsigned int ftpServerPort = 21);
~SAB()
{
delete _connectivityManager;
}
ScreenManager& getScreenManager();
@ -45,7 +43,7 @@ class SAB
void run();
const char *getSoftVersion() const;
unsigned char getError() const;
uint8_t getError() const;
private:
void initGPIO();
static time_t myTimeCallback();
@ -58,7 +56,7 @@ class SAB
RTC_DS3231 _rtc;
RtcManager _rtcManager;
static RtcManager *_rtcManagerP;
ConnectivityManager *_connectivityManager;
ConnectivityManager _connectivityManager;
//WEBServerManager _webServerManager;
WEBServer<WEBClient> _webServer;
FTPServer<FTPClient> _ftpServer;
@ -68,7 +66,7 @@ class SAB
TaskSchedulerManager _taskSchedulerManager;
PowerManager _powerManager;
DateTime _powerUpTime;
uint8_t _error;
uint8_t _error = NO_ERROR;
};
#endif //SAB_H

View File

@ -1,8 +1,6 @@
#include "ScreenManager.h"
ScreenManager::ScreenManager(Adafruit_SSD1306 &display, SDCardManager *sdCardManager) : _displayRef(display), _error(OK)
, _displayColorInverted(false), _displayDimmed(false), _enabled(true), _refreshRateHz(1), _refreshInterval(1000), _timeRef(0),_forceRefresh(false)
, _currentView(NO_CURRENT_VIEW), _tail(NULL)
ScreenManager::ScreenManager(Adafruit_SSD1306 &display, SDCardManager *sdCardManager) : _displayRef(display)
, _viewNotFound{&(displayError), (ErrorInfo *)malloc(sizeof(ErrorInfo)), RESERVED_VIEW_UID, NULL, NULL}
, _viewFuncUndefined{&(displayError), (ErrorInfo *)malloc(sizeof(ErrorInfo)), RESERVED_VIEW_UID, NULL, NULL}
, _currentViewUndefined{&(displayError), (ErrorInfo *)malloc(sizeof(ErrorInfo)), RESERVED_VIEW_UID, NULL, NULL}
@ -46,6 +44,7 @@ boolean ScreenManager::applyCfgFromSD()
_displayRef.invertDisplay(cfgDictionary->get("INVERTED")->booleanValue());
_displayRef.dim(cfgDictionary->get("DIMMED")->booleanValue());
_displayRef.setTextColor(WHITE);
setAutoOFFDelay(cfgDictionary->get("AUTO_OFF")->uintValue());
delete cfgDictionary;
return true;
@ -212,6 +211,13 @@ ScreenManager::ViewLink* ScreenManager::getLinkByUID(ViewLinkedList viewLinkedLi
void ScreenManager::run()
{
//We handle the auto off logic here
if(_autoOFFDelay && _enabled)
{
if(millis() - _autoOFFDelayRef > _autoOFFDelay)
setEnabled(false);
}
if((millis() - _timeRef < _refreshInterval && !_forceRefresh) || !_enabled) return;
_timeRef = millis();
@ -262,7 +268,8 @@ void ScreenManager::forceRefresh()
boolean ScreenManager::displayView(const uint8_t UID)
{
if(!_enabled) return true;
_autoOFFDelayRef = millis();
if(!_enabled) return false;
_forceRefresh = true;
ViewLink *viewLink = getLinkByUID(_viewLinkedList, UID);
@ -290,6 +297,8 @@ boolean ScreenManager::displayView(const uint8_t UID)
void ScreenManager::displayNextView()
{
_autoOFFDelayRef = millis();
if(!_enabled) return;
_forceRefresh = true;
_error = OK;
if(isListEmpty(_viewLinkedList))return;
@ -323,6 +332,8 @@ void ScreenManager::displayNextView()
void ScreenManager::displayPreviousView()
{
_autoOFFDelayRef = millis();
if(!_enabled) return;
_forceRefresh = true;
_error = OK;
if(isListEmpty(_tail))return;
@ -368,11 +379,14 @@ void ScreenManager::dimDisplay(const boolean dimmed)
void ScreenManager::sleep()
{
_enabled = false;
_displayRef.sleep();
}
void ScreenManager::wakeUp()
{
_enabled = true;
_autoOFFDelayRef = millis();
_displayRef.wakeUp();
}
@ -423,13 +437,17 @@ void ScreenManager::clearViews()
void ScreenManager::setEnabled(boolean value)
{
_enabled = value;
if(value)
wakeUp();
else
sleep();
}
void ScreenManager::setAutoOFFDelay(const uint64_t delay)
{
_autoOFFDelay = delay;
}
boolean ScreenManager::getEnabled()
{
return _enabled;
@ -454,6 +472,11 @@ int ScreenManager::getCurrentViewUID() const
return _currentView->UID < 0 ? -1 : _currentView->UID;
}
uint64_t ScreenManager::getAutoOFFDelay() const
{
return _autoOFFDelay;
}
boolean ScreenManager::displayError(Adafruit_SSD1306 &display, void *pData)
{
const ErrorInfo *errorInfo = (ErrorInfo *) pData;

View File

@ -38,6 +38,7 @@ class ScreenManager
void sleep();
void wakeUp();
void setEnabled(boolean value);
void setAutoOFFDelay(const uint64_t delay);
boolean getEnabled();
boolean init();
void run();
@ -48,6 +49,7 @@ class ScreenManager
Orientation getDisplayOrientation() const;
boolean isDisplayDimmed() const;
int getCurrentViewUID() const;
uint64_t getAutoOFFDelay() const;
unsigned char getViewCount();
@ -66,15 +68,15 @@ class ScreenManager
Adafruit_SSD1306 &_displayRef;
ViewLinkedList _viewLinkedList;
Error _error;
boolean _displayColorInverted;
boolean _displayDimmed;
boolean _enabled;
uint8_t _refreshRateHz;
uint16_t _refreshInterval;
uint64_t _timeRef;
boolean _forceRefresh;
ViewLink *_currentView, *_tail;
Error _error = OK;
boolean _displayColorInverted = false;
boolean _displayDimmed = false;
boolean _enabled = true;
uint8_t _refreshRateHz = 1;
uint16_t _refreshInterval = 1000;
uint64_t _timeRef = 0, _autoOFFDelayRef = 0, _autoOFFDelay = 0;
boolean _forceRefresh = false;
ViewLink *_currentView = NO_CURRENT_VIEW, *_tail = nullptr;
ViewLink _viewNotFound, _viewFuncUndefined, _currentViewUndefined, _viewFunctionFailedToExecute;
SDCardManager *_sdCardManager;

View File

@ -13,7 +13,7 @@ template <typename T>
class TCPServer
{
public:
TCPServer(uint16_t port = 80, uint8_t maxClient = MAX_CLIENT, uint16_t clientDataBufferSize = 255) : _serverStarted(true), _maxClient(maxClient), _clientDataBufferSize(clientDataBufferSize), _wifiServer(port), _currentClient(NULL)
TCPServer(uint16_t port = 80, uint8_t maxClient = MAX_CLIENT, uint16_t clientDataBufferSize = 256) : _maxClient(maxClient), _clientDataBufferSize(clientDataBufferSize), _wifiServer(port)
{
_wifiServer.begin();
}
@ -108,12 +108,12 @@ class TCPServer
_currentClient = _clientList.removeLastRef();//We pick a client in the list to process it's request
if(_currentClient != NULL)
if(_currentClient != nullptr)
{
if(_currentClient->_error != TCPClient::OK)
{
_currentClient->closeConnection();
delete _currentClient; _currentClient = NULL;
delete _currentClient; _currentClient = nullptr;
}
}
}
@ -125,7 +125,7 @@ class TCPServer
virtual void getClientData()
{
if(_currentClient == NULL)
if(_currentClient == nullptr)
{
return;
}
@ -170,7 +170,7 @@ class TCPServer
Serial.printf("TCPServer : Client was discarded : %u\n", _currentClient->_id);
#endif
delete _currentClient;
_currentClient = NULL;
_currentClient = nullptr;
return;
}
@ -204,11 +204,11 @@ class TCPServer
return freeId;
}
boolean _serverStarted;
boolean _serverStarted = true;
uint8_t _maxClient, _TKACount = 0;
uint16_t _clientDataBufferSize, _TKAIdleSec = 0, _TKAIntvSec = 0;
WiFiServer _wifiServer;
T *_currentClient; //current client to be processed
T *_currentClient = nullptr; //current client to be processed
List<T> _clientList;
private:
};

View File

@ -12,11 +12,10 @@ WEBClient::WEBClient(WiFiClient client, uint8_t id, uint16_t maxResourceBuffer,
_httpRequestData.HV = WEBServer<WEBClient>::HttpVersion::UNKNOWN;
_httpRequestData.HMT = WEBServer<WEBClient>::HttpMIMEType::UNKNOWN_MIME;
_httpRequestData.getParamsDataPointer = NULL;
_httpRequestData.postParamsDataPointer = NULL;
_httpRequestData.httpResource = NULL;
_httpRequestData.maxResourceBuffer = maxResourceBuffer;
_httpRequestData.maxResourceBuffer = maxResourceBuffer; // \0 included
_httpRequestData.httpBody = NULL;
_httpRequestData.maxBodyBuffer = maxBodyBuffer;
}

View File

@ -9,13 +9,13 @@ class WEBClient : public TCPClient
template <typename T>
friend class WEBServer;
public:
WEBClient(WiFiClient client, uint8_t id, uint16_t maxResourceBuffer = 255, uint16_t maxBodyBuffer = 255, uint16_t dataBufferSize = 511);
WEBClient(WiFiClient client, uint8_t id, uint16_t maxResourceBuffer = 256, uint16_t maxBodyBuffer = 256, uint16_t dataBufferSize = 512);
virtual ~WEBClient();
protected:
WEBServer<WEBClient>::WEBClientState _WEBClientState = WEBServer<WEBClient>::WEBClientState::ACCEPTED;
private:
WEBServer<WEBClient>::HttpRequestData _httpRequestData;
WEBServer<WEBClient>::HttpParserStatus _httpParserState = WEBServer<WEBClient>::HttpParserStatus::HTTP_VERB;
WEBServer<WEBClient>::HttpParserStatus _httpParserState = WEBServer<WEBClient>::HttpParserStatus::PARSE_HTTP_VERB;
uint64_t _fileSentBytes = 0;
struct
{

View File

@ -13,7 +13,15 @@ template <typename T>
class WEBServer : public TCPServer<T>, public HttpConstants
{
public:
enum HttpParserStatus {HTTP_VERB, HTTP_RESSOURCE, HTTP_VERSION, HTTP_PARAMS, POST_DATA, HEADER_PARAMS};
enum HttpParserStatus
{
PARSE_HTTP_VERB,
PARSE_HTTP_RESOURCE,
PARSE_HTTP_VERSION,
PARSE_HTTP_RESOURCE_QUERY,
PARSE_HTTP_POST_DATA,
PARSE_HTTP_HEADER_PARAMS
};
enum WEBClientState {ACCEPTED, PARSING, QUERY_PARSED, RESPONSE_SENT, DONE};
struct HttpRequestData
@ -23,7 +31,6 @@ class WEBServer : public TCPServer<T>, public HttpConstants
HttpMIMEType HMT;
Dictionary<DictionaryHelper::StringEntity> getParams;
char *getParamsDataPointer; //Used in the getParams algorithm
Dictionary<DictionaryHelper::StringEntity> postParams;
char *postParamsDataPointer; //Used in the postParams algorithm
@ -33,7 +40,7 @@ class WEBServer : public TCPServer<T>, public HttpConstants
uint16_t maxBodyBuffer;
};
WEBServer(uint16_t port = 80, SDClass *sdClass = NULL, uint8_t maxClient = MAX_CLIENT, uint16_t clientDataBufferSize = 255) : TCPServer<T>(port, maxClient, clientDataBufferSize), _sdClass(sdClass) {}
WEBServer(uint16_t port = 80, SDClass *sdClass = NULL, uint8_t maxClient = MAX_CLIENT, uint16_t clientDataBufferSize = 256) : TCPServer<T>(port, maxClient, clientDataBufferSize), _sdClass(sdClass) {}
boolean addApiRoutine(const char *uri, boolean (*apiRoutine)(HttpRequestData&, WiFiClient*, void*), void *pData, HttpRequestMethod HRM = UNDEFINED)
{
@ -112,13 +119,13 @@ class WEBServer : public TCPServer<T>, public HttpConstants
{
switch(client->_httpParserState)
{
case HttpParserStatus::HTTP_VERB:
case HttpParserStatus::PARSE_HTTP_VERB:
{
#ifdef DEBUG_WEBS
Serial.println((char *)client->_data);
#endif
char *pVerb = strstr((char *)client->_data, " ");
char *pVerb(strchr((char *)client->_data, ' '));
if(pVerb != NULL)
{
@ -138,7 +145,7 @@ class WEBServer : public TCPServer<T>, public HttpConstants
Serial.println((char *)client->_data);
#endif
client->_httpParserState = HttpParserStatus::HTTP_RESSOURCE;
client->_httpParserState = HttpParserStatus::PARSE_HTTP_RESOURCE;
}
else
{
@ -147,24 +154,46 @@ class WEBServer : public TCPServer<T>, public HttpConstants
}
}
break;
case HttpParserStatus::HTTP_RESSOURCE:
case HttpParserStatus::PARSE_HTTP_RESOURCE:
{
char *pRsrc = strstr((char *)client->_data, " ");
if(pRsrc != NULL)
char *pRsrc(strchr((char *)client->_data, ' ')), *pRsrcQuery(strchr((char *)client->_data, '?'));
//The case where we have the resource complete or not complete with query parameters like : GET /some/path/resource.rsrc?param1=one&param2 HTTP/1.1
if(pRsrc || pRsrcQuery)
{
uint16_t rawLengthOfResource(0);
if(pRsrcQuery)
{
*pRsrcQuery = '\0'; // The ? is the end of the resource string
rawLengthOfResource = pRsrcQuery - (char *)client->_data;
#ifdef DEBUG_WEBS
Serial.printf("Resource w/ query\n");
#endif
}
else
{
*pRsrc = '\0';
uint16_t safeLength = pRsrc - (char *)client->_data <= client->_httpRequestData.maxResourceBuffer ? pRsrc - (char *)client->_data : client->_httpRequestData.maxResourceBuffer;
rawLengthOfResource = pRsrc - (char *)client->_data;
#ifdef DEBUG_WEBS
Serial.print("Resrc length : ");Serial.println(safeLength);
Serial.printf("Resource w/o query\n");
#endif
}
client->_httpRequestData.httpResource = (char *) malloc(sizeof(char) * (safeLength+1) ); //for \0
if(client->_httpRequestData.httpResource != NULL)
if(rawLengthOfResource >= client->_httpRequestData.maxResourceBuffer) //Then we cannot handle the full resource and there is no point of truncating it
//better tell the client about it ...
{
strncpy(client->_httpRequestData.httpResource, (char *)client->_data, safeLength);
client->_httpRequestData.httpResource[safeLength] = '\0';
#ifdef DEBUG_WEBS
Serial.printf("Resource too long\nResource raw length is : %u (\\0 included)\nMax length is : %u (\\0 included)\nclient->_data : #%s#\n", rawLengthOfResource + 1, client->_httpRequestData.maxResourceBuffer, (char *)client->_data);
#endif
sendInfoResponse(HTTP_CODE::HTTP_CODE_URI_TOO_LONG, client, "Resource too long");
client->_clientState = TCPClient::ClientState::DISCARDED;
break;
}
client->_httpRequestData.httpResource = (char *) malloc(sizeof(char) * (rawLengthOfResource + 1)); // +1 for the \0
if(client->_httpRequestData.httpResource != nullptr)
{
strncpy(client->_httpRequestData.httpResource, (char *)client->_data, rawLengthOfResource);
client->_httpRequestData.httpResource[rawLengthOfResource] = '\0';
}
else //Error 500
{
@ -173,38 +202,38 @@ class WEBServer : public TCPServer<T>, public HttpConstants
break;
}
client->freeDataBuffer(safeLength + 1);
client->freeDataBuffer(rawLengthOfResource + 1); //+1 to go past the \0, only the query parameters left in the buffer '?' excluded
#ifdef DEBUG_WEBS
Serial.print("Resrc : ");Serial.println(client->_httpRequestData.httpResource);
Serial.println((char *)client->_data);
Serial.printf("Resource length : %u\nRsrc : %s\nclient->_data : #%s#\n",
rawLengthOfResource,
client->_httpRequestData.httpResource,
(char *)client->_data);
#endif
if(pRsrcQuery)
client->_httpParserState = HttpParserStatus::PARSE_HTTP_RESOURCE_QUERY;
else
client->_httpParserState = HttpParserStatus::PARSE_HTTP_VERSION;
}
else //Resource is probably too long, so we truncate it
else //The URL is too long to fit in the buffer, we dont know it's length nor we now if it has query parameters.
//TODO : Maybe the query is incomplete and the client will send more data, case to handle.
{
client->_httpRequestData.httpResource = (char *) malloc(sizeof(char) * (client->_httpRequestData.maxResourceBuffer+1) ); //for \0
if(client->_httpRequestData.httpResource != NULL)
{
strncpy(client->_httpRequestData.httpResource, (char *)client->_data, client->_httpRequestData.maxResourceBuffer);
client->_httpRequestData.httpResource[client->_httpRequestData.maxResourceBuffer] = '\0';
}
else //Error 500
{
sendInfoResponse(HTTP_CODE::HTTP_CODE_INTERNAL_SERVER_ERROR, client, "Failed to allocate memory for resources");
#ifdef DEBUG_WEBS
Serial.printf("Could not find ' ' or '?' delimiter\nclient->_data : #%s#\n",
(char *)client->_data);
#endif
sendInfoResponse(HTTP_CODE::HTTP_CODE_URI_TOO_LONG, client, "Resource too long");
client->_clientState = TCPClient::ClientState::DISCARDED;
break;
}
client->freeDataBuffer(client->_httpRequestData.maxResourceBuffer + 1);
}
client->_httpParserState = HttpParserStatus::HTTP_PARAMS;
}
break;
case HttpParserStatus::HTTP_VERSION:
case HttpParserStatus::PARSE_HTTP_VERSION:
{
char *pEndline = strstr((char *)client->_data, "\r\n");
if(pEndline == NULL) pEndline = strstr((char *)client->_data, "\n");
if(pEndline == NULL) pEndline = strchr((char *)client->_data, '\n');
char *pVers = strstr((char *)client->_data, "HTTP/");
@ -224,25 +253,29 @@ class WEBServer : public TCPServer<T>, public HttpConstants
Serial.println((char *)client->_data);
#endif
client->_httpParserState = HttpParserStatus::HEADER_PARAMS;
client->_httpParserState = HttpParserStatus::PARSE_HTTP_HEADER_PARAMS;
}
}
break;
case HttpParserStatus::HTTP_PARAMS: //index.htm?var1=1&var2=2...
//index.htm?var1=1&var2=2...
//----------^^^^^^^^^^^^^^
case HttpParserStatus::PARSE_HTTP_RESOURCE_QUERY:
//If we are here, it means we are sure that there is at least one parameter
if(!httpRsrcParamParser(client))
{
#ifdef DEBUG_WEBS
Serial.print("Resrc : ");Serial.println(client->_httpRequestData.httpResource);
Serial.println("Get params :");
for(int i = 0; i < client->_httpRequestData.getParams.count(); i++)
for(unsigned int i = 0; i < client->_httpRequestData.getParams.count(); i++)
{
Serial.print(client->_httpRequestData.getParams.getParameter(i));Serial.print(" : ");Serial.println(client->_httpRequestData.getParams.getAt(i)->getString());
Serial.printf("%s : %s\n", client->_httpRequestData.getParams.getParameter(i), client->_httpRequestData.getParams.getAt(i)->getString());
}
Serial.printf("client->_data : #%s#\n", client->_data);
#endif
client->_httpParserState = HttpParserStatus::HTTP_VERSION;
client->_httpParserState = HttpParserStatus::PARSE_HTTP_VERSION;
}
break;
case HttpParserStatus::HEADER_PARAMS: //Here we parse the different header params until we arrive to \r\n\r\n
case HttpParserStatus::PARSE_HTTP_HEADER_PARAMS: //Here we parse the different header params until we arrive to \r\n\r\n
{
char *pEndLine = strstr((char *)client->_data, "\r\n");
@ -254,7 +287,7 @@ class WEBServer : public TCPServer<T>, public HttpConstants
if(*(pEndLine+2) == '\r') //We got \r\n\r\n -> so we go to the post data section
{
client->_httpParserState = HttpParserStatus::POST_DATA;
client->_httpParserState = HttpParserStatus::PARSE_HTTP_POST_DATA;
client->freeDataBuffer((pEndLine - (char *)client->_data) +3); //client->_data must not be empty...
break;
}
@ -265,11 +298,11 @@ class WEBServer : public TCPServer<T>, public HttpConstants
}
else //Error : indeed, we should at least have : \r\n. We go to the next step anyway
{
client->_httpParserState = HttpParserStatus::POST_DATA;
client->_httpParserState = HttpParserStatus::PARSE_HTTP_POST_DATA;
}
}
break;
case HttpParserStatus::POST_DATA:
case HttpParserStatus::PARSE_HTTP_POST_DATA:
switch(client->_httpRequestData.HMT)
{
@ -391,65 +424,59 @@ class WEBServer : public TCPServer<T>, public HttpConstants
}
/*
* This function is here to parse resources parameters
* This function is here to parse resources query parameters
*/
boolean httpRsrcParamParser(T *client)
{
char *pGetParam = strchr((char *)client->_httpRequestData.httpResource, '?');
char *end(strchr((char *)client->_data, ' '));
//If we find the end we mark it, this is needed for subsequent strchr
if(end)*end = '\0';
if(pGetParam != NULL) //There are some params to be parsed
char *key(strchr((char *)client->_data, '=')), *value(strchr((char *)client->_data, '&'));
if(key == nullptr && value == nullptr) //Only the key is present
{
if(client->_httpRequestData.getParamsDataPointer == NULL)
{
client->_httpRequestData.getParamsDataPointer = pGetParam +1;//We save the starting position of the string to parse
}
char *key = strchr(client->_httpRequestData.getParamsDataPointer, '=');
char *value = strchr(client->_httpRequestData.getParamsDataPointer, '&');
if(key == NULL && value == NULL) //Only the key is present
{
client->_httpRequestData.getParams.add(client->_httpRequestData.getParamsDataPointer, new DictionaryHelper::StringEntity(NULL));
*pGetParam = '\0';
client->_httpRequestData.getParams.add((char *)client->_data, new DictionaryHelper::StringEntity(NULL));
client->freeDataBuffer(strlen((char *)client->_data) + 1);
#ifdef DEBUG_WEBS
Serial.printf("client->_data : #%s#\n", client->_data);
#endif
return false;
}
else if(key != NULL && value != NULL)
else if(key != nullptr && value != nullptr)
{
if(key < value)*key = '\0';
*value = '\0';
client->_httpRequestData.getParams.add(client->_httpRequestData.getParamsDataPointer, new DictionaryHelper::StringEntity(key > value ? NULL : key + 1));
memmove(client->_httpRequestData.getParamsDataPointer, value+1, strlen(value+1)+1);
client->_httpRequestData.getParams.add((char *)client->_data, new DictionaryHelper::StringEntity(key > value ? NULL : key + 1));
client->freeDataBuffer((value - (char *)client->_data) + 1);
#ifdef DEBUG_WEBS
Serial.print("Params pointer : ");Serial.println(client->_httpRequestData.getParamsDataPointer);
Serial.printf("client->_data : #%s#\n", client->_data);
#endif
}
else if(key != NULL && value == NULL) //Only one key/value pair present
else if(key != nullptr && value == nullptr) //Only one key/value pair present
{
*key = '\0';
client->_httpRequestData.getParams.add(client->_httpRequestData.getParamsDataPointer, new DictionaryHelper::StringEntity(key+1));
*pGetParam = '\0';
return false;
}
else if(key == NULL && value != NULL)
{
*value = '\0';
client->_httpRequestData.getParams.add(client->_httpRequestData.getParamsDataPointer, new DictionaryHelper::StringEntity(NULL));
memmove(client->_httpRequestData.getParamsDataPointer, value+1, strlen(value+1)+1);
}
}
else //nothing to parse or done
{
client->_httpRequestData.getParams.add((char *)client->_data, new DictionaryHelper::StringEntity(key+1));
client->freeDataBuffer((key - (char *)client->_data) + strlen(key+1) + 2);
#ifdef DEBUG_WEBS
Serial.println("Nothing to parse or done");
Serial.printf("client->_data : #%s#\n", client->_data);
#endif
return false;
}
else if(key == nullptr && value != nullptr)
{
*value = '\0';
client->_httpRequestData.getParams.add((char *)client->_data, new DictionaryHelper::StringEntity(NULL));
client->freeDataBuffer((value - (char *)client->_data) + 1);
#ifdef DEBUG_WEBS
Serial.printf("client->_data : #%s#\n", client->_data);
#endif
}
return true;
}
@ -674,15 +701,18 @@ class WEBServer : public TCPServer<T>, public HttpConstants
case HTTP_CODE_BAD_REQUEST:
strcpy_P(codeLiteral,PSTR("Bad Request"));
break;
case HTTP_CODE_NOT_FOUND:
strcpy_P(codeLiteral,PSTR("Not Found"));
break;
case HTTP_CODE_FORBIDDEN:
strcpy_P(codeLiteral,PSTR("Forbidden"));
break;
case HTTP_CODE_NOT_FOUND:
strcpy_P(codeLiteral,PSTR("Not Found"));
break;
case HTTP_CODE_METHOD_NOT_ALLOWED:
strcpy_P(codeLiteral,PSTR("Method Not Allowed"));
break;
case HTTP_CODE_URI_TOO_LONG:
strcpy_P(codeLiteral,PSTR("URI Too Long"));
break;
case HTTP_CODE_INTERNAL_SERVER_ERROR:
strcpy_P(codeLiteral,PSTR("Internal Server Error"));
break;
@ -745,8 +775,7 @@ class WEBServer : public TCPServer<T>, public HttpConstants
static char *getFileExtension(char *name)
{
char *p(lastIndexOf(name, '.'));
char *p(strrchr(name, '.'));
return p != NULL ? p+1 : NULL;
}

View File

@ -1,3 +1,15 @@
/**
* @file WEBServerManager.cpp
* @author Anatole SCHRAMM-HENRY
* @brief Single client WEB Server.
* This class is now retired and replaced by the much better WEBServer class
* which handles multiclients among other things.
* @version 0.1
* @date 31/03/2019
*
* @copyright MIT
*
*/
#include "WEBServerManager.h"
//#define DEBUG

View File

@ -1,3 +1,15 @@
/**
* @file WEBServerManager.h
* @author Anatole SCHRAMM-HENRY
* @brief Single client WEB Server.
* This class is now retired and replaced by the much better WEBServer class
* which handles multiclients among other things.
* @version 0.1
* @date 31/03/2019
*
* @copyright MIT
*
*/
#ifndef WEBSERVERMANAGER_H
#define WEBSERVERMANAGER_H

View File

@ -1,9 +1,11 @@
/**
* Author : Anatole SCHRAMM-HENRY
* Created on : 24/02/2019
* Licence : MIT
* @file app.ino
* @author Anatole SCHRAMM-HENRY
* @brief SAB App entry point.
* @date 24/02/2019
*
* @copyright MIT
*
* SAB App entry point.
*/
#include "definition.h"
#include "SAB.h"
@ -95,7 +97,7 @@ void setup()
sab.getIoManager().setISROnIOChange(&(ioISR), GPIO_3_RX);
sab.getTaskSchedulerManager().addTask((uint16_t)0, TaskSchedulerManagerHelper::Schedule::scheduleBuilder()->setMillis(5000), &(task_blink), &sab);
sab.getTaskSchedulerManager().addTask(1, TaskSchedulerManagerHelper::Schedule::scheduleBuilder()->setSeconds(10), &(task_batt_sensing), &v1p);
sab.getTaskSchedulerManager().addTask(1, TaskSchedulerManagerHelper::Schedule::scheduleBuilder()->setSeconds(10), &(task_sys_info), &v1p);
//dataLogger.client.keepAlive(true);
//sab.getTaskSchedulerManager().addTask(2, TaskSchedulerManagerHelper::Schedule::scheduleBuilder()->setSeconds(1)->setTriggerRightAway(false), &(task_post_data_logger), &dataLogger);
@ -131,16 +133,26 @@ void loop()
switch(evt)
{
case EventHandler::Event::FLASH_BUTTON_PRESS:
if(sab.getScreenManager().getEnabled())
{
sab.getScreenManager().displayNextView();
#ifdef DEBUG
Serial.printf("Changing view\nSelected view is : %d\n",sab.getScreenManager().getCurrentViewUID());
#endif
}
else
sab.getScreenManager().wakeUp();
break;
case EventHandler::Event::FLASH_BUTTON_LONG_PRESS:
if(sab.getScreenManager().getEnabled())
{
sab.getScreenManager().displayPreviousView();
#ifdef DEBUG
Serial.printf("Changing view\nSelected view is : %d\n",sab.getScreenManager().getCurrentViewUID());
#endif
}
else
sab.getScreenManager().wakeUp();
break;
default: //NO_EVENT
break;

View File

@ -8,10 +8,24 @@ boolean task_blink(void *pData)
return true;
}
boolean task_batt_sensing(void *pData)
boolean task_sys_info(void *pData)
{
View1Packet *p = (View1Packet *) pData;
Serial.printf_P(PSTR("BATT SENSING...\nRunning since : %d s\nWEB Server clients : %u\n"), millis()/1000,p->sab->getWebServer().getConnectedClientsCount());
uint32_t freeRAM;
uint16_t biggestContigMemBlock;
uint8_t HEAPfrag;
ESP.getHeapStats(&freeRAM, &biggestContigMemBlock, &HEAPfrag);
Serial.printf_P(PSTR("BATT SENSING...\nRunning since : %d s\nSystem error : %u\nIP : %s, %d dBm\nWEB Server clients : %u\nMemory info:\n\tFree RAM : %u\n\tHeap frag : %u\n\tMax block %u\n"),
millis()/1000,
p->sab->getError(),
p->sab->getConnectivityManager().localIP().toString().c_str(),
p->sab->getConnectivityManager().RSSI(),
p->sab->getWebServer().getConnectedClientsCount(),
freeRAM,
HEAPfrag,
biggestContigMemBlock);
p->powerInfo = p->sab->getPowerManager().getPowerInfo();
return true;

View File

@ -6,7 +6,7 @@
#include "HttpClient.h"
boolean task_blink(void *);
boolean task_batt_sensing(void *);
boolean task_sys_info(void *);
boolean task_esp_reset_restart(void *);
typedef struct dataLogger

View File

@ -50,24 +50,6 @@ char *dateTimeFormater(char *pointer, const uint8_t value, const char character)
return pointer;
}
char *lastIndexOf(char *str, const char character)
{
char *last(NULL), *current(str);
do
{
current = strchr(current, character);
if(current != NULL)
{
last = current;
if(*(current+1) == '\0')break;
current += 1;
}
}while(current != NULL);
return last;
}
/**
* The monthNumTo3LetterAbbreviation function takes the month number from 1 to 12 and returns the abbreviation in a 3 letter
* format.

View File

@ -3,7 +3,6 @@
#include <Arduino.h>
char *addChar(char *pointer, const char character);
char *lastIndexOf(char *str, const char character);
char *dateTimeFormater(char *pointer, const uint8_t value, const char character);
uint32_t monthNumTo3LetterAbbreviation(const uint8_t monthNumber);
#endif // UTILITIES_H

View File

@ -39,6 +39,9 @@
//#define SOFT_VERSION "1.6.7" //Changed the way we store and return the 3 letter month abbreviation
//#define SOFT_VERSION "1.6.8" //Finally fixed the random crash issue concerning the servers :)
//#define SOFT_VERSION "1.6.9" //Updated the whole app to work with the esp8266 core 3.0.2 version, removed a bunch of warnings, corrected an array index overflow in apiTesterApi function
#define SOFT_VERSION "1.6.10" //Introduced new class : NonBlockingDelay which is used in the app.ino file.
//#define SOFT_VERSION "1.6.10" //Introduced new class : NonBlockingDelay which is used in the app.ino file.
//#define SOFT_VERSION "1.6.11" //WEBServer now handling partial request when sending audio, video etc.
//#define SOFT_VERSION "1.6.12" //WEBServer parsing http query parameters differently, allowing for longer URI and RAM savings.
#define SOFT_VERSION "1.6.13" //ScreenManager now providing and handling display auto power off functionality to save power as well as to fight OLED burn-in.
#endif //VERSIONS_H