make data store times configurable
This commit is contained in:
parent
358710ef03
commit
c266bddea3
|
@ -1,6 +1,7 @@
|
|||
#include "GwBoatData.h"
|
||||
#include <GwJsonDocument.h>
|
||||
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||
#include "GWConfig.h"
|
||||
#define GWTYPE_DOUBLE 1
|
||||
#define GWTYPE_UINT32 2
|
||||
#define GWTYPE_UINT16 3
|
||||
|
@ -35,6 +36,23 @@ GwBoatItemBase::GwBoatItemBase(String name, String format, unsigned long invalid
|
|||
this->format = format;
|
||||
this->type = 0;
|
||||
this->lastUpdateSource = -1;
|
||||
this->toType=TOType::user;
|
||||
}
|
||||
GwBoatItemBase::GwBoatItemBase(String name, String format, GwBoatItemBase::TOType toType)
|
||||
{
|
||||
lastSet = 0;
|
||||
this->invalidTime = INVALID_TIME;
|
||||
this->toType=toType;
|
||||
this->name = name;
|
||||
this->format = format;
|
||||
this->type = 0;
|
||||
this->lastUpdateSource = -1;
|
||||
this->toType=TOType::user;
|
||||
}
|
||||
void GwBoatItemBase::setInvalidTime(unsigned long it, bool force){
|
||||
if (toType != TOType::user || force ){
|
||||
invalidTime=it;
|
||||
}
|
||||
}
|
||||
size_t GwBoatItemBase::getJsonSize() { return JSON_OBJECT_SIZE(10); }
|
||||
#define STRING_SIZE 40
|
||||
|
@ -113,6 +131,16 @@ GwBoatItem<T>::GwBoatItem(String name, String formatInfo, unsigned long invalidT
|
|||
(*map)[name] = this;
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
GwBoatItem<T>::GwBoatItem(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map) : GwBoatItemBase(name, formatInfo, toType)
|
||||
{
|
||||
T dummy;
|
||||
this->type = GwBoatItemTypes::getType(dummy);
|
||||
if (map)
|
||||
{
|
||||
(*map)[name] = this;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool GwBoatItem<T>::update(T nv, int source)
|
||||
|
@ -246,14 +274,13 @@ void GwSatInfoList::houseKeeping(unsigned long ts)
|
|||
sats.end(),
|
||||
[ts, this](const GwSatInfo &info)
|
||||
{
|
||||
return (info.timestamp + lifeTime) < ts;
|
||||
return info.validTill < ts;
|
||||
}),
|
||||
sats.end());
|
||||
}
|
||||
void GwSatInfoList::update(GwSatInfo entry)
|
||||
void GwSatInfoList::update(GwSatInfo entry, unsigned long validTill)
|
||||
{
|
||||
unsigned long now = millis();
|
||||
entry.timestamp = now;
|
||||
entry.validTill = validTill;
|
||||
for (auto it = sats.begin(); it != sats.end(); it++)
|
||||
{
|
||||
if (it->PRN == entry.PRN)
|
||||
|
@ -267,7 +294,7 @@ void GwSatInfoList::update(GwSatInfo entry)
|
|||
sats.push_back(entry);
|
||||
}
|
||||
|
||||
GwBoatDataSatList::GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime, GwBoatItemMap *map) : GwBoatItem<GwSatInfoList>(name, formatInfo, invalidTime, map) {}
|
||||
GwBoatDataSatList::GwBoatDataSatList(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map) : GwBoatItem<GwSatInfoList>(name, formatInfo, toType, map) {}
|
||||
|
||||
bool GwBoatDataSatList::update(GwSatInfo info, int source)
|
||||
{
|
||||
|
@ -284,7 +311,7 @@ bool GwBoatDataSatList::update(GwSatInfo info, int source)
|
|||
}
|
||||
lastUpdateSource = source;
|
||||
uls(now);
|
||||
data.update(info);
|
||||
data.update(info,now+invalidTime);
|
||||
return true;
|
||||
}
|
||||
void GwBoatDataSatList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime)
|
||||
|
@ -293,9 +320,31 @@ void GwBoatDataSatList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime)
|
|||
GwBoatItem<GwSatInfoList>::toJsonDoc(doc, minTime);
|
||||
}
|
||||
|
||||
GwBoatData::GwBoatData(GwLog *logger)
|
||||
GwBoatData::GwBoatData(GwLog *logger, GwConfigHandler *cfg)
|
||||
{
|
||||
this->logger = logger;
|
||||
for (auto &&it : values){
|
||||
unsigned long timeout=GwBoatItemBase::INVALID_TIME;
|
||||
switch(it.second->getToType()){
|
||||
case GwBoatItemBase::TOType::ais:
|
||||
timeout=cfg->getInt(GwConfigDefinitions::timoAis);
|
||||
break;
|
||||
case GwBoatItemBase::TOType::def:
|
||||
timeout=cfg->getInt(GwConfigDefinitions::timoDefault);
|
||||
break;
|
||||
case GwBoatItemBase::TOType::lng:
|
||||
timeout=cfg->getInt(GwConfigDefinitions::timoLong);
|
||||
break;
|
||||
case GwBoatItemBase::TOType::sensor:
|
||||
timeout=cfg->getInt(GwConfigDefinitions::timoSensor);
|
||||
break;
|
||||
case GwBoatItemBase::TOType::keep:
|
||||
timeout=0;
|
||||
break;
|
||||
}
|
||||
it.second->setInvalidTime(timeout);
|
||||
}
|
||||
|
||||
}
|
||||
GwBoatData::~GwBoatData()
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _GWBOATDATA_H
|
||||
|
||||
#include "GwLog.h"
|
||||
#include "GWConfig.h"
|
||||
#include <Arduino.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
@ -15,6 +16,14 @@
|
|||
class GwJsonDocument;
|
||||
class GwBoatItemBase{
|
||||
public:
|
||||
using TOType=enum{
|
||||
def=1,
|
||||
ais=2,
|
||||
sensor=3,
|
||||
lng=4,
|
||||
user=5,
|
||||
keep=6
|
||||
};
|
||||
class StringWriter{
|
||||
uint8_t *buffer =NULL;
|
||||
uint8_t *wp=NULL;
|
||||
|
@ -31,7 +40,7 @@ class GwBoatItemBase{
|
|||
bool baseFilled();
|
||||
void reset();
|
||||
};
|
||||
static const unsigned long INVALID_TIME=60000;
|
||||
static const long INVALID_TIME=60000;
|
||||
//the formatter names that must be known in js
|
||||
GWSC(formatCourse);
|
||||
GWSC(formatKnots);
|
||||
|
@ -51,10 +60,11 @@ class GwBoatItemBase{
|
|||
protected:
|
||||
int type;
|
||||
unsigned long lastSet=0;
|
||||
unsigned long invalidTime=INVALID_TIME;
|
||||
long invalidTime=INVALID_TIME;
|
||||
String name;
|
||||
String format;
|
||||
StringWriter writer;
|
||||
TOType toType=TOType::def;
|
||||
void uls(unsigned long ts=0){
|
||||
if (ts) lastSet=ts;
|
||||
else lastSet=millis();
|
||||
|
@ -65,7 +75,8 @@ class GwBoatItemBase{
|
|||
int getCurrentType(){return type;}
|
||||
unsigned long getLastSet() const {return lastSet;}
|
||||
bool isValid(unsigned long now=0) const ;
|
||||
GwBoatItemBase(String name,String format,unsigned long invalidTime=INVALID_TIME);
|
||||
GwBoatItemBase(String name,String format,TOType toType);
|
||||
GwBoatItemBase(String name,String format,unsigned long invalidTime);
|
||||
virtual ~GwBoatItemBase(){}
|
||||
void invalidate(){
|
||||
lastSet=0;
|
||||
|
@ -82,6 +93,8 @@ class GwBoatItemBase{
|
|||
virtual double getDoubleValue()=0;
|
||||
String getName(){return name;}
|
||||
const String & getFormat() const{return format;}
|
||||
virtual void setInvalidTime(unsigned long it, bool force=true);
|
||||
TOType getToType(){return toType;}
|
||||
};
|
||||
class GwBoatData;
|
||||
template<class T> class GwBoatItem : public GwBoatItemBase{
|
||||
|
@ -90,6 +103,7 @@ template<class T> class GwBoatItem : public GwBoatItemBase{
|
|||
bool lastStringValid=false;
|
||||
public:
|
||||
GwBoatItem(String name,String formatInfo,unsigned long invalidTime=INVALID_TIME,GwBoatItemMap *map=NULL);
|
||||
GwBoatItem(String name,String formatInfo,TOType toType,GwBoatItemMap *map=NULL);
|
||||
virtual ~GwBoatItem(){}
|
||||
bool update(T nv, int source=-1);
|
||||
bool updateMax(T nv,int sourceId=-1);
|
||||
|
@ -118,14 +132,14 @@ class GwSatInfo{
|
|||
uint32_t Elevation;
|
||||
uint32_t Azimut;
|
||||
uint32_t SNR;
|
||||
unsigned long timestamp;
|
||||
unsigned long validTill;
|
||||
};
|
||||
class GwSatInfoList{
|
||||
public:
|
||||
static const unsigned long lifeTime=32000;
|
||||
static const GwBoatItemBase::TOType toType=GwBoatItemBase::TOType::lng;
|
||||
std::vector<GwSatInfo> sats;
|
||||
void houseKeeping(unsigned long ts=0);
|
||||
void update(GwSatInfo entry);
|
||||
void update(GwSatInfo entry, unsigned long validTill);
|
||||
int getNumSats() const{
|
||||
return sats.size();
|
||||
}
|
||||
|
@ -139,7 +153,7 @@ class GwSatInfoList{
|
|||
class GwBoatDataSatList : public GwBoatItem<GwSatInfoList>
|
||||
{
|
||||
public:
|
||||
GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime = INVALID_TIME, GwBoatItemMap *map = NULL);
|
||||
GwBoatDataSatList(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map = NULL);
|
||||
bool update(GwSatInfo info, int source);
|
||||
virtual void toJsonDoc(GwJsonDocument *doc, unsigned long minTime);
|
||||
GwSatInfo *getAt(int idx){
|
||||
|
@ -164,56 +178,59 @@ public:
|
|||
virtual unsigned long getInvalidTime(){ return GwBoatItemBase::INVALID_TIME;}
|
||||
virtual ~GwBoatItemNameProvider() {}
|
||||
};
|
||||
#define GWBOATDATA(type,name,time,fmt) \
|
||||
#define GWBOATDATAT(type,name,toType,fmt) \
|
||||
static constexpr const char* _##name=#name; \
|
||||
GwBoatItem<type> *name=new GwBoatItem<type>(#name,GwBoatItemBase::fmt,time,&values) ;
|
||||
#define GWSPECBOATDATA(clazz,name,time,fmt) \
|
||||
clazz *name=new clazz(#name,GwBoatItemBase::fmt,time,&values) ;
|
||||
GwBoatItem<type> *name=new GwBoatItem<type>(#name,GwBoatItemBase::fmt,toType,&values) ;
|
||||
#define GWBOATDATA(type,name,fmt) GWBOATDATAT(type,name,GwBoatItemBase::TOType::def,fmt)
|
||||
#define GWSPECBOATDATA(clazz,name,toType,fmt) \
|
||||
clazz *name=new clazz(#name,GwBoatItemBase::fmt,toType,&values) ;
|
||||
class GwBoatData{
|
||||
static const unsigned long DEF_TIME=4000;
|
||||
private:
|
||||
GwLog *logger;
|
||||
GwBoatItemBase::GwBoatItemMap values;
|
||||
public:
|
||||
|
||||
GWBOATDATA(double,COG,4000,formatCourse) // course over ground
|
||||
GWBOATDATA(double,SOG,4000,formatKnots) // speed over ground
|
||||
GWBOATDATA(double,HDT,4000,formatCourse) // true heading
|
||||
GWBOATDATA(double,HDM,4000,formatCourse) // magnetic heading
|
||||
GWBOATDATA(double,STW,4000,formatKnots) // water speed
|
||||
GWBOATDATA(double,VAR,4000,formatWind) // variation
|
||||
GWBOATDATA(double,DEV,4000,formatWind) // deviation
|
||||
GWBOATDATA(double,AWA,4000,formatWind) // apparent wind ANGLE
|
||||
GWBOATDATA(double,AWS,4000,formatKnots) // apparent wind speed
|
||||
GWBOATDATA(double,MaxAws,0,formatKnots)
|
||||
GWBOATDATA(double,TWD,4000,formatCourse) // true wind DIRECTION
|
||||
GWBOATDATA(double,TWA,4000,formatWind) // true wind ANGLE
|
||||
GWBOATDATA(double,TWS,4000,formatKnots) // true wind speed
|
||||
GWBOATDATA(double,MaxTws,0,formatKnots)
|
||||
GWBOATDATA(double,ROT,4000,formatRot) // rate of turn
|
||||
GWBOATDATA(double,RPOS,4000,formatWind) // rudder position
|
||||
GWBOATDATA(double,PRPOS,4000,formatWind) // secondary rudder position
|
||||
GWBOATDATA(double,LAT,4000,formatLatitude)
|
||||
GWBOATDATA(double,LON,4000,formatLongitude)
|
||||
GWBOATDATA(double,ALT,4000,formatFixed0) //altitude
|
||||
GWBOATDATA(double,HDOP,4000,formatDop)
|
||||
GWBOATDATA(double,PDOP,4000,formatDop)
|
||||
GWBOATDATA(double,VDOP,4000,formatDop)
|
||||
GWBOATDATA(double,DBS,4000,formatDepth) //waterDepth (below surface)
|
||||
GWBOATDATA(double,DBT,4000,formatDepth) //DepthTransducer
|
||||
GWBOATDATA(double,GPST,4000,formatTime) // GPS time (seconds of day)
|
||||
GWBOATDATA(uint32_t,GPSD,4000,formatDate) // GPS date (days since 1979-01-01)
|
||||
GWBOATDATA(int16_t,TZ,8000,formatFixed0)
|
||||
GWBOATDATA(double,WTemp,4000,kelvinToC)
|
||||
GWBOATDATA(uint32_t,Log,16000,mtr2nm)
|
||||
GWBOATDATA(uint32_t,TripLog,16000,mtr2nm)
|
||||
GWBOATDATA(double,DTW,4000,mtr2nm) // distance to waypoint
|
||||
GWBOATDATA(double,BTW,4000,formatCourse) // bearing to waypoint
|
||||
GWBOATDATA(double,XTE,4000,formatXte) // cross track error
|
||||
GWBOATDATA(double,WPLat,4000,formatLatitude) // waypoint latitude
|
||||
GWBOATDATA(double,WPLon,4000,formatLongitude) // waypoint longitude
|
||||
GWSPECBOATDATA(GwBoatDataSatList,SatInfo,GwSatInfoList::lifeTime,formatFixed0);
|
||||
GWBOATDATA(double,COG,formatCourse) // course over ground
|
||||
GWBOATDATA(double,SOG,formatKnots) // speed over ground
|
||||
GWBOATDATA(double,HDT,formatCourse) // true heading
|
||||
GWBOATDATA(double,HDM,formatCourse) // magnetic heading
|
||||
GWBOATDATA(double,STW,formatKnots) // water speed
|
||||
GWBOATDATA(double,VAR,formatWind) // variation
|
||||
GWBOATDATA(double,DEV,formatWind) // deviation
|
||||
GWBOATDATA(double,AWA,formatWind) // apparent wind ANGLE
|
||||
GWBOATDATA(double,AWS,formatKnots) // apparent wind speed
|
||||
GWBOATDATAT(double,MaxAws,GwBoatItemBase::TOType::keep,formatKnots)
|
||||
GWBOATDATA(double,TWD,formatCourse) // true wind DIRECTION
|
||||
GWBOATDATA(double,TWA,formatWind) // true wind ANGLE
|
||||
GWBOATDATA(double,TWS,formatKnots) // true wind speed
|
||||
|
||||
GWBOATDATAT(double,MaxTws,GwBoatItemBase::TOType::keep,formatKnots)
|
||||
GWBOATDATA(double,ROT,formatRot) // rate of turn
|
||||
GWBOATDATA(double,RPOS,formatWind) // rudder position
|
||||
GWBOATDATA(double,PRPOS,formatWind) // secondary rudder position
|
||||
GWBOATDATA(double,LAT,formatLatitude)
|
||||
GWBOATDATA(double,LON,formatLongitude)
|
||||
GWBOATDATA(double,ALT,formatFixed0) //altitude
|
||||
GWBOATDATA(double,HDOP,formatDop)
|
||||
GWBOATDATA(double,PDOP,formatDop)
|
||||
GWBOATDATA(double,VDOP,formatDop)
|
||||
GWBOATDATA(double,DBS,formatDepth) //waterDepth (below surface)
|
||||
GWBOATDATA(double,DBT,formatDepth) //DepthTransducer
|
||||
GWBOATDATA(double,GPST,formatTime) // GPS time (seconds of day)
|
||||
GWBOATDATA(uint32_t,GPSD,formatDate) // GPS date (days since 1979-01-01)
|
||||
GWBOATDATAT(int16_t,TZ,GwBoatItemBase::TOType::lng,formatFixed0)
|
||||
GWBOATDATA(double,WTemp,kelvinToC)
|
||||
GWBOATDATAT(uint32_t,Log,GwBoatItemBase::TOType::lng,mtr2nm)
|
||||
GWBOATDATAT(uint32_t,TripLog,GwBoatItemBase::TOType::lng,mtr2nm)
|
||||
GWBOATDATA(double,DTW,mtr2nm) // distance to waypoint
|
||||
GWBOATDATA(double,BTW,formatCourse) // bearing to waypoint
|
||||
GWBOATDATA(double,XTE,formatXte) // cross track error
|
||||
GWBOATDATA(double,WPLat,formatLatitude) // waypoint latitude
|
||||
GWBOATDATA(double,WPLon,formatLongitude) // waypoint longitude
|
||||
GWSPECBOATDATA(GwBoatDataSatList,SatInfo,GwSatInfoList::toType,formatFixed0);
|
||||
public:
|
||||
GwBoatData(GwLog *logger);
|
||||
GwBoatData(GwLog *logger, GwConfigHandler *cfg);
|
||||
~GwBoatData();
|
||||
template<class T> GwBoatItem<T> *getOrCreate(T initial,GwBoatItemNameProvider *provider);
|
||||
template<class T> bool update(T value,int source,GwBoatItemNameProvider *provider);
|
||||
|
|
|
@ -355,6 +355,7 @@ void GwXDRMappings::begin()
|
|||
GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list, int instance, const char *key)
|
||||
{
|
||||
GwXDRMapping *candidate = NULL;
|
||||
unsigned long invalidTime=config->getInt(GwConfigDefinitions::timoSensor);
|
||||
for (auto mit = list->begin(); mit != list->end(); mit++)
|
||||
{
|
||||
GwXDRMappingDef *def = (*mit)->definition;
|
||||
|
@ -369,7 +370,7 @@ GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list,
|
|||
{
|
||||
LOG_DEBUG(GwLog::DEBUG + 1, "selected mapping %s for %s, i=%d",
|
||||
def->toString().c_str(), key, instance);
|
||||
return GwXDRFoundMapping(*mit, instance);
|
||||
return GwXDRFoundMapping(*mit,invalidTime, instance);
|
||||
}
|
||||
if (instance < 0)
|
||||
{
|
||||
|
@ -393,7 +394,7 @@ GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list,
|
|||
{
|
||||
LOG_DEBUG(GwLog::DEBUG + 1, "selected mapping %s for %s, i=%d",
|
||||
candidate->definition->toString().c_str(), key, instance);
|
||||
return GwXDRFoundMapping(candidate, instance>=0?instance:candidate->definition->instanceId);
|
||||
return GwXDRFoundMapping(candidate, invalidTime,instance>=0?instance:candidate->definition->instanceId);
|
||||
}
|
||||
LOG_DEBUG(GwLog::DEBUG + 1, "no instance mapping found for key=%s, i=%d", key, instance);
|
||||
return GwXDRFoundMapping();
|
||||
|
@ -472,8 +473,9 @@ String GwXDRMappings::getXdrEntry(String mapping, double value,int instance){
|
|||
}
|
||||
GwXDRType *type = findType(code, &typeIndex);
|
||||
bool first=true;
|
||||
unsigned long invalidTime=config->getInt(GwConfigDefinitions::timoSensor);
|
||||
while (type){
|
||||
GwXDRFoundMapping found(def,type);
|
||||
GwXDRFoundMapping found(def,type,invalidTime);
|
||||
found.instanceId=instance;
|
||||
if (first) first=false;
|
||||
else rt+=",";
|
||||
|
|
|
@ -167,15 +167,18 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{
|
|||
GwXDRType *type=NULL;
|
||||
int instanceId=-1;
|
||||
bool empty=true;
|
||||
GwXDRFoundMapping(GwXDRMappingDef *definition,GwXDRType *type){
|
||||
unsigned long timeout=0;
|
||||
GwXDRFoundMapping(GwXDRMappingDef *definition,GwXDRType *type, unsigned long timeout){
|
||||
this->definition=definition;
|
||||
this->type=type;
|
||||
this->timeout=timeout;
|
||||
empty=false;
|
||||
}
|
||||
GwXDRFoundMapping(GwXDRMapping* mapping,int instance=0){
|
||||
GwXDRFoundMapping(GwXDRMapping* mapping,unsigned long timeout,int instance){
|
||||
this->definition=mapping->definition;
|
||||
this->type=mapping->type;
|
||||
this->instanceId=instance;
|
||||
this->timeout=timeout;
|
||||
empty=false;
|
||||
}
|
||||
GwXDRFoundMapping(){}
|
||||
|
@ -195,6 +198,9 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{
|
|||
return "formatXdr:"+type->xdrtype+":"+type->boatDataUnit;
|
||||
};
|
||||
virtual ~GwXDRFoundMapping(){}
|
||||
virtual unsigned long getInvalidTime() override{
|
||||
return timeout;
|
||||
}
|
||||
};
|
||||
|
||||
//the class GwXDRMappings is not intended to be deleted
|
||||
|
|
|
@ -138,7 +138,7 @@ bool fixedApPass=true;
|
|||
#endif
|
||||
GwWifi gwWifi(&config,&logger,fixedApPass);
|
||||
GwChannelList channels(&logger,&config);
|
||||
GwBoatData boatData(&logger);
|
||||
GwBoatData boatData(&logger,&config);
|
||||
GwXDRMappings xdrMappings(&logger,&config);
|
||||
bool sendOutN2k=true;
|
||||
|
||||
|
|
|
@ -250,6 +250,46 @@
|
|||
"description": "the n2k instance to be used as port rudder 0...253, -1 to disable",
|
||||
"category": "converter"
|
||||
},
|
||||
{
|
||||
"name": "timeouts",
|
||||
"type": "array",
|
||||
"replace":[
|
||||
{
|
||||
"n":"Default",
|
||||
"d":"4000",
|
||||
"l": "default",
|
||||
"t": "NMEA"
|
||||
},
|
||||
{
|
||||
"n":"Sensor",
|
||||
"d":"60000",
|
||||
"l": "sensor",
|
||||
"t": "sensor"
|
||||
},
|
||||
{
|
||||
"n":"Long",
|
||||
"d":"32000",
|
||||
"l": "long",
|
||||
"t": "special NMEA"
|
||||
},
|
||||
{
|
||||
"n":"Ais",
|
||||
"d":"120000",
|
||||
"l": "ais",
|
||||
"t": "ais"
|
||||
}
|
||||
],
|
||||
"children":[
|
||||
{
|
||||
"name":"timo$n",
|
||||
"label":"timeout $l",
|
||||
"default": "$d",
|
||||
"type": "number",
|
||||
"description": "data timeouts(ms) for $t data",
|
||||
"category": "converter"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "usbActisense",
|
||||
"label": "USB mode",
|
||||
|
|
Loading…
Reference in New Issue