intermediate: udp reader
This commit is contained in:
parent
b0d5e27b5a
commit
82f5e17987
|
@ -96,6 +96,7 @@ class GwApi{
|
||||||
unsigned long tcpSerRx=0;
|
unsigned long tcpSerRx=0;
|
||||||
unsigned long tcpSerTx=0;
|
unsigned long tcpSerTx=0;
|
||||||
unsigned long udpwTx=0;
|
unsigned long udpwTx=0;
|
||||||
|
unsigned long udprRx=0;
|
||||||
int tcpClients=0;
|
int tcpClients=0;
|
||||||
unsigned long tcpClRx=0;
|
unsigned long tcpClRx=0;
|
||||||
unsigned long tcpClTx=0;
|
unsigned long tcpClTx=0;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "GwSerial.h"
|
#include "GwSerial.h"
|
||||||
#include "GwTcpClient.h"
|
#include "GwTcpClient.h"
|
||||||
#include "GwUdpWriter.h"
|
#include "GwUdpWriter.h"
|
||||||
|
#include "GwUdpReader.h"
|
||||||
class SerInit{
|
class SerInit{
|
||||||
public:
|
public:
|
||||||
int serial=-1;
|
int serial=-1;
|
||||||
|
@ -260,8 +261,27 @@ static ChannelParam channelParameters[]={
|
||||||
.maxId=-1,
|
.maxId=-1,
|
||||||
.rxstatus=0,
|
.rxstatus=0,
|
||||||
.txstatus=offsetof(GwApi::Status,GwApi::Status::udpwTx)
|
.txstatus=offsetof(GwApi::Status,GwApi::Status::udpwTx)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id=UDPR_CHANNEL_ID,
|
||||||
|
.baud="",
|
||||||
|
.receive=GwConfigDefinitions::udprEnabled,
|
||||||
|
.send="",
|
||||||
|
.direction="",
|
||||||
|
.toN2K=GwConfigDefinitions::udprToN2k,
|
||||||
|
.readF=GwConfigDefinitions::udprReadFilter,
|
||||||
|
.writeF="",
|
||||||
|
.preventLog="",
|
||||||
|
.readAct="",
|
||||||
|
.writeAct="",
|
||||||
|
.sendSeasmart="",
|
||||||
|
.name="UDPReader",
|
||||||
|
.maxId=-1,
|
||||||
|
.rxstatus=offsetof(GwApi::Status,GwApi::Status::udprRx),
|
||||||
|
.txstatus=0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -451,6 +471,12 @@ void GwChannelList::begin(bool fallbackSerial){
|
||||||
writer->begin();
|
writer->begin();
|
||||||
addChannel(createChannel(logger,config,UDPW_CHANNEL_ID,writer));
|
addChannel(createChannel(logger,config,UDPW_CHANNEL_ID,writer));
|
||||||
}
|
}
|
||||||
|
//udp reader
|
||||||
|
if (config->getBool(GwConfigDefinitions::udprEnabled)){
|
||||||
|
GwUdpReader *reader=new GwUdpReader(config,logger,UDPR_CHANNEL_ID);
|
||||||
|
reader->begin();
|
||||||
|
addChannel(createChannel(logger,config,UDPR_CHANNEL_ID,reader));
|
||||||
|
}
|
||||||
logger->flush();
|
logger->flush();
|
||||||
}
|
}
|
||||||
String GwChannelList::getMode(int id){
|
String GwChannelList::getMode(int id){
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define TCP_CLIENT_CHANNEL_ID 4
|
#define TCP_CLIENT_CHANNEL_ID 4
|
||||||
#define MIN_TCP_CHANNEL_ID 5
|
#define MIN_TCP_CHANNEL_ID 5
|
||||||
#define UDPW_CHANNEL_ID 20
|
#define UDPW_CHANNEL_ID 20
|
||||||
|
#define UDPR_CHANNEL_ID 21
|
||||||
|
|
||||||
#define MIN_USER_TASK 200
|
#define MIN_USER_TASK 200
|
||||||
class GwSocketServer;
|
class GwSocketServer;
|
||||||
|
|
|
@ -21,7 +21,7 @@ GwBuffer::~GwBuffer(){
|
||||||
}
|
}
|
||||||
void GwBuffer::reset(String reason)
|
void GwBuffer::reset(String reason)
|
||||||
{
|
{
|
||||||
LOG_DEBUG(GwLog::LOG,"reseting buffer %s, reason %s",this->name.c_str(),reason.c_str());
|
if (! reason.isEmpty())LOG_DEBUG(GwLog::LOG,"reseting buffer %s, reason %s",this->name.c_str(),reason.c_str());
|
||||||
writePointer = buffer;
|
writePointer = buffer;
|
||||||
readPointer = buffer;
|
readPointer = buffer;
|
||||||
lp("reset");
|
lp("reset");
|
||||||
|
@ -33,6 +33,16 @@ size_t GwBuffer::freeSpace()
|
||||||
}
|
}
|
||||||
return readPointer - writePointer - 1;
|
return readPointer - writePointer - 1;
|
||||||
}
|
}
|
||||||
|
size_t GwBuffer::continousSpace() const{
|
||||||
|
if (readPointer <= writePointer){
|
||||||
|
return bufferSize-offset(writePointer);
|
||||||
|
}
|
||||||
|
return readPointer-writePointer-1;
|
||||||
|
}
|
||||||
|
void GwBuffer::moveWp(size_t offset){
|
||||||
|
if (offset > continousSpace()) return;
|
||||||
|
writePointer+=offset;
|
||||||
|
}
|
||||||
size_t GwBuffer::usedSpace()
|
size_t GwBuffer::usedSpace()
|
||||||
{
|
{
|
||||||
if (readPointer <= writePointer)
|
if (readPointer <= writePointer)
|
||||||
|
|
|
@ -33,7 +33,7 @@ class GwBuffer{
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
uint8_t *writePointer;
|
uint8_t *writePointer;
|
||||||
uint8_t *readPointer;
|
uint8_t *readPointer;
|
||||||
size_t offset(uint8_t* ptr){
|
size_t offset(uint8_t* ptr) const{
|
||||||
return (size_t)(ptr-buffer);
|
return (size_t)(ptr-buffer);
|
||||||
}
|
}
|
||||||
GwLog *logger;
|
GwLog *logger;
|
||||||
|
@ -54,6 +54,9 @@ class GwBuffer{
|
||||||
* find the first occurance of x in the buffer, -1 if not found
|
* find the first occurance of x in the buffer, -1 if not found
|
||||||
*/
|
*/
|
||||||
int findChar(char x);
|
int findChar(char x);
|
||||||
|
uint8_t *getWp(){return writePointer;}
|
||||||
|
size_t continousSpace() const; //free space from wp
|
||||||
|
void moveWp(size_t offset); //move the wp forward
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -22,4 +22,7 @@ class GwSocketHelper{
|
||||||
if (inet_pton(AF_INET,addr.c_str(),&iaddr) != 1) return false;
|
if (inet_pton(AF_INET,addr.c_str(),&iaddr) != 1) return false;
|
||||||
return IN_MULTICAST(ntohl(iaddr.s_addr));
|
return IN_MULTICAST(ntohl(iaddr.s_addr));
|
||||||
}
|
}
|
||||||
|
static bool equals(const in_addr &left, const in_addr &right){
|
||||||
|
return left.s_addr == right.s_addr;
|
||||||
|
}
|
||||||
};
|
};
|
|
@ -0,0 +1,158 @@
|
||||||
|
#include "GwUdpReader.h"
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "GwBuffer.h"
|
||||||
|
#include "GwSocketConnection.h"
|
||||||
|
#include "GwSocketHelper.h"
|
||||||
|
#include "GWWifi.h"
|
||||||
|
|
||||||
|
|
||||||
|
GwUdpReader::GwUdpReader(const GwConfigHandler *config, GwLog *logger, int minId)
|
||||||
|
{
|
||||||
|
this->config = config;
|
||||||
|
this->logger = logger;
|
||||||
|
this->minId = minId;
|
||||||
|
port=config->getInt(GwConfigDefinitions::udprPort);
|
||||||
|
buffer= new GwBuffer(logger,GwBuffer::RX_BUFFER_SIZE,"udprd");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GwUdpReader::createAndBind(){
|
||||||
|
if (fd >= 0){
|
||||||
|
::close(fd);
|
||||||
|
}
|
||||||
|
if (currentStationIp.isEmpty() && (type == T_STA || type == T_MCSTA)) return;
|
||||||
|
fd=socket(AF_INET,SOCK_DGRAM,IPPROTO_IP);
|
||||||
|
if (fd < 0){
|
||||||
|
LOG_ERROR("UDPR: unable to create udp socket: %d",errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int enable = 1;
|
||||||
|
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
|
||||||
|
if (type == T_STA)
|
||||||
|
{
|
||||||
|
if (inet_pton(AF_INET, currentStationIp.c_str(), &listenA.sin_addr) != 1)
|
||||||
|
{
|
||||||
|
LOG_ERROR("UDPR: invalid station ip address %s", currentStationIp.c_str());
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bind(fd,(struct sockaddr *)&listenA,sizeof(listenA)) < 0){
|
||||||
|
LOG_ERROR("UDPR: unable to bind: %d",errno);
|
||||||
|
close(fd);
|
||||||
|
fd=-1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG_INFO("UDPR: socket created and bound");
|
||||||
|
if (type != T_MCALL && type != T_MCAP && type != T_MCSTA) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct ip_mreq mc;
|
||||||
|
String mcAddr=config->getString(GwConfigDefinitions::udprMC);
|
||||||
|
if (inet_pton(AF_INET,mcAddr.c_str(),&mc.imr_multiaddr) != 1){
|
||||||
|
LOG_ERROR("UDPR: invalid multicast addr %s",mcAddr.c_str());
|
||||||
|
::close(fd);
|
||||||
|
fd=-1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type == T_MCALL || type == T_MCAP){
|
||||||
|
mc.imr_interface=apAddr;
|
||||||
|
int res=setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mc,sizeof(mc));
|
||||||
|
if (res != 0){
|
||||||
|
LOG_ERROR("UDPR: unable to add MC membership for AP:%d",errno);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
LOG_INFO("UDPR: membership for %s for AP",mcAddr.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!currentStationIp.isEmpty() && (type == T_MCALL || type == T_MCSTA))
|
||||||
|
{
|
||||||
|
mc.imr_interface = staAddr;
|
||||||
|
int res = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mc, sizeof(mc));
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("UDPR: unable to add MC membership for STA:%d", errno);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
LOG_INFO("UDPR: membership for %s for STA %s",mcAddr.c_str(),currentStationIp.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GwUdpReader::begin()
|
||||||
|
{
|
||||||
|
if (type != T_UNKNOWN) return; //already started
|
||||||
|
type=(UType)(config->getInt(GwConfigDefinitions::udprType));
|
||||||
|
LOG_INFO("UDPR begin, mode=%d",(int)type);
|
||||||
|
port=config->getInt(GwConfigDefinitions::udprPort);
|
||||||
|
listenA.sin_family=AF_INET;
|
||||||
|
listenA.sin_port=htons(port);
|
||||||
|
if (type != T_STA){
|
||||||
|
listenA.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||||
|
}
|
||||||
|
String ap=WiFi.softAPIP().toString();
|
||||||
|
if (inet_pton(AF_INET, ap.c_str(), &apAddr) != 1)
|
||||||
|
{
|
||||||
|
LOG_ERROR("UDPR: invalid ap ip address %s", ap.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String sta;
|
||||||
|
if (WiFi.isConnected()) sta=WiFi.localIP().toString();
|
||||||
|
setStationAdd(sta);
|
||||||
|
createAndBind();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GwUdpReader::setStationAdd(const String &sta){
|
||||||
|
if (sta == currentStationIp) return false;
|
||||||
|
currentStationIp=sta;
|
||||||
|
if (inet_pton(AF_INET, currentStationIp.c_str(), &staAddr) != 1){
|
||||||
|
LOG_ERROR("UDPR: invalid station ip address %s", currentStationIp.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOG_INFO("UDPR: new station IP %s",currentStationIp.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void GwUdpReader::loop(bool handleRead, bool handleWrite)
|
||||||
|
{
|
||||||
|
if (handleRead){
|
||||||
|
if (type == T_STA || type == T_MCALL || type == T_MCSTA){
|
||||||
|
//only change anything if we considered the station IP
|
||||||
|
String nextStationIp;
|
||||||
|
if (WiFi.isConnected()){
|
||||||
|
String nextStationIp=WiFi.localIP().toString();
|
||||||
|
}
|
||||||
|
if (setStationAdd(nextStationIp)){
|
||||||
|
LOG_INFO("UDPR: wifi client IP changed, restart");
|
||||||
|
createAndBind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GwUdpReader::readMessages(GwMessageFetcher *writer)
|
||||||
|
{
|
||||||
|
if (fd < 0) return;
|
||||||
|
//we expect one NMEA message in one UDP packet
|
||||||
|
buffer->reset();
|
||||||
|
struct sockaddr_in from;
|
||||||
|
socklen_t fromLen=sizeof(from);
|
||||||
|
ssize_t res=recvfrom(fd,buffer->getWp(),buffer->continousSpace(),MSG_DONTWAIT,
|
||||||
|
(struct sockaddr*)&from,&fromLen);
|
||||||
|
if (res <= 0) return;
|
||||||
|
if (GwSocketHelper::equals(from.sin_addr,apAddr)) return;
|
||||||
|
if (!currentStationIp.isEmpty() && (GwSocketHelper::equals(from.sin_addr,staAddr))) return;
|
||||||
|
buffer->moveWp(res);
|
||||||
|
LOG_DEBUG(GwLog::DEBUG,"UDPR: received %d bytes",res);
|
||||||
|
writer->handleBuffer(buffer);
|
||||||
|
}
|
||||||
|
size_t GwUdpReader::sendToClients(const char *buf, int source,bool partial)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GwUdpReader::~GwUdpReader()
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef _GWUDPREADER_H
|
||||||
|
#define _GWUDPREADER_H
|
||||||
|
#include "GWConfig.h"
|
||||||
|
#include "GwLog.h"
|
||||||
|
#include "GwBuffer.h"
|
||||||
|
#include "GwChannelInterface.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
class GwUdpReader: public GwChannelInterface{
|
||||||
|
public:
|
||||||
|
using UType=enum{
|
||||||
|
T_ALL=0,
|
||||||
|
T_AP=1,
|
||||||
|
T_STA=2,
|
||||||
|
T_MCALL=4,
|
||||||
|
T_MCAP=5,
|
||||||
|
T_MCSTA=6,
|
||||||
|
T_UNKNOWN=-1
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
const GwConfigHandler *config;
|
||||||
|
GwLog *logger;
|
||||||
|
int minId;
|
||||||
|
int port;
|
||||||
|
int fd=-1;
|
||||||
|
struct sockaddr_in listenA;
|
||||||
|
String listenIp;
|
||||||
|
String currentStationIp;
|
||||||
|
struct in_addr apAddr;
|
||||||
|
struct in_addr staAddr;
|
||||||
|
UType type=T_UNKNOWN;
|
||||||
|
void createAndBind();
|
||||||
|
bool setStationAdd(const String &sta);
|
||||||
|
GwBuffer *buffer=nullptr;
|
||||||
|
public:
|
||||||
|
GwUdpReader(const GwConfigHandler *config,GwLog *logger,int minId);
|
||||||
|
~GwUdpReader();
|
||||||
|
void begin();
|
||||||
|
virtual void loop(bool handleRead=true,bool handleWrite=true);
|
||||||
|
virtual size_t sendToClients(const char *buf,int sourceId, bool partialWrite=false);
|
||||||
|
virtual void readMessages(GwMessageFetcher *writer);
|
||||||
|
};
|
||||||
|
#endif
|
143
web/config.json
143
web/config.json
|
@ -691,6 +691,7 @@
|
||||||
"label": "TCP port",
|
"label": "TCP port",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": "10110",
|
"default": "10110",
|
||||||
|
"check":"checkPort",
|
||||||
"description": "the TCP port we listen on",
|
"description": "the TCP port we listen on",
|
||||||
"category": "TCP server"
|
"category": "TCP server"
|
||||||
},
|
},
|
||||||
|
@ -766,8 +767,12 @@
|
||||||
"label": "remote port",
|
"label": "remote port",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": "10110",
|
"default": "10110",
|
||||||
|
"check":"checkPort",
|
||||||
"description": "the TCP port we connect to",
|
"description": "the TCP port we connect to",
|
||||||
"category": "TCP client"
|
"category": "TCP client",
|
||||||
|
"condition":{
|
||||||
|
"tclEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "remoteAddress",
|
"name": "remoteAddress",
|
||||||
|
@ -776,7 +781,10 @@
|
||||||
"default": "",
|
"default": "",
|
||||||
"check": "checkIpAddress",
|
"check": "checkIpAddress",
|
||||||
"description": "the IP address we connect to in the form 192.168.1.2\nor an MDNS name like ESP32NMEA2K.local",
|
"description": "the IP address we connect to in the form 192.168.1.2\nor an MDNS name like ESP32NMEA2K.local",
|
||||||
"category": "TCP client"
|
"category": "TCP client",
|
||||||
|
"condition":{
|
||||||
|
"tclEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sendTCL",
|
"name": "sendTCL",
|
||||||
|
@ -784,7 +792,10 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "send out NMEA data to remote TCP server",
|
"description": "send out NMEA data to remote TCP server",
|
||||||
"category": "TCP client"
|
"category": "TCP client",
|
||||||
|
"condition":{
|
||||||
|
"tclEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "readTCL",
|
"name": "readTCL",
|
||||||
|
@ -792,7 +803,10 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "receive NMEA data from remote TCP server",
|
"description": "receive NMEA data from remote TCP server",
|
||||||
"category": "TCP client"
|
"category": "TCP client",
|
||||||
|
"condition":{
|
||||||
|
"tclEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tclToN2k",
|
"name": "tclToN2k",
|
||||||
|
@ -800,7 +814,10 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "convert NMEA0183 from remote TCP server to NMEA2000",
|
"description": "convert NMEA0183 from remote TCP server to NMEA2000",
|
||||||
"category": "TCP client"
|
"category": "TCP client",
|
||||||
|
"condition":{
|
||||||
|
"tclEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tclReadFilter",
|
"name": "tclReadFilter",
|
||||||
|
@ -808,7 +825,10 @@
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when reading from remote TCP server\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
"description": "filter for NMEA0183 data when reading from remote TCP server\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"category": "TCP client"
|
"category": "TCP client",
|
||||||
|
"condition":{
|
||||||
|
"tclEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tclWriteFilter",
|
"name": "tclWriteFilter",
|
||||||
|
@ -816,7 +836,10 @@
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when writing to remote TCP server\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
"description": "filter for NMEA0183 data when writing to remote TCP server\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"category": "TCP client"
|
"category": "TCP client",
|
||||||
|
"condition":{
|
||||||
|
"tclEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tclSeasmart",
|
"name": "tclSeasmart",
|
||||||
|
@ -824,7 +847,10 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "false",
|
"default": "false",
|
||||||
"description": "send NMEA2000 as seasmart to remote TCP server",
|
"description": "send NMEA2000 as seasmart to remote TCP server",
|
||||||
"category": "TCP client"
|
"category": "TCP client",
|
||||||
|
"condition":{
|
||||||
|
"tclEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "udpwEnabled",
|
"name": "udpwEnabled",
|
||||||
|
@ -840,7 +866,11 @@
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": "10110",
|
"default": "10110",
|
||||||
"description": "the UDP port we send to",
|
"description": "the UDP port we send to",
|
||||||
"category": "UDP writer"
|
"check":"checkPort",
|
||||||
|
"category": "UDP writer",
|
||||||
|
"condition":{
|
||||||
|
"udpwEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "udpwType",
|
"name": "udpwType",
|
||||||
|
@ -857,7 +887,10 @@
|
||||||
{"l":"mc-ap","v":"5"},
|
{"l":"mc-ap","v":"5"},
|
||||||
{"l":"mc-cli","v":"6"}
|
{"l":"mc-cli","v":"6"}
|
||||||
],
|
],
|
||||||
"category": "UDP writer"
|
"category": "UDP writer",
|
||||||
|
"condition":{
|
||||||
|
"udpwEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "udpwAddress",
|
"name": "udpwAddress",
|
||||||
|
@ -868,7 +901,8 @@
|
||||||
"description": "the IP address we connect to in the form 192.168.1.2",
|
"description": "the IP address we connect to in the form 192.168.1.2",
|
||||||
"category": "UDP writer",
|
"category": "UDP writer",
|
||||||
"condition":{
|
"condition":{
|
||||||
"udpwType":["3"]
|
"udpwType":["3"],
|
||||||
|
"udpwEnabled":"true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -880,7 +914,8 @@
|
||||||
"description": "the multicast address we send to 224.0.0.0...239.255.255.255",
|
"description": "the multicast address we send to 224.0.0.0...239.255.255.255",
|
||||||
"category": "UDP writer",
|
"category": "UDP writer",
|
||||||
"condition":{
|
"condition":{
|
||||||
"udpwType":["4","5","6"]
|
"udpwType":["4","5","6"],
|
||||||
|
"udpwEnabled":"true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -889,7 +924,10 @@
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when writing to remote UDP server\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
"description": "filter for NMEA0183 data when writing to remote UDP server\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"category": "UDP writer"
|
"category": "UDP writer",
|
||||||
|
"condition":{
|
||||||
|
"udpwEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "udpwSeasmart",
|
"name": "udpwSeasmart",
|
||||||
|
@ -897,7 +935,84 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "false",
|
"default": "false",
|
||||||
"description": "send NMEA2000 as seasmart to remote UDP server",
|
"description": "send NMEA2000 as seasmart to remote UDP server",
|
||||||
"category": "UDP writer"
|
"category": "UDP writer",
|
||||||
|
"condition":{
|
||||||
|
"udpwEnabled":"true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "udprEnabled",
|
||||||
|
"label": "enable",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "false",
|
||||||
|
"description":"enable the UDP reader",
|
||||||
|
"category":"UDP reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "udprPort",
|
||||||
|
"label": "local port",
|
||||||
|
"type": "number",
|
||||||
|
"default": "10110",
|
||||||
|
"check":"checkPort",
|
||||||
|
"description": "the UDP port we listen on",
|
||||||
|
"category": "UDP reader",
|
||||||
|
"condition":{
|
||||||
|
"udprEnabled":"true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "udprType",
|
||||||
|
"label": "local address type",
|
||||||
|
"type": "list",
|
||||||
|
"default": "0",
|
||||||
|
"description": "to which networks/addresses do we listen\nall: listen on AP and wifi client network\nap: listen in access point network only\ncli: listen in wifi client network\nmc-all: receive multicast from AP and wifi client network\nmc-ap:receive multicast from AP network\nmc-cli: receive muticast wifi client network",
|
||||||
|
"list":[
|
||||||
|
{"l":"all","v":"0"},
|
||||||
|
{"l":"ap","v":"1"},
|
||||||
|
{"l":"cli","v":"2"},
|
||||||
|
{"l":"mc-all","v":"4"},
|
||||||
|
{"l":"mc-ap","v":"5"},
|
||||||
|
{"l":"mc-cli","v":"6"}
|
||||||
|
],
|
||||||
|
"category": "UDP reader",
|
||||||
|
"condition":{
|
||||||
|
"udprEnabled":"true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "udprToN2k",
|
||||||
|
"label": "to NMEA2000",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "true",
|
||||||
|
"description": "convert NMEA0183 from UDP to NMEA2000",
|
||||||
|
"category": "UDP reader",
|
||||||
|
"condition":{
|
||||||
|
"udprEnabled":"true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "udprMC",
|
||||||
|
"label": "multicast address",
|
||||||
|
"type": "string",
|
||||||
|
"default": "224.0.0.1",
|
||||||
|
"check": "checkMCAddress",
|
||||||
|
"description": "the multicast address we listen on 224.0.0.0...239.255.255.255",
|
||||||
|
"category": "UDP reader",
|
||||||
|
"condition":{
|
||||||
|
"udprType":["4","5","6"],
|
||||||
|
"udprEnabled":"true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "udprReadFilter",
|
||||||
|
"label": "NMEA read Filter",
|
||||||
|
"type": "filter",
|
||||||
|
"default": "",
|
||||||
|
"description": "filter for NMEA0183 data when receiving\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
|
"category": "UDP reader",
|
||||||
|
"condition":{
|
||||||
|
"udprEnabled":"true"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "wifiClient",
|
"name": "wifiClient",
|
||||||
|
|
34
web/index.js
34
web/index.js
|
@ -181,6 +181,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkers.checkPort=function(v,allValues,def){
|
||||||
|
let parsed=parseInt(v);
|
||||||
|
if (isNaN(parsed)) return "must be a number";
|
||||||
|
if (parsed <1 || parsed >= 65536) return "port must be in the range 1..65536";
|
||||||
|
}
|
||||||
|
|
||||||
checkers.checkSystemName=function(v) {
|
checkers.checkSystemName=function(v) {
|
||||||
//2...32 characters for ssid
|
//2...32 characters for ssid
|
||||||
let allowed = v.replace(/[^a-zA-Z0-9]*/g, '');
|
let allowed = v.replace(/[^a-zA-Z0-9]*/g, '');
|
||||||
|
@ -213,13 +219,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
checkers.checkIpAddress=function(v, allValues, def) {
|
checkers.checkIpAddress=function(v, allValues, def) {
|
||||||
if (allValues.tclEnabled != "true") return;
|
|
||||||
if (!v) return "cannot be empty";
|
if (!v) return "cannot be empty";
|
||||||
if (!v.match(/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/)
|
if (!v.match(/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/)
|
||||||
&& !v.match(/.*\.local/))
|
&& !v.match(/.*\.local/))
|
||||||
return "must be either in the form 192.168.1.1 or xxx.local";
|
return "must be either in the form 192.168.1.1 or xxx.local";
|
||||||
}
|
}
|
||||||
|
checkers.checkMCAddress=function(v, allValues, def) {
|
||||||
|
if (!v) return "cannot be empty";
|
||||||
|
if (!v.match(/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/))
|
||||||
|
return "must be in the form 224.0.0.1";
|
||||||
|
let parts=v.split(".");
|
||||||
|
let o1=parseInt(v[0]);
|
||||||
|
if (o1 < 224 || o1 > 239) return "mulicast address must be in the range 224.0.0.0 to 239.255.255.255"
|
||||||
|
|
||||||
|
}
|
||||||
checkers.checkXDR=function(v, allValues) {
|
checkers.checkXDR=function(v, allValues) {
|
||||||
if (!v) return;
|
if (!v) return;
|
||||||
let parts = v.split(',');
|
let parts = v.split(',');
|
||||||
|
@ -264,21 +277,22 @@
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let check = v.getAttribute('data-check');
|
let check = v.getAttribute('data-check');
|
||||||
if (check) {
|
if (check && conditionOk(name)) {
|
||||||
|
let cfgDef=getConfigDefition(name);
|
||||||
let checkFunction=checkers[check];
|
let checkFunction=checkers[check];
|
||||||
if (typeof (checkFunction) === 'function') {
|
if (typeof (checkFunction) === 'function') {
|
||||||
if (! loggedChecks[check]){
|
if (! loggedChecks[check]){
|
||||||
loggedChecks[check]=true;
|
loggedChecks[check]=true;
|
||||||
//console.log("check:"+check);
|
//console.log("check:"+check);
|
||||||
}
|
}
|
||||||
let res = checkFunction(v.value, allValues, getConfigDefition(name));
|
let res = checkFunction(v.value, allValues, cfgDef);
|
||||||
if (res) {
|
if (res) {
|
||||||
let value = v.value;
|
let value = v.value;
|
||||||
if (v.type === 'password') value = "******";
|
if (v.type === 'password') value = "******";
|
||||||
let label = v.getAttribute('data-label');
|
let label = v.getAttribute('data-label');
|
||||||
if (!label) label = v.getAttribute('name');
|
if (!label) label = v.getAttribute('name');
|
||||||
v.classList.add("error");
|
v.classList.add("error");
|
||||||
alert("invalid config for " + label + "(" + value + "):\n" + res);
|
alert("invalid config for "+cfgDef.category+":" + label + "(" + value + "):\n" + res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -472,10 +486,10 @@
|
||||||
if (!(condition instanceof Array)) condition = [condition];
|
if (!(condition instanceof Array)) condition = [condition];
|
||||||
return condition;
|
return condition;
|
||||||
}
|
}
|
||||||
function checkCondition(element) {
|
|
||||||
let name = element.getAttribute('name');
|
function conditionOk(name){
|
||||||
let condition = getConditions(name);
|
let condition = getConditions(name);
|
||||||
if (!condition) return;
|
if (!condition) return true;
|
||||||
let visible = false;
|
let visible = false;
|
||||||
if (!condition instanceof Array) condition = [condition];
|
if (!condition instanceof Array) condition = [condition];
|
||||||
condition.forEach(function (cel) {
|
condition.forEach(function (cel) {
|
||||||
|
@ -494,6 +508,12 @@
|
||||||
}
|
}
|
||||||
if (lvis) visible = true;
|
if (lvis) visible = true;
|
||||||
});
|
});
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkCondition(element) {
|
||||||
|
let name = element.getAttribute('name');
|
||||||
|
let visible=conditionOk(name);
|
||||||
let row = closestParent(element, 'row');
|
let row = closestParent(element, 'row');
|
||||||
if (!row) return;
|
if (!row) return;
|
||||||
if (visible) row.classList.remove('hidden');
|
if (visible) row.classList.remove('hidden');
|
||||||
|
|
Loading…
Reference in New Issue