Merge branch 'wellenvogel:master' into feature/env2
This commit is contained in:
commit
0bc071f856
|
@ -10,6 +10,16 @@ GwBoatData::~GwBoatData(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class T> GwBoatItem<T> *GwBoatData::getOrCreate(T dummy, String name, String format,
|
||||||
|
unsigned long invalidTime)
|
||||||
|
{
|
||||||
|
for (auto it=values.begin();it != values.end();it++){
|
||||||
|
if ((*it)->getName() == name){
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new GwBoatItem<T>(name,format,invalidTime,&values);
|
||||||
|
}
|
||||||
String GwBoatData::toJson() const {
|
String GwBoatData::toJson() const {
|
||||||
unsigned long minTime=millis();
|
unsigned long minTime=millis();
|
||||||
GwBoatItemBase::GwBoatItemMap::const_iterator it;
|
GwBoatItemBase::GwBoatItemMap::const_iterator it;
|
||||||
|
|
|
@ -55,6 +55,7 @@ class GwBoatItemBase{
|
||||||
virtual size_t getJsonSize(){return JSON_OBJECT_SIZE(15);}
|
virtual size_t getJsonSize(){return JSON_OBJECT_SIZE(15);}
|
||||||
virtual int getLastSource()=0;
|
virtual int getLastSource()=0;
|
||||||
virtual void refresh(unsigned long ts=0){uls(ts);}
|
virtual void refresh(unsigned long ts=0){uls(ts);}
|
||||||
|
String getName(){return name;}
|
||||||
};
|
};
|
||||||
class GwBoatData;
|
class GwBoatData;
|
||||||
template<class T> class GwBoatItem : public GwBoatItemBase{
|
template<class T> class GwBoatItem : public GwBoatItemBase{
|
||||||
|
@ -253,8 +254,43 @@ class GwBoatData{
|
||||||
public:
|
public:
|
||||||
GwBoatData(GwLog *logger);
|
GwBoatData(GwLog *logger);
|
||||||
~GwBoatData();
|
~GwBoatData();
|
||||||
|
template<class T> GwBoatItem<T> *getOrCreate(T dummy,String name,String format,
|
||||||
|
unsigned long invalidTime=GwBoatItemBase::INVALID_TIME);
|
||||||
String toJson() const;
|
String toJson() const;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* class for lazy creation of a boat item
|
||||||
|
* once we have someone that knows the name for it
|
||||||
|
* and providing fast access without searching all the time trough the map
|
||||||
|
* xdr mappings implement such a provider
|
||||||
|
*/
|
||||||
|
class GwBoatItemNameProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual String getBoatItemName() = 0;
|
||||||
|
virtual String getBoatItemFormat() = 0;
|
||||||
|
virtual ~GwBoatItemNameProvider() {}
|
||||||
|
};
|
||||||
|
template<class T> class GwBoatItemHolder{
|
||||||
|
private:
|
||||||
|
GwBoatItem<T> *item=NULL;
|
||||||
|
GwBoatData *data;
|
||||||
|
unsigned long invalidTime=GwBoatItemBase::INVALID_TIME;
|
||||||
|
public:
|
||||||
|
GwBoatItemHolder(GwBoatData *data,unsigned long invalidTime=GwBoatItemBase::INVALID_TIME){
|
||||||
|
this->data=data;
|
||||||
|
this->invalidTime=invalidTime;
|
||||||
|
}
|
||||||
|
GwBoatItem<T> *getItem(GwBoatItemNameProvider *provider){
|
||||||
|
if (item) return item;
|
||||||
|
T dummy;
|
||||||
|
item=data->getOrCreate(dummy,
|
||||||
|
provider->getBoatItemName() ,
|
||||||
|
provider->getBoatItemFormat(),
|
||||||
|
invalidTime);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
GwBoatItem<T> *getItem(){return item;}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -2,6 +2,7 @@
|
||||||
#define _GWXDRMAPPINGS_H
|
#define _GWXDRMAPPINGS_H
|
||||||
#include "GwLog.h"
|
#include "GwLog.h"
|
||||||
#include "GWConfig.h"
|
#include "GWConfig.h"
|
||||||
|
#include "GwBoatData.h"
|
||||||
#include <WString.h>
|
#include <WString.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -141,7 +142,7 @@ class GwXDRMapping{
|
||||||
typedef std::map<String,MappingList> N138Map;
|
typedef std::map<String,MappingList> N138Map;
|
||||||
typedef std::map<unsigned long,MappingList> N2KMap;
|
typedef std::map<unsigned long,MappingList> N2KMap;
|
||||||
};
|
};
|
||||||
class GwXDRFoundMapping{
|
class GwXDRFoundMapping : public GwBoatItemNameProvider{
|
||||||
public:
|
public:
|
||||||
GwXDRMappingDef *definition=NULL;
|
GwXDRMappingDef *definition=NULL;
|
||||||
GwXDRType *type=NULL;
|
GwXDRType *type=NULL;
|
||||||
|
@ -163,6 +164,14 @@ class GwXDRFoundMapping{
|
||||||
return definition->getTransducerName(instanceId);
|
return definition->getTransducerName(instanceId);
|
||||||
}
|
}
|
||||||
String buildXdrEntry(double value);
|
String buildXdrEntry(double value);
|
||||||
|
//boat Data info
|
||||||
|
virtual String getBoatItemName(){
|
||||||
|
return getTransducerName();
|
||||||
|
};
|
||||||
|
virtual String getBoatItemFormat(){
|
||||||
|
return "formatXdr"+type->xdrunit; //TODO: use the type def for the correct format
|
||||||
|
};
|
||||||
|
virtual ~GwXDRFoundMapping(){}
|
||||||
};
|
};
|
||||||
|
|
||||||
//the class GwXDRMappings is not intended to be deleted
|
//the class GwXDRMappings is not intended to be deleted
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#! /bin/sh
|
||||||
|
i=0
|
||||||
|
[ "$2" != "" ] && i=$2
|
||||||
|
if [ "$1" = "" ] ; then
|
||||||
|
echo "usage: $0 num [start]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
num=$1
|
||||||
|
|
||||||
|
while [ $num -gt 0 ]
|
||||||
|
do
|
||||||
|
echo '{"name": "XDR'$i'","label": "XDR'$i'","type": "xdr","default": "", "check": "checkXDR","category":"xdr'$i'"},'
|
||||||
|
num=`expr $num - 1`
|
||||||
|
i=`expr $i + 1`
|
||||||
|
done
|
480
web/config.json
480
web/config.json
|
@ -6,16 +6,101 @@
|
||||||
"default": "ESP32NMEA2K",
|
"default": "ESP32NMEA2K",
|
||||||
"check": "checkSystemName",
|
"check": "checkSystemName",
|
||||||
"description": "system name, used for the access point and for services",
|
"description": "system name, used for the access point and for services",
|
||||||
"category":"system"
|
"category": "system"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name":"talkerId",
|
"name": "talkerId",
|
||||||
"label":"NMEA0183 ID",
|
"label": "NMEA0183 ID",
|
||||||
"type":"list",
|
"type": "list",
|
||||||
"default":"GP",
|
"default": "GP",
|
||||||
"list":["AB","AD","AG","AP","AI","AN","AR","AS","AT","AX","BI","BN","CA","CD","CR","CS","CT","CV","CX","DF","DU","DP","EC","EI","EP","ER","FD","FE","FR","FS","GA","GB","GI","GL","GN","GP","GQ","HC","HE","HF","HN","HD","HS","II","IN","JA","JB","JC","JD","JE","JF","JG","JH","LC","NL","NV","RA","RB","RC","RI","SA","SC","SD","SG","SN","SS","TC","TI","UP","VD","VM","VW","VA","VS","VT","VR","WD","WI","WL","YX","ZA","ZC","ZQ","ZV"],
|
"list": [
|
||||||
"description":"the talkerId used in generated NMEA0183 records",
|
"AB",
|
||||||
"category":"system"
|
"AD",
|
||||||
|
"AG",
|
||||||
|
"AP",
|
||||||
|
"AI",
|
||||||
|
"AN",
|
||||||
|
"AR",
|
||||||
|
"AS",
|
||||||
|
"AT",
|
||||||
|
"AX",
|
||||||
|
"BI",
|
||||||
|
"BN",
|
||||||
|
"CA",
|
||||||
|
"CD",
|
||||||
|
"CR",
|
||||||
|
"CS",
|
||||||
|
"CT",
|
||||||
|
"CV",
|
||||||
|
"CX",
|
||||||
|
"DF",
|
||||||
|
"DU",
|
||||||
|
"DP",
|
||||||
|
"EC",
|
||||||
|
"EI",
|
||||||
|
"EP",
|
||||||
|
"ER",
|
||||||
|
"FD",
|
||||||
|
"FE",
|
||||||
|
"FR",
|
||||||
|
"FS",
|
||||||
|
"GA",
|
||||||
|
"GB",
|
||||||
|
"GI",
|
||||||
|
"GL",
|
||||||
|
"GN",
|
||||||
|
"GP",
|
||||||
|
"GQ",
|
||||||
|
"HC",
|
||||||
|
"HE",
|
||||||
|
"HF",
|
||||||
|
"HN",
|
||||||
|
"HD",
|
||||||
|
"HS",
|
||||||
|
"II",
|
||||||
|
"IN",
|
||||||
|
"JA",
|
||||||
|
"JB",
|
||||||
|
"JC",
|
||||||
|
"JD",
|
||||||
|
"JE",
|
||||||
|
"JF",
|
||||||
|
"JG",
|
||||||
|
"JH",
|
||||||
|
"LC",
|
||||||
|
"NL",
|
||||||
|
"NV",
|
||||||
|
"RA",
|
||||||
|
"RB",
|
||||||
|
"RC",
|
||||||
|
"RI",
|
||||||
|
"SA",
|
||||||
|
"SC",
|
||||||
|
"SD",
|
||||||
|
"SG",
|
||||||
|
"SN",
|
||||||
|
"SS",
|
||||||
|
"TC",
|
||||||
|
"TI",
|
||||||
|
"UP",
|
||||||
|
"VD",
|
||||||
|
"VM",
|
||||||
|
"VW",
|
||||||
|
"VA",
|
||||||
|
"VS",
|
||||||
|
"VT",
|
||||||
|
"VR",
|
||||||
|
"WD",
|
||||||
|
"WI",
|
||||||
|
"WL",
|
||||||
|
"YX",
|
||||||
|
"ZA",
|
||||||
|
"ZC",
|
||||||
|
"ZQ",
|
||||||
|
"ZV"
|
||||||
|
],
|
||||||
|
"description": "the talkerId used in generated NMEA0183 records",
|
||||||
|
"category": "system"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "stopApTime",
|
"name": "stopApTime",
|
||||||
|
@ -23,7 +108,7 @@
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"check": "checkStopApTime",
|
"check": "checkStopApTime",
|
||||||
"description": "stop the access point after that many minutes if not used",
|
"description": "stop the access point after that many minutes if not used",
|
||||||
"category":"system"
|
"category": "system"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "apPassword",
|
"name": "apPassword",
|
||||||
|
@ -31,8 +116,12 @@
|
||||||
"default": "esp32nmea2k",
|
"default": "esp32nmea2k",
|
||||||
"check": "checkApPass",
|
"check": "checkApPass",
|
||||||
"description": "set the password for the Wifi access point",
|
"description": "set the password for the Wifi access point",
|
||||||
"category":"system",
|
"category": "system",
|
||||||
"capabilities":{"hardwareReset":["true"]}
|
"capabilities": {
|
||||||
|
"hardwareReset": [
|
||||||
|
"true"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "usbBaud",
|
"name": "usbBaud",
|
||||||
|
@ -40,8 +129,21 @@
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"default": "115200",
|
"default": "115200",
|
||||||
"description": "baud rate for the USB port",
|
"description": "baud rate for the USB port",
|
||||||
"list": [1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800],
|
"list": [
|
||||||
"category":"usb port"
|
1200,
|
||||||
|
2400,
|
||||||
|
4800,
|
||||||
|
9600,
|
||||||
|
14400,
|
||||||
|
19200,
|
||||||
|
28800,
|
||||||
|
38400,
|
||||||
|
57600,
|
||||||
|
115200,
|
||||||
|
230400,
|
||||||
|
460800
|
||||||
|
],
|
||||||
|
"category": "usb port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sendUsb",
|
"name": "sendUsb",
|
||||||
|
@ -49,7 +151,7 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "send out NMEA data on the USB port",
|
"description": "send out NMEA data on the USB port",
|
||||||
"category":"usb port"
|
"category": "usb port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "receiveUsb",
|
"name": "receiveUsb",
|
||||||
|
@ -57,7 +159,7 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "receive NMEA data on the USB port",
|
"description": "receive NMEA data on the USB port",
|
||||||
"category":"usb port"
|
"category": "usb port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "usbToN2k",
|
"name": "usbToN2k",
|
||||||
|
@ -65,7 +167,7 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "convert NMEA0183 from the USB port to NMEA2000",
|
"description": "convert NMEA0183 from the USB port to NMEA2000",
|
||||||
"category":"usb port"
|
"category": "usb port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "usbReadFilter",
|
"name": "usbReadFilter",
|
||||||
|
@ -73,7 +175,7 @@
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when reading from USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
"description": "filter for NMEA0183 data when reading from USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"category":"usb port"
|
"category": "usb port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "usbWriteFilter",
|
"name": "usbWriteFilter",
|
||||||
|
@ -81,17 +183,25 @@
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when writing to USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
"description": "filter for NMEA0183 data when writing to USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"category":"usb port"
|
"category": "usb port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "serialDirection",
|
"name": "serialDirection",
|
||||||
"label": "serial direction",
|
"label": "serial direction",
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"default": "receive",
|
"default": "receive",
|
||||||
"list": ["send","receive","off"],
|
"list": [
|
||||||
|
"send",
|
||||||
|
"receive",
|
||||||
|
"off"
|
||||||
|
],
|
||||||
"description": "use the serial port to send or receive data",
|
"description": "use the serial port to send or receive data",
|
||||||
"capabilities":{"serialmode":["UNI"]},
|
"capabilities": {
|
||||||
"category":"serial port"
|
"serialmode": [
|
||||||
|
"UNI"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"category": "serial port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "serialBaud",
|
"name": "serialBaud",
|
||||||
|
@ -99,9 +209,29 @@
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"default": "115200",
|
"default": "115200",
|
||||||
"description": "baud rate for the serial port",
|
"description": "baud rate for the serial port",
|
||||||
"list": [1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800],
|
"list": [
|
||||||
"capabilities":{"serialmode":["RX","TX","UNI","BI"]},
|
1200,
|
||||||
"category":"serial port"
|
2400,
|
||||||
|
4800,
|
||||||
|
9600,
|
||||||
|
14400,
|
||||||
|
19200,
|
||||||
|
28800,
|
||||||
|
38400,
|
||||||
|
57600,
|
||||||
|
115200,
|
||||||
|
230400,
|
||||||
|
460800
|
||||||
|
],
|
||||||
|
"capabilities": {
|
||||||
|
"serialmode": [
|
||||||
|
"RX",
|
||||||
|
"TX",
|
||||||
|
"UNI",
|
||||||
|
"BI"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"category": "serial port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sendSerial",
|
"name": "sendSerial",
|
||||||
|
@ -109,8 +239,13 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "send out NMEA data on the serial port",
|
"description": "send out NMEA data on the serial port",
|
||||||
"capabilities":{"serialmode":["TX","BI"]},
|
"capabilities": {
|
||||||
"category":"serial port"
|
"serialmode": [
|
||||||
|
"TX",
|
||||||
|
"BI"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"category": "serial port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "receiveSerial",
|
"name": "receiveSerial",
|
||||||
|
@ -118,8 +253,13 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "receive NMEA data on the serial port",
|
"description": "receive NMEA data on the serial port",
|
||||||
"capabilities":{"serialmode":["RX","BI"]},
|
"capabilities": {
|
||||||
"category":"serial port"
|
"serialmode": [
|
||||||
|
"RX",
|
||||||
|
"BI"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"category": "serial port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "serialToN2k",
|
"name": "serialToN2k",
|
||||||
|
@ -127,8 +267,14 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "convert NMEA0183 from the serial port to NMEA2000",
|
"description": "convert NMEA0183 from the serial port to NMEA2000",
|
||||||
"capabilities":{"serialmode":["RX","BI","UNI"]},
|
"capabilities": {
|
||||||
"category":"serial port"
|
"serialmode": [
|
||||||
|
"RX",
|
||||||
|
"BI",
|
||||||
|
"UNI"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"category": "serial port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "serialReadF",
|
"name": "serialReadF",
|
||||||
|
@ -136,8 +282,14 @@
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when reading from serial\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
"description": "filter for NMEA0183 data when reading from serial\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"capabilities":{"serialmode":["RX","BI","UNI"]},
|
"capabilities": {
|
||||||
"category":"serial port"
|
"serialmode": [
|
||||||
|
"RX",
|
||||||
|
"BI",
|
||||||
|
"UNI"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"category": "serial port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "serialWriteF",
|
"name": "serialWriteF",
|
||||||
|
@ -145,8 +297,14 @@
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when writing to serial\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
"description": "filter for NMEA0183 data when writing to serial\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"capabilities":{"serialmode":["TX","BI","UNI"]},
|
"capabilities": {
|
||||||
"category":"serial port"
|
"serialmode": [
|
||||||
|
"TX",
|
||||||
|
"BI",
|
||||||
|
"UNI"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"category": "serial port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "serverPort",
|
"name": "serverPort",
|
||||||
|
@ -154,16 +312,16 @@
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": "10110",
|
"default": "10110",
|
||||||
"description": "the TCP port we listen on",
|
"description": "the TCP port we listen on",
|
||||||
"category":"TCP port"
|
"category": "TCP port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "maxClients",
|
"name": "maxClients",
|
||||||
"label": "max. TCP clients",
|
"label": "max. TCP clients",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": "10",
|
"default": "10",
|
||||||
"check":"checkMaxClients",
|
"check": "checkMaxClients",
|
||||||
"description": "the number of clients we allow to connect to us",
|
"description": "the number of clients we allow to connect to us",
|
||||||
"category":"TCP port"
|
"category": "TCP port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sendTCP",
|
"name": "sendTCP",
|
||||||
|
@ -171,7 +329,7 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "send out NMEA data to connected TCP clients",
|
"description": "send out NMEA data to connected TCP clients",
|
||||||
"category":"TCP port"
|
"category": "TCP port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "readTCP",
|
"name": "readTCP",
|
||||||
|
@ -179,7 +337,7 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "receive NMEA data from connected TCP clients",
|
"description": "receive NMEA data from connected TCP clients",
|
||||||
"category":"TCP port"
|
"category": "TCP port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tcpToN2k",
|
"name": "tcpToN2k",
|
||||||
|
@ -187,7 +345,7 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "convert NMEA0183 from TCP clients to NMEA2000",
|
"description": "convert NMEA0183 from TCP clients to NMEA2000",
|
||||||
"category":"TCP port"
|
"category": "TCP port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tcpReadFilter",
|
"name": "tcpReadFilter",
|
||||||
|
@ -195,7 +353,7 @@
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when reading from TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
"description": "filter for NMEA0183 data when reading from TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"category":"TCP port"
|
"category": "TCP port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tcpWriteFilter",
|
"name": "tcpWriteFilter",
|
||||||
|
@ -203,7 +361,7 @@
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when writing to TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
"description": "filter for NMEA0183 data when writing to TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"category":"TCP port"
|
"category": "TCP port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sendSeasmart",
|
"name": "sendSeasmart",
|
||||||
|
@ -211,7 +369,7 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "false",
|
"default": "false",
|
||||||
"description": "send NMEA2000 as seasmart to connected TCP clients",
|
"description": "send NMEA2000 as seasmart to connected TCP clients",
|
||||||
"category":"TCP port"
|
"category": "TCP port"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "wifiClient",
|
"name": "wifiClient",
|
||||||
|
@ -219,7 +377,7 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "false",
|
"default": "false",
|
||||||
"description": "connect to an external WIFI network",
|
"description": "connect to an external WIFI network",
|
||||||
"category":"wifi client"
|
"category": "wifi client"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "wifiPass",
|
"name": "wifiPass",
|
||||||
|
@ -227,7 +385,7 @@
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "the password for an external WIFI network",
|
"description": "the password for an external WIFI network",
|
||||||
"category":"wifi client"
|
"category": "wifi client"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "wifiSSID",
|
"name": "wifiSSID",
|
||||||
|
@ -236,7 +394,7 @@
|
||||||
"default": "",
|
"default": "",
|
||||||
"check": "checkSSID",
|
"check": "checkSSID",
|
||||||
"description": "the SSID for an external WIFI network",
|
"description": "the SSID for an external WIFI network",
|
||||||
"category":"wifi client"
|
"category": "wifi client"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "XDR1",
|
"name": "XDR1",
|
||||||
|
@ -244,7 +402,7 @@
|
||||||
"type": "xdr",
|
"type": "xdr",
|
||||||
"default": "",
|
"default": "",
|
||||||
"check": "checkXDR",
|
"check": "checkXDR",
|
||||||
"category":"xdr1"
|
"category": "xdr1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "XDR2",
|
"name": "XDR2",
|
||||||
|
@ -252,8 +410,230 @@
|
||||||
"type": "xdr",
|
"type": "xdr",
|
||||||
"default": "",
|
"default": "",
|
||||||
"check": "checkXDR",
|
"check": "checkXDR",
|
||||||
"category":"xdr2"
|
"category": "xdr2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR3",
|
||||||
|
"label": "XDR3",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR4",
|
||||||
|
"label": "XDR4",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR5",
|
||||||
|
"label": "XDR5",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR6",
|
||||||
|
"label": "XDR6",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR7",
|
||||||
|
"label": "XDR7",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR8",
|
||||||
|
"label": "XDR8",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR9",
|
||||||
|
"label": "XDR9",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR10",
|
||||||
|
"label": "XDR10",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR11",
|
||||||
|
"label": "XDR11",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr11"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR12",
|
||||||
|
"label": "XDR12",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr12"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR13",
|
||||||
|
"label": "XDR13",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr13"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR14",
|
||||||
|
"label": "XDR14",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr14"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR15",
|
||||||
|
"label": "XDR15",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr15"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR16",
|
||||||
|
"label": "XDR16",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR17",
|
||||||
|
"label": "XDR17",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr17"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR18",
|
||||||
|
"label": "XDR18",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr18"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR19",
|
||||||
|
"label": "XDR19",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr19"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR20",
|
||||||
|
"label": "XDR20",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR21",
|
||||||
|
"label": "XDR21",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr21"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR22",
|
||||||
|
"label": "XDR22",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr22"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR23",
|
||||||
|
"label": "XDR23",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr23"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR24",
|
||||||
|
"label": "XDR24",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr24"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR25",
|
||||||
|
"label": "XDR25",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr25"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR26",
|
||||||
|
"label": "XDR26",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr26"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR27",
|
||||||
|
"label": "XDR27",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr27"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR28",
|
||||||
|
"label": "XDR28",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr28"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR29",
|
||||||
|
"label": "XDR29",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XDR30",
|
||||||
|
"label": "XDR30",
|
||||||
|
"type": "xdr",
|
||||||
|
"default": "",
|
||||||
|
"check": "checkXDR",
|
||||||
|
"category": "xdr30"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
]
|
]
|
|
@ -146,7 +146,15 @@ body{
|
||||||
.xdrexample {
|
.xdrexample {
|
||||||
max-width: 16em;
|
max-width: 16em;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
.uploadXdr{
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
button.addunassigned {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
.msgDetails .value {
|
.msgDetails .value {
|
||||||
width: 5em;
|
width: 5em;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
@ -162,6 +170,7 @@ body{
|
||||||
right: 0;
|
right: 0;
|
||||||
background-color: #80808070;
|
background-color: #80808070;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
div#overlay {
|
div#overlay {
|
||||||
|
|
|
@ -65,6 +65,8 @@
|
||||||
<button id="resetForm">ReloadConfig</button>
|
<button id="resetForm">ReloadConfig</button>
|
||||||
<button id="changeConfig">Save&Restart</button>
|
<button id="changeConfig">Save&Restart</button>
|
||||||
<button id="loadUnassigned">Show Unmapped</button>
|
<button id="loadUnassigned">Show Unmapped</button>
|
||||||
|
<button id="exportXdr">Export</button>
|
||||||
|
<button id="importXdr">Import</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tabPage hidden" id="dashboardPage">
|
<div class="tabPage hidden" id="dashboardPage">
|
||||||
|
@ -82,6 +84,40 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="xdrHelp" class="hidden">
|
||||||
|
<h1>XDR Help</h1>
|
||||||
|
<p>You can configure the mapping of various NMEA2000 entities to XDR records.</p>
|
||||||
|
<p>To set up such a mapping you select the category, the source of data
|
||||||
|
(if the category has different sources) and the field (if the category has multiple fields).</p>
|
||||||
|
<p>You have to provide the name of the transducer for the XDR record.</p>
|
||||||
|
<p>Many of the NMEA2000 messages have an instance id (0..255) to allow
|
||||||
|
for different sources of the data. You need to decide how do you want to
|
||||||
|
map such IDs to XDR records.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>IGNORE: the instance id will be ignored</li>
|
||||||
|
<li>AUTO: the instance will be appended to the transducer name: #123</li>
|
||||||
|
<li>SINGLE: just map exactlly one instance to this transducer name</li>
|
||||||
|
</ul>
|
||||||
|
<p>You can also decide if you want a both way mapping, i.e. also map
|
||||||
|
received XDR records back to NMEA 2000.
|
||||||
|
</p>
|
||||||
|
<p>Once you create a mapping the system will show an example of the
|
||||||
|
generated XDR records (and the accepted ones).
|
||||||
|
</p>
|
||||||
|
<p>To ease the set up the system will track received NMEA2000 data
|
||||||
|
that it currently does not map.
|
||||||
|
With clicking <span class="txtShowUnmapped">"Show Unmapped"</span> you bring up such a list and for each
|
||||||
|
found mapping there is a "+" button that will allow you to create a mapping
|
||||||
|
for this record.
|
||||||
|
</p>
|
||||||
|
<p>The set of handled PGNs that can be mapped to XDR records can be found
|
||||||
|
in the documentation.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="hidden">
|
||||||
|
<a id="downloadXdr"></a>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
299
web/index.js
299
web/index.js
|
@ -110,9 +110,39 @@ function checkApPass(v) {
|
||||||
return "password must be at least 8 characters";
|
return "password must be at least 8 characters";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function checkXDR(v,allValues){
|
||||||
|
if (! v) return;
|
||||||
|
let parts=v.split(',');
|
||||||
|
if (parseInt(parts[1]) == 0) return;
|
||||||
|
if (parseInt(parts[1]) != 0 && ! parts[6]) return "missing transducer name";
|
||||||
|
for (let k in allValues){
|
||||||
|
if (! k.match(/^XDR/)) continue;
|
||||||
|
let cmp=allValues[k];
|
||||||
|
if (cmp == v){
|
||||||
|
return "same mapping already defined in "+k;
|
||||||
|
}
|
||||||
|
let cmpParts=cmp.split(',');
|
||||||
|
if (parseInt(cmpParts[1]) != 0 && parts[6] == cmpParts[6]){
|
||||||
|
return "transducer "+parts[6]+" already defined in "+k;
|
||||||
|
}
|
||||||
|
//check similar mappings
|
||||||
|
if (parts[0]==cmpParts[0] && parts[2] == cmpParts[2] && parts[3] == cmpParts[3]){
|
||||||
|
if (parts[4] == cmpParts[4] && parts[5] == cmpParts[5]){
|
||||||
|
return "mapping for the same entity already defined in "+k;
|
||||||
|
}
|
||||||
|
if ((parseInt(parts[4]) == 0 && parseInt(cmpParts[4]) == 1)||
|
||||||
|
(parseInt(parts[4]) == 1 && parseInt(cmpParts[4]) == 0)
|
||||||
|
){
|
||||||
|
//ignore and single for the same mapping
|
||||||
|
return "mapping for the same entity already defined in "+k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
function changeConfig() {
|
function changeConfig() {
|
||||||
let url = "/api/setConfig?";
|
let url = "/api/setConfig?";
|
||||||
let values = document.querySelectorAll('.configForm select , .configForm input');
|
let values = document.querySelectorAll('.configForm select , .configForm input');
|
||||||
|
let allValues={};
|
||||||
for (let i = 0; i < values.length; i++) {
|
for (let i = 0; i < values.length; i++) {
|
||||||
let v = values[i];
|
let v = values[i];
|
||||||
let name = v.getAttribute('name');
|
let name = v.getAttribute('name');
|
||||||
|
@ -121,7 +151,7 @@ function changeConfig() {
|
||||||
let check = v.getAttribute('data-check');
|
let check = v.getAttribute('data-check');
|
||||||
if (check) {
|
if (check) {
|
||||||
if (typeof (self[check]) === 'function') {
|
if (typeof (self[check]) === 'function') {
|
||||||
let res = self[check](v.value);
|
let res = self[check](v.value,allValues);
|
||||||
if (res) {
|
if (res) {
|
||||||
let value = v.value;
|
let value = v.value;
|
||||||
if (v.type === 'password') value = "******";
|
if (v.type === 'password') value = "******";
|
||||||
|
@ -130,6 +160,7 @@ function changeConfig() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
allValues[name]=v.value;
|
||||||
url += name + "=" + encodeURIComponent(v.value) + "&";
|
url += name + "=" + encodeURIComponent(v.value) + "&";
|
||||||
}
|
}
|
||||||
getJson(url)
|
getJson(url)
|
||||||
|
@ -236,8 +267,8 @@ function checkChange(el, row) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let configDefinitions;
|
let configDefinitions={};
|
||||||
let xdrConfig;
|
let xdrConfig={};
|
||||||
function createInput(configItem, frame,clazz) {
|
function createInput(configItem, frame,clazz) {
|
||||||
let el;
|
let el;
|
||||||
if (configItem.type === 'boolean' || configItem.type === 'list') {
|
if (configItem.type === 'boolean' || configItem.type === 'list') {
|
||||||
|
@ -295,9 +326,11 @@ function createInput(configItem, frame,clazz) {
|
||||||
|
|
||||||
function updateSelectList(item,slist){
|
function updateSelectList(item,slist){
|
||||||
item.innerHTML='';
|
item.innerHTML='';
|
||||||
|
let idx=0;
|
||||||
slist.forEach(function (sitem) {
|
slist.forEach(function (sitem) {
|
||||||
let sitemEl = addEl('option','',item,sitem.l);
|
let sitemEl = addEl('option','',item,sitem.l);
|
||||||
sitemEl.setAttribute('value', sitem.v);
|
sitemEl.setAttribute('value', sitem.v !== undefined?sitem.v:idx);
|
||||||
|
idx++;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function getXdrCategories(){
|
function getXdrCategories(){
|
||||||
|
@ -309,25 +342,39 @@ function getXdrCategories(){
|
||||||
}
|
}
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
function getXdrSelectors(category){
|
function getXdrCategoryName(cid){
|
||||||
category=parseInt(category);
|
category=parseInt(cid);
|
||||||
for (let c in xdrConfig){
|
for (let c in xdrConfig){
|
||||||
let base=xdrConfig[c];
|
let base=xdrConfig[c];
|
||||||
if (parseInt(base.id) == category){
|
if (parseInt(base.id) == category){
|
||||||
return base.selector || [];
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [];
|
}
|
||||||
|
function getXdrCategory(cid){
|
||||||
|
category=parseInt(cid);
|
||||||
|
for (let c in xdrConfig){
|
||||||
|
let base=xdrConfig[c];
|
||||||
|
if (parseInt(base.id) == category){
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
function getXdrSelectors(category){
|
||||||
|
let base=getXdrCategory(category);
|
||||||
|
return base.selector || [];
|
||||||
}
|
}
|
||||||
function getXdrFields(category){
|
function getXdrFields(category){
|
||||||
category=parseInt(category);
|
let base=getXdrCategory(category);
|
||||||
for (let c in xdrConfig){
|
if (!base.fields) return [];
|
||||||
let base=xdrConfig[c];
|
let rt=[];
|
||||||
if (parseInt(base.id) == category){
|
base.fields.forEach(function(f){
|
||||||
return base.fields || [];
|
if (f.t === undefined) return;
|
||||||
}
|
if (parseInt(f.t) == 99) return; //unknown type
|
||||||
}
|
rt.push(f);
|
||||||
return [];
|
});
|
||||||
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createXdrLine(parent,label){
|
function createXdrLine(parent,label){
|
||||||
|
@ -421,10 +468,16 @@ function createXdrInput(configItem,frame){
|
||||||
if (used) {
|
if (used) {
|
||||||
el.classList.add('xdrcused');
|
el.classList.add('xdrcused');
|
||||||
el.classList.remove('xdrcunused');
|
el.classList.remove('xdrcunused');
|
||||||
|
forEl('.categoryAdd',function(add){
|
||||||
|
add.textContent=xdrName.value;
|
||||||
|
},el);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
el.classList.remove('xdrcused');
|
el.classList.remove('xdrcused');
|
||||||
el.classList.add('xdrcunused');
|
el.classList.add('xdrcunused');
|
||||||
|
forEl('.categoryAdd',function(add){
|
||||||
|
add.textContent='';
|
||||||
|
},el);
|
||||||
}
|
}
|
||||||
if (modified){
|
if (modified){
|
||||||
el.classList.add('changed');
|
el.classList.add('changed');
|
||||||
|
@ -443,7 +496,12 @@ function createXdrInput(configItem,frame){
|
||||||
example.textContent='';
|
example.textContent='';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let updateFunction = function () {
|
let updateFunction = function (evt) {
|
||||||
|
if (evt.target == category){
|
||||||
|
selector.value=0;
|
||||||
|
field.value=0;
|
||||||
|
instance.value=0;
|
||||||
|
}
|
||||||
let txt=category.value+","+direction.value+","+
|
let txt=category.value+","+direction.value+","+
|
||||||
selector.value+","+field.value+","+imode.value;
|
selector.value+","+field.value+","+imode.value;
|
||||||
let instanceValue=parseInt(instance.value||0);
|
let instanceValue=parseInt(instance.value||0);
|
||||||
|
@ -471,7 +529,8 @@ function createXdrInput(configItem,frame){
|
||||||
|
|
||||||
function isXdrUsed(element){
|
function isXdrUsed(element){
|
||||||
let parts=element.value.split(',');
|
let parts=element.value.split(',');
|
||||||
if (! parts[0]) return false;
|
if (! parts[1]) return false;
|
||||||
|
if (! parseInt(parts[1])) return false;
|
||||||
if (! parts[6]) return false;
|
if (! parts[6]) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -520,6 +579,194 @@ function createFilterInput(configItem, frame) {
|
||||||
data.setAttribute('name', configItem.name);
|
data.setAttribute('name', configItem.name);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
let moreicons=['icon-more','icon-less'];
|
||||||
|
|
||||||
|
function collapseCategories(parent,expand){
|
||||||
|
let doExpand=expand;
|
||||||
|
forEl('.category',function(cat){
|
||||||
|
if (typeof(expand) === 'function') doExpand=expand(cat);
|
||||||
|
forEl('.content',function(content){
|
||||||
|
if (doExpand){
|
||||||
|
content.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
content.classList.add('hidden');
|
||||||
|
}
|
||||||
|
},cat);
|
||||||
|
forEl('.title .icon',function(icon){
|
||||||
|
toggleClass(icon,doExpand?1:0,moreicons);
|
||||||
|
},cat);
|
||||||
|
},parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function findFreeXdr(data){
|
||||||
|
let page=document.getElementById('xdrPage');
|
||||||
|
let el=undefined;
|
||||||
|
collapseCategories(page,function(cat){
|
||||||
|
if (el) return false;
|
||||||
|
let vEl=cat.querySelector('.xdrvalue');
|
||||||
|
if (!vEl) return false;
|
||||||
|
if (isXdrUsed(vEl)) return false;
|
||||||
|
el=vEl;
|
||||||
|
if (data){
|
||||||
|
el.value=data;
|
||||||
|
let ev=new Event('change');
|
||||||
|
el.dispatchEvent(ev);
|
||||||
|
window.setTimeout(function(){
|
||||||
|
cat.scrollIntoView();
|
||||||
|
},50);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertUnassigned(value){
|
||||||
|
let rt={};
|
||||||
|
value=parseInt(value);
|
||||||
|
if (isNaN(value)) return;
|
||||||
|
//see GwXDRMappings::addUnknown
|
||||||
|
let instance=value & 0x1ff;
|
||||||
|
value = value >> 9;
|
||||||
|
let field=value & 0x7f;
|
||||||
|
value = value >> 7;
|
||||||
|
let selector=value & 0x7f;
|
||||||
|
value = value >> 7;
|
||||||
|
let cid=value & 0x7f;
|
||||||
|
let category=getXdrCategory(cid);
|
||||||
|
let cname=getXdrCategoryName(cid);
|
||||||
|
if (! cname) return rt;
|
||||||
|
let fieldName="";
|
||||||
|
(category.fields || []).forEach(function(f){
|
||||||
|
if (parseInt(f.v) == field) fieldName=f.l;
|
||||||
|
});
|
||||||
|
let selectorName=selector+"";
|
||||||
|
(category.selector ||[]).forEach(function(s){
|
||||||
|
if (parseInt(s.v) == selector) selectorName=s.l;
|
||||||
|
});
|
||||||
|
rt.l=cname+","+selectorName+","+fieldName+","+instance;
|
||||||
|
rt.v=cid+",1,"+selector+","+field+",1,"+instance+",";
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unassignedAdd(ev) {
|
||||||
|
let dv = ev.target.getAttribute('data-value');
|
||||||
|
if (dv) {
|
||||||
|
findFreeXdr(dv);
|
||||||
|
hideOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function loadUnassigned(){
|
||||||
|
getText("/api/xdrUnmapped")
|
||||||
|
.then(function(txt){
|
||||||
|
let ot="";
|
||||||
|
txt.split('\n').forEach(function(line){
|
||||||
|
let cv=convertUnassigned(line);
|
||||||
|
if (!cv || !cv.l) return;
|
||||||
|
ot+='<div class="xdrunassigned"><span>'+
|
||||||
|
cv.l+'</span>'+
|
||||||
|
'<button class="addunassigned" data-value="'+
|
||||||
|
cv.v+
|
||||||
|
'">+</button></div>';
|
||||||
|
})
|
||||||
|
showOverlay(ot,true);
|
||||||
|
forEl('.addunassigned',function(bt){
|
||||||
|
bt.onclick=unassignedAdd;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function showXdrHelp(){
|
||||||
|
let helpContent=document.getElementById('xdrHelp');
|
||||||
|
if (helpContent){
|
||||||
|
showOverlay(helpContent.innerHTML,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function formatDate(d){
|
||||||
|
if (! d) d=new Date();
|
||||||
|
let rt=""+d.getFullYear();
|
||||||
|
let v=d.getMonth();
|
||||||
|
if (v < 10) rt+="0"+v;
|
||||||
|
else rt+=v;
|
||||||
|
v=d.getDate();
|
||||||
|
if (v < 10) rt+="0"+v;
|
||||||
|
else rt+=v;
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
function exportXdr(){
|
||||||
|
let data={};
|
||||||
|
forEl('.xdrvalue',function(el) {
|
||||||
|
let name=el.getAttribute('name');
|
||||||
|
let value=el.value;
|
||||||
|
let err=checkXDR(value,data);
|
||||||
|
if (err){
|
||||||
|
alert("error in "+name+": "+value+"\n"+err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[name]=value;
|
||||||
|
})
|
||||||
|
let url="data:application/octet-stream,"+encodeURIComponent(JSON.stringify(data,undefined,2));
|
||||||
|
let target=document.getElementById('downloadXdr');
|
||||||
|
if (! target) return;
|
||||||
|
target.setAttribute('href',url);
|
||||||
|
target.setAttribute('download',"xdr"+formatDate()+".json");
|
||||||
|
target.click();
|
||||||
|
}
|
||||||
|
function importXdr(){
|
||||||
|
forEl('.uploadXdr',function(ul){
|
||||||
|
ul.remove();
|
||||||
|
});
|
||||||
|
let ip=addEl('input','uploadXdr',document.body);
|
||||||
|
ip.setAttribute('type','file');
|
||||||
|
ip.addEventListener('change',function(ev){
|
||||||
|
if (ip.files.length > 0){
|
||||||
|
let f=ip.files[0];
|
||||||
|
let reader=new FileReader();
|
||||||
|
reader.onloadend=function(status){
|
||||||
|
try{
|
||||||
|
let idata=JSON.parse(reader.result);
|
||||||
|
let hasOverwrites=false;
|
||||||
|
for (let k in idata){
|
||||||
|
if (! k.match(/^XDR[0-9][0-9]*/)){
|
||||||
|
alert("file contains invalid key "+k);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let del=document.querySelector('input[name='+k+']');
|
||||||
|
if (del){
|
||||||
|
hasOverwrites=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasOverwrites){
|
||||||
|
if (!confirm("overwrite existing data?")) return;
|
||||||
|
}
|
||||||
|
for (let k in idata){
|
||||||
|
let del=document.querySelector('input[name='+k+']');
|
||||||
|
if (del){
|
||||||
|
del.value=idata[k];
|
||||||
|
let ev=new Event('change');
|
||||||
|
del.dispatchEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (error){
|
||||||
|
alert("unable to parse upload: "+error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsBinaryString(f);
|
||||||
|
}
|
||||||
|
ip.remove();
|
||||||
|
});
|
||||||
|
ip.click();
|
||||||
|
}
|
||||||
|
function toggleClass(el,id,classList){
|
||||||
|
let nc=classList[id];
|
||||||
|
let rt=false;
|
||||||
|
if (nc && !el.classList.contains(nc)) rt=true;
|
||||||
|
for (let i in classList){
|
||||||
|
if (i == id) continue;
|
||||||
|
el.classList.remove(classList[i])
|
||||||
|
}
|
||||||
|
if (nc) el.classList.add(nc);
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
function createConfigDefinitions(parent, capabilities, defs,includeXdr) {
|
function createConfigDefinitions(parent, capabilities, defs,includeXdr) {
|
||||||
let category;
|
let category;
|
||||||
|
@ -542,18 +789,17 @@ function createConfigDefinitions(parent, capabilities, defs,includeXdr) {
|
||||||
let categoryTitle = addEl('div', 'title', categoryFrame);
|
let categoryTitle = addEl('div', 'title', categoryFrame);
|
||||||
let categoryButton = addEl('span', 'icon icon-more', categoryTitle);
|
let categoryButton = addEl('span', 'icon icon-more', categoryTitle);
|
||||||
addEl('span', 'label', categoryTitle, item.category);
|
addEl('span', 'label', categoryTitle, item.category);
|
||||||
|
addEl('span','categoryAdd',categoryTitle);
|
||||||
categoryEl = addEl('div', 'content', categoryFrame);
|
categoryEl = addEl('div', 'content', categoryFrame);
|
||||||
categoryEl.classList.add('hidden');
|
categoryEl.classList.add('hidden');
|
||||||
let currentEl = categoryEl;
|
let currentEl = categoryEl;
|
||||||
categoryTitle.addEventListener('click', function (ev) {
|
categoryTitle.addEventListener('click', function (ev) {
|
||||||
let rs = currentEl.classList.toggle('hidden');
|
let rs = currentEl.classList.toggle('hidden');
|
||||||
if (rs) {
|
if (rs) {
|
||||||
categoryButton.classList.add('icon-more');
|
toggleClass(categoryButton,0,moreicons);
|
||||||
categoryButton.classList.remove('icon-less');
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
categoryButton.classList.remove('icon-more');
|
toggleClass(categoryButton,1,moreicons);
|
||||||
categoryButton.classList.add('icon-less');
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
category = item.category;
|
category = item.category;
|
||||||
|
@ -591,7 +837,14 @@ function createConfigDefinitions(parent, capabilities, defs,includeXdr) {
|
||||||
})
|
})
|
||||||
bt = addEl('button', 'infoButton', btContainer, '?');
|
bt = addEl('button', 'infoButton', btContainer, '?');
|
||||||
bt.addEventListener('click', function (ev) {
|
bt.addEventListener('click', function (ev) {
|
||||||
showOverlay(item.description);
|
if (item.description){
|
||||||
|
showOverlay(item.description);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (item.category.match(/^xdr/)){
|
||||||
|
showXdrHelp();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue