1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-13 05:53:06 +01:00

use async web server

This commit is contained in:
andreas
2021-10-25 18:31:34 +02:00
parent 2b1eda27d4
commit c893025cd3
5 changed files with 440 additions and 198 deletions

145
lib/queue/GwBuffer.cpp Normal file
View File

@@ -0,0 +1,145 @@
#include "GwBuffer.h"
void GwBuffer::lp(const char *fkt, int p)
{
LOG_DEBUG(GwLog::DEBUG + 1, "Buffer[%s]: buf=%p,wp=%d,rp=%d,used=%d,free=%d, p=%d",
fkt, buffer, offset(writePointer), offset(readPointer), usedSpace(), freeSpace(), p);
}
GwBuffer::GwBuffer(GwLog *logger)
{
this->logger = logger;
}
void GwBuffer::reset()
{
writePointer = buffer;
readPointer = buffer;
lp("reset");
}
size_t GwBuffer::freeSpace()
{
if (readPointer < writePointer)
{
size_t rt = BUFFER_SIZE - offset(writePointer) - 1 + offset(readPointer);
return rt;
}
if (readPointer == writePointer)
return BUFFER_SIZE - 1;
return readPointer - writePointer - 1;
}
size_t GwBuffer::usedSpace()
{
if (readPointer == writePointer)
return 0;
if (readPointer < writePointer)
return writePointer - readPointer;
return BUFFER_SIZE - offset(readPointer) - 1 + offset(writePointer);
}
size_t GwBuffer::addData(const uint8_t *data, size_t len)
{
lp("addDataE", len);
if (len == 0)
return 0;
if (freeSpace() < len)
return 0;
size_t written = 0;
if (writePointer >= readPointer)
{
written = BUFFER_SIZE - offset(writePointer) - 1;
if (written > len)
written = len;
if (written)
{
memcpy(writePointer, data, written);
len -= written;
data += written;
writePointer += written;
if (offset(writePointer) >= (BUFFER_SIZE - 1))
writePointer = buffer;
}
lp("addData1", written);
if (len <= 0)
{
return written;
}
}
//now we have the write pointer before the read pointer
//and we did the length check before - so we can safely copy
memcpy(writePointer, data, len);
writePointer += len;
lp("addData2", len);
return len + written;
}
/**
* write some data to the buffer writer
* return an error if the buffer writer returned < 0
*/
GwBuffer::WriteStatus GwBuffer::fetchData(GwBufferWriter *writer, bool errorIf0 )
{
lp("fetchDataE");
size_t len = usedSpace();
if (len == 0)
return OK;
size_t written = 0;
size_t plen = len;
if (writePointer < readPointer)
{
//we need to write from readPointer till end and then till writePointer-1
plen = BUFFER_SIZE - offset(readPointer) - 1;
int rt = writer->write(readPointer, plen);
lp("fetchData1", rt);
if (rt < 0)
{
LOG_DEBUG(GwLog::DEBUG + 1, "buffer: write returns error %d", rt);
return ERROR;
}
if (rt > plen)
{
LOG_DEBUG(GwLog::DEBUG + 1, "buffer: write too many bytes(1) %d", rt);
return ERROR;
}
if (rt == 0)
{
LOG_DEBUG(GwLog::DEBUG + 1, "buffer: write returns 0 (1)");
return (errorIf0 ? ERROR : AGAIN);
}
readPointer += rt;
if (offset(readPointer) >= (BUFFER_SIZE - 1))
readPointer = buffer;
if (rt < plen)
return AGAIN;
if (plen >= len)
return OK;
len -= rt;
written += rt;
//next part - readPointer should be at buffer now
}
plen = writePointer - readPointer;
if (plen == 0)
return OK;
int rt = writer->write(readPointer, plen);
lp("fetchData2", rt);
if (rt < 0)
{
LOG_DEBUG(GwLog::DEBUG + 1, "buffer: write returns error %d", rt);
return ERROR;
}
if (rt == 0)
{
LOG_DEBUG(GwLog::DEBUG + 1, "buffer: write returns 0 (1)");
return (errorIf0 ? ERROR : AGAIN);
}
if (rt > plen)
{
LOG_DEBUG(GwLog::DEBUG + 1, "buffer: write too many bytes(2)");
return ERROR;
}
readPointer += rt;
if (offset(readPointer) >= (BUFFER_SIZE - 1))
readPointer = buffer;
lp("fetchData3");
written += rt;
if (written < len)
return AGAIN;
return OK;
}

View File

@@ -10,6 +10,11 @@ class GwBufferWriter{
virtual ~GwBufferWriter(){};
};
/**
* an implementation of a
* buffer to safely inserte data if it fits
* and to write out data if possible
*/
class GwBuffer{
public:
static const size_t BUFFER_SIZE=1620; // app. 20 NMEA messages
@@ -26,126 +31,18 @@ class GwBuffer{
return (size_t)(ptr-buffer);
}
GwLog *logger;
void lp(const char *fkt,int p=0){
LOG_DEBUG(GwLog::DEBUG + 1,"Buffer[%s]: buf=%p,wp=%d,rp=%d,used=%d,free=%d, p=%d",
fkt,buffer,offset(writePointer),offset(readPointer),usedSpace(),freeSpace(),p
);
}
void lp(const char *fkt,int p=0);
public:
GwBuffer(GwLog *logger){
this->logger=logger;
}
void reset(){
writePointer=buffer;
readPointer=buffer;
lp("reset");
}
size_t freeSpace(){
if (readPointer < writePointer){
size_t rt=BUFFER_SIZE-offset(writePointer)-1+offset(readPointer);
return rt;
}
if (readPointer == writePointer) return BUFFER_SIZE-1;
return readPointer-writePointer-1;
}
size_t usedSpace(){
if (readPointer == writePointer) return 0;
if (readPointer < writePointer) return writePointer-readPointer;
return BUFFER_SIZE-offset(readPointer)-1+offset(writePointer);
}
size_t addData(const uint8_t *data,size_t len){
lp("addDataE",len);
if (len == 0) return 0;
if (freeSpace() < len) return 0;
size_t written=0;
if (writePointer >= readPointer){
written=BUFFER_SIZE-offset(writePointer)-1;
if (written > len) written=len;
if (written) {
memcpy(writePointer,data,written);
len-=written;
data+=written;
writePointer+=written;
if (offset(writePointer) >= (BUFFER_SIZE-1)) writePointer=buffer;
}
lp("addData1",written);
if (len <= 0) {
return written;
}
}
//now we have the write pointer before the read pointer
//and we did the length check before - so we can safely copy
memcpy(writePointer,data,len);
writePointer+=len;
lp("addData2",len);
return len+written;
}
GwBuffer(GwLog *logger);
void reset();
size_t freeSpace();
size_t usedSpace();
size_t addData(const uint8_t *data,size_t len);
/**
* write some data to the buffer writer
* return an error if the buffer writer returned < 0
*/
WriteStatus fetchData(GwBufferWriter *writer, bool errorIf0 = true)
{
lp("fetchDataE");
size_t len = usedSpace();
if (len == 0)
return OK;
size_t written=0;
size_t plen=len;
if (writePointer < readPointer)
{
//we need to write from readPointer till end and then till writePointer-1
plen = BUFFER_SIZE - offset(readPointer)-1;
int rt = writer->write(readPointer, plen);
lp("fetchData1",rt);
if (rt < 0){
LOG_DEBUG(GwLog::DEBUG+1,"buffer: write returns error %d",rt);
return ERROR;
}
if (rt > plen){
LOG_DEBUG(GwLog::DEBUG+1,"buffer: write too many bytes(1) %d",rt);
return ERROR;
}
if (rt == 0){
LOG_DEBUG(GwLog::DEBUG+1,"buffer: write returns 0 (1)");
return (errorIf0 ? ERROR : AGAIN);
}
readPointer += rt;
if (offset(readPointer) >= (BUFFER_SIZE-1))
readPointer = buffer;
if (rt < plen)
return AGAIN;
if (plen >= len)
return OK;
len -=rt;
written+=rt;
//next part - readPointer should be at buffer now
}
plen=writePointer - readPointer;
if (plen == 0) return OK;
int rt = writer->write(readPointer, plen);
lp("fetchData2",rt);
if (rt < 0){
LOG_DEBUG(GwLog::DEBUG+1,"buffer: write returns error %d",rt);
return ERROR;
}
if (rt == 0){
LOG_DEBUG(GwLog::DEBUG+1,"buffer: write returns 0 (1)");
return (errorIf0 ? ERROR : AGAIN);
}
if (rt > plen){
LOG_DEBUG(GwLog::DEBUG+1,"buffer: write too many bytes(2)");
return ERROR;
}
readPointer += rt;
if (offset(readPointer) >= (BUFFER_SIZE-1))
readPointer = buffer;
lp("fetchData3");
written+=rt;
if (written < len)
return AGAIN;
return OK;
}
WriteStatus fetchData(GwBufferWriter *writer, bool errorIf0 = true);
};
#endif

111
lib/queue/GwMessage.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef _GWMESSAGE_H
#define _GWMESSAGE_H
#include <Arduino.h>
#include <ESPAsyncWebServer.h>
#include "esp_task_wdt.h"
#ifdef GW_MESSAGE_DEBUG_ENABLED
#define GW_MESSAGE_DEBUG(...) Serial.printf(__VA_ARGS__);
#else
#define GW_MESSAGE_DEBUG(...)
#endif
/**
* a message class intended to be send from one task to another
*/
class Message{
private:
SemaphoreHandle_t locker;
SemaphoreHandle_t notifier;
int refcount=0;
protected:
virtual void processImpl()=0;
public:
Message(){
locker=xSemaphoreCreateMutex();
notifier=xSemaphoreCreateCounting(1,0);
refcount=1;
GW_MESSAGE_DEBUG("Message: %p\n",this);
}
virtual ~Message(){
GW_MESSAGE_DEBUG("~Message %p\n",this);
}
void unref(){
GW_MESSAGE_DEBUG("Message::unref %p\n",this);
bool mustDelete=false;
xSemaphoreTake(locker,portMAX_DELAY);
if (refcount > 0){
refcount--;
if (refcount == 0) mustDelete=true;
}
xSemaphoreGive(locker);
if (mustDelete){
delete this;
}
}
void ref(){
xSemaphoreTake(locker,portMAX_DELAY);
refcount++;
xSemaphoreGive(locker);
}
int wait(int maxWaitMillis){
static const int maxWait=1000;
int maxRetries=maxWaitMillis/maxWait;
int lastWait=maxWaitMillis - maxWait*maxRetries;
for (int retries=maxRetries;retries>0;retries--){
if (xSemaphoreTake(notifier,pdMS_TO_TICKS(maxWait))) return true;
esp_task_wdt_reset();
}
if (lastWait){
return xSemaphoreTake(notifier,pdMS_TO_TICKS(maxWait));
}
return false;
}
void process(){
GW_MESSAGE_DEBUG("Message::process %p\n",this);
processImpl();
xSemaphoreGive(notifier);
}
};
/**
* a class to executa an async web request that returns a string
*/
class RequestMessage : public Message{
protected:
String result;
private:
int len=0;
int consumed=0;
bool handled=false;
protected:
virtual void processRequest()=0;
virtual void processImpl(){
GW_MESSAGE_DEBUG("RequestMessage processImpl(1)");
processRequest();
GW_MESSAGE_DEBUG("RequestMessage processImpl(2)");
len=strlen(result.c_str());
consumed=0;
handled=true;
}
public:
RequestMessage():Message(){
}
virtual ~RequestMessage(){
}
String getResult(){return result;}
int getLen(){return len;}
int consume(uint8_t *destination,int maxLen){
if (!handled) return RESPONSE_TRY_AGAIN;
if (consumed >= len) return 0;
int cplen=maxLen;
if (cplen > (len-consumed)) cplen=len-consumed;
memcpy(destination,result.c_str()+consumed,cplen);
consumed+=cplen;
return cplen;
}
bool isHandled(){return handled;}
};
#endif