allow a counter for user tasks, reorganize generated config handling

This commit is contained in:
andreas 2023-10-14 19:20:21 +02:00
parent f52428366f
commit 6cdaab4d60
11 changed files with 205 additions and 119 deletions

View File

@ -14,6 +14,7 @@ GEN_DIR='lib/generated'
CFG_FILE='web/config.json' CFG_FILE='web/config.json'
XDR_FILE='web/xdrconfig.json' XDR_FILE='web/xdrconfig.json'
CFG_INCLUDE='GwConfigDefinitions.h' CFG_INCLUDE='GwConfigDefinitions.h'
CFG_INCLUDE_IMPL='GwConfigDefImpl.h'
XDR_INCLUDE='GwXdrTypeMappings.h' XDR_INCLUDE='GwXdrTypeMappings.h'
TASK_INCLUDE='GwUserTasks.h' TASK_INCLUDE='GwUserTasks.h'
EMBEDDED_INCLUDE="GwEmbeddedFiles.h" EMBEDDED_INCLUDE="GwEmbeddedFiles.h"
@ -112,66 +113,62 @@ def generateMergedConfig(inFile,outFile,addDirs=[]):
data=json.dumps(config,indent=2) data=json.dumps(config,indent=2)
writeFileIfChanged(outFile,data) writeFileIfChanged(outFile,data)
def generateCfg(inFile,outFile,addDirs=[]): def generateCfg(inFile,outFile,impl):
if not os.path.exists(inFile): if not os.path.exists(inFile):
raise Exception("unable to read cfg file %s"%inFile) raise Exception("unable to read cfg file %s"%inFile)
data="" data=""
with open(inFile,'rb') as ch: with open(inFile,'rb') as ch:
config=json.load(ch) config=json.load(ch)
config=mergeConfig(config,addDirs)
data+="//generated from %s\n"%inFile data+="//generated from %s\n"%inFile
data+='#include "GwConfigItem.h"\n'
l=len(config) l=len(config)
data+='class GwConfigDefinitions{\n' idx=0
data+=' public:\n' if not impl:
data+=' int getNumConfig() const{return %d;}\n'%(l) data+='#include "GwConfigItem.h"\n'
for item in config: data+='class GwConfigDefinitions{\n'
n=item.get('name') data+=' public:\n'
if n is None: data+=' int getNumConfig() const{return %d;}\n'%(l)
continue for item in config:
if len(n) > 15: n=item.get('name')
raise Exception("%s: config names must be max 15 caracters"%n) if n is None:
data+=' static constexpr const char* %s="%s";\n'%(n,n) continue
data+=' protected:\n' if len(n) > 15:
data+=' GwConfigInterface *configs[%d]={\n'%(l) raise Exception("%s: config names must be max 15 caracters"%n)
first=True data+=' static constexpr const char* %s="%s";\n'%(n,n)
for item in config: data+="};\n"
name=item.get('name') else:
if name is None: data+='void GwConfigHandler::populateConfigs(GwConfigInterface **config){\n'
continue for item in config:
if not first: name=item.get('name')
data+=',\n' if name is None:
first=False continue
secret="false"; data+=' configs[%d]=\n'%(idx)
if item.get('type') == 'password': idx+=1
secret="true" secret="false";
data+=" #undef __CFGMODE\n" if item.get('type') == 'password':
data+=" #ifdef CFGMODE_%s\n"%(name) secret="true"
data+=" #define __CFGMODE CFGMODE_%s\n"%(name) data+=" #undef __CFGMODE\n"
data+=" #else\n" data+=" #ifdef CFGMODE_%s\n"%(name)
data+=" #define __CFGMODE GwConfigInterface::NORMAL\n" data+=" #define __CFGMODE CFGMODE_%s\n"%(name)
data+=" #endif\n" data+=" #else\n"
data+=" #ifdef CFGDEFAULT_%s\n"%(name) data+=" #define __CFGMODE GwConfigInterface::NORMAL\n"
data+=" new GwConfigInterface(%s,CFGDEFAULT_%s,%s,__CFGMODE)\n"%(name,name,secret) data+=" #endif\n"
data+=" #else\n" data+=" #ifdef CFGDEFAULT_%s\n"%(name)
data+=" new GwConfigInterface(%s,\"%s\",%s,__CFGMODE)\n"%(name,item.get('default'),secret) data+=" new GwConfigInterface(%s,CFGDEFAULT_%s,%s,__CFGMODE)\n"%(name,name,secret)
data+=" #endif\n" data+=" #else\n"
data+=" new GwConfigInterface(%s,\"%s\",%s,__CFGMODE)\n"%(name,item.get('default'),secret)
data+='};\n' data+=" #endif\n"
data+='};\n' data+=";\n"
data+="#ifdef CFG_MESSAGES\n" data+='}\n'
for item in config: for item in config:
name=item.get('name') name=item.get('name')
if name is None: if name is None:
continue continue
data+="#ifdef CFGMODE_%s\n"%(name) data+="#ifdef CFGMODE_%s\n"%(name)
data+=" __MSG(\"CFGMODE_%s=\" __XSTR(CFGMODE_%s))\n"%(name,name) data+=" __MSG(\"CFGMODE_%s=\" __XSTR(CFGMODE_%s))\n"%(name,name)
data+="#endif\n" data+="#endif\n"
data+="#ifdef CFGDEFAULT_%s\n"%(name) data+="#ifdef CFGDEFAULT_%s\n"%(name)
data+=" __MSG(\"CFGDEFAULT_%s=\" CFGDEFAULT_%s)\n"%(name,name) data+=" __MSG(\"CFGDEFAULT_%s=\" CFGDEFAULT_%s)\n"%(name,name)
data+="#endif\n" data+="#endif\n"
data+="#endif"
writeFileIfChanged(outFile,data) writeFileIfChanged(outFile,data)
@ -273,7 +270,8 @@ def prebuild(env):
mergedConfig=os.path.join(outPath(),os.path.basename(CFG_FILE)) mergedConfig=os.path.join(outPath(),os.path.basename(CFG_FILE))
generateMergedConfig(os.path.join(basePath(),CFG_FILE),mergedConfig,userTaskDirs) generateMergedConfig(os.path.join(basePath(),CFG_FILE),mergedConfig,userTaskDirs)
compressFile(mergedConfig,mergedConfig+".gz") compressFile(mergedConfig,mergedConfig+".gz")
generateCfg(mergedConfig,os.path.join(outPath(),CFG_INCLUDE)) generateCfg(mergedConfig,os.path.join(outPath(),CFG_INCLUDE),False)
generateCfg(mergedConfig,os.path.join(outPath(),CFG_INCLUDE_IMPL),True)
embedded=getEmbeddedFiles(env) embedded=getEmbeddedFiles(env)
filedefs=[] filedefs=[]
for ef in embedded: for ef in embedded:

View File

@ -35,6 +35,12 @@ class GwApi{
class Status{ class Status{
public: public:
typedef enum{
OFF,
PRESSED,
PRESSED_5, //5...10s
PRESSED_10 //>10s...30s
} ButtonState;
bool wifiApOn=false; bool wifiApOn=false;
bool wifiClientOn=false; bool wifiClientOn=false;
bool wifiClientConnected=false; bool wifiClientConnected=false;
@ -47,6 +53,8 @@ class GwApi{
unsigned long usbTx=0; unsigned long usbTx=0;
unsigned long serRx=0; unsigned long serRx=0;
unsigned long serTx=0; unsigned long serTx=0;
unsigned long ser2Rx=0;
unsigned long ser2Tx=0;
unsigned long tcpSerRx=0; unsigned long tcpSerRx=0;
unsigned long tcpSerTx=0; unsigned long tcpSerTx=0;
int tcpClients=0; int tcpClients=0;
@ -55,6 +63,8 @@ class GwApi{
bool tcpClientConnected=false; bool tcpClientConnected=false;
unsigned long n2kRx=0; unsigned long n2kRx=0;
unsigned long n2kTx=0; unsigned long n2kTx=0;
ButtonState button=OFF;
unsigned long buttonPresses=0;
void empty(){ void empty(){
wifiApOn=false; wifiApOn=false;
wifiClientOn=false; wifiClientOn=false;
@ -68,6 +78,8 @@ class GwApi{
usbTx=0; usbTx=0;
serRx=0; serRx=0;
serTx=0; serTx=0;
ser2Rx=0;
ser2Tx=0;
tcpSerRx=0; tcpSerRx=0;
tcpSerTx=0; tcpSerTx=0;
tcpClients=0; tcpClients=0;
@ -75,7 +87,9 @@ class GwApi{
tcpClTx=0; tcpClTx=0;
tcpClientConnected=false; tcpClientConnected=false;
n2kRx=0; n2kRx=0;
n2kTx=0; n2kTx=0;
button=OFF;
buttonPresses=0;
} }
}; };
/** /**
@ -109,7 +123,14 @@ class GwApi{
/** /**
* fill the status information * fill the status information
*/ */
virtual void getStatus(Status &status); virtual void getStatus(Status &status)=0;
/**
* access to counters for a task
* thread safe
*/
virtual void setCounterDisplayName(const String &){}
virtual void increment(const String &name,bool failed=false){}
virtual void reset(){}
/** /**
* not thread safe methods * not thread safe methods
* accessing boat data must only be executed from within the main thread * accessing boat data must only be executed from within the main thread

View File

@ -322,6 +322,11 @@ void GwChannelList::fillStatus(GwApi::Status &status){
status.serRx=channel->countRx(); status.serRx=channel->countRx();
status.serTx=channel->countTx(); status.serTx=channel->countTx();
} }
channel=getChannelById(SERIAL2_CHANNEL_ID);
if (channel){
status.ser2Rx=channel->countRx();
status.ser2Tx=channel->countTx();
}
channel=getChannelById(MIN_TCP_CHANNEL_ID); channel=getChannelById(MIN_TCP_CHANNEL_ID);
if (channel){ if (channel){
status.tcpSerRx=channel->countRx(); status.tcpSerRx=channel->countRx();

View File

@ -1,8 +1,11 @@
#define CFG_MESSAGES #define CFG_MESSAGES
#include <Preferences.h>
#include "GWConfig.h" #include "GWConfig.h"
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <string.h> #include <string.h>
#include <MD5Builder.h> #include <MD5Builder.h>
#include "GwHardware.h"
#include "GwConfigDefImpl.h"
#define B(v) (v?"true":"false") #define B(v) (v?"true":"false")
@ -56,14 +59,20 @@ GwConfigInterface * GwConfigHandler::getConfigItem(const String name, bool dummy
GwConfigHandler::GwConfigHandler(GwLog *logger): GwConfigDefinitions(){ GwConfigHandler::GwConfigHandler(GwLog *logger): GwConfigDefinitions(){
this->logger=logger; this->logger=logger;
saltBase=esp_random(); saltBase=esp_random();
configs=new GwConfigInterface*[getNumConfig()];
populateConfigs(configs);
prefs=new Preferences();
}
GwConfigHandler::~GwConfigHandler(){
delete prefs;
} }
bool GwConfigHandler::loadConfig(){ bool GwConfigHandler::loadConfig(){
prefs.begin(PREF_NAME,true); prefs->begin(PREF_NAME,true);
for (int i=0;i<getNumConfig();i++){ for (int i=0;i<getNumConfig();i++){
String v=prefs.getString(configs[i]->getName().c_str(),configs[i]->getDefault()); String v=prefs->getString(configs[i]->getName().c_str(),configs[i]->getDefault());
configs[i]->value=v; configs[i]->value=v;
} }
prefs.end(); prefs->end();
return true; return true;
} }
@ -78,19 +87,19 @@ bool GwConfigHandler::updateValue(String name, String value){
return false; return false;
} }
LOG_DEBUG(GwLog::LOG,"update config %s=>%s",name.c_str(),i->isSecret()?"***":value.c_str()); LOG_DEBUG(GwLog::LOG,"update config %s=>%s",name.c_str(),i->isSecret()?"***":value.c_str());
prefs.begin(PREF_NAME,false); prefs->begin(PREF_NAME,false);
prefs.putString(i->getName().c_str(),value); prefs->putString(i->getName().c_str(),value);
prefs.end(); prefs->end();
} }
return true; return true;
} }
bool GwConfigHandler::reset(){ bool GwConfigHandler::reset(){
LOG_DEBUG(GwLog::LOG,"reset config"); LOG_DEBUG(GwLog::LOG,"reset config");
prefs.begin(PREF_NAME,false); prefs->begin(PREF_NAME,false);
for (int i=0;i<getNumConfig();i++){ for (int i=0;i<getNumConfig();i++){
prefs.putString(configs[i]->getName().c_str(),configs[i]->getDefault()); prefs->putString(configs[i]->getName().c_str(),configs[i]->getDefault());
} }
prefs.end(); prefs->end();
return true; return true;
} }
String GwConfigHandler::getString(const String name, String defaultv) const{ String GwConfigHandler::getString(const String name, String defaultv) const{

View File

@ -1,21 +1,20 @@
#ifndef _GWCONFIG_H #ifndef _GWCONFIG_H
#define _GWCONFIG_H #define _GWCONFIG_H
#include <Arduino.h> #include <Arduino.h>
#include <Preferences.h>
#include "GwLog.h" #include "GwLog.h"
#include "GwConfigItem.h" #include "GwConfigItem.h"
#include "GwHardware.h"
#include "GwConfigDefinitions.h" #include "GwConfigDefinitions.h"
#include <map> #include <map>
#include <vector> #include <vector>
class Preferences;
class GwConfigHandler: public GwConfigDefinitions{ class GwConfigHandler: public GwConfigDefinitions{
private: private:
Preferences prefs; Preferences *prefs;
GwLog *logger; GwLog *logger;
typedef std::map<String,String> StringMap; typedef std::map<String,String> StringMap;
boolean allowChanges=true; boolean allowChanges=true;
GwConfigInterface **configs;
public: public:
public: public:
GwConfigHandler(GwLog *logger); GwConfigHandler(GwLog *logger);
@ -40,7 +39,9 @@ class GwConfigHandler: public GwConfigDefinitions{
bool setValue(String name, String value); bool setValue(String name, String value);
static void toHex(unsigned long v,char *buffer,size_t bsize); static void toHex(unsigned long v,char *buffer,size_t bsize);
unsigned long getSaltBase(){return saltBase;} unsigned long getSaltBase(){return saltBase;}
~GwConfigHandler();
private: private:
unsigned long saltBase=0; unsigned long saltBase=0;
void populateConfigs(GwConfigInterface **);
}; };
#endif #endif

View File

@ -11,9 +11,12 @@ template<class T> class GwCounter{
unsigned long globalFail=0; unsigned long globalFail=0;
String name; String name;
public: public:
GwCounter(String name){ GwCounter(const String &name){
this->name=name; this->name=name;
}; };
void setName(const String &name){
this->name=name;
}
void reset(){ void reset(){
okCounter.clear(); okCounter.clear();
failCounter.clear(); failCounter.clear();

View File

@ -3,6 +3,7 @@
#ifdef BOARD_TEST #ifdef BOARD_TEST
#include "GwExampleTask.h" #include "GwExampleTask.h"
#include "GwApi.h" #include "GwApi.h"
#include "GWConfig.h"
#include <vector> #include <vector>
/** /**
@ -97,6 +98,7 @@ void exampleTask(GwApi *api){
GwApi::BoatValue *testValue=new GwApi::BoatValue(boatItemName); GwApi::BoatValue *testValue=new GwApi::BoatValue(boatItemName);
GwApi::BoatValue *valueList[]={longitude,latitude,testValue}; GwApi::BoatValue *valueList[]={longitude,latitude,testValue};
GwApi::Status status; GwApi::Status status;
api->setCounterDisplayName("usertest");
while(true){ while(true){
delay(1000); delay(1000);
/* /*
@ -193,7 +195,9 @@ void exampleTask(GwApi *api){
status.tcpClRx, status.tcpClRx,
status.tcpClTx, status.tcpClTx,
status.n2kRx, status.n2kRx,
status.n2kTx); status.n2kTx);
//increment some counter
api->increment("Test");
} }
vTaskDelete(NULL); vTaskDelete(NULL);

View File

@ -2,32 +2,11 @@
#include "GwApi.h" #include "GwApi.h"
//we only compile for some boards //we only compile for some boards
#ifdef BOARD_TEST #ifdef BOARD_TEST
//we could add the following defines also in our local platformio.ini
#define ESP32_CAN_TX_PIN GPIO_NUM_22 //CAN base
#define ESP32_CAN_RX_PIN GPIO_NUM_19 #define M5_CAN_KIT
//if using tail485 //RS485 on groove
#define GWSERIAL_TX 26 #define SERIAL_GROOVE_485
#define GWSERIAL_RX 32
#define GWSERIAL_MODE "UNI"
#define GWSERIAL2_TX 14
#define GWSERIAL2_RX 15
#define GWSERIAL2_MODE "BI"
#define GWBUTTON_PIN GPIO_NUM_39
#define GWBUTTON_ACTIVE LOW
//if GWBUTTON_PULLUPDOWN we enable a pulup/pulldown
#define GWBUTTON_PULLUPDOWN
//led handling
//if we define GWLED_FASTNET the arduino fastnet lib is used
#define GWLED_FASTLED
#define GWLED_TYPE SK6812
//color schema for fastled
#define GWLED_SCHEMA GRB
#define GWLED_PIN GPIO_NUM_27
//brightness 0...255
#define GWLED_BRIGHTNESS 64
#define USBSerial Serial
void exampleTask(GwApi *param); void exampleTask(GwApi *param);
void exampleInit(GwApi *param); void exampleInit(GwApi *param);

View File

@ -1,8 +1,15 @@
#define DECLARE_USERTASK(task) GwUserTaskDef __##task##__(task,#task);
#define DECLARE_USERTASK_PARAM(task,...) GwUserTaskDef __##task##__(task,#task,__VA_ARGS__);
#define DECLARE_INITFUNCTION(task) GwInitTask __Init##task##__(task,#task);
#define DECLARE_CAPABILITY(name,value) GwUserCapability __CAP##name##__(#name,#value);
#define DECLARE_STRING_CAPABILITY(name,value) GwUserCapability __CAP##name##__(#name,value);
#include "GwUserCode.h" #include "GwUserCode.h"
#include "GwSynchronized.h" #include "GwSynchronized.h"
#include <Arduino.h> #include <Arduino.h>
#include <vector> #include <vector>
#include <map> #include <map>
#include "GwCounter.h"
//user task handling //user task handling
@ -38,25 +45,24 @@ class GwUserCapability{
userCapabilities[name]=value; userCapabilities[name]=value;
} }
}; };
#define DECLARE_USERTASK(task) GwUserTaskDef __##task##__(task,#task);
#define DECLARE_USERTASK_PARAM(task,...) GwUserTaskDef __##task##__(task,#task,__VA_ARGS__);
#define DECLARE_INITFUNCTION(task) GwInitTask __Init##task##__(task,#task);
#define DECLARE_CAPABILITY(name,value) GwUserCapability __CAP##name##__(#name,#value);
#define DECLARE_STRING_CAPABILITY(name,value) GwUserCapability __CAP##name##__(#name,value);
#include "GwApi.h"
#include "GwUserTasks.h" #include "GwUserTasks.h"
class TaskApi : public GwApi class TaskApi : public GwApiInternal
{ {
GwApi *api; GwApiInternal *api;
int sourceId; int sourceId;
SemaphoreHandle_t *mainLock; SemaphoreHandle_t *mainLock;
SemaphoreHandle_t localLock;
GwCounter<String> *counter=NULL;
bool counterUsed=false;
public: public:
TaskApi(GwApi *api, int sourceId, SemaphoreHandle_t *mainLock) TaskApi(GwApiInternal *api, int sourceId, SemaphoreHandle_t *mainLock, const String &name)
{ {
this->sourceId = sourceId; this->sourceId = sourceId;
this->api = api; this->api = api;
this->mainLock=mainLock; this->mainLock=mainLock;
localLock=xSemaphoreCreateMutex();
counter=new GwCounter<String>("count"+name);
} }
virtual GwRequestQueue *getQueue() virtual GwRequestQueue *getQueue()
{ {
@ -104,10 +110,39 @@ public:
GWSYNCHRONIZED(mainLock); GWSYNCHRONIZED(mainLock);
api->getStatus(status); api->getStatus(status);
} }
virtual ~TaskApi(){}; virtual ~TaskApi(){
vSemaphoreDelete(localLock);
delete counter;
};
virtual void fillStatus(GwJsonDocument &status){
GWSYNCHRONIZED(&localLock);
if (! counterUsed) return;
return counter->toJson(status);
};
virtual int getJsonSize(){
GWSYNCHRONIZED(&localLock);
if (! counterUsed) return 0;
return counter->getJsonSize();
};
virtual void increment(const String &name,bool failed=false){
GWSYNCHRONIZED(&localLock);
counterUsed=true;
if (failed) counter->addFail(name);
else (counter->add(name));
};
virtual void reset(){
GWSYNCHRONIZED(&localLock);
counterUsed=true;
counter->reset();
};
virtual void setCounterDisplayName(const String &name){
GWSYNCHRONIZED(&localLock);
counterUsed=true;
counter->setName("count"+name);
}
}; };
GwUserCode::GwUserCode(GwApi *api,SemaphoreHandle_t *mainLock){ GwUserCode::GwUserCode(GwApiInternal *api,SemaphoreHandle_t *mainLock){
this->logger=api->getLogger(); this->logger=api->getLogger();
this->api=api; this->api=api;
this->mainLock=mainLock; this->mainLock=mainLock;
@ -123,8 +158,8 @@ void userTaskStart(void *p){
delete task->api; delete task->api;
task->api=NULL; task->api=NULL;
} }
void GwUserCode::startAddOnTask(GwApi *api,GwUserTask *task,int sourceId,String name){ void GwUserCode::startAddOnTask(GwApiInternal *api,GwUserTask *task,int sourceId,String name){
task->api=new TaskApi(api,sourceId,mainLock); task->api=new TaskApi(api,sourceId,mainLock,name);
xTaskCreate(userTaskStart,name.c_str(),task->stackSize,task,3,NULL); xTaskCreate(userTaskStart,name.c_str(),task->stackSize,task,3,NULL);
} }
void GwUserCode::startUserTasks(int baseId){ void GwUserCode::startUserTasks(int baseId){
@ -139,7 +174,7 @@ void GwUserCode::startInitTasks(int baseId){
LOG_DEBUG(GwLog::DEBUG,"starting %d user init tasks",initTasks.size()); LOG_DEBUG(GwLog::DEBUG,"starting %d user init tasks",initTasks.size());
for (auto it=initTasks.begin();it != initTasks.end();it++){ for (auto it=initTasks.begin();it != initTasks.end();it++){
LOG_DEBUG(GwLog::LOG,"starting user init task %s with id %d",it->name.c_str(),baseId); LOG_DEBUG(GwLog::LOG,"starting user init task %s with id %d",it->name.c_str(),baseId);
it->api=new TaskApi(api,baseId,mainLock); it->api=new TaskApi(api,baseId,mainLock,it->name);
userTaskStart(&(*it)); userTaskStart(&(*it));
baseId++; baseId++;
} }
@ -152,4 +187,21 @@ void GwUserCode::startAddonTask(String name, TaskFunction_t task, int id){
GwUserCode::Capabilities * GwUserCode::getCapabilities(){ GwUserCode::Capabilities * GwUserCode::getCapabilities(){
return &userCapabilities; return &userCapabilities;
}
void GwUserCode::fillStatus(GwJsonDocument &status){
for (auto it=userTasks.begin();it != userTasks.end();it++){
if (it->api){
it->api->fillStatus(status);
}
}
}
int GwUserCode::getJsonSize(){
int rt=0;
for (auto it=userTasks.begin();it != userTasks.end();it++){
if (it->api){
rt+=it->api->getJsonSize();
}
}
return rt;
} }

View File

@ -2,16 +2,24 @@
#define _GWUSERCODE_H #define _GWUSERCODE_H
#include <Arduino.h> #include <Arduino.h>
#include <map> #include <map>
#include "GwApi.h"
#include "GwJsonDocument.h"
class GwLog; class GwLog;
class GwApi;
typedef void (*GwUserTaskFunction)(GwApi *); typedef void (*GwUserTaskFunction)(GwApi *);
class GwApiInternal : public GwApi{
public:
~GwApiInternal(){}
virtual void fillStatus(GwJsonDocument &status){};
virtual int getJsonSize(){return 0;};
};
class GwUserTask{ class GwUserTask{
public: public:
String name; String name;
TaskFunction_t task=NULL; TaskFunction_t task=NULL;
GwUserTaskFunction usertask=NULL; GwUserTaskFunction usertask=NULL;
bool isUserTask=false; bool isUserTask=false;
GwApi *api=NULL; GwApiInternal *api=NULL;
int stackSize=2000; int stackSize=2000;
GwUserTask(String name,TaskFunction_t task,int stackSize=2000){ GwUserTask(String name,TaskFunction_t task,int stackSize=2000){
this->name=name; this->name=name;
@ -25,17 +33,21 @@ class GwUserTask{
this->stackSize=stackSize; this->stackSize=stackSize;
} }
}; };
class GwUserCode{ class GwUserCode{
GwLog *logger; GwLog *logger;
GwApi *api; GwApiInternal *api;
SemaphoreHandle_t *mainLock; SemaphoreHandle_t *mainLock;
void startAddOnTask(GwApi *api,GwUserTask *task,int sourceId,String name); void startAddOnTask(GwApiInternal *api,GwUserTask *task,int sourceId,String name);
public: public:
typedef std::map<String,String> Capabilities; typedef std::map<String,String> Capabilities;
GwUserCode(GwApi *api, SemaphoreHandle_t *mainLock); GwUserCode(GwApiInternal *api, SemaphoreHandle_t *mainLock);
void startUserTasks(int baseId); void startUserTasks(int baseId);
void startInitTasks(int baseId); void startInitTasks(int baseId);
void startAddonTask(String name,TaskFunction_t task, int id); void startAddonTask(String name,TaskFunction_t task, int id);
Capabilities *getCapabilities(); Capabilities *getCapabilities();
void fillStatus(GwJsonDocument &status);
int getJsonSize();
}; };
#endif #endif

View File

@ -235,7 +235,7 @@ void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId,bool conv
}); });
} }
class ApiImpl : public GwApi class ApiImpl : public GwApiInternal
{ {
private: private:
int sourceId = -1; int sourceId = -1;
@ -374,7 +374,8 @@ protected:
GwJsonDocument status(300 + GwJsonDocument status(300 +
countNMEA2KIn.getJsonSize()+ countNMEA2KIn.getJsonSize()+
countNMEA2KOut.getJsonSize() + countNMEA2KOut.getJsonSize() +
channels.getJsonSize() channels.getJsonSize()+
userCodeHandler.getJsonSize()
); );
status["version"] = VERSION; status["version"] = VERSION;
status["wifiConnected"] = gwWifi.clientConnected(); status["wifiConnected"] = gwWifi.clientConnected();
@ -406,6 +407,7 @@ protected:
countNMEA2KIn.toJson(status); countNMEA2KIn.toJson(status);
countNMEA2KOut.toJson(status); countNMEA2KOut.toJson(status);
channels.toJson(status); channels.toJson(status);
userCodeHandler.fillStatus(status);
serializeJson(status, result); serializeJson(status, result);
} }
}; };