1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-14 14:33:07 +01:00

Merge branch 'wellenvogel:master' into master

This commit is contained in:
Norbert Walter
2024-11-30 17:03:11 +01:00
committed by GitHub
41 changed files with 804 additions and 578 deletions

View File

@@ -9,6 +9,9 @@
#include "GwSynchronized.h"
#include <map>
#include <ESPAsyncWebServer.h>
#include "GwSensor.h"
#include <functional>
#include <memory>
class GwApi;
typedef void (*GwUserTaskFunction)(GwApi *);
//API to be used for additional tasks
@@ -43,11 +46,7 @@ class GwApi{
* the core part will not handle this data at all but
* this interface ensures that there is a correct locking of the
* data to correctly handle multi threading
* The user code should not use this intterface directly
* but instead it should use the static functions
* apiGetXXX(GwApi *,...)
* apiSetXXX(GwApi *,...)
* that will be created by the macro DECLARE_TASK_INTERFACE
* there is no protection - i.e. every task can get and set the data
*/
class TaskInterfaces
{
@@ -61,9 +60,9 @@ class GwApi{
};
using Ptr = std::shared_ptr<Base>;
protected:
virtual bool iset(const String &file, const String &name, Ptr v) = 0;
virtual bool iset(const String &name, Ptr v) = 0;
virtual Ptr iget(const String &name, int &result) = 0;
virtual bool iclaim(const String &name, const String &task)=0;
virtual bool iupdate(const String &name,std::function<Ptr(Ptr v)>)=0;
public:
template <typename T>
bool set(const T &v){
@@ -76,6 +75,10 @@ class GwApi{
}
template <typename T>
bool claim(const String &task){
return true;
}
template <typename T>
bool update(std::function<bool(T *)>){
return false;
}
};
@@ -206,7 +209,13 @@ class GwApi{
* @param name: the config name this value is used for
* @param value: the current value
*/
virtual void setCalibrationValue(const String &name, double value);
virtual void setCalibrationValue(const String &name, double value)=0;
/**
* add a sensor
* depending on the type it will be added to the appropriate task
* @param sensor: created sensor config
*/
virtual void addSensor(SensorBase* sensor,bool readConfig=true){};
/**
* not thread safe methods
@@ -231,7 +240,10 @@ static void checkDef(T... args){};
#define DECLARE_USERTASK_PARAM(task,...)
#endif
#ifndef DECLARE_INITFUNCTION
#define DECLARE_INITFUNCTION(task)
#define DECLARE_INITFUNCTION(task,...)
#endif
#ifndef DECLARE_INITFUNCTION_ORDER
#define DECLARE_INITFUNCTION_ORDER(task,...)
#endif
#ifndef DECLARE_CAPABILITY
#define DECLARE_CAPABILITY(name,value)
@@ -255,27 +267,20 @@ static void checkDef(T... args){};
* int ival2=99;
* String sval="unset";
* };
* DECLARE_TASKIF(testTask,TestTaskApi);
* The macro will generate 2 static funtions:
* DECLARE_TASKIF(TestTaskApi);
*
* bool apiSetTestTaskApi(GwApi *api, const TestTaskApi &v);
* TestTaskApi apiGetTestTaskApi(GwApi *api, int &result);
*
* The setter will return true on success.
* It is intended to be used by the task that did declare the api.
* The getter will set the result to -1 if no data is available, otherwise
* it will return the update count (so you can check if there was a change
* compared to the last call).
* It is intended to be used by any task.
* Be aware that all the apis share a common namespace - so be sure to somehow
* make your API names unique.
*
* To utilize this interface a task can call:
* api->taskInterfaces()->get<TestTaskApi>(res) //and check the result in res
* api->taskInterfaces()->set<TestTaskApi>(value)
*
*/
#define DECLARE_TASKIF_IMPL(type) \
template<> \
inline bool GwApi::TaskInterfaces::set(const type & v) {\
return iset(__FILE__,#type,GwApi::TaskInterfaces::Ptr(new type(v))); \
return iset(#type,GwApi::TaskInterfaces::Ptr(new type(v))); \
}\
template<> \
inline type GwApi::TaskInterfaces::get<type>(int &result) {\
@@ -286,13 +291,42 @@ static void checkDef(T... args){};
}\
type *tp=(type*)ptr.get(); \
return type(*tp); \
}\
} \
template<> \
inline bool GwApi::TaskInterfaces::claim<type>(const String &task) {\
return iclaim(#type,task);\
}\
inline bool GwApi::TaskInterfaces::update(std::function<bool(type *)> f) { \
return iupdate(#type,[f](GwApi::TaskInterfaces::Ptr cp)->GwApi::TaskInterfaces::Ptr{ \
if (cp) { \
f((type *)cp.get()); \
return cp; \
} \
type * et=new type(); \
bool res=f(et); \
if (! res){ \
delete et; \
return GwApi::TaskInterfaces::Ptr(); \
} \
return GwApi::TaskInterfaces::Ptr(et); \
}); \
} \
#ifndef DECLARE_TASKIF
#define DECLARE_TASKIF(type) DECLARE_TASKIF_IMPL(type)
#endif
/**
* do not use this interface directly
* instead use the API function addSensor
*/
class ConfiguredSensors : public GwApi::TaskInterfaces::Base{
public:
SensorList sensors;
};
DECLARE_TASKIF(ConfiguredSensors);
//order for late init functions
//all user tasks should have lower orders (default: 0)
#define GWLATEORDER 9999
#endif

View File

@@ -427,6 +427,7 @@ void GwChannelList::begin(bool fallbackSerial){
if (! fallbackSerial){
GwSerial *usbSerial=createSerialImpl(config, logger,USB_CHANNEL_ID,GWUSB_RX,GWUSB_TX,true);
if (usbSerial != nullptr){
usbSerial->enableWriteLock(); //as it is used for logging we need this additionally
GwChannel *usbChannel=createChannel(logger,config,USB_CHANNEL_ID,usbSerial,GWSERIAL_TYPE_BI);
if (usbChannel != nullptr){
addChannel(usbChannel);

View File

@@ -71,9 +71,12 @@ class GwConverterConfig{
int rmcInterval=1000;
int rmcCheckTime=4000;
int winst312=256;
bool unmappedXdr=false;
unsigned long xdrTimeout=60000;
std::vector<WindMapping> windMappings;
void init(GwConfigHandler *config, GwLog*logger){
minXdrInterval=config->getInt(GwConfigDefinitions::minXdrInterval,100);
xdrTimeout=config->getInt(GwConfigDefinitions::timoSensor);
starboardRudderInstance=config->getInt(GwConfigDefinitions::stbRudderI,0);
portRudderInstance=config->getInt(GwConfigDefinitions::portRudderI,-1);
min2KInterval=config->getInt(GwConfigDefinitions::min2KInterval,50);
@@ -83,6 +86,7 @@ class GwConverterConfig{
rmcInterval=config->getInt(GwConfigDefinitions::sendRMCi,1000);
if (rmcInterval < 0) rmcInterval=0;
if (rmcInterval > 0 && rmcInterval <100) rmcInterval=100;
unmappedXdr=config->getBool(GwConfigDefinitions::unknownXdr);
winst312=config->getInt(GwConfigDefinitions::winst312,256);
for (auto && it:windConfigs){
String cfg=config->getString(it.second);

View File

@@ -156,11 +156,11 @@ class ExampleWebData{
vSemaphoreDelete(lock);
}
void set(int v){
GWSYNCHRONIZED(&lock);
GWSYNCHRONIZED(lock);
data=v;
}
int get(){
GWSYNCHRONIZED(&lock);
GWSYNCHRONIZED(lock);
return data;
}
};

View File

@@ -108,7 +108,7 @@ void GwWifi::loop(){
}
else{
if (! clientIsConnected){
LOG_DEBUG(GwLog::LOG,"wifiClient %s now connected to",wifiSSID->asCString());
LOG_DEBUG(GwLog::LOG,"wifiClient now connected to %s at %s",wifiSSID->asCString(),WiFi.localIP().toString().c_str());
clientIsConnected=true;
}
}

View File

@@ -64,15 +64,15 @@
#endif
#GROVE
#ifdef M5_ENV4$GS$
#ifndef M5_GROOVEIIC$GS$
#define M5_GROOVEIIC$GS$
#endif
GROOVE_IIC(SHT3X,$Z$,1)
GROOVE_IIC(BMP280,$Z$,1)
#define _GWSHT3X
#define _GWBMP280
#endif
//#ifdef M5_ENV4$GS$
// #ifndef M5_GROOVEIIC$GS$
// #define M5_GROOVEIIC$GS$
// #endif
// GROOVE_IIC(SHT3X,$Z$,1)
// GROOVE_IIC(BMP280,$Z$,1)
// #define _GWSHT3X
// #define _GWBMP280
//#endif
#GROVE
//example: -DSHT3XG1_A : defines STH3Xn1 on grove A - x depends on the other devices

View File

@@ -15,11 +15,9 @@
#include <Adafruit_BME280.h>
#endif
#ifdef _GWBME280
#define TYPE "BME280"
#define PRFX1 TYPE "11"
#define PRFX2 TYPE "12"
#define PRFX3 TYPE "21"
#define PRFX4 TYPE "22"
class BME280Config;
static GwSensorConfigInitializerList<BME280Config> configs;
class BME280Config : public IICSensorBase{
public:
bool prAct=true;
@@ -35,7 +33,7 @@ class BME280Config : public IICSensorBase{
float prOff=0;
Adafruit_BME280 *device=nullptr;
uint32_t sensorId=-1;
BME280Config(GwApi * api, const String &prfx):SensorBase(TYPE,api,prfx){
BME280Config(GwApi * api, const String &prfx):IICSensorBase(api,prfx){
}
virtual bool isActive(){return prAct||huAct||tmAct;}
virtual bool initDevice(GwApi *api,TwoWire *wire){
@@ -57,7 +55,6 @@ class BME280Config : public IICSensorBase{
virtual bool preinit(GwApi * api){
GwLog *logger=api->getLogger();
LOG_DEBUG(GwLog::LOG,"%s configured",prefix.c_str());
api->addCapability(prefix,"true");
addPressureXdr(api,*this);
addTempXdr(api,*this);
addHumidXdr(api,*this);
@@ -97,96 +94,80 @@ class BME280Config : public IICSensorBase{
sendN2kEnvironmentalParameters(api, *this, temperature, humidity, computed,counterId);
}
}
#define CFG280(prefix) \
CFG_GET(prAct,prefix); \
CFG_GET(tmAct,prefix);\
CFG_GET(huAct,prefix);\
CFG_GET(tmSrc,prefix);\
CFG_GET(huSrc,prefix);\
CFG_GET(iid,prefix);\
CFG_GET(intv,prefix);\
CFG_GET(tmNam,prefix);\
CFG_GET(huNam,prefix);\
CFG_GET(prNam,prefix);\
CFG_GET(tmOff,prefix);\
CFG_GET(prOff,prefix);
virtual void readConfig(GwConfigHandler *cfg) override
{
if (ok) return;
if (prefix == PRFX1)
{
busId = 1;
addr = 0x76;
CFG280(BME28011);
ok=true;
}
if (prefix == PRFX2)
{
busId = 1;
addr = 0x77;
CFG280(BME28012);
ok=true;
}
if (prefix == PRFX3)
{
busId = 2;
addr = 0x76;
CFG280(BME28021);
ok=true;
}
if (prefix == PRFX4)
{
busId = 2;
addr = 0x77;
CFG280(BME28022);
ok=true;
}
intv *= 1000;
configs.readConfig(this,cfg);
}
};
static IICSensorBase::Creator creator([](GwApi *api, const String &prfx){
static SensorBase::Creator creator([](GwApi *api, const String &prfx){
return new BME280Config(api,prfx);
});
IICSensorBase::Creator registerBME280(GwApi *api,IICSensorList &sensors){
#if defined(GWBME280) || defined(GWBME28011)
SensorBase::Creator registerBME280(GwApi *api){
#if defined(GWBME280) || defined(GWBME28011)
{
auto *cfg=creator(api,PRFX1);
sensors.add(api,cfg);
api->addSensor(creator(api,"BME28011"));
CHECK_IIC1();
#pragma message "GWBME28011 defined"
}
#endif
#if defined(GWBME28012)
#endif
#if defined(GWBME28012)
{
auto *cfg=creator(api,PRFX2);
sensors.add(api,cfg);
api->addSensor(creator(api,"BME28012"));
CHECK_IIC1();
#pragma message "GWBME28012 defined"
}
#endif
#if defined(GWBME28021)
#endif
#if defined(GWBME28021)
{
auto *cfg=creator(api,PRFX3);
sensors.add(api,cfg);
api->addSensor(creator(api,"BME28021"));
CHECK_IIC2();
#pragma message "GWBME28021 defined"
}
#endif
#if defined(GWBME28022)
#endif
#if defined(GWBME28022)
{
auto *cfg=creator(api,PRFX4);
sensors.add(api,cfg);
api->addSensor(creator(api,"BME28022"));
CHECK_IIC1();
#pragma message "GWBME28022 defined"
}
#endif
#endif
return creator;
}
#define CFG280(s, prefix, bus, baddr) \
CFG_SGET(s, prAct, prefix); \
CFG_SGET(s, tmAct, prefix); \
CFG_SGET(s, huAct, prefix); \
CFG_SGET(s, tmSrc, prefix); \
CFG_SGET(s, huSrc, prefix); \
CFG_SGET(s, iid, prefix); \
CFG_SGET(s, intv, prefix); \
CFG_SGET(s, tmNam, prefix); \
CFG_SGET(s, huNam, prefix); \
CFG_SGET(s, prNam, prefix); \
CFG_SGET(s, tmOff, prefix); \
CFG_SGET(s, prOff, prefix); \
s->busId = bus; \
s->addr = baddr; \
s->ok = true; \
s->intv *= 1000;
#define SCBME280(list, prefix, bus, addr) \
GWSENSORCONFIG(list, BME280Config, prefix, [](BME280Config *s, GwConfigHandler *cfg) { CFG280(s, prefix, bus, addr); });
SCBME280(configs,BME28011,1,0x76);
SCBME280(configs,BME28012,1,0x77);
SCBME280(configs,BME28021,2,0x76);
SCBME280(configs,BME28022,2,0x77);
#else
IICSensorBase::Creator registerBME280(GwApi *api,IICSensorList &sensors){
return IICSensorBase::Creator();
SensorBase::Creator registerBME280(GwApi *api){
return SensorBase::Creator();
}
#endif

View File

@@ -1,5 +1,5 @@
#ifndef _GWBME280_H
#define _GWBME280_H
#include "GwIicSensors.h"
IICSensorBase::Creator registerBME280(GwApi *api,IICSensorList &sensors);
SensorBase::Creator registerBME280(GwApi *api);
#endif

View File

@@ -15,11 +15,16 @@
#include <Adafruit_BMP280.h>
#endif
#ifdef _GWBMP280
#define TYPE "BMP280"
#define PRFX1 TYPE "11"
#define PRFX2 TYPE "12"
#define PRFX3 TYPE "21"
#define PRFX4 TYPE "22"
/**
* we need a forward declaration here as the config list has to go before the
* class implementation
*/
class BMP280Config;
static GwSensorConfigInitializerList<BMP280Config> configs;
class BMP280Config : public IICSensorBase{
public:
bool prAct=true;
@@ -33,14 +38,13 @@ class BMP280Config : public IICSensorBase{
float prOff=0;
Adafruit_BMP280 *device=nullptr;
uint32_t sensorId=-1;
BMP280Config(GwApi * api, const String &prfx):SensorBase(TYPE,api,prfx){
}
using IICSensorBase::IICSensorBase;
virtual bool isActive(){return prAct||tmAct;}
virtual bool initDevice(GwApi *api,TwoWire *wire){
GwLog *logger=api->getLogger();
device= new Adafruit_BMP280(wire);
if (! device->begin(addr)){
LOG_DEBUG(GwLog::ERROR,"unable to initialize %s at %d",prefix.c_str(),addr);
LOG_DEBUG(GwLog::ERROR,"unable to initialize %s at 0x%x",prefix.c_str(),addr);
delete device;
device=nullptr;
return false;
@@ -52,7 +56,6 @@ class BMP280Config : public IICSensorBase{
virtual bool preinit(GwApi * api){
GwLog *logger=api->getLogger();
LOG_DEBUG(GwLog::LOG,"%s configured",prefix.c_str());
api->addCapability(prefix,"true");
addPressureXdr(api,*this);
addTempXdr(api,*this);
return isActive();
@@ -85,96 +88,90 @@ class BMP280Config : public IICSensorBase{
sendN2kEnvironmentalParameters(api, *this, temperature, humidity, computed,counterId);
}
}
#define CFGBMP280(prefix) \
CFG_GET(prAct,prefix); \
CFG_GET(tmAct,prefix);\
CFG_GET(tmSrc,prefix);\
CFG_GET(iid,prefix);\
CFG_GET(intv,prefix);\
CFG_GET(tmNam,prefix);\
CFG_GET(prNam,prefix);\
CFG_GET(tmOff,prefix);\
CFG_GET(prOff,prefix);
virtual void readConfig(GwConfigHandler *cfg) override
{
if (prefix == PRFX1)
{
busId = 1;
addr = 0x76;
CFGBMP280(BMP28011);
ok=true;
}
if (prefix == PRFX2)
{
busId = 1;
addr = 0x77;
CFGBMP280(BMP28012);
ok=true;
}
if (prefix == PRFX3)
{
busId = 2;
addr = 0x76;
CFGBMP280(BMP28021);
ok=true;
}
if (prefix == PRFX4)
{
busId = 2;
addr = 0x77;
CFGBMP280(BMP28022);
ok=true;
}
intv *= 1000;
if (ok) return;
configs.readConfig(this,cfg);
}
};
static IICSensorBase::Creator creator([](GwApi *api, const String &prfx){
static SensorBase::Creator creator([](GwApi *api, const String &prfx)->BMP280Config*{
if (! configs.knowsPrefix(prfx)){
return nullptr;
}
return new BMP280Config(api,prfx);
});
IICSensorBase::Creator registerBMP280(GwApi *api,IICSensorList &sensors){
SensorBase::Creator registerBMP280(GwApi *api){
#if defined(GWBMP280) || defined(GWBMP28011)
{
auto *cfg=creator(api,PRFX1);
//BMP280Config *cfg=new BMP280Config(api,PRFX1);
sensors.add(api,cfg);
api->addSensor(creator(api,"BMP28011"));
CHECK_IIC1();
#pragma message "GWBMP28011 defined"
}
#endif
#if defined(GWBMP28012)
{
auto *cfg=creator(api,PRFX2);
//BMP280Config *cfg=new BMP280Config(api,PRFX2);
sensors.add(api,cfg);
api->addSensor(creator(api,"BMP28012"));
CHECK_IIC1();
#pragma message "GWBMP28012 defined"
}
#endif
#if defined(GWBMP28021)
{
auto *cfg=creator(api,PRFX3);
//BMP280Config *cfg=new BMP280Config(api,PRFX3);
sensors.add(api,cfg);
api->addSensor(creator(api,"BMP28021"));
CHECK_IIC2();
#pragma message "GWBMP28021 defined"
}
#endif
#if defined(GWBMP28022)
{
auto *cfg=creator(api,PRFX4);
//BMP280Config *cfg=new BMP280Config(api,PRFX4);
sensors.add(api,cfg);
api->addSensor(creator(api,"BMP28022"));
CHECK_IIC1();
#pragma message "GWBMP28022 defined"
}
#endif
return creator;
}
/**
* a define for the readConfig function
* we use a define here as we want to be able to check the config
* definitions at compile time
*/
#define CFGBMP280P(s, prefix, bus, baddr) \
CFG_SGET(s, prAct, prefix); \
CFG_SGET(s, tmAct, prefix); \
CFG_SGET(s, tmSrc, prefix); \
CFG_SGET(s, iid, prefix); \
CFG_SGET(s, intv, prefix); \
CFG_SGET(s, tmNam, prefix); \
CFG_SGET(s, prNam, prefix); \
CFG_SGET(s, tmOff, prefix); \
CFG_SGET(s, prOff, prefix); \
s->busId = bus; \
s->addr = baddr; \
s->ok = true; \
s->intv*=1000;
/**
* a config initializer for our sensor
*/
#define SCBMP280(list, prefix, bus, addr) \
GWSENSORCONFIG(list, BMP280Config, prefix, [](BMP280Config *s, GwConfigHandler *cfg) { CFGBMP280P(s, prefix, bus, addr); });
/**
* four possible sensor configs
*/
SCBMP280(configs, BMP28011, 1, 0x76);
SCBMP280(configs, BMP28012, 1, 0x77);
SCBMP280(configs, BMP28021, 2, 0x76);
SCBMP280(configs, BMP28022, 2, 0x77);
#else
IICSensorBase::Creator registerBMP280(GwApi *api,IICSensorList &sensors){
return IICSensorBase::Creator();
SensorBase::Creator registerBMP280(GwApi *api){
return SensorBase::Creator();
}
#endif

View File

@@ -1,6 +1,6 @@
#ifndef _GWBMP280_H
#define _GWBMP280_H
#include "GwIicSensors.h"
IICSensorBase::Creator registerBMP280(GwApi *api,IICSensorList &sensors);
SensorBase::Creator registerBMP280(GwApi *api);
#endif

View File

@@ -11,9 +11,9 @@
class TwoWire;
#endif
using BusType=TwoWire;
using IICSensorList=SensorList<BusType>;
using IICSensorBase=SensorBase<BusType>;
using BUSTYPE=TwoWire;
using IICSensorList=SensorList;
using IICSensorBase=SensorTemplate<BUSTYPE,SensorBase::IIC>;
template <class CFG>

View File

@@ -43,8 +43,7 @@ static std::vector<IICGrove> iicGroveList;
void runIicTask(GwApi *api);
static IICSensorList sensors;
static void addGroveItems(std::vector<IICSensorBase::Creator> &creators,GwApi *api, IICSensorList &sensors, const String &bus,const String &grove, int, int)
static void addGroveItems(std::vector<SensorBase::Creator> &creators,GwApi *api, const String &bus,const String &grove, int, int)
{
GwLog *logger=api->getLogger();
for (auto &&init : iicGroveList)
@@ -61,17 +60,18 @@ static void addGroveItems(std::vector<IICSensorBase::Creator> &creators,GwApi *a
{
if (! creator) continue;
auto *scfg = creator(api, prfx);
if (scfg == nullptr) continue;
scfg->readConfig(api->getConfig());
if (scfg->ok)
{
LOG_DEBUG(GwLog::LOG, "adding %s from grove config", prfx.c_str());
sensors.add(api, scfg);
api->addSensor(scfg,false);
found=true;
break;
}
else
{
LOG_DEBUG(GwLog::DEBUG, "unmatched grove sensor config %s for %s", prfx.c_str(), scfg->type.c_str());
LOG_DEBUG(GwLog::DEBUG, "unmatched grove sensor config %s", prfx.c_str());
delete scfg;
}
}
@@ -89,19 +89,26 @@ void initIicTask(GwApi *api){
#else
bool addTask=false;
GwConfigHandler *config=api->getConfig();
std::vector<IICSensorBase::Creator> creators;
creators.push_back(registerSHT3X(api,sensors));
creators.push_back(registerQMP6988(api,sensors));
creators.push_back(registerBME280(api,sensors));
creators.push_back(registerBMP280(api,sensors));
std::vector<SensorBase::Creator> creators;
creators.push_back(registerSHT3X(api));
creators.push_back(registerQMP6988(api));
creators.push_back(registerBME280(api));
creators.push_back(registerBMP280(api));
#ifdef _GWI_IIC1
addGroveItems(creators,api,sensors,"1",_GWI_IIC1);
addGroveItems(creators,api,"1",_GWI_IIC1);
#endif
#ifdef _GWI_IIC2
addGroveItems(creators,api,sensors,"2",_GWI_IIC2);
addGroveItems(creators,api,"2",_GWI_IIC2);
#endif
for (auto it=sensors.begin();it != sensors.end();it++){
if ((*it)->preinit(api)) addTask=true;
//TODO: ensure that we run after other init tasks...
int res=-1;
ConfiguredSensors sensorList=api->taskInterfaces()->get<ConfiguredSensors>(res);
for (auto &&it: sensorList.sensors){
if (it->busType != SensorBase::IIC) continue;
if (it->preinit(api)) {
addTask=true;
api->addCapability(it->prefix,"true");
}
}
if (addTask){
api->addUserTask(runIicTask,"iicTask",4000);
@@ -154,8 +161,11 @@ void runIicTask(GwApi *api){
GwLog *logger=api->getLogger();
std::map<int,TwoWire *> buses;
LOG_DEBUG(GwLog::LOG,"iic task started");
for (auto it=sensors.begin();it != sensors.end();it++){
int busId=(*it)->busId;
int res=-1;
ConfiguredSensors sensorList=api->taskInterfaces()->get<ConfiguredSensors>(res);
for (auto &&it : sensorList.sensors){
if (it->busType != SensorBase::IIC) continue;
int busId=it->busId;
auto bus=buses.find(busId);
if (bus == buses.end()){
switch (busId)
@@ -175,7 +185,7 @@ void runIicTask(GwApi *api){
}
break;
default:
LOG_DEBUG(GwLog::ERROR, "invalid bus id %d at config %s", busId, (*it)->prefix.c_str());
LOG_DEBUG(GwLog::ERROR, "invalid bus id %d at config %s", busId, it->prefix.c_str());
break;
}
}
@@ -184,8 +194,8 @@ void runIicTask(GwApi *api){
bool runLoop=false;
GwIntervalRunner timers;
int counterId=api->addCounter("iicsensors");
for (auto it=sensors.begin();it != sensors.end();it++){
IICSensorBase *cfg=*it;
for (auto && cfg: sensorList.sensors){
if (cfg->busType != SensorBase::IIC) continue;
auto bus=buses.find(cfg->busId);
if (! cfg->isActive()) continue;
if (bus == buses.end()){

View File

@@ -1,6 +1,7 @@
#ifndef _GWIICTASK_H
#define _GWIICTASK_H
#include "GwApi.h"
#include "GwSensor.h"
void initIicTask(GwApi *api);
DECLARE_INITFUNCTION(initIicTask);
DECLARE_INITFUNCTION_ORDER(initIicTask,GWLATEORDER);
#endif

View File

@@ -1,11 +1,10 @@
#define _IIC_GROOVE_LIST
#include "GwQMP6988.h"
#ifdef _GWQMP6988
#define TYPE "QMP6988"
#define PRFX1 TYPE "11"
#define PRFX2 TYPE "12"
#define PRFX3 TYPE "21"
#define PRFX4 TYPE "22"
class QMP6988Config;
static GwSensorConfigInitializerList<QMP6988Config> configs;
class QMP6988Config : public IICSensorBase{
public:
String prNam="Pressure";
@@ -13,7 +12,7 @@ class QMP6988Config : public IICSensorBase{
tN2kPressureSource prSrc=tN2kPressureSource::N2kps_Atmospheric;
float prOff=0;
QMP6988 *device=nullptr;
QMP6988Config(GwApi* api,const String &prefix):SensorBase(TYPE,api,prefix){}
QMP6988Config(GwApi* api,const String &prefix):IICSensorBase(api,prefix){}
virtual bool isActive(){return prAct;};
virtual bool initDevice(GwApi *api,TwoWire *wire){
if (!isActive()) return false;
@@ -31,7 +30,6 @@ class QMP6988Config : public IICSensorBase{
virtual bool preinit(GwApi * api){
GwLog *logger=api->getLogger();
LOG_DEBUG(GwLog::LOG,"QMP6988 configured");
api->addCapability(prefix,"true");
addPressureXdr(api,*this);
return isActive();
}
@@ -42,76 +40,43 @@ class QMP6988Config : public IICSensorBase{
LOG_DEBUG(GwLog::DEBUG,"%s measure %2.0fPa, computed %2.0fPa",prefix.c_str(), pressure,computed);
sendN2kPressure(api,*this,computed,counterId);
}
#define CFG6988(prefix)\
CFG_GET(prNam,prefix); \
CFG_GET(iid,prefix); \
CFG_GET(prAct,prefix); \
CFG_GET(intv,prefix); \
CFG_GET(prOff,prefix);
virtual void readConfig(GwConfigHandler *cfg){
if (ok) return;
if (prefix == PRFX1){
busId=1;
addr=86;
CFG6988(QMP698811);
ok=true;
}
if (prefix == PRFX2){
busId=1;
addr=112;
CFG6988(QMP698812);
ok=true;
}
if (prefix == PRFX3){
busId=2;
addr=86;
CFG6988(QMP698821);
ok=true;
}
if (prefix == PRFX4){
busId=2;
addr=112;
CFG6988(QMP698822);
ok=true;
}
intv*=1000;
configs.readConfig(this,cfg);
}
};
static IICSensorBase::Creator creator=[](GwApi *api,const String &prfx){
static SensorBase::Creator creator=[](GwApi *api,const String &prfx)-> SensorBase*{
if (! configs.knowsPrefix(prfx)) return nullptr;
return new QMP6988Config(api,prfx);
};
IICSensorBase::Creator registerQMP6988(GwApi *api,IICSensorList &sensors){
SensorBase::Creator registerQMP6988(GwApi *api){
GwLog *logger=api->getLogger();
#if defined(GWQMP6988) || defined(GWQMP698811)
{
QMP6988Config *scfg=new QMP6988Config(api,PRFX1);
sensors.add(api,scfg);
api->addSensor(new QMP6988Config(api,"QMP698811"));
CHECK_IIC1();
#pragma message "GWQMP698811 defined"
}
#endif
#if defined(GWQMP698812)
{
QMP6988Config *scfg=new QMP6988Config(api,PRFX2);
sensors.add(api,scfg);
api->addSensor(new QMP6988Config(api,"QMP698812"));
CHECK_IIC1();
#pragma message "GWQMP698812 defined"
}
#endif
#if defined(GWQMP698821)
{
QMP6988Config *scfg=new QMP6988Config(api,PRFX3);
sensors.add(api,scfg);
api->addSensor(new QMP6988Config(api,"QMP698821"));
CHECK_IIC2();
#pragma message "GWQMP698821 defined"
}
#endif
#if defined(GWQMP698822)
{
QMP6988Config *scfg=new QMP6988Config(api,PRFX4);
sensors.add(api,scfg);
api->addSensor(new QMP6988Config(api,"QMP698822"));
CHECK_IIC2();
#pragma message "GWQMP698822 defined"
}
@@ -119,8 +84,28 @@ IICSensorBase::Creator registerQMP6988(GwApi *api,IICSensorList &sensors){
return creator;
}
#define CFG6988(s,prefix,bus,baddr)\
CFG_SGET(s,prNam,prefix); \
CFG_SGET(s,iid,prefix); \
CFG_SGET(s,prAct,prefix); \
CFG_SGET(s,intv,prefix); \
CFG_SGET(s,prOff,prefix); \
s->busId = bus; \
s->addr = baddr; \
s->ok = true; \
s->intv*=1000;
#define SC6988(prefix,bus,addr) \
GWSENSORDEF(configs,QMP6988Config,CFG6988,prefix,bus,addr)
SC6988(QMP698811,1,86);
SC6988(QMP698812,1,112);
SC6988(QMP698821,2,86);
SC6988(QMP698822,2,112);
#else
IICSensorBase::Creator registerQMP6988(GwApi *api,IICSensorList &sensors){
return IICSensorBase::Creator();
SensorBase::Creator registerQMP6988(GwApi *api){
return SensorBase::Creator();
}
#endif

View File

@@ -16,5 +16,5 @@
#ifdef _GWQMP6988
#include "QMP6988.h"
#endif
IICSensorBase::Creator registerQMP6988(GwApi *api,IICSensorList &sensors);
SensorBase::Creator registerQMP6988(GwApi *api);
#endif

View File

@@ -1,11 +1,7 @@
#include "GwSHT3X.h"
#ifdef _GWSHT3X
#define TYPE "SHT3X"
#define PRFX1 TYPE "11"
#define PRFX2 TYPE "12"
#define PRFX3 TYPE "21"
#define PRFX4 TYPE "22"
class SHT3XConfig;
static GwSensorConfigInitializerList<SHT3XConfig> configs;
class SHT3XConfig : public IICSensorBase{
public:
String tmNam;
@@ -15,8 +11,7 @@ class SHT3XConfig : public IICSensorBase{
tN2kHumiditySource huSrc;
tN2kTempSource tmSrc;
SHT3X *device=nullptr;
SHT3XConfig(GwApi *api,const String &prefix):
SensorBase(TYPE,api,prefix){}
using IICSensorBase::IICSensorBase;
virtual bool isActive(){
return tmAct || huAct;
}
@@ -31,7 +26,6 @@ class SHT3XConfig : public IICSensorBase{
virtual bool preinit(GwApi * api){
GwLog *logger=api->getLogger();
LOG_DEBUG(GwLog::LOG,"%s configured",prefix.c_str());
api->addCapability(prefix,"true");
addHumidXdr(api,*this);
addTempXdr(api,*this);
return isActive();
@@ -62,83 +56,43 @@ class SHT3XConfig : public IICSensorBase{
LOG_DEBUG(GwLog::DEBUG, "unable to query %s: %d",prefix.c_str(), rt);
}
}
/**
* we do not dynamically compute the config names
* just to get compile time errors if something does not fit
* correctly
*/
#define CFG3X(prefix) \
CFG_GET(tmNam,prefix); \
CFG_GET(huNam,prefix); \
CFG_GET(iid,prefix); \
CFG_GET(tmAct,prefix); \
CFG_GET(huAct,prefix); \
CFG_GET(intv,prefix); \
CFG_GET(huSrc,prefix); \
CFG_GET(tmSrc,prefix);
virtual void readConfig(GwConfigHandler *cfg){
if (ok) return;
if (prefix == PRFX1){
busId=1;
addr=0x44;
CFG3X(SHT3X11);
ok=true;
}
if (prefix == PRFX2){
busId=1;
addr=0x45;
CFG3X(SHT3X12);
ok=true;
}
if (prefix == PRFX3){
busId=2;
addr=0x44;
CFG3X(SHT3X21);
ok=true;
}
if (prefix == PRFX4){
busId=2;
addr=0x45;
CFG3X(SHT3X22);
ok=true;
}
intv*=1000;
configs.readConfig(this,cfg);
return;
}
};
IICSensorBase::Creator creator=[](GwApi *api,const String &prfx){
SensorBase::Creator creator=[](GwApi *api,const String &prfx)-> SensorBase*{
if (! configs.knowsPrefix(prfx)) return nullptr;
return new SHT3XConfig(api,prfx);
};
IICSensorBase::Creator registerSHT3X(GwApi *api,IICSensorList &sensors){
SensorBase::Creator registerSHT3X(GwApi *api){
GwLog *logger=api->getLogger();
#if defined(GWSHT3X) || defined (GWSHT3X11)
{
auto *scfg=creator(api,PRFX1);
sensors.add(api,scfg);
api->addSensor(creator(api,"SHT3X11"));
CHECK_IIC1();
#pragma message "GWSHT3X11 defined"
}
#endif
#if defined(GWSHT3X12)
{
auto *scfg=creator(api,PRFX2);
sensors.add(api,scfg);
api->addSensor(creator(api,"SHT3X12"));
CHECK_IIC1();
#pragma message "GWSHT3X12 defined"
}
#endif
#if defined(GWSHT3X21)
{
auto *scfg=creator(api,PRFX3);
sensors.add(api,scfg);
api->addSensor(creator(api,"SHT3X21"));
CHECK_IIC2();
#pragma message "GWSHT3X21 defined"
}
#endif
#if defined(GWSHT3X22)
{
auto *scfg=creator(api,PRFX4);
sensors.add(api,scfg);
api->addSensor(creator(api,"SHT3X22"));
CHECK_IIC2();
#pragma message "GWSHT3X22 defined"
}
@@ -146,9 +100,36 @@ IICSensorBase::Creator registerSHT3X(GwApi *api,IICSensorList &sensors){
return creator;
};
/**
* we do not dynamically compute the config names
* just to get compile time errors if something does not fit
* correctly
*/
#define CFGSHT3X(s, prefix, bus, baddr) \
CFG_SGET(s, tmNam, prefix); \
CFG_SGET(s, huNam, prefix); \
CFG_SGET(s, iid, prefix); \
CFG_SGET(s, tmAct, prefix); \
CFG_SGET(s, huAct, prefix); \
CFG_SGET(s, intv, prefix); \
CFG_SGET(s, huSrc, prefix); \
CFG_SGET(s, tmSrc, prefix); \
s->busId = bus; \
s->addr = baddr; \
s->ok = true; \
s->intv *= 1000;
#define SCSHT3X(prefix, bus, addr) \
GWSENSORDEF(configs, SHT3XConfig, CFGSHT3X, prefix, bus, addr)
SCSHT3X(SHT3X11, 1, 0x44);
SCSHT3X(SHT3X12, 1, 0x45);
SCSHT3X(SHT3X21, 2, 0x44);
SCSHT3X(SHT3X22, 2, 0x45);
#else
IICSensorBase::Creator registerSHT3X(GwApi *api,IICSensorList &sensors){
return IICSensorBase::Creator();
SensorBase::Creator registerSHT3X(GwApi *api){
return SensorBase::Creator();
}
#endif

View File

@@ -16,5 +16,5 @@
#ifdef _GWSHT3X
#include "SHT3X.h"
#endif
IICSensorBase::Creator registerSHT3X(GwApi *api,IICSensorList &sensors);
SensorBase::Creator registerSHT3X(GwApi *api);
#endif

View File

@@ -11,16 +11,6 @@ build_flags=
-D M5_CAN_KIT
${env.build_flags}
[env:m5stack-atom-env4]
extends = sensors
board = m5stack-atom
lib_deps =
${env.lib_deps}
${sensors.lib_deps}
build_flags=
-D M5_ENV4
-D M5_CAN_KIT
${env.build_flags}
[env:m5stack-atom-bme280]
extends = sensors
@@ -55,6 +45,7 @@ lib_deps =
${sensors.lib_deps}
build_flags=
-D GWBMP280G1
-D GWSHT3X11
-D M5_GROOVEIIC
-D M5_CAN_KIT
${env.build_flags}

View File

@@ -189,6 +189,7 @@ private:
if (N2kIsNA(v)) return N2kInt8NA;
return v;
}
void convertXDR(const SNMEA0183Msg &msg){
XdrMappingList foundMappings;
for (int offset=0;offset <= (msg.FieldCount()-4);offset+=4){
@@ -199,7 +200,19 @@ private:
String unit=msg.Field(offset+2);
String transducerName=msg.Field(offset+3);
GwXDRFoundMapping found=xdrMappings->getMapping(transducerName,type,unit);
if (found.empty) continue;
if (found.empty) {
if (config.unmappedXdr){
const GwXDRType *typeDef=xdrMappings->findType(type,unit);
GwXdrUnknownMapping mapping(transducerName,unit,typeDef,config.xdrTimeout);
value=mapping.valueFromXdr(value);
if (boatData->update(value,msg.sourceId,&mapping)){
//TODO: potentially update the format
LOG_DEBUG(GwLog::DEBUG+1,"found unmapped XDR %s:%s, value %f",
transducerName.c_str(),mapping.getBoatItemFormat().c_str(),value);
}
}
continue;
}
value=found.valueFromXdr(value);
if (!boatData->update(value,msg.sourceId,&found)) continue;
LOG_DEBUG(GwLog::DEBUG+1,"found mapped XDR %s:%s, value %f",
@@ -307,7 +320,7 @@ private:
return;
}
tN2kMsg n2kMsg;
if (boatData->XTE->update(rmb.xte,msg.sourceId)){
if (updateDouble(boatData->XTE,rmb.xte,msg.sourceId)){
tN2kXTEMode mode=N2kxtem_Autonomous;
if (msg.FieldCount() > 13){
const char *modeChar=msg.Field(13);
@@ -318,10 +331,10 @@ private:
}
uint8_t destinationId=getWaypointId(rmb.destID);
uint8_t sourceId=getWaypointId(rmb.originID);
if (boatData->DTW->update(rmb.dtw,msg.sourceId)
&& boatData->BTW->update(rmb.btw,msg.sourceId)
&& boatData->WPLat->update(rmb.latitude,msg.sourceId)
&& boatData->WPLon->update(rmb.longitude,msg.sourceId)
if (updateDouble(boatData->DTW,rmb.dtw,msg.sourceId)
&& updateDouble(boatData->BTW,rmb.btw,msg.sourceId)
&& updateDouble(boatData->WPLat,rmb.latitude,msg.sourceId)
&& updateDouble(boatData->WPLon,rmb.longitude,msg.sourceId)
){
SetN2kNavigationInfo(n2kMsg,1,rmb.dtw,N2khr_true,
false,

View File

@@ -3,14 +3,26 @@
class GwSynchronized{
private:
SemaphoreHandle_t *locker;
SemaphoreHandle_t locker=nullptr;
void lock(){
if (locker != nullptr) xSemaphoreTake(locker, portMAX_DELAY);
}
public:
/**
* deprecated
* as SemaphoreHandle_t is already a pointer just use this directly
*/
GwSynchronized(SemaphoreHandle_t *locker){
if (locker == nullptr) return;
this->locker=*locker;
lock();
}
GwSynchronized(SemaphoreHandle_t locker){
this->locker=locker;
if (locker != nullptr) xSemaphoreTake(*locker, portMAX_DELAY);
lock();
}
~GwSynchronized(){
if (locker != nullptr) xSemaphoreGive(*locker);
if (locker != nullptr) xSemaphoreGive(locker);
}
};

20
lib/sensors/GwSensor.cpp Normal file
View File

@@ -0,0 +1,20 @@
/*
(C) Andreas Vogel andreas@wellenvogel.de
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "GwSensor.h"
#include "GwApi.h"
void SensorList::add(SensorBase::Ptr sensor){
this->push_back(sensor);
}

View File

@@ -14,42 +14,124 @@
*/
#ifndef _GWSENSORS_H
#define _GWSENSORS_H
#include "GwApi.h"
#include "GwLog.h"
template<typename BUS>
#include "GwConfigItem.h"
#include <Arduino.h>
#include <memory>
#include <vector>
class GwApi;
class GwConfigHandler;
class SensorBase{
public:
using BusType=enum{
IIC=0,
SPI=1,
UNKNOWN=-1
};
using Ptr=std::shared_ptr<SensorBase>;
BusType busType=BusType::UNKNOWN;
int busId=0;
int iid=99; //N2K instanceId
int addr=-1;
const String prefix;
const String type;
long intv=0;
bool ok=false;
virtual void readConfig(GwConfigHandler *cfg)=0;
SensorBase(const String &tn,GwApi *api,const String &prfx):type(tn),prefix(prfx){
SensorBase(BusType bt,GwApi *api,const String &prfx)
:busType(bt),prefix(prfx){
}
using Creator=std::function<SensorBase<BUS> *(GwApi *api,const String &prfx)>;
using Creator=std::function<SensorBase *(GwApi *api,const String &prfx)>;
virtual bool isActive(){return false;};
virtual bool initDevice(GwApi *api,BUS *wire){return false;};
virtual bool initDevice(GwApi *api,void *bus){return false;};
virtual bool preinit(GwApi * api){return false;}
virtual void measure(GwApi * api,BUS *wire, int counterId){};
virtual void measure(GwApi * api,void *bus, int counterId){};
virtual ~SensorBase(){}
virtual void readConfig(GwConfigHandler *cfg)=0;
};
template<typename BUS,SensorBase::BusType bt>
class SensorTemplate : public SensorBase{
public:
SensorTemplate(GwApi *api,const String &prfx)
:SensorBase(bt,api,prfx){}
virtual bool initDevice(GwApi *api,BUS *bus){return false;};
virtual bool initDevice(GwApi *api,void *bus){
if (busType != bt) return false;
return initDevice(api,(BUS*)bus);
}
virtual void measure(GwApi * api,void *bus, int counterId){
if (busType != bt) return;
measure(api,(BUS*)bus,counterId);
};
protected:
virtual void measure(GwApi *api,BUS *bus, int counterId)=0;
};
template<typename BUS>
class SensorList : public std::vector<SensorBase<BUS>*>{
class SensorList : public std::vector<SensorBase::Ptr>{
public:
void add(GwApi *api, SensorBase<BUS> *sensor){
sensor->readConfig(api->getConfig());
api->getLogger()->logDebug(GwLog::LOG,"configured sensor %s, status %d",sensor->prefix.c_str(),(int)sensor->ok);
this->push_back(sensor);
}
using std::vector<SensorBase<BUS>*>::vector;
void add(SensorBase::Ptr sensor);
using std::vector<SensorBase::Ptr>::vector;
};
/**
* helper classes for a simplified sensor configuration
* by creating a list of type GwSensorConfigInitializerList<SensorClass> we can populate
* it by static instances of GwSensorConfigInitializer (using GWSENSORCONFIG ) that each has
* a function that populates the sensor config from the config data.
* For using sensors this is not really necessary - but it can simplify the code for a sensor
* if you want to support a couple of instances on different buses.
* By using this approach you still can write functions using the CFG_SGET macros that will check
* your config definitions at compile time.
*
*/
template <typename T>
class GwSensorConfig{
public:
using ReadConfig=std::function<void(T*,GwConfigHandler*)>;
ReadConfig configReader;
String prefix;
GwSensorConfig(const String &prfx,ReadConfig f):prefix(prfx),configReader(f){
}
bool readConfig(T* s,GwConfigHandler *cfg){
if (s == nullptr) return false;
configReader(s,cfg);
return s->ok;
}
};
template<typename T>
class GwSensorConfigInitializer : public GwInitializer<GwSensorConfig<T>>{
public:
using GwInitializer<GwSensorConfig<T>>::GwInitializer;
};
template<typename T>
class GwSensorConfigInitializerList : public GwInitializer<GwSensorConfig<T>>::List{
public:
using GwInitializer<GwSensorConfig<T>>::List::List;
bool readConfig(T *s,GwConfigHandler *cfg){
for (auto &&scfg:*this){
if (scfg.readConfig(s,cfg)) return true;
}
return false;
}
bool knowsPrefix(const String &prefix){
for (auto &&scfg:*this){
if (scfg.prefix == prefix) return true;
}
return false;
}
};
#define CFG_SGET(s, name, prefix) \
cfg->getValue(s->name, GwConfigDefinitions::prefix##name)
#define GWSENSORCONFIG(list,type,prefix,initFunction) \
GwSensorConfigInitializer<type> __init ## type ## prefix(list,GwSensorConfig<type>(#prefix,initFunction));
#define GWSENSORDEF(list,type,init,prefix,bus,baddr) \
GWSENSORCONFIG(list, type, prefix, [](type *s, GwConfigHandler *cfg) { init(s, prefix, bus, baddr); });
#define CFG_GET(name,prefix) \
cfg->getValue(name, GwConfigDefinitions::prefix ## name)
#endif

View File

@@ -63,6 +63,7 @@ GwSerial::~GwSerial()
{
delete buffer;
if (readBuffer) delete readBuffer;
if (lock != nullptr) vSemaphoreDelete(lock);
}
String GwSerial::getMode(){
@@ -87,10 +88,14 @@ size_t GwSerial::enqueue(const uint8_t *data, size_t len, bool partial)
}
GwBuffer::WriteStatus GwSerial::write(){
if (! isInitialized()) return GwBuffer::ERROR;
size_t numWrite=availableForWrite();
size_t rt=buffer->fetchData(numWrite,[](uint8_t *buffer,size_t len, void *p){
return ((GwSerial *)p)->stream->write(buffer,len);
},this);
size_t rt=0;
{
GWSYNCHRONIZED(lock);
size_t numWrite=availableForWrite();
rt=buffer->fetchData(numWrite,[](uint8_t *buffer,size_t len, void *p){
return ((GwSerial *)p)->stream->write(buffer,len);
},this);
}
if (rt != 0){
LOG_DEBUG(GwLog::DEBUG+1,"Serial %d write %d",id,rt);
}

View File

@@ -4,6 +4,7 @@
#include "GwLog.h"
#include "GwBuffer.h"
#include "GwChannelInterface.h"
#include "GwSynchronized.h"
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#include "hal/usb_serial_jtag_ll.h"
#endif
@@ -26,8 +27,12 @@ class GwSerial : public GwChannelInterface{
virtual long getFlushTimeout(){return 2000;}
virtual int availableForWrite()=0;
int type=0;
SemaphoreHandle_t lock=nullptr;
public:
GwSerial(GwLog *logger,Stream *stream,int id,int type,bool allowRead=true);
void enableWriteLock(){
lock=xSemaphoreCreateMutex();
}
virtual ~GwSerial();
bool isInitialized();
virtual size_t sendToClients(const char *buf,int sourceId,bool partial=false);
@@ -94,6 +99,7 @@ template<typename T>
if (c->isConnected()){
//this retriggers the ISR
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
usb_serial_jtag_ll_txfifo_flush();
}
}
return rt;

View File

@@ -246,7 +246,7 @@ void GwTcpClient::resolveHost(String host)
{
LOG_DEBUG(GwLog::LOG,"start resolving %s",host.c_str());
{
GWSYNCHRONIZED(&locker);
GWSYNCHRONIZED(locker);
resolvedAddress.resolved = false;
}
state = C_RESOLVING;
@@ -283,12 +283,12 @@ void GwTcpClient::resolveHost(String host)
void GwTcpClient::setResolved(IPAddress addr, bool valid){
LOG_DEBUG(GwLog::LOG,"setResolved %s, valid=%s",
addr.toString().c_str(),(valid?"true":"false"));
GWSYNCHRONIZED(&locker);
GWSYNCHRONIZED(locker);
resolvedAddress.address=addr;
resolvedAddress.resolved=valid;
state=C_RESOLVED;
}
GwTcpClient::ResolvedAddress GwTcpClient::getResolved(){
GWSYNCHRONIZED(&locker);
GWSYNCHRONIZED(locker);
return resolvedAddress;
}

View File

@@ -21,76 +21,23 @@
#define CHECK_BUS(BUS) \
checkDef("missing config for " #BUS,GW ## BUS ## _CLK ,GW ## BUS ## _MISO);
#define ADD22B(PRFX,BUS) \
{\
CHECK_BUS(BUS); \
GWDMS22B *dms=new GWDMS22B(api,#PRFX,GW ## BUS ## _HOST);\
sensors.add(api,dms); \
}
#ifdef GWDMS22B11
#define ADD22B11 ADD22B(DMS22B11,SPI1)
#ifndef GWDMS22B11_CS
#define GWDMS22B11_CS -1
#endif
#else
#define GWDMS22B11_CS -1
#define ADD22B11
#endif
#ifdef GWDMS22B12
#define ADD22B12 ADD22B(DMS22B12,SPI1)
#ifndef GWDMS22B12_CS
#error "you need to define GWDMS22B12_CS"
#endif
#if GWDMS22B11_CS == -1
#error "multiple devices on one SPI bus need chip select defines - GWDMS22B11_CS is unset"
#endif
#else
#define GWDMS22B12_CS -1
#define ADD22B12
#endif
#ifdef GWDMS22B21
#define ADD22B21 ADD22B(DMS22B21,SPI2)
#ifndef GWDMS22B21_CS
#define GWDMS22B21_CS -1
#endif
#else
#define GWDMS22B21_CS -1
#define ADD22B21
#endif
#ifdef GWDMS22B22
#define ADD22B22 ADD22B(DMS22B22,SPI2)
#ifndef GWDMS22B22_CS
#error "you need to define GWDMS22B22_CS"
#endif
#if GWDMS22B21_CS == -1
#error "multiple devices on one SPI bus need chip select defines - GWDMS22B21_CS is unset"
#endif
#else
#define GWDMS22B22_CS -1
#define ADD22B22
#endif
class GWDMS22B;
static GwSensorConfigInitializerList<GWDMS22B> configs;
class GWDMS22B : public SSISensor{
public:
int zero=2047;
bool invt=false;
String zeroConfigName;
public:
GWDMS22B(GwApi *api,const String &prfx, int host):SSISensor("DMS22B",api,prfx,host){}
GWDMS22B(GwApi *api,const String &prfx):SSISensor(api,prfx){}
virtual bool preinit(GwApi * api){
GwLog *logger=api->getLogger();
LOG_DEBUG(GwLog::LOG,"DMS22B configured, prefix=%s, intv=%f, active=%d",prefix.c_str(),fintv,(int)act);
api->addCapability(prefix,"true");
return act;
}
virtual void measure(GwApi * api,BusType *bus, int counterId){
virtual void measure(GwApi * api,BUSTYPE *bus, int counterId){
GwLog *logger=api->getLogger();
uint32_t value=0;
esp_err_t res=readData(value);
@@ -106,34 +53,84 @@ class GWDMS22B : public SSISensor{
api->increment(counterId,prefix);
api->setCalibrationValue(zeroConfigName,(double)value);
}
#define DMS22B(PRFX,...) \
if (prefix == #PRFX) {\
CFG_GET(act,PRFX); \
CFG_GET(iid,PRFX); \
CFG_GET(fintv,PRFX); \
CFG_GET(zero,PRFX); \
zeroConfigName=GwConfigDefinitions::PRFX ## zero;\
CFG_GET(invt,PRFX); \
bits=12; \
clock=500000; \
cs=GW ## PRFX ## _CS; \
__VA_ARGS__ \
}
virtual void readConfig(GwConfigHandler *cfg){
DMS22B(DMS22B11);
DMS22B(DMS22B12);
DMS22B(DMS22B21);
DMS22B(DMS22B22);
intv=1000*fintv;
if (ok) return;
configs.readConfig(this,cfg);
}
};
void registerDMS22B(GwApi *api,SpiSensorList &sensors){
ADD22B11
ADD22B12
ADD22B21
ADD22B22
#define ADD22B(PRFX,BUS) \
{\
CHECK_BUS(BUS); \
GWDMS22B *dms=new GWDMS22B(api,#PRFX);\
api->addSensor(dms,true); \
}
void registerDMS22B(GwApi *api){
#ifdef GWDMS22B11
ADD22B(DMS22B11,SPI1)
#ifndef GWDMS22B11_CS
#define GWDMS22B11_CS -1
#endif
#else
#define GWDMS22B11_CS -1
#endif
#ifdef GWDMS22B12
ADD22B(DMS22B12,SPI1)
#ifndef GWDMS22B12_CS
#error "you need to define GWDMS22B12_CS"
#endif
#if GWDMS22B11_CS == -1
#error "multiple devices on one SPI bus need chip select defines - GWDMS22B11_CS is unset"
#endif
#else
#define GWDMS22B12_CS -1
#endif
#ifdef GWDMS22B21
ADD22B(DMS22B21,SPI2)
#ifndef GWDMS22B21_CS
#define GWDMS22B21_CS -1
#endif
#else
#define GWDMS22B21_CS -1
#endif
#ifdef GWDMS22B22
ADD22B(DMS22B22,SPI2)
#ifndef GWDMS22B22_CS
#error "you need to define GWDMS22B22_CS"
#endif
#if GWDMS22B21_CS == -1
#error "multiple devices on one SPI bus need chip select defines - GWDMS22B21_CS is unset"
#endif
#else
#define GWDMS22B22_CS -1
#endif
}
#define CFGDMS22B(s,PRFX,bus,csv) \
CFG_SGET(s,act,PRFX); \
CFG_SGET(s,iid,PRFX); \
CFG_SGET(s,fintv,PRFX); \
CFG_SGET(s,zero,PRFX); \
s->zeroConfigName=GwConfigDefinitions::PRFX ## zero;\
CFG_SGET(s,invt,PRFX); \
s->bits=12; \
s->clock=500000; \
s->cs=csv; \
s->busId=bus; \
s->intv=1000*s->fintv; \
s->ok=true;
#define SCDMS22B(prefix,bus) \
GWSENSORDEF(configs,GWDMS22B,CFGDMS22B,prefix,GW ## bus ## _HOST,GW ## prefix ## _CS)
SCDMS22B(DMS22B11,SPI1);
SCDMS22B(DMS22B12,SPI1);
SCDMS22B(DMS22B21,SPI2);
SCDMS22B(DMS22B22,SPI2);

View File

@@ -18,5 +18,5 @@ SSI sensor DMS22B - https://www.mouser.de/datasheet/2/54/bour_s_a0011704065_1-22
#ifndef _GWDMS22B_H
#define _GWDMS22B_H
#include "GwSpiSensor.h"
void registerDMS22B(GwApi *api,SpiSensorList &sensors);
void registerDMS22B(GwApi *api);
#endif

View File

@@ -16,7 +16,7 @@
#ifndef _GWSPISENSOR_H
#define _GWSPISENSOR_H
#include <driver/spi_master.h>
#include "GwSensor.h"
#include "GwApi.h"
#include <memory>
class SPIBus{
@@ -48,7 +48,7 @@ class SPIBus{
spi_host_device_t host() const { return hd;}
};
using BusType=SPIBus;
using BUSTYPE=SPIBus;
class SSIDevice{
spi_device_handle_t spi;
@@ -90,15 +90,16 @@ class SSIDevice{
};
class SSISensor : public SensorBase<BusType>{
class SSISensor : public SensorTemplate<BUSTYPE,SensorBase::SPI>{
std::unique_ptr<SSIDevice> device;
protected:
public:
int bits=12;
int mask=0xffff;
int cs=-1;
int clock=0;
bool act=false;
float fintv=0;
protected:
virtual bool initSSI(GwLog*logger,const SPIBus *bus,
int clock,int cs, int bits){
mask= (1 << bits)-1;
@@ -125,17 +126,16 @@ class SSISensor : public SensorBase<BusType>{
}
public:
SSISensor(const String &type,GwApi *api,const String &prfx, int host):SensorBase(type,api,prfx)
SSISensor(GwApi *api,const String &prfx):SensorTemplate<BUSTYPE,SensorBase::SPI>(api,prfx)
{
busId=host;
}
virtual bool isActive(){return act;};
virtual bool initDevice(GwApi *api,BusType *bus){
virtual bool initDevice(GwApi *api,BUSTYPE *bus){
return initSSI(api->getLogger(),bus, clock,cs,bits);
};
};
using SpiSensorList=SensorList<BusType>;
using SpiSensorList=SensorList;
#define GWSPI1_HOST SPI2_HOST
#define GWSPI2_HOST SPI3_HOST
#endif

View File

@@ -21,8 +21,6 @@
static SPIBus bus1(GWSPI1_HOST);
static SPIBus bus2(GWSPI2_HOST);
static SpiSensorList sensors;
#ifdef GWSPI1_CLK
static const int spi1clk=GWSPI1_CLK;
#else
@@ -57,8 +55,11 @@ static const int spi2mosi=-1;
void runSpiTask(GwApi *api){
GwLog *logger=api->getLogger();
int res=-1;
ConfiguredSensors sensorList=api->taskInterfaces()->get<ConfiguredSensors>(res);
std::map<int,SPIBus *> buses;
for (auto && sensor:sensors){
for (auto && sensor: sensorList.sensors){
if (sensor->busType != SensorBase::BusType::SPI) continue;
int busId=sensor->busId;
auto bus=buses.find(busId);
if (bus == buses.end()){
@@ -93,7 +94,7 @@ void runSpiTask(GwApi *api){
bool runLoop=false;
GwIntervalRunner timers;
int counterId=api->addCounter("spisensors");
for (auto && sensor:sensors){
for (auto && sensor: sensorList.sensors){
if (!sensor->isActive()) continue;
auto bus=buses.find(sensor->busId);
if (bus == buses.end()){
@@ -122,10 +123,16 @@ void runSpiTask(GwApi *api){
void initSpiTask(GwApi *api){
GwLog *logger=api->getLogger();
registerDMS22B(api,sensors);
int res=-1;
registerDMS22B(api);
ConfiguredSensors sensorList=api->taskInterfaces()->get<ConfiguredSensors>(res);
bool addTask=false;
for (auto && sensor:sensors){
if (sensor->preinit(api)) addTask=true;
for (auto && sensor:sensorList.sensors){
if (sensor->busType != SensorBase::BusType::SPI) continue;
if (sensor->preinit(api)) {
api->addCapability(sensor->prefix,"true");
addTask=true;
}
}
if (addTask){
api->addUserTask(runSpiTask,"spiTask",3000);

View File

@@ -16,5 +16,5 @@
#define _GWSPITASK_H
#include "GwApi.h"
void initSpiTask(GwApi *api);
DECLARE_INITFUNCTION(initSpiTask);
DECLARE_INITFUNCTION_ORDER(initSpiTask,GWLATEORDER);
#endif

View File

@@ -1,11 +1,12 @@
#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_INITFUNCTION_ORDER(task,order) GwInitTask __Init##task##__(task,#task,order);
#define DECLARE_CAPABILITY(name,value) GwUserCapability __CAP##name##__(#name,#value);
#define DECLARE_STRING_CAPABILITY(name,value) GwUserCapability __CAP##name##__(#name,value);
#define DECLARE_TASKIF(type) \
DECLARE_TASKIF_IMPL(type) \
GwIreg __register##type(__FILE__,#type)
static int __taskInterface##type=0; //avoid duplicate declarations
#include "GwUserCode.h"
#include "GwSynchronized.h"
@@ -28,45 +29,6 @@ bool taskExists(V &list, const String &name){
}
return false;
}
class RegEntry{
public:
String file;
String task;
RegEntry(const String &t, const String &f):file(f),task(t){}
RegEntry(){}
};
using RegMap=std::map<String,RegEntry>;
static RegMap &registrations(){
static RegMap *regMap=new RegMap();
return *regMap;
}
static void registerInterface(const String &task,const String &file, const String &name){
auto it=registrations().find(name);
if (it != registrations().end()){
if (it->second.file != file){
ESP_LOGE("Assert","type %s redefined in %s original in %s",name,file,it->second.file);
std::abort();
};
if (it->second.task != task){
ESP_LOGE("Assert","type %s registered for multiple tasks %s and %s",name,task,it->second.task);
std::abort();
};
}
else{
registrations()[name]=RegEntry(task,file);
}
}
class GwIreg{
public:
GwIreg(const String &file, const String &name){
registerInterface("",file,name);
}
};
class GwUserTaskDef{
public:
GwUserTaskDef(TaskFunction_t task,String name, int stackSize=2000){
@@ -82,8 +44,8 @@ class GwInitTask{
GwInitTask(TaskFunction_t task, String name){
initTasks.push_back(GwUserTask(name,task));
}
GwInitTask(GwUserTaskFunction task, String name){
initTasks.push_back(GwUserTask(name,task));
GwInitTask(GwUserTaskFunction task, String name,int order=0){
initTasks.push_back(GwUserTask(name,task,GwUserTask::DEFAULT_STACKSIZE,order));
}
};
class GwUserCapability{
@@ -112,21 +74,8 @@ class TaskInterfacesStorage{
logger(l){
lock=xSemaphoreCreateMutex();
}
bool set(const String &file, const String &name, const String &task,GwApi::TaskInterfaces::Ptr v){
GWSYNCHRONIZED(&lock);
auto it=registrations().find(name);
if (it == registrations().end()){
LOG_DEBUG(GwLog::ERROR,"TaskInterfaces: invalid set %s not known",name.c_str());
return false;
}
if (it->second.file != file){
LOG_DEBUG(GwLog::ERROR,"TaskInterfaces: invalid set %s wrong file, expected %s , got %s",name.c_str(),it->second.file.c_str(),file.c_str());
return false;
}
if (it->second.task != task){
LOG_DEBUG(GwLog::ERROR,"TaskInterfaces: invalid set %s wrong task, expected %s , got %s",name.c_str(),it->second.task.c_str(),task.c_str());
return false;
}
bool set(const String &name, GwApi::TaskInterfaces::Ptr v){
GWSYNCHRONIZED(lock);
auto vit=values.find(name);
if (vit != values.end()){
vit->second.updates++;
@@ -141,7 +90,7 @@ class TaskInterfacesStorage{
return true;
}
GwApi::TaskInterfaces::Ptr get(const String &name, int &result){
GWSYNCHRONIZED(&lock);
GWSYNCHRONIZED(lock);
auto it = values.find(name);
if (it == values.end())
{
@@ -150,36 +99,59 @@ class TaskInterfacesStorage{
}
result = it->second.updates;
return it->second.ptr;
}
bool update(const String &name, std::function<GwApi::TaskInterfaces::Ptr(GwApi::TaskInterfaces::Ptr)>f){
GWSYNCHRONIZED(lock);
auto vit=values.find(name);
bool rt=false;
int mode=0;
if (vit == values.end()){
mode=1;
auto np=f(GwApi::TaskInterfaces::Ptr());
if (np){
mode=11;
values[name]=TaskDataEntry(np);
rt=true;
}
}
else
{
auto np = f(vit->second.ptr);
mode=2;
if (np)
{
mode=22;
vit->second = np;
vit->second.updates++;
if (vit->second.updates < 0)
{
vit->second.updates = 0;
}
rt=true;
}
}
LOG_DEBUG(GwLog::DEBUG,"TaskApi::update %s (mode %d)returns %d",name.c_str(),mode,(int)rt);
return rt;
}
};
class TaskInterfacesImpl : public GwApi::TaskInterfaces{
String task;
TaskInterfacesStorage *storage;
GwLog *logger;
bool isInit=false;
public:
TaskInterfacesImpl(const String &n,TaskInterfacesStorage *s, GwLog *l,bool i):
task(n),storage(s),isInit(i),logger(l){}
virtual bool iset(const String &file, const String &name, Ptr v){
return storage->set(file,name,task,v);
TaskInterfacesImpl(TaskInterfacesStorage *s, GwLog *l,bool i):
storage(s),isInit(i),logger(l){}
protected:
virtual bool iset(const String &name, Ptr v){
return storage->set(name,v);
}
virtual Ptr iget(const String &name, int &result){
return storage->get(name,result);
}
virtual bool iclaim(const String &name, const String &task){
if (! isInit) return false;
auto it=registrations().find(name);
if (it == registrations().end()){
LOG_DEBUG(GwLog::ERROR,"unable to claim interface %s for task %s, not registered",name.c_str(),task.c_str());
return false;
}
if (!it->second.task.isEmpty()){
LOG_DEBUG(GwLog::ERROR,"unable to claim interface %s for task %s, already claimed by %s",name.c_str(),task.c_str(),it->second.task.c_str());
return false;
}
it->second.task=task;
LOG_DEBUG(GwLog::LOG,"claimed interface %s for task %s",name.c_str(),task.c_str());
return true;
virtual bool iupdate(const String &name,std::function<Ptr(Ptr v)> f){
return storage->update(name,f);
}
};
@@ -188,7 +160,7 @@ class TaskApi : public GwApiInternal
{
GwApiInternal *api=nullptr;
int sourceId;
SemaphoreHandle_t *mainLock;
SemaphoreHandle_t mainLock;
SemaphoreHandle_t localLock;
std::map<int,GwCounter<String>> counter;
std::map<String,GwApi::HandlerFunction> webHandlers;
@@ -200,7 +172,7 @@ class TaskApi : public GwApiInternal
public:
TaskApi(GwApiInternal *api,
int sourceId,
SemaphoreHandle_t *mainLock,
SemaphoreHandle_t mainLock,
const String &name,
TaskInterfacesStorage *s,
bool init=false)
@@ -210,7 +182,7 @@ public:
this->mainLock=mainLock;
this->name=name;
localLock=xSemaphoreCreateMutex();
interfaces=new TaskInterfacesImpl(name,s,api->getLogger(),init);
interfaces=new TaskInterfacesImpl(s,api->getLogger(),init);
isInit=init;
}
virtual GwRequestQueue *getQueue()
@@ -264,14 +236,14 @@ public:
vSemaphoreDelete(localLock);
};
virtual void fillStatus(GwJsonDocument &status){
GWSYNCHRONIZED(&localLock);
GWSYNCHRONIZED(localLock);
if (! counterUsed) return;
for (auto it=counter.begin();it != counter.end();it++){
it->second.toJson(status);
}
};
virtual int getJsonSize(){
GWSYNCHRONIZED(&localLock);
GWSYNCHRONIZED(localLock);
if (! counterUsed) return 0;
int rt=0;
for (auto it=counter.begin();it != counter.end();it++){
@@ -280,7 +252,7 @@ public:
return rt;
};
virtual void increment(int idx,const String &name,bool failed=false){
GWSYNCHRONIZED(&localLock);
GWSYNCHRONIZED(localLock);
counterUsed=true;
auto it=counter.find(idx);
if (it == counter.end()) return;
@@ -288,18 +260,18 @@ public:
else (it->second.add(name));
};
virtual void reset(int idx){
GWSYNCHRONIZED(&localLock);
GWSYNCHRONIZED(localLock);
counterUsed=true;
auto it=counter.find(idx);
if (it == counter.end()) return;
it->second.reset();
};
virtual void remove(int idx){
GWSYNCHRONIZED(&localLock);
GWSYNCHRONIZED(localLock);
counter.erase(idx);
}
virtual int addCounter(const String &name){
GWSYNCHRONIZED(&localLock);
GWSYNCHRONIZED(localLock);
counterUsed=true;
counterIdx++;
//avoid the need for an empty counter constructor
@@ -317,7 +289,7 @@ public:
return api->addXdrMapping(def);
}
virtual void registerRequestHandler(const String &url,HandlerFunction handler){
GWSYNCHRONIZED(&localLock);
GWSYNCHRONIZED(localLock);
webHandlers[url]=handler;
}
virtual void addCapability(const String &name, const String &value){
@@ -344,7 +316,7 @@ public:
{
GwApi::HandlerFunction handler;
{
GWSYNCHRONIZED(&localLock);
GWSYNCHRONIZED(localLock);
auto it = webHandlers.find(url);
if (it == webHandlers.end())
{
@@ -357,12 +329,25 @@ public:
handler(req);
return true;
}
virtual void addSensor(SensorBase *sb,bool readConfig=true) override{
if (sb == nullptr) return;
SensorBase::Ptr sensor(sb);
if (readConfig) sb->readConfig(this->getConfig());
if (! sensor->ok){
api->getLogger()->logDebug(GwLog::ERROR,"sensor %s nok , bustype=%d",sensor->prefix.c_str(),(int)sensor->busType);
return;
}
bool rt=taskInterfaces()->update<ConfiguredSensors>( [sensor,this](ConfiguredSensors *sensors)->bool{
api->getLogger()->logDebug(GwLog::LOG,"adding sensor %s, type=%d",sensor->prefix,(int)sensor->busType);
sensors->sensors.add(sensor);
return true;
});
}
};
GwUserCode::GwUserCode(GwApiInternal *api,SemaphoreHandle_t *mainLock){
GwUserCode::GwUserCode(GwApiInternal *api){
this->logger=api->getLogger();
this->api=api;
this->mainLock=mainLock;
this->taskData=new TaskInterfacesStorage(this->logger);
}
GwUserCode::~GwUserCode(){
@@ -392,6 +377,9 @@ void GwUserCode::startUserTasks(int baseId){
}
}
void GwUserCode::startInitTasks(int baseId){
std::sort(initTasks.begin(),initTasks.end(),[](const GwUserTask &a, const GwUserTask &b){
return a.order < b.order;
});
LOG_DEBUG(GwLog::DEBUG,"starting %d user init tasks",initTasks.size());
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);

View File

@@ -15,22 +15,25 @@ class GwApiInternal : public GwApi{
};
class GwUserTask{
public:
static const int DEFAULT_STACKSIZE=2000;
String name;
TaskFunction_t task=NULL;
GwUserTaskFunction usertask=NULL;
bool isUserTask=false;
GwApiInternal *api=NULL;
int stackSize=2000;
GwUserTask(String name,TaskFunction_t task,int stackSize=2000){
int order=0;
GwUserTask(String name,TaskFunction_t task,int stackSize=DEFAULT_STACKSIZE){
this->name=name;
this->task=task;
this->stackSize=stackSize;
}
GwUserTask(String name, GwUserTaskFunction task,int stackSize=2000){
GwUserTask(String name, GwUserTaskFunction task,int stackSize=DEFAULT_STACKSIZE, int order=0){
this->name=name;
this->usertask=task;
this->isUserTask=true;
this->stackSize=stackSize;
this->order=order;
}
};
@@ -38,13 +41,14 @@ class TaskInterfacesStorage;
class GwUserCode{
GwLog *logger;
GwApiInternal *api;
SemaphoreHandle_t *mainLock;
SemaphoreHandle_t mainLock=nullptr;
TaskInterfacesStorage *taskData;
void startAddOnTask(GwApiInternal *api,GwUserTask *task,int sourceId,String name);
public:
~GwUserCode();
typedef std::map<String,String> Capabilities;
GwUserCode(GwApiInternal *api, SemaphoreHandle_t *mainLock);
GwUserCode(GwApiInternal *api);
void begin(SemaphoreHandle_t mainLock){this->mainLock=mainLock;}
void startUserTasks(int baseId);
void startInitTasks(int baseId);
void startAddonTask(String name,TaskFunction_t task, int id);

View File

@@ -58,6 +58,7 @@ GwXDRType *types[] = {
new GwXDRType(GwXDRType::DISPLACEMENTD, "A", "D",DegToRad,RadToDeg,"rd"),
new GwXDRType(GwXDRType::RPM,"T","R")
};
static GwXDRType genericType(GwXDRType::GENERIC, "G", "");
template<typename T, int size>
int GetArrLength(T(&)[size]){return size;}
static GwXDRType *findType(GwXDRType::TypeCode type, int *start = NULL)
@@ -82,6 +83,19 @@ static GwXDRType *findType(GwXDRType::TypeCode type, int *start = NULL)
return NULL;
}
static GwXDRType *findType(const String &typeString, const String &unitString)
{
int len=GetArrLength(types);
for (int i=0; i< len; i++)
{
if (types[i]->xdrtype == typeString && types[i]->xdrunit == unitString)
{
return types[i];
}
}
return &genericType;
}
#include "GwXdrTypeMappings.h"
static GwXDRType::TypeCode findTypeMapping(GwXDRCategory category, int field)
@@ -199,7 +213,7 @@ GwXDRMappingDef *GwXDRMappingDef::fromString(String s)
}
return rt;
}
String GwXDRMappingDef::getTransducerName(int instance)
String GwXDRMappingDef::getTransducerName(int instance) const
{
String name = xdrName;
if (instanceMode == GwXDRMappingDef::IS_AUTO)
@@ -257,7 +271,7 @@ bool GwXDRMappings::addMapping(GwXDRMappingDef *def)
LOG_DEBUG(GwLog::ERROR, "no type mapping for %s", def->toString().c_str());
return false;
}
GwXDRType *type = findType(code, &typeIndex);
GwXDRType *type = ::findType(code, &typeIndex);
if (!type)
{
LOG_DEBUG(GwLog::ERROR, "no type definition for %s", def->toString().c_str());
@@ -298,7 +312,7 @@ bool GwXDRMappings::addMapping(GwXDRMappingDef *def)
LOG_DEBUG(GwLog::LOG, "append mapping with n183key %s", n183key.c_str());
it->second.push_back(mapping);
}
type = findType(code, &typeIndex);
type = ::findType(code, &typeIndex);
if (!type)
break;
mapping = new GwXDRMapping(def, type);
@@ -471,7 +485,7 @@ String GwXDRMappings::getXdrEntry(String mapping, double value,int instance){
{
return rt;
}
GwXDRType *type = findType(code, &typeIndex);
GwXDRType *type = ::findType(code, &typeIndex);
bool first=true;
unsigned long invalidTime=config->getInt(GwConfigDefinitions::timoSensor);
while (type){
@@ -480,8 +494,12 @@ String GwXDRMappings::getXdrEntry(String mapping, double value,int instance){
if (first) first=false;
else rt+=",";
rt+=found.buildXdrEntry(value).entry;
type = findType(code, &typeIndex);
type = ::findType(code, &typeIndex);
}
delete def;
return rt;
}
const GwXDRType * GwXDRMappings::findType(const String &typeString, const String &unitString) const{
return ::findType(typeString,unitString);
}

View File

@@ -140,7 +140,7 @@ class GwXDRMappingDef{
rt += xdrUnit;
return rt;
}
String getTransducerName(int instance);
String getTransducerName(int instance) const;
private:
static bool handleToken(String tok,int index,GwXDRMappingDef *def);
};
@@ -163,12 +163,12 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{
String entry;
String transducer;
};
GwXDRMappingDef *definition=NULL;
GwXDRType *type=NULL;
const GwXDRMappingDef *definition=NULL;
const GwXDRType *type=NULL;
int instanceId=-1;
bool empty=true;
unsigned long timeout=0;
GwXDRFoundMapping(GwXDRMappingDef *definition,GwXDRType *type, unsigned long timeout){
GwXDRFoundMapping(const GwXDRMappingDef *definition,const GwXDRType *type, unsigned long timeout){
this->definition=definition;
this->type=type;
this->timeout=timeout;
@@ -182,7 +182,7 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{
empty=false;
}
GwXDRFoundMapping(){}
String getTransducerName(){
virtual String getTransducerName(){
return definition->getTransducerName(instanceId);
}
double valueFromXdr(double value){
@@ -203,6 +203,24 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{
}
};
class GwXdrUnknownMapping : public GwXDRFoundMapping{
String name;
String unit;
public:
GwXdrUnknownMapping(const String &xdrName, const String &xdrUnit,const GwXDRType *type,unsigned long timeout):
name(xdrName),unit(xdrUnit), GwXDRFoundMapping(nullptr,type,timeout){
}
virtual String getTransducerName(){
return name;
}
virtual String getBoatItemFormat(){
String rt=GwXDRFoundMapping::getBoatItemFormat();
if (type->xdrunit.isEmpty()) rt+=unit;
return rt;
}
};
//the class GwXDRMappings is not intended to be deleted
//the deletion will leave memory leaks!
class GwConfigHandler;
@@ -229,6 +247,7 @@ class GwXDRMappings{
GwXDRFoundMapping getMapping(GwXDRCategory category,int selector,int field=0,int instance=-1);
String getXdrEntry(String mapping, double value,int instance=0);
const char * getUnMapped();
const GwXDRType * findType(const String &typeString, const String &unitString) const;
};