Added sketches to test the software
This commit is contained in:
parent
01303f97bf
commit
0c19650188
57
src/software_test/dataStructure_test/dataStructure_test.ino
Normal file
57
src/software_test/dataStructure_test/dataStructure_test.ino
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* This sketch was written in order to test the List and Queue datastructures used in my project
|
||||
* This test was aimed toward spotting memory leaks
|
||||
* Anatole SCHRAMM-HENRY 08/05/2019
|
||||
*/
|
||||
|
||||
#include "D:/Users/Think/Desktop/Mes documents/Programmation/Arduino/ESP8266_swiss_army_board/src/app/List.h"
|
||||
#include "D:/Users/Think/Desktop/Mes documents/Programmation/Arduino/ESP8266_swiss_army_board/src/app/Queue.h"
|
||||
|
||||
uint32_t timer(0);
|
||||
|
||||
List<String> strList;
|
||||
Queue<String> strQueue;
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
Serial.begin(115200);
|
||||
timer = millis();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
strList.addFirst(String("Vive l'esp"));
|
||||
strList.addLast(strList.removeFirstRef());
|
||||
strList.addFirst(strList.removeLastRef());
|
||||
strList.addLast(String("Vive l'esp"));
|
||||
|
||||
|
||||
strQueue.add(String("Meme pas vrai"));
|
||||
delete strQueue.removeRef();
|
||||
strQueue.add(String("Meme pas vrai"));
|
||||
strQueue.remove();
|
||||
if(millis() - timer >= 1000)
|
||||
{
|
||||
debugInfo();
|
||||
timer = millis();
|
||||
}
|
||||
|
||||
if(strList.count() > 20)
|
||||
{
|
||||
//Serial.println("Cleared");
|
||||
strList.clear();
|
||||
}
|
||||
strList.removeFirst();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void debugInfo()
|
||||
{
|
||||
uint32_t freeMem;
|
||||
uint16_t biggestContigMemBlock;
|
||||
uint8_t frag;
|
||||
ESP.getHeapStats(&freeMem, &biggestContigMemBlock, &frag);
|
||||
Serial.print("Free MEM : ");Serial.println(freeMem);
|
||||
Serial.print("Heap Frag : ");Serial.println(frag);
|
||||
}
|
304
src/software_test/tcpServer_test/Dictionary.h
Normal file
304
src/software_test/tcpServer_test/Dictionary.h
Normal file
@ -0,0 +1,304 @@
|
||||
#ifndef DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
template <typename T>
|
||||
class Dictionary;
|
||||
|
||||
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;}
|
||||
Dictionary<StringEntity> *split(char character);
|
||||
private:
|
||||
char *_string;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class Dictionary
|
||||
{
|
||||
public:
|
||||
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()
|
||||
{
|
||||
if(_head == this)
|
||||
dispose();
|
||||
free(_parameter);
|
||||
//_parameter = NULL; Useless, just my c habits
|
||||
delete _value;
|
||||
//_value = NULL; //Useless, just my c habits
|
||||
}
|
||||
|
||||
boolean add(const char *parameter, T *value)
|
||||
{
|
||||
Dictionary *dictionaryNode = new Dictionary(parameter, value);
|
||||
return addNewNodeAtTheEnd(dictionaryNode);
|
||||
}
|
||||
|
||||
boolean add(int indice, T *value)
|
||||
{
|
||||
char indiceToStr[10];
|
||||
sprintf(indiceToStr,"%d", indice);
|
||||
Dictionary *dictionaryNode = new Dictionary(indiceToStr, value);
|
||||
return addNewNodeAtTheEnd(dictionaryNode);
|
||||
}
|
||||
|
||||
boolean add(const char *parameter, T value)
|
||||
{
|
||||
Dictionary *dictionaryNode = new Dictionary(parameter, new T(value));
|
||||
return addNewNodeAtTheEnd(dictionaryNode);
|
||||
}
|
||||
|
||||
boolean add(int indice, T value)
|
||||
{
|
||||
char indiceToStr[10];
|
||||
sprintf(indiceToStr,"%d", indice);
|
||||
Dictionary *dictionaryNode = new Dictionary(indiceToStr, new T(value));
|
||||
return addNewNodeAtTheEnd(dictionaryNode);
|
||||
}
|
||||
|
||||
boolean remove(const char *parameter)
|
||||
{
|
||||
if(_head->_next == NULL) return false;
|
||||
|
||||
Dictionary *cursor = _head, *toDelete(NULL);
|
||||
|
||||
while(!isListEmpty(cursor->_next))
|
||||
{
|
||||
if(strcmp(cursor->_next->_parameter, parameter) == 0)
|
||||
{
|
||||
toDelete = cursor->_next;
|
||||
cursor->_next = cursor->_next->_next;
|
||||
|
||||
delete toDelete;
|
||||
return true;
|
||||
}
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean remove(int indice)
|
||||
{
|
||||
char indiceToStr[10];
|
||||
sprintf(indiceToStr,"%d", indice);
|
||||
return remove(indiceToStr);
|
||||
}
|
||||
|
||||
boolean removeAt(unsigned int index)
|
||||
{
|
||||
unsigned int position(0);
|
||||
if(_head->_next == NULL) return false;
|
||||
|
||||
Dictionary *cursor = _head, *toDelete(NULL);
|
||||
|
||||
while(!isListEmpty(cursor->_next))
|
||||
{
|
||||
if(position++ == index)
|
||||
{
|
||||
toDelete = cursor->_next;
|
||||
cursor->_next = cursor->_next->_next;
|
||||
|
||||
delete toDelete;
|
||||
return true;
|
||||
}
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
T* get(const char *parameter)
|
||||
{
|
||||
if(parameter == NULL) return NULL;
|
||||
if(isListEmpty(_head->_next))return NULL;
|
||||
|
||||
Dictionary *cursor = _head->_next;
|
||||
|
||||
while(!isListEmpty(cursor))
|
||||
{
|
||||
if(strcmp(cursor->_parameter,parameter) == 0)
|
||||
return cursor->_value;
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
T* operator()(const char *parameter)
|
||||
{
|
||||
return get(parameter);
|
||||
}
|
||||
|
||||
T* get(const unsigned int index)
|
||||
{
|
||||
unsigned int position(0);
|
||||
if(isListEmpty(_head->_next))return NULL;
|
||||
|
||||
Dictionary *cursor = _head->_next;
|
||||
|
||||
while(!isListEmpty(cursor))
|
||||
{
|
||||
if(position++ == index)
|
||||
return cursor->_value;
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
T* operator()(const unsigned int index)
|
||||
{
|
||||
return get(index);
|
||||
}
|
||||
|
||||
unsigned int count()
|
||||
{
|
||||
unsigned int counter(0);
|
||||
if(isListEmpty(_head->_next))return counter;
|
||||
|
||||
Dictionary *cursor = _head->_next;
|
||||
while(!isListEmpty(cursor))
|
||||
{
|
||||
counter++;
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
void clear() {this->dispose();}
|
||||
|
||||
void dispose()
|
||||
{
|
||||
if(isListEmpty(_head->_next))return;
|
||||
|
||||
Dictionary *cursor = _head->_next, *toDelete(NULL);
|
||||
|
||||
while(!isListEmpty(cursor))
|
||||
{
|
||||
toDelete = cursor;
|
||||
cursor = cursor->_next;
|
||||
|
||||
delete toDelete;
|
||||
}
|
||||
_head = this;
|
||||
_next = NULL;
|
||||
}
|
||||
|
||||
const char *stringValue() const {return _value == NULL ? "" : _value->toString();}
|
||||
const char *getParameter(const unsigned int index)
|
||||
{
|
||||
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:
|
||||
Dictionary(const char *parameter, T *value) : Dictionary()
|
||||
{
|
||||
//We copy the parameter and the value
|
||||
_parameter = (char *) malloc((strlen(parameter) * sizeof(char)) + 1); //+1 for the string terminating character
|
||||
|
||||
strcpy(_parameter, parameter);
|
||||
_value = value;
|
||||
}
|
||||
|
||||
boolean addNewNodeAtTheEnd(Dictionary *node)
|
||||
{
|
||||
if(node == NULL) return false;
|
||||
|
||||
node->_head = _head; //Every node should point to the first node
|
||||
|
||||
if(_next == NULL) //This is our first node then
|
||||
{
|
||||
_next = node;
|
||||
return true;
|
||||
}
|
||||
|
||||
// /!\ We have to work with the _next reference in the loop, if we don't it won't work as expected
|
||||
Dictionary *cursor = _head;
|
||||
while(!isListEmpty(cursor->_next))
|
||||
{
|
||||
if(strcmp(cursor->_next->_parameter, node->_parameter) == 0)//If we find the same parameter name, we replace it
|
||||
{
|
||||
delete (cursor->_next->_value);
|
||||
cursor->_next->_value = new T(*(node->_value));
|
||||
if(cursor->_next->_value == NULL)return false;
|
||||
|
||||
delete node;
|
||||
|
||||
return true;
|
||||
}
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
cursor->_next = node;
|
||||
|
||||
return true;
|
||||
}
|
||||
boolean isListEmpty(Dictionary *node) {return node == NULL;}
|
||||
|
||||
char *_parameter;
|
||||
T *_value;
|
||||
Dictionary *_next;
|
||||
Dictionary *_head;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //DICTIONARY_H
|
318
src/software_test/tcpServer_test/List.h
Normal file
318
src/software_test/tcpServer_test/List.h
Normal file
@ -0,0 +1,318 @@
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
template <typename T>
|
||||
class List
|
||||
{
|
||||
public:
|
||||
List():_next(NULL), _head(this), _value(NULL)
|
||||
{
|
||||
}
|
||||
~List()
|
||||
{
|
||||
if(_head == this)
|
||||
dispose();
|
||||
}
|
||||
|
||||
boolean addFirst(T value)
|
||||
{
|
||||
List *listNode = new List(new T(value));
|
||||
return addNewNodeAtTheStart(listNode);
|
||||
}
|
||||
boolean addFirst(T *value)
|
||||
{
|
||||
List *listNode = new List(value);
|
||||
return addNewNodeAtTheStart(listNode);
|
||||
}
|
||||
|
||||
boolean addLast(T value)
|
||||
{
|
||||
List *listNode = new List(new T(value));
|
||||
return addNewNodeAtTheEnd(listNode);
|
||||
}
|
||||
boolean addLast(T *value)
|
||||
{
|
||||
List *listNode = new List(value);
|
||||
return addNewNodeAtTheEnd(listNode);
|
||||
}
|
||||
|
||||
T* getRef(unsigned int index)
|
||||
{
|
||||
unsigned int position(0);
|
||||
if(_head->_next == NULL) return NULL;
|
||||
|
||||
List *cursor = _head;
|
||||
|
||||
while(!isListEmpty(cursor->_next))
|
||||
{
|
||||
if(position++ == index)
|
||||
{
|
||||
return cursor->_next->_value;
|
||||
}
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
T get(unsigned int index)
|
||||
{
|
||||
T* p = getRef(index);
|
||||
if(p == NULL)
|
||||
{
|
||||
T value;
|
||||
return value;
|
||||
}else
|
||||
{
|
||||
T value(*p);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
T* getFirstRef()
|
||||
{
|
||||
if(_head->_next == NULL) return NULL;
|
||||
|
||||
return _head->_next->_value;
|
||||
}
|
||||
T getFirst()
|
||||
{
|
||||
T* p = getFirstRef();
|
||||
if(p == NULL)
|
||||
{
|
||||
T value;
|
||||
return value;
|
||||
}else
|
||||
{
|
||||
T value(*p);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
T* getLastRef()
|
||||
{
|
||||
if(_head->_next == NULL) return NULL;
|
||||
|
||||
List *cursor = _head;
|
||||
while(!isListEmpty(cursor->_next))
|
||||
{
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
|
||||
return cursor->_value;
|
||||
}
|
||||
T getLast()
|
||||
{
|
||||
T* p = getLastRef();
|
||||
if(p == NULL)
|
||||
{
|
||||
T value;
|
||||
return value;
|
||||
}else
|
||||
{
|
||||
T value(*p);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
T* removeRef(unsigned int index)
|
||||
{
|
||||
unsigned int position(0);
|
||||
if(_head->_next == NULL) return NULL;
|
||||
|
||||
List *cursor = _head, *toRemove(NULL);
|
||||
|
||||
while(!isListEmpty(cursor->_next))
|
||||
{
|
||||
if(position++ == index || position == _head->count())
|
||||
{
|
||||
toRemove = cursor->_next;
|
||||
cursor->_next = cursor->_next->_next;
|
||||
|
||||
T *toReturn = toRemove->_value;
|
||||
delete toRemove;
|
||||
return toReturn;
|
||||
}
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
T remove(unsigned int index)
|
||||
{
|
||||
T *ref = removeRef(index);
|
||||
if(ref != NULL)
|
||||
{
|
||||
T value(*ref);
|
||||
delete ref;
|
||||
return value;
|
||||
}else
|
||||
{
|
||||
T value;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
T* removeFirstRef()
|
||||
{
|
||||
if(isListEmpty(_head->_next))return NULL;
|
||||
|
||||
T *refToReturn = _head->_next->_value;
|
||||
List *toDelete(_head->_next);
|
||||
_head->_next = _head->_next->_next;
|
||||
|
||||
delete toDelete;
|
||||
return refToReturn;
|
||||
}
|
||||
T removeFirst()
|
||||
{
|
||||
T *ref = removeFirstRef();
|
||||
if(ref != NULL)
|
||||
{
|
||||
T value(*ref);
|
||||
delete ref;
|
||||
return value;
|
||||
}else
|
||||
{
|
||||
T value;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
T* removeLastRef()
|
||||
{
|
||||
unsigned int position(0);
|
||||
if(_head->_next == NULL) return NULL;
|
||||
|
||||
List *cursor = _head, *toRemove(NULL);
|
||||
|
||||
while(!isListEmpty(cursor->_next->_next))
|
||||
{
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
toRemove = cursor->_next;
|
||||
cursor->_next = cursor->_next->_next;
|
||||
|
||||
T *toReturn = toRemove->_value;
|
||||
delete toRemove;
|
||||
return toReturn;
|
||||
}
|
||||
T removeLast()
|
||||
{
|
||||
T *ref = removeLastRef();
|
||||
if(ref != NULL)
|
||||
{
|
||||
T value(*ref);
|
||||
delete ref;
|
||||
return value;
|
||||
}else
|
||||
{
|
||||
T value;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
int contains(T *value)
|
||||
{
|
||||
unsigned int position(-1);
|
||||
if(_head->_next == NULL) return NULL;
|
||||
|
||||
List *cursor = _head;
|
||||
|
||||
while(!isListEmpty(cursor->_next))
|
||||
{
|
||||
position++;
|
||||
|
||||
if(*(cursor->_next->_value) == *value)
|
||||
return position;
|
||||
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int contains(T value)
|
||||
{
|
||||
return contains(new T(value));
|
||||
}
|
||||
unsigned int count()
|
||||
{
|
||||
unsigned int counter(0);
|
||||
if(isListEmpty(_head->_next))return counter;
|
||||
|
||||
List *cursor = _head->_next;
|
||||
while(!isListEmpty(cursor))
|
||||
{
|
||||
counter++;
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
void clear(){_head->dispose();}
|
||||
void dispose()
|
||||
{
|
||||
if(isListEmpty(_head->_next))return;
|
||||
|
||||
List *cursor = _head->_next, *toDelete(NULL);
|
||||
|
||||
while(!isListEmpty(cursor))
|
||||
{
|
||||
toDelete = cursor;
|
||||
cursor = cursor->_next;
|
||||
|
||||
delete toDelete->_value;
|
||||
delete toDelete;
|
||||
}
|
||||
_head = this;
|
||||
_next = NULL;
|
||||
}
|
||||
protected:
|
||||
List(T *value):List()
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
boolean isListEmpty(List *node){return node == NULL;}
|
||||
boolean addNewNodeAtTheEnd(List *node)
|
||||
{
|
||||
if(node == NULL) return false;
|
||||
|
||||
node->_head = _head;
|
||||
|
||||
if(_next == NULL)
|
||||
{
|
||||
_next = node;
|
||||
return true;
|
||||
}
|
||||
|
||||
// /!\ We have to work with the _next reference in the loop, if we don't it won't work as expected
|
||||
List *cursor = _head;
|
||||
while(!isListEmpty(cursor->_next))
|
||||
{
|
||||
cursor = cursor->_next;
|
||||
}
|
||||
cursor->_next = node;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean addNewNodeAtTheStart(List *node)
|
||||
{
|
||||
if(node == NULL) return false;
|
||||
|
||||
node->_head = _head;
|
||||
|
||||
if(_next == NULL)
|
||||
{
|
||||
_next = node;
|
||||
return true;
|
||||
}
|
||||
|
||||
List *temp = _next;
|
||||
_next = node;
|
||||
node->_next = temp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
List *_next;
|
||||
List *_head;
|
||||
T* _value;
|
||||
private:
|
||||
};
|
||||
|
||||
#endif //LIST_H
|
117
src/software_test/tcpServer_test/TCPServer.cpp
Normal file
117
src/software_test/tcpServer_test/TCPServer.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include "TCPServer.h"
|
||||
#define DEBUG
|
||||
|
||||
TCPServer::TCPServer(unsigned int port, uint8_t maxClient) : _wifiServer(port), _port(port), _serverStarted(true), _maxClient(maxClient), _currentClient(NULL)
|
||||
{
|
||||
_wifiServer.begin();
|
||||
}
|
||||
|
||||
TCPServer::~TCPServer()
|
||||
{
|
||||
_clientList.dispose();
|
||||
}
|
||||
|
||||
void TCPServer::runServer()
|
||||
{
|
||||
handleNewClients();
|
||||
getClientData();
|
||||
}
|
||||
|
||||
void TCPServer::handleNewClients()
|
||||
{
|
||||
WiFiClient wc;
|
||||
|
||||
if(_maxClient == -1 || _maxClient > _clientList.count())
|
||||
{
|
||||
wc = _wifiServer.available();
|
||||
}
|
||||
|
||||
if(wc && wc.connected())
|
||||
{
|
||||
_clientList.addFirst(new TCPServerHelper::TCPServerClient({wc, TCPServerHelper::TCPServerClient::NEW,{'/0'},0,false,_clientList.count(),{TCPServerHelper::UNDEFINED, TCPServerHelper::UNKNOWN, TCPServerHelper::UNKNOWN_MIME, Dictionary<DictionaryHelper::StringEntity>(), Dictionary<DictionaryHelper::StringEntity>(), NULL,NULL},TCPServerHelper::HTTP_VERB}));
|
||||
#ifdef DEBUG
|
||||
Serial.print("New client accepted : ");Serial.println(_clientList.count()-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
_currentClient = _clientList.removeLastRef();//We pick a client in the list to process it's request
|
||||
|
||||
}
|
||||
|
||||
void TCPServer::getClientData()
|
||||
{
|
||||
if(_currentClient == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t bytesAvailable((_currentClient->client).available());
|
||||
|
||||
if(bytesAvailable)
|
||||
{
|
||||
if(_currentClient->dataSize < 255)
|
||||
{
|
||||
int freeSpace = (255-1/*for \0*/ - _currentClient->dataSize);
|
||||
int amountToBeRead = bytesAvailable < freeSpace ? bytesAvailable : freeSpace;//;bytesAvailable < 254 ? bytesAvailable : 254;
|
||||
|
||||
_currentClient->client.read(_currentClient->data + _currentClient->dataSize, amountToBeRead);
|
||||
_currentClient->dataSize+=amountToBeRead;
|
||||
_currentClient->data[_currentClient->dataSize] = '\0';
|
||||
_currentClient->newDataAvailable = true;
|
||||
}
|
||||
}
|
||||
else if(!(_currentClient->client).connected())
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Serial.print("Client can be discarded : ");Serial.println(_currentClient->id);
|
||||
#endif
|
||||
_currentClient->clientState = TCPServerHelper::TCPServerClient::DISCARDED;
|
||||
}
|
||||
|
||||
|
||||
if(_currentClient->dataSize > 0)
|
||||
{
|
||||
processClientData(_currentClient);//We process the actual data
|
||||
_currentClient->newDataAvailable = false;
|
||||
}
|
||||
|
||||
if(_currentClient->clientState == TCPServerHelper::TCPServerClient::DISCARDED)
|
||||
{
|
||||
_currentClient->client.stop();
|
||||
#ifdef DEBUG
|
||||
Serial.print("Client was discarded : ");Serial.println(_currentClient->id);
|
||||
#endif
|
||||
delete _currentClient;
|
||||
_currentClient = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
_clientList.addFirst(_currentClient);
|
||||
|
||||
}
|
||||
|
||||
void TCPServer::processClientData(TCPServerHelper::TCPServerClient *client)
|
||||
{
|
||||
Serial.print("Client --> ");Serial.print(client->id);Serial.print(" : ");Serial.println((char *)client->data);
|
||||
}
|
||||
|
||||
uint8_t TCPServer::getMaxClient()
|
||||
{
|
||||
return _maxClient;
|
||||
}
|
||||
|
||||
uint8_t TCPServer::getClientsCount()
|
||||
{
|
||||
return _clientList.count();
|
||||
}
|
||||
|
||||
void TCPServer::startServer()
|
||||
{
|
||||
_serverStarted = true;
|
||||
}
|
||||
|
||||
void TCPServer::stopServer()
|
||||
{
|
||||
_serverStarted = false;
|
||||
_clientList.dispose();
|
||||
}
|
86
src/software_test/tcpServer_test/TCPServer.h
Normal file
86
src/software_test/tcpServer_test/TCPServer.h
Normal file
@ -0,0 +1,86 @@
|
||||
#ifndef TCPSERVER_H
|
||||
#define TCPSERVER_H
|
||||
#include <Arduino.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "List.h"
|
||||
#include "Dictionary.h"
|
||||
|
||||
#define MAX_CLIENT -1
|
||||
|
||||
namespace TCPServerHelper
|
||||
{
|
||||
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 HttpMIMEType{UNKNOWN_MIME, TEXT_PLAIN, TEXT_CSS, TEXT_HTML, TEXT_JAVASCRIPT, APPLICATION_JSON, APPLICATION_X_WWW_FORM_URLENCODED, IMAGE_PNG, IMAGE_JPEG, AUDIO_MPEG, APPLICATION_OCTET_STREAM};
|
||||
enum HttpParserStatus {HTTP_VERB, HTTP_RESSOURCE, HTTP_VERSION, HTTP_PARAMS, POST_DATA};
|
||||
|
||||
struct HttpRequestData
|
||||
{
|
||||
HttpRequestMethod HRM;
|
||||
HttpVersion HV;
|
||||
HttpMIMEType HMT;
|
||||
Dictionary<DictionaryHelper::StringEntity> getParams;
|
||||
Dictionary<DictionaryHelper::StringEntity> postParams;
|
||||
char *httpResource;
|
||||
char *httpBody;
|
||||
};
|
||||
|
||||
struct TCPServerClient
|
||||
{
|
||||
WiFiClient client;
|
||||
enum ClientState {NEW, HANDLED, QUERY_PARSED, RESPONSE_SENT, DISCARDED} clientState;
|
||||
uint8_t data[255];
|
||||
uint16_t dataSize;
|
||||
boolean newDataAvailable;
|
||||
uint8_t id;
|
||||
HttpRequestData httpRequestData;
|
||||
HttpParserStatus httpParserState;
|
||||
|
||||
bool operator==(TCPServerClient& Object){return this->client == Object.client;}
|
||||
void clearHttpRequestData(TCPServerHelper::HttpRequestData *httpRequestData)
|
||||
{
|
||||
free(httpRequestData->httpResource);free(httpRequestData->httpBody);
|
||||
httpRequestData->getParams.dispose();
|
||||
httpRequestData->postParams.dispose();
|
||||
}
|
||||
~TCPServerClient()
|
||||
{
|
||||
client.stop();
|
||||
clearHttpRequestData(&httpRequestData);
|
||||
}
|
||||
void freeDataBuffer(uint16_t size)
|
||||
{
|
||||
if(size > 254) size = 254;
|
||||
|
||||
uint16_t secureSize = size > dataSize ? dataSize : size;
|
||||
strcpy((char *)data, (char *)data + secureSize);
|
||||
dataSize -= secureSize;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class TCPServer
|
||||
{
|
||||
public:
|
||||
TCPServer(unsigned int port = 80, uint8_t maxClient = MAX_CLIENT);
|
||||
~TCPServer();
|
||||
uint8_t getMaxClient();
|
||||
uint8_t getClientsCount();
|
||||
virtual void runServer();
|
||||
virtual void startServer();
|
||||
virtual void stopServer();
|
||||
protected:
|
||||
private:
|
||||
virtual void handleNewClients();
|
||||
virtual void getClientData();
|
||||
virtual void processClientData(TCPServerHelper::TCPServerClient *client);
|
||||
|
||||
boolean _serverStarted;
|
||||
uint8_t _maxClient;
|
||||
unsigned int _port;
|
||||
WiFiServer _wifiServer;
|
||||
TCPServerHelper::TCPServerClient *_currentClient; //current client to be processed
|
||||
List<TCPServerHelper::TCPServerClient> _clientList;
|
||||
};
|
||||
|
||||
#endif //TCPSERVER_H
|
143
src/software_test/tcpServer_test/TCPWebServer.cpp
Normal file
143
src/software_test/tcpServer_test/TCPWebServer.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
#include "TCPWebServer.h"
|
||||
#define DEBUG
|
||||
|
||||
TCPWebServer::TCPWebServer(unsigned int port, uint8_t maxClient) : TCPServer(port, maxClient)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void debugInfo()
|
||||
{
|
||||
uint32_t freeMem;
|
||||
uint16_t biggestContigMemBlock;
|
||||
uint8_t frag;
|
||||
ESP.getHeapStats(&freeMem, &biggestContigMemBlock, &frag);
|
||||
Serial.print("Free MEM : ");Serial.println(freeMem);
|
||||
Serial.print("Heap Frag : ");Serial.println(frag);
|
||||
}
|
||||
|
||||
void TCPWebServer::processClientData(TCPServerHelper::TCPServerClient *client)
|
||||
{
|
||||
if(client->newDataAvailable)
|
||||
{
|
||||
switch(client->httpParserState)
|
||||
{
|
||||
case TCPServerHelper::HTTP_VERB:
|
||||
{
|
||||
char *pVerb = strstr((char *)client->data, " ");
|
||||
|
||||
if(pVerb != NULL)
|
||||
{
|
||||
*pVerb = '\0';
|
||||
client->httpRequestData.HRM = getHttpVerbEnumValue((char *)client->data);
|
||||
client->freeDataBuffer((pVerb - (char *)client->data) +1);
|
||||
#ifdef DEBUG
|
||||
Serial.print("Verb : ");Serial.println(client->httpRequestData.HRM);
|
||||
#endif
|
||||
client->httpParserState = TCPServerHelper::HttpParserStatus::HTTP_RESSOURCE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TCPServerHelper::HTTP_RESSOURCE:
|
||||
{
|
||||
char *pRsrc = strstr((char *)client->data, " ");
|
||||
|
||||
if(pRsrc != NULL)
|
||||
{
|
||||
*pRsrc = '\0';
|
||||
uint16_t length = pRsrc - (char *)client->data;
|
||||
client->httpRequestData.httpResource = (char *) malloc(sizeof(char) * length + 1 ); //for \0
|
||||
if(client->httpRequestData.httpResource != NULL)
|
||||
strcpy(client->httpRequestData.httpResource, (char *)client->data);
|
||||
else
|
||||
{
|
||||
client->clientState = TCPServerHelper::TCPServerClient::ClientState::DISCARDED;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print("Resrc : ");Serial.println(client->httpRequestData.httpResource);
|
||||
#endif
|
||||
client->freeDataBuffer(length + 1);
|
||||
|
||||
client->httpParserState = TCPServerHelper::HttpParserStatus::HTTP_VERSION;
|
||||
}
|
||||
else if(client->dataSize == 254)
|
||||
{
|
||||
client->httpRequestData.httpResource = (char *) malloc(sizeof(char) * client->dataSize + 1 ); //for \0
|
||||
if(client->httpRequestData.httpResource != NULL)
|
||||
strcpy(client->httpRequestData.httpResource, (char *)client->data);
|
||||
else
|
||||
{
|
||||
client->clientState = TCPServerHelper::TCPServerClient::ClientState::DISCARDED;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print("Resrc : ");Serial.println(client->httpRequestData.httpResource);
|
||||
#endif
|
||||
client->freeDataBuffer(client->dataSize);
|
||||
client->httpParserState = TCPServerHelper::HttpParserStatus::HTTP_VERSION;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TCPServerHelper::HTTP_VERSION:
|
||||
{
|
||||
char *pEndline = strstr((char *)client->data, "\r\n");
|
||||
char *pVers = strstr((char *)client->data, "HTTP/");
|
||||
|
||||
if(pEndline != NULL && pVers!= NULL)
|
||||
{
|
||||
*pEndline = '\0';
|
||||
client->httpRequestData.HV = getHttpVersionEnumValue(pVers+5);
|
||||
#ifdef DEBUG
|
||||
Serial.print("Vers : ");Serial.println(pVers+5);
|
||||
Serial.print("Vers : ");Serial.println(client->httpRequestData.HV);
|
||||
#endif
|
||||
client->freeDataBuffer((pEndline - (char *)client->data)+2);
|
||||
client->clientState = TCPServerHelper::TCPServerClient::ClientState::DISCARDED;
|
||||
}
|
||||
else //If we do not find it, it's probably split at the end of the buffer, so we ignore some of the resource left over
|
||||
{
|
||||
client->freeDataBuffer(100);
|
||||
}
|
||||
}
|
||||
break;
|
||||
/*case TCPServerHelper::HTTP_PARAMS:
|
||||
break;
|
||||
case TCPServerHelper::POST_DATA:
|
||||
break;
|
||||
default :*/
|
||||
}
|
||||
/*Serial.print("WEB Client --> ");Serial.print(client->id);Serial.print(" : ");Serial.println((char *)client->data);
|
||||
client->freeDataBuffer(client->dataSize);*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TCPServerHelper::HttpRequestMethod TCPWebServer::getHttpVerbEnumValue(const char *parseBuffer)
|
||||
{
|
||||
//UNDEFINED, GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH
|
||||
if(strcmp(parseBuffer,"GET") == 0){return TCPServerHelper::HttpRequestMethod::GET;}
|
||||
else if(strcmp(parseBuffer,"POST") == 0){return TCPServerHelper::HttpRequestMethod::POST;}
|
||||
else if(strcmp(parseBuffer,"HEAD") == 0){return TCPServerHelper::HttpRequestMethod::HEAD;}
|
||||
else if(strcmp(parseBuffer,"PUT") == 0){return TCPServerHelper::HttpRequestMethod::PUT;}
|
||||
else if(strcmp(parseBuffer,"DELETE") == 0){return TCPServerHelper::HttpRequestMethod::DELETE;}
|
||||
else if(strcmp(parseBuffer,"CONNECT") == 0){return TCPServerHelper::HttpRequestMethod::CONNECT;}
|
||||
else if(strcmp(parseBuffer,"TRACE") == 0){return TCPServerHelper::HttpRequestMethod::TRACE;}
|
||||
else if(strcmp(parseBuffer,"PATCH") == 0){return TCPServerHelper::HttpRequestMethod::PATCH;}
|
||||
else if(strcmp(parseBuffer,"OPTIONS") == 0){return TCPServerHelper::HttpRequestMethod::OPTIONS;}
|
||||
else
|
||||
return TCPServerHelper::HttpRequestMethod::UNDEFINED;
|
||||
}
|
||||
|
||||
TCPServerHelper::HttpVersion TCPWebServer::getHttpVersionEnumValue(const char *parseBuffer)
|
||||
{
|
||||
//HTTP_0_9, HTTP_1_1, HTTP_1_0, HTTP_2_0
|
||||
if(strcmp(parseBuffer,"1.1") == 0){return TCPServerHelper::HttpVersion::HTTP_1_1;}
|
||||
else if(strcmp(parseBuffer,"2.0") == 0){return TCPServerHelper::HttpVersion::HTTP_2_0;}
|
||||
else if(strcmp(parseBuffer,"1.0") == 0){return TCPServerHelper::HttpVersion::HTTP_1_0;}
|
||||
else if(strcmp(parseBuffer,"0.9") == 0){return TCPServerHelper::HttpVersion::HTTP_0_9;}
|
||||
else
|
||||
return TCPServerHelper::HttpVersion::UNKNOWN;
|
||||
}
|
17
src/software_test/tcpServer_test/TCPWebServer.h
Normal file
17
src/software_test/tcpServer_test/TCPWebServer.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef TCPWEBSERVER_H
|
||||
#define TCPWEBSERVER_H
|
||||
|
||||
#include "TCPServer.h"
|
||||
|
||||
class TCPWebServer : public TCPServer
|
||||
{
|
||||
public:
|
||||
TCPWebServer(unsigned int port = 80, uint8_t maxClient = MAX_CLIENT);
|
||||
protected:
|
||||
private:
|
||||
virtual void processClientData(TCPServerHelper::TCPServerClient *client);
|
||||
TCPServerHelper::HttpRequestMethod getHttpVerbEnumValue(const char *parseBuffer);
|
||||
TCPServerHelper::HttpVersion getHttpVersionEnumValue(const char *parseBuffer);
|
||||
};
|
||||
|
||||
#endif //TCPWEBSERVER_H
|
36
src/software_test/tcpServer_test/tcpServer_test.ino
Normal file
36
src/software_test/tcpServer_test/tcpServer_test.ino
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* This sketch was written in order to developp and test the multi client tcp server which will be used in my project
|
||||
* Anatole SCHRAMM-HENRY 08/05/2019
|
||||
*/
|
||||
|
||||
#include "TCPWebServer.h"
|
||||
|
||||
WiFiEventHandler gotIpEventHandler, disconnectedEventHandler;
|
||||
TCPWebServer tws(80,2);
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
Serial.begin(115200);
|
||||
|
||||
gotIpEventHandler = WiFi.onStationModeGotIP(&(gotIp));
|
||||
disconnectedEventHandler = WiFi.onStationModeDisconnected(&(lostCon));
|
||||
|
||||
WiFi.persistent(false);
|
||||
WiFi.begin("freebox_Henry","eustache1930");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
tws.runServer();
|
||||
}
|
||||
|
||||
|
||||
void gotIp(const WiFiEventStationModeGotIP& event)
|
||||
{
|
||||
Serial.print("Got IP : ");Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
void lostCon(const WiFiEventStationModeDisconnected& event)
|
||||
{
|
||||
Serial.println("Lost connection");
|
||||
}
|
Loading…
Reference in New Issue
Block a user