Compare commits

..

No commits in common. "e68ab0419573fc04fc636a1d92a346a5a346ee69" and "4296eeac281fdb011682d67ebd9c59926c161296" have entirely different histories.

20 changed files with 208 additions and 300 deletions

View File

@ -1,29 +1,20 @@
#include "ConnectivityManager.h" #include "ConnectivityManager.h"
ConnectivityManager::ConnectivityManager(bool persistent) ConnectivityManager::ConnectivityManager() : _error(0), _sdCardManager(NULL)
{ {
ConnectivityManager::persistent(persistent); persistent(false);
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;
} }
ConnectivityManager::ConnectivityManager(SDCardManager &sdCardManager, bool persistent) : _sdCardManager(&sdCardManager) ConnectivityManager::ConnectivityManager(SDCardManager &sdCardManager) : _error(0), _sdCardManager(&sdCardManager)
{ {
ConnectivityManager::persistent(persistent); persistent(false);
}
startAP();
boolean ConnectivityManager::connect() connectToSTA();
{
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;
}
else
{
return connectToSTA() && startAP();
}
} }
boolean ConnectivityManager::connectToSTA() boolean ConnectivityManager::connectToSTA()

View File

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

View File

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

View File

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

View File

@ -10,13 +10,15 @@ _display(_boardConfig.getScreenWidth(),_boardConfig.getScreenHeight(), &Wire),
_screenManager(_display, &_sdCardManager), _screenManager(_display, &_sdCardManager),
_rtc(), _rtc(),
_rtcManager(_rtc), _rtcManager(_rtc),
_connectivityManager(_sdCardManager), _connectivityManager(NULL),
//_webServerManager(80, &_sdCardManager),
_webServer(80, &_sdCardManager, 10), _webServer(80, &_sdCardManager, 10),
_ftpServer(21, &_sdCardManager, "ESP8266", "12345678", 10), _ftpServer(21, &_sdCardManager, "ESP8266", "12345678", 10),
_dbWSServer(81), _dbWSServer(81),
_pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire), _pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire),
_ioManager(_pcf), _ioManager(_pcf),
_taskSchedulerManager(_rtcManager) _taskSchedulerManager(_rtcManager),
_error(0)
{ {
initCommonConfig(); initCommonConfig();
} }
@ -27,13 +29,15 @@ _display(_boardConfig.getScreenWidth(), _boardConfig.getScreenHeight(), &Wire),
_screenManager(_display, &_sdCardManager), _screenManager(_display, &_sdCardManager),
_rtc(), _rtc(),
_rtcManager(_rtc), _rtcManager(_rtc),
_connectivityManager(_sdCardManager), _connectivityManager(NULL),
//_webServerManager(webServerPort, &_sdCardManager),
_webServer(webServerPort, &_sdCardManager, 10), _webServer(webServerPort, &_sdCardManager, 10),
_ftpServer(ftpServerPort, &_sdCardManager, "ESP8266", "12345678", 10), _ftpServer(ftpServerPort, &_sdCardManager, "ESP8266", "12345678", 10),
_dbWSServer(81), _dbWSServer(81),
_pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire), _pcf(_boardConfig.getI2C_IOExpanderAddress(), Wire),
_ioManager(_pcf), _ioManager(_pcf),
_taskSchedulerManager(_rtcManager) _taskSchedulerManager(_rtcManager),
_error(0)
{ {
initCommonConfig(); initCommonConfig();
} }
@ -54,19 +58,13 @@ void SAB::initCommonConfig()
SAB::_rtcManagerP = &_rtcManager; SAB::_rtcManagerP = &_rtcManager;
} }
if(!_display.begin(SSD1306_SWITCHCAPVCC, _boardConfig.getI2C_screenAddress())){ _error |= DISP_BEGIN_ERR;} if(!_display.begin(SSD1306_SWITCHCAPVCC, _boardConfig.getI2C_screenAddress())){ _error |= DISP_BEGIN_ERR;}
if(!_sdCardManager.mountSD()) 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());}
{
_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 else
{ {
_sdCardManager.setTimeCallback(&(SAB::myTimeCallback)); _sdCardManager.setTimeCallback(&(SAB::myTimeCallback));
} }
_screenManager.init(); _screenManager.init();
if(!_connectivityManager.connect()){ _error |= CONNECT_ERR;} _connectivityManager = new ConnectivityManager(_sdCardManager);
if(!_pcf.begin()){_error |= IO_INIT_ERR;} if(!_pcf.begin()){_error |= IO_INIT_ERR;}
_powerUpTime = _rtcManager.getDateTime(); _powerUpTime = _rtcManager.getDateTime();
@ -109,9 +107,14 @@ SDCardManager& SAB::getSdCardManager()
ConnectivityManager& SAB::getConnectivityManager() ConnectivityManager& SAB::getConnectivityManager()
{ {
return _connectivityManager; return *_connectivityManager;
} }
/*WEBServerManager& SAB::getWebServerManager()
{
return _webServerManager;
}*/
WEBServer<WEBClient>& SAB::getWebServer() WEBServer<WEBClient>& SAB::getWebServer()
{ {
return _webServer; return _webServer;
@ -152,7 +155,7 @@ const char *SAB::getSoftVersion() const
return SOFT_VERSION; return SOFT_VERSION;
} }
uint8_t SAB::getError() const unsigned char SAB::getError() const
{ {
return _error; return _error;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,15 +1,3 @@
/**
* @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" #include "WEBServerManager.h"
//#define DEBUG //#define DEBUG

View File

@ -1,15 +1,3 @@
/**
* @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 #ifndef WEBSERVERMANAGER_H
#define WEBSERVERMANAGER_H #define WEBSERVERMANAGER_H

View File

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

View File

@ -8,24 +8,10 @@ boolean task_blink(void *pData)
return true; return true;
} }
boolean task_sys_info(void *pData) boolean task_batt_sensing(void *pData)
{ {
View1Packet *p = (View1Packet *) 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(); p->powerInfo = p->sab->getPowerManager().getPowerInfo();
return true; return true;

View File

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

View File

@ -50,6 +50,24 @@ char *dateTimeFormater(char *pointer, const uint8_t value, const char character)
return pointer; 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 * The monthNumTo3LetterAbbreviation function takes the month number from 1 to 12 and returns the abbreviation in a 3 letter
* format. * format.

View File

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

View File

@ -39,9 +39,6 @@
//#define SOFT_VERSION "1.6.7" //Changed the way we store and return the 3 letter month abbreviation //#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.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.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 #endif //VERSIONS_H