Added Dictionary string entity class for char * manipulation, completed webApi, updated main app and other small things

This commit is contained in:
anschrammh 2019-04-04 07:56:37 +02:00
parent bd99e8ff27
commit bd5afe4592
6 changed files with 155 additions and 31 deletions

View File

@ -6,6 +6,36 @@
#include <stdio.h> #include <stdio.h>
#include <Arduino.h> #include <Arduino.h>
namespace DictionaryHelper
{
//String helper class with c style char array
class StringEntity
{
public:
StringEntity(const char *string) : _string(NULL)
{
if(string == NULL)
{
_string = (char *) malloc((sizeof(char)) * 2); //+1 for the string terminating character
strcpy(_string, "");
}
else
{
_string = (char *) malloc((strlen(string) * sizeof(char)) + 1); //+1 for the string terminating character
strcpy(_string, string);
}
}
StringEntity(const StringEntity &Object)
{
_string = (char *) malloc((strlen(Object._string) * sizeof(char)) + 1); //+1 for the string terminating character
strcpy(_string, Object._string);
}
~StringEntity(){free(_string);}
char *getString(){return _string;}
private:
char *_string;
};
}
template <typename T> template <typename T>
class Dictionary class Dictionary
@ -13,6 +43,25 @@ class Dictionary
public: public:
Dictionary() :_parameter(NULL), _value(NULL), _next(NULL), _head(this){} Dictionary() :_parameter(NULL), _value(NULL), _next(NULL), _head(this){}
Dictionary(Dictionary const& dictionaryToCopy) //Copy constructor needed because of pointers
{
_head = this;
_next = NULL;
if(dictionaryToCopy._parameter != NULL)
{
_parameter = (char *) malloc((strlen(dictionaryToCopy._parameter) * sizeof(char)) + 1); //+1 for the string terminating character
_value = new T(*(dictionaryToCopy._value));
strcpy(_parameter, dictionaryToCopy._parameter);
}else
{
_parameter = NULL;
_value = NULL;
}
}
~Dictionary() ~Dictionary()
{ {
if(_head == this) if(_head == this)
@ -133,9 +182,22 @@ public:
} }
const char *stringValue() const {return _value == NULL ? "" : _value->toString();} const char *stringValue() const {return _value == NULL ? "" : _value->toString();}
T getValue(){return T(*_value);} const char *getParameter(const unsigned int index)
T* getValueRef(){return _value;} {
const char *getParameter() const{return _parameter == NULL ? "" : _parameter;} unsigned int position(0);
if(isListEmpty(_head->_next))return "";
Dictionary *cursor = _head->_next;
while(!isListEmpty(cursor))
{
if(position++ == index)
return cursor->_parameter;
cursor = cursor->_next;
}
return "";
}
protected: protected:
Dictionary(const char *parameter, T *value) : Dictionary() Dictionary(const char *parameter, T *value) : Dictionary()
{ {
@ -146,17 +208,6 @@ protected:
_value = value; _value = value;
} }
Dictionary(Dictionary const& dictionaryToCopy) //Copy constructor needed because of pointers
{
_head = NULL;
_next = NULL;
_parameter = (char *) malloc((strlen(dictionaryToCopy._parameter) * sizeof(char)) + 1); //+1 for the string terminating character
_value = dictionaryToCopy._value;
strcpy(_parameter, dictionaryToCopy._parameter);
}
boolean addNewNodeAtTheEnd(Dictionary *node) boolean addNewNodeAtTheEnd(Dictionary *node)
{ {
if(node == NULL) return false; if(node == NULL) return false;

View File

@ -3,7 +3,7 @@
#define DEBUG #define DEBUG
#define DEBUG_RAW #define DEBUG_RAW
WEBServerManager::WEBServerManager(unsigned int port, SDCardManager *sdCardManager) : _wifiServer(port), _sdCardManager(sdCardManager), _httpRequestData({UNDEFINED, UNKNOWN, UNKNOWN_MIME, NULL,NULL}), _httpParserState(INIT), _clientState(WAITING_FOR_CLIENT), _port(port), _clientTimeout(0) WEBServerManager::WEBServerManager(unsigned int port, SDCardManager *sdCardManager) : _wifiServer(port), _sdCardManager(sdCardManager), _httpRequestData({UNDEFINED, UNKNOWN, UNKNOWN_MIME, Dictionary<DictionaryHelper::StringEntity>(), Dictionary<DictionaryHelper::StringEntity>(), NULL,NULL}), _httpParserState(INIT), _clientState(WAITING_FOR_CLIENT), _port(port), _clientTimeout(0)
{ {
_wifiServer.begin(); _wifiServer.begin();
} }
@ -82,11 +82,12 @@ boolean WEBServerManager::runServer()
boolean WEBServerManager::parseQuery(WiFiClient *wifiClient) boolean WEBServerManager::parseQuery(WiFiClient *wifiClient)
{ {
char readChar(0), *parseBuffer(NULL); char readChar(0), *parseBuffer(NULL), *parseKey(NULL), *parseValue(NULL);
boolean smallTimeout(false); boolean smallTimeout(false), isKey(true);
_httpParserState = INIT; _httpParserState = INIT;
_clientTimeout = millis(); _clientTimeout = millis();
boolean slashesOrantiSlashesOnly(true);
while(wifiClient->available() || millis() - _clientTimeout < (smallTimeout ? 100 : 5000)) while(wifiClient->available() || millis() - _clientTimeout < (smallTimeout ? 100 : 5000))
{ {
if(wifiClient->available()) if(wifiClient->available())
@ -131,18 +132,60 @@ boolean WEBServerManager::parseQuery(WiFiClient *wifiClient)
_httpParserState = ERROR; _httpParserState = ERROR;
break; break;
case HTTP_RESOURCE_SECTION: case HTTP_RESOURCE_SECTION:
if(readChar != ' ') if(readChar == '?' )
{
free(_httpRequestData.httpResource);_httpRequestData.httpResource = NULL;
_httpRequestData.httpResource = parseBuffer;parseBuffer = NULL;
_httpParserState = HTTP_RESOURCE_PARAM_SECTION;
}
else if(readChar != ' ')
{ {
//if(readChar != '/' && readChar != '\\') slashesOrantiSlashesOnly = false;
parseBuffer = addChar(parseBuffer, readChar); parseBuffer = addChar(parseBuffer, readChar);
_httpParserState = HTTP_RESOURCE_SECTION; _httpParserState = HTTP_RESOURCE_SECTION;
} }
else else
{ {
free(_httpRequestData.httpResource);_httpRequestData.httpResource = NULL; free(_httpRequestData.httpResource);_httpRequestData.httpResource = NULL;
_httpRequestData.httpResource = parseBuffer;parseBuffer = NULL; if(slashesOrantiSlashesOnly)
_httpParserState = HTTP_VER_SECTION; {
free(parseBuffer);parseBuffer = NULL;
_httpRequestData.httpResource = (char *) malloc(sizeof(char)*2);
strcpy(_httpRequestData.httpResource,"/");
}
else
_httpRequestData.httpResource = parseBuffer;parseBuffer = NULL;
_httpParserState = HTTP_VER_SECTION;
} }
break; break;
case HTTP_RESOURCE_PARAM_SECTION:
if(readChar == ' ')
{
_httpRequestData.getParams.add(parseKey,new DictionaryHelper::StringEntity(parseValue));
free(parseKey);free(parseValue);
parseKey = NULL;parseValue = NULL;
_httpParserState = HTTP_VER_SECTION;
}
else if( readChar == '=')
isKey = false;
else if(readChar == '&')
{
isKey = true;
_httpRequestData.getParams.add(parseKey, new DictionaryHelper::StringEntity(parseValue));
free(parseKey);free(parseValue);
parseKey = NULL;parseValue = NULL;
}
else
{
if(isKey)
parseKey = addChar(parseKey, readChar);
else
parseValue = addChar(parseValue, readChar);
}
break;
case HTTP_VER_SECTION: case HTTP_VER_SECTION:
if((readChar >= 48 && readChar <= 57) || readChar == '.') if((readChar >= 48 && readChar <= 57) || readChar == '.')
{ {
@ -194,6 +237,11 @@ boolean WEBServerManager::parseQuery(WiFiClient *wifiClient)
Serial.println(_httpRequestData.HV); Serial.println(_httpRequestData.HV);
Serial.print("BODY CONTENT : "); Serial.print("BODY CONTENT : ");
Serial.println(_httpRequestData.httpBody); Serial.println(_httpRequestData.httpBody);
Serial.println("GET PARAMS :");
for(int i = 0; i < _httpRequestData.getParams.count(); i++)
{
Serial.print(_httpRequestData.getParams.getParameter(i));Serial.print(" : ");Serial.println(_httpRequestData.getParams(i)->getString());
}
#endif #endif
return true; return true;
@ -323,8 +371,9 @@ boolean WEBServerManager::sendPageToClientFromSdCard(WiFiClient *wifiClient)
boolean WEBServerManager::sendPageToClientFromApiDictio(WiFiClient *wifiClient) boolean WEBServerManager::sendPageToClientFromApiDictio(WiFiClient *wifiClient)
{ {
if(_apiDictionary.count() == 0) if(_apiDictionary.count() == 0 || _httpRequestData.httpResource == NULL)
return false; return false;
ApiRoutine *ref = _apiDictionary(_httpRequestData.httpResource); ApiRoutine *ref = _apiDictionary(_httpRequestData.httpResource);
if(ref == NULL) if(ref == NULL)
@ -441,5 +490,5 @@ void WEBServerManager::clearHttpRequestData()
_httpRequestData.HMT = UNKNOWN_MIME; _httpRequestData.HMT = UNKNOWN_MIME;
free(_httpRequestData.httpResource);free(_httpRequestData.httpBody); free(_httpRequestData.httpResource);free(_httpRequestData.httpBody);
_httpRequestData.httpResource = NULL;_httpRequestData.httpBody = NULL; _httpRequestData.httpResource = NULL;_httpRequestData.httpBody = NULL;
_httpRequestData.getParams.dispose();
} }

View File

@ -15,12 +15,14 @@ class WEBServerManager
enum ClientStatus {NOT_HANDLED, HANDLED, NEW, WAITING_FOR_CLIENT, QUERY_PARSED, RESPONSE_SENT}; enum ClientStatus {NOT_HANDLED, HANDLED, NEW, WAITING_FOR_CLIENT, QUERY_PARSED, RESPONSE_SENT};
enum HttpRequestMethod {UNDEFINED, GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH}; enum HttpRequestMethod {UNDEFINED, GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH};
enum HttpVersion {UNKNOWN, HTTP_0_9, HTTP_1_1, HTTP_1_0, HTTP_2_0}; enum HttpVersion {UNKNOWN, HTTP_0_9, HTTP_1_1, HTTP_1_0, HTTP_2_0};
enum HttpParserStatus {INIT, LINE_BREAK, HTTP_VERB_SECTION, HTTP_RESOURCE_SECTION, HTTP_VER_SECTION, PARAMETER_SECTION, BODY_SECTION, IGNORED, ERROR}; enum HttpParserStatus {INIT, LINE_BREAK, HTTP_VERB_SECTION, HTTP_RESOURCE_SECTION, HTTP_RESOURCE_PARAM_SECTION, HTTP_VER_SECTION, PARAMETER_SECTION, BODY_SECTION, IGNORED, ERROR};
enum HttpMIMEType{UNKNOWN_MIME, TEXT_PLAIN, TEXT_CSS, TEXT_HTML, TEXT_JAVASCRIPT, APPLICATION_JSON, APPLICATION_X_WWW_FORM_URLENCODED, IMAGE_PNG}; enum HttpMIMEType{UNKNOWN_MIME, TEXT_PLAIN, TEXT_CSS, TEXT_HTML, TEXT_JAVASCRIPT, APPLICATION_JSON, APPLICATION_X_WWW_FORM_URLENCODED, IMAGE_PNG};
struct HttpRequestData{ struct HttpRequestData{
HttpRequestMethod HRM; HttpRequestMethod HRM;
HttpVersion HV; HttpVersion HV;
HttpMIMEType HMT; HttpMIMEType HMT;
Dictionary<DictionaryHelper::StringEntity> getParams;
Dictionary<DictionaryHelper::StringEntity> postParams;
char *httpResource; char *httpResource;
char *httpBody; char *httpBody;
}; };

View File

@ -16,6 +16,8 @@ ViewSTAPacket vstap = {sab.getConnectivityManager().macAddress(), sab.getConnect
void setup() void setup()
{ {
// put your setup code here, to run once: // put your setup code here, to run once:
pinMode(GPIO_0, INPUT);
Serial.println("Starting setup"); Serial.println("Starting setup");
CFGFileParser cfgFileParser(sab.getSdCardManager(), AP_CFG_FILE); CFGFileParser cfgFileParser(sab.getSdCardManager(), AP_CFG_FILE);
CFGDictionary<CFGParameterValue> *cfgDictionary = (CFGDictionary<CFGParameterValue> *) cfgFileParser.parseFile(); CFGDictionary<CFGParameterValue> *cfgDictionary = (CFGDictionary<CFGParameterValue> *) cfgFileParser.parseFile();
@ -23,8 +25,6 @@ void setup()
Serial.print("AP PASSWORD : ");if((*cfgDictionary)("PASSWORD") != NULL)Serial.println((*cfgDictionary)("PASSWORD")->stringValue()); Serial.print("AP PASSWORD : ");if((*cfgDictionary)("PASSWORD") != NULL)Serial.println((*cfgDictionary)("PASSWORD")->stringValue());
delete cfgDictionary; delete cfgDictionary;
pinMode(GPIO_0, INPUT);
sab.getScreenManager().addView(&(view_1), &v1p, 0); sab.getScreenManager().addView(&(view_1), &v1p, 0);
sab.getScreenManager().addView(&(view_2), &vap, 1); sab.getScreenManager().addView(&(view_2), &vap, 1);
sab.getScreenManager().addView(&(view_3), &vstap, 2); sab.getScreenManager().addView(&(view_3), &vstap, 2);
@ -34,7 +34,10 @@ void setup()
Serial.println("Clock lost power"); Serial.println("Clock lost power");
sab.getRtcManager().setDateTime(DateTime(F(__DATE__), F(__TIME__))); sab.getRtcManager().setDateTime(DateTime(F(__DATE__), F(__TIME__)));
} }
sab.getWebServerManager().addApiRoutine("/hello", &(helloServerApi), &sab);
sab.getWebServerManager().addApiRoutine("/helloServer", &(helloServerApi), NULL);
sab.getWebServerManager().addApiRoutine("/view/next", &(nextViewApi), &sab, WEBServerManager::GET);
sab.getWebServerManager().addApiRoutine("/rtc/get/time", &(rtcTimeApi), &sab, WEBServerManager::GET);
Serial.println("End setup"); Serial.println("End setup");
} }

View File

@ -1,12 +1,29 @@
#include "SAB.h" #include "SAB.h"
#include "webApi.h" #include "webApi.h"
boolean helloServerApi(WEBServerManager::HttpRequestData& HRD, WiFiClient* wc, void* pData) boolean helloServerApi(WEBServerManager::HttpRequestData &HRD, WiFiClient* wc, void* pData)
{ {
SAB *sab = (SAB *)pData; wc->print(F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n<p>Hello client !!!</p>\r\n</html>"));
Serial.println("Before"); return true;
wc->print(F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n<p>Hello Client !!!</p>\r\n</html>")); }
Serial.println("After");
boolean nextViewApi(WEBServerManager::HttpRequestData &HRD, WiFiClient *wc, void *pData)
{
SAB *p = (SAB *)pData;
char buffer[200];
p->getScreenManager().displayNextView();
sprintf(buffer,"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n{ \"status\" : \"ok\", \"ViewUID\" : \"%d\" }", p->getScreenManager().getCurrentViewUID());
wc->print(buffer);
return true;
}
boolean rtcTimeApi(WEBServerManager::HttpRequestData &HRD, WiFiClient *wc, void *pData)
{
SAB *p = (SAB *)pData;
char buffer[200];
DateTime d = p->getRtcManager().getDateTime();
sprintf(buffer,"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n{ \"status\" : \"ok\", \"date\" : \"%d/%d/%d\", \"time\" : \"%d:%d:%d\" }", d.day(), d.month(), d.year(), d.hour(), d.minute(), d.second());
wc->print(buffer);
return true; return true;
} }

View File

@ -3,5 +3,7 @@
#include "WebServerManager.h" #include "WebServerManager.h"
boolean helloServerApi(WEBServerManager::HttpRequestData&, WiFiClient*, void*); boolean helloServerApi(WEBServerManager::HttpRequestData&, WiFiClient*, void*);
boolean nextViewApi(WEBServerManager::HttpRequestData&, WiFiClient*, void*);
boolean rtcTimeApi(WEBServerManager::HttpRequestData&, WiFiClient*, void*);
#endif #endif