esp32-nmea2000-obp60/lib/queue/GwMessage.h

119 lines
3.0 KiB
C++

#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);
vSemaphoreDelete(locker);
vSemaphoreDelete(notifier);
}
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;
String contentType;
private:
int len=0;
int consumed=0;
bool handled=false;
protected:
virtual void processRequest()=0;
virtual void processImpl(){
GW_MESSAGE_DEBUG("RequestMessage processImpl(1) %p\n",this);
processRequest();
GW_MESSAGE_DEBUG("RequestMessage processImpl(2) %p\n",this);
len=strlen(result.c_str());
consumed=0;
handled=true;
}
public:
RequestMessage(String contentType):Message(){
this->contentType=contentType;
}
virtual ~RequestMessage(){
GW_MESSAGE_DEBUG("~RequestMessage %p\n",this)
}
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;}
String getContentType(){
return contentType;
}
};
#endif