intermediate: udp reader
This commit is contained in:
		
							parent
							
								
									b0d5e27b5a
								
							
						
					
					
						commit
						82f5e17987
					
				|  | @ -96,6 +96,7 @@ class GwApi{ | |||
|                 unsigned long tcpSerRx=0; | ||||
|                 unsigned long tcpSerTx=0; | ||||
|                 unsigned long udpwTx=0; | ||||
|                 unsigned long udprRx=0; | ||||
|                 int tcpClients=0; | ||||
|                 unsigned long tcpClRx=0; | ||||
|                 unsigned long tcpClTx=0; | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include "GwSerial.h" | ||||
| #include "GwTcpClient.h" | ||||
| #include "GwUdpWriter.h" | ||||
| #include "GwUdpReader.h" | ||||
| class SerInit{ | ||||
|     public: | ||||
|         int serial=-1; | ||||
|  | @ -260,8 +261,27 @@ static  ChannelParam channelParameters[]={ | |||
|         .maxId=-1, | ||||
|         .rxstatus=0, | ||||
|         .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> | ||||
|  | @ -451,6 +471,12 @@ void GwChannelList::begin(bool fallbackSerial){ | |||
|         writer->begin(); | ||||
|         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(); | ||||
| } | ||||
| String GwChannelList::getMode(int id){ | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ | |||
| #define TCP_CLIENT_CHANNEL_ID 4 | ||||
| #define MIN_TCP_CHANNEL_ID 5 | ||||
| #define UDPW_CHANNEL_ID 20 | ||||
| #define UDPR_CHANNEL_ID 21 | ||||
| 
 | ||||
| #define MIN_USER_TASK 200 | ||||
| class GwSocketServer; | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ GwBuffer::~GwBuffer(){ | |||
| } | ||||
| 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; | ||||
|     readPointer = buffer; | ||||
|     lp("reset"); | ||||
|  | @ -33,6 +33,16 @@ size_t GwBuffer::freeSpace() | |||
|     } | ||||
|     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() | ||||
| { | ||||
|     if (readPointer <= writePointer) | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ class GwBuffer{ | |||
|         uint8_t *buffer; | ||||
|         uint8_t *writePointer; | ||||
|         uint8_t *readPointer; | ||||
|         size_t offset(uint8_t* ptr){ | ||||
|         size_t offset(uint8_t* ptr) const{ | ||||
|             return (size_t)(ptr-buffer); | ||||
|         } | ||||
|         GwLog *logger; | ||||
|  | @ -54,6 +54,9 @@ class GwBuffer{ | |||
|          * find the first occurance of x in the buffer, -1 if not found | ||||
|          */ | ||||
|         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 | ||||
|  | @ -22,4 +22,7 @@ class GwSocketHelper{ | |||
|             if (inet_pton(AF_INET,addr.c_str(),&iaddr) != 1) return false; | ||||
|             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", | ||||
|         "type": "number", | ||||
|         "default": "10110", | ||||
|         "check":"checkPort", | ||||
|         "description": "the TCP port we listen on", | ||||
|         "category": "TCP server" | ||||
|     }, | ||||
|  | @ -766,8 +767,12 @@ | |||
|         "label": "remote port", | ||||
|         "type": "number", | ||||
|         "default": "10110", | ||||
|         "check":"checkPort", | ||||
|         "description": "the TCP port we connect to", | ||||
|         "category": "TCP client" | ||||
|         "category": "TCP client", | ||||
|         "condition":{ | ||||
|             "tclEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "name": "remoteAddress", | ||||
|  | @ -776,7 +781,10 @@ | |||
|         "default": "", | ||||
|         "check": "checkIpAddress", | ||||
|         "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", | ||||
|  | @ -784,7 +792,10 @@ | |||
|         "type": "boolean", | ||||
|         "default": "true", | ||||
|         "description": "send out NMEA data to remote TCP server", | ||||
|         "category": "TCP client" | ||||
|         "category": "TCP client", | ||||
|         "condition":{ | ||||
|             "tclEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "name": "readTCL", | ||||
|  | @ -792,7 +803,10 @@ | |||
|         "type": "boolean", | ||||
|         "default": "true", | ||||
|         "description": "receive NMEA data from remote TCP server", | ||||
|         "category": "TCP client" | ||||
|         "category": "TCP client", | ||||
|         "condition":{ | ||||
|             "tclEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "name": "tclToN2k", | ||||
|  | @ -800,7 +814,10 @@ | |||
|         "type": "boolean", | ||||
|         "default": "true", | ||||
|         "description": "convert NMEA0183 from remote TCP server to NMEA2000", | ||||
|         "category": "TCP client" | ||||
|         "category": "TCP client", | ||||
|         "condition":{ | ||||
|             "tclEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "name": "tclReadFilter", | ||||
|  | @ -808,7 +825,10 @@ | |||
|         "type": "filter", | ||||
|         "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", | ||||
|         "category": "TCP client" | ||||
|         "category": "TCP client", | ||||
|         "condition":{ | ||||
|             "tclEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "name": "tclWriteFilter", | ||||
|  | @ -816,7 +836,10 @@ | |||
|         "type": "filter", | ||||
|         "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", | ||||
|         "category": "TCP client" | ||||
|         "category": "TCP client", | ||||
|         "condition":{ | ||||
|             "tclEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "name": "tclSeasmart", | ||||
|  | @ -824,7 +847,10 @@ | |||
|         "type": "boolean", | ||||
|         "default": "false", | ||||
|         "description": "send NMEA2000 as seasmart to remote TCP server", | ||||
|         "category": "TCP client" | ||||
|         "category": "TCP client", | ||||
|         "condition":{ | ||||
|             "tclEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "name": "udpwEnabled", | ||||
|  | @ -840,7 +866,11 @@ | |||
|         "type": "number", | ||||
|         "default": "10110", | ||||
|         "description": "the UDP port we send to", | ||||
|         "category": "UDP writer" | ||||
|         "check":"checkPort", | ||||
|         "category": "UDP writer", | ||||
|         "condition":{ | ||||
|             "udpwEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "name": "udpwType", | ||||
|  | @ -857,7 +887,10 @@ | |||
|             {"l":"mc-ap","v":"5"}, | ||||
|             {"l":"mc-cli","v":"6"} | ||||
|         ], | ||||
|         "category": "UDP writer" | ||||
|         "category": "UDP writer", | ||||
|         "condition":{ | ||||
|             "udpwEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "name": "udpwAddress", | ||||
|  | @ -868,7 +901,8 @@ | |||
|         "description": "the IP address we connect to in the form 192.168.1.2", | ||||
|         "category": "UDP writer", | ||||
|         "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", | ||||
|         "category": "UDP writer", | ||||
|         "condition":{ | ||||
|             "udpwType":["4","5","6"] | ||||
|             "udpwType":["4","5","6"], | ||||
|             "udpwEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|  | @ -889,7 +924,10 @@ | |||
|         "type": "filter", | ||||
|         "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", | ||||
|         "category": "UDP writer" | ||||
|         "category": "UDP writer", | ||||
|         "condition":{ | ||||
|             "udpwEnabled":"true" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "name": "udpwSeasmart", | ||||
|  | @ -897,7 +935,84 @@ | |||
|         "type": "boolean", | ||||
|         "default": "false", | ||||
|         "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", | ||||
|  |  | |||
							
								
								
									
										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) { | ||||
|         //2...32 characters for ssid
 | ||||
|         let allowed = v.replace(/[^a-zA-Z0-9]*/g, ''); | ||||
|  | @ -213,13 +219,20 @@ | |||
|     } | ||||
| 
 | ||||
|     checkers.checkIpAddress=function(v, allValues, def) { | ||||
|         if (allValues.tclEnabled != "true") return; | ||||
|         if (!v) return "cannot be empty"; | ||||
|         if (!v.match(/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/) | ||||
|             && !v.match(/.*\.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) { | ||||
|         if (!v) return; | ||||
|         let parts = v.split(','); | ||||
|  | @ -264,21 +277,22 @@ | |||
|                 continue; | ||||
|             } | ||||
|             let check = v.getAttribute('data-check'); | ||||
|             if (check) { | ||||
|             if (check && conditionOk(name)) { | ||||
|                 let cfgDef=getConfigDefition(name); | ||||
|                 let checkFunction=checkers[check]; | ||||
|                 if (typeof (checkFunction) === 'function') { | ||||
|                     if (! loggedChecks[check]){ | ||||
|                         loggedChecks[check]=true; | ||||
|                         //console.log("check:"+check);
 | ||||
|                     } | ||||
|                     let res = checkFunction(v.value, allValues, getConfigDefition(name)); | ||||
|                     let res = checkFunction(v.value, allValues, cfgDef); | ||||
|                     if (res) { | ||||
|                         let value = v.value; | ||||
|                         if (v.type === 'password') value = "******"; | ||||
|                         let label = v.getAttribute('data-label'); | ||||
|                         if (!label) label = v.getAttribute('name'); | ||||
|                         v.classList.add("error"); | ||||
|                         alert("invalid config for " + label + "(" + value + "):\n" + res); | ||||
|                         alert("invalid config for "+cfgDef.category+":" + label + "(" + value + "):\n" + res); | ||||
|                         return; | ||||
|                     } | ||||
|                 } | ||||
|  | @ -472,10 +486,10 @@ | |||
|         if (!(condition instanceof Array)) condition = [condition]; | ||||
|         return condition; | ||||
|     } | ||||
|     function checkCondition(element) { | ||||
|         let name = element.getAttribute('name'); | ||||
| 
 | ||||
|     function conditionOk(name){ | ||||
|         let condition = getConditions(name); | ||||
|         if (!condition) return; | ||||
|         if (!condition) return true; | ||||
|         let visible = false; | ||||
|         if (!condition instanceof Array) condition = [condition]; | ||||
|         condition.forEach(function (cel) { | ||||
|  | @ -494,6 +508,12 @@ | |||
|             } | ||||
|             if (lvis) visible = true; | ||||
|         });  | ||||
|         return visible;    | ||||
|     } | ||||
| 
 | ||||
|     function checkCondition(element) { | ||||
|         let name = element.getAttribute('name'); | ||||
|         let visible=conditionOk(name); | ||||
|         let row = closestParent(element, 'row'); | ||||
|         if (!row) return; | ||||
|         if (visible) row.classList.remove('hidden'); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue