From 490a5b9ba1781e9ea4fef40f6e584eac1b62833d Mon Sep 17 00:00:00 2001 From: andreas Date: Mon, 4 Nov 2024 20:21:33 +0100 Subject: [PATCH] #79: add udp writer --- lib/api/GwApi.h | 1 + lib/channel/GwChannelList.cpp | 26 ++++++++++++++ lib/channel/GwChannelList.h | 1 + lib/socketserver/GwUdpWriter.cpp | 59 ++++++++++++++++++++++++++++++++ lib/socketserver/GwUdpWriter.h | 28 +++++++++++++++ web/config.json | 41 ++++++++++++++++++++++ 6 files changed, 156 insertions(+) create mode 100644 lib/socketserver/GwUdpWriter.cpp create mode 100644 lib/socketserver/GwUdpWriter.h diff --git a/lib/api/GwApi.h b/lib/api/GwApi.h index d4d0716..00dbc1f 100644 --- a/lib/api/GwApi.h +++ b/lib/api/GwApi.h @@ -95,6 +95,7 @@ class GwApi{ unsigned long ser2Tx=0; unsigned long tcpSerRx=0; unsigned long tcpSerTx=0; + unsigned long udpwTx=0; int tcpClients=0; unsigned long tcpClRx=0; unsigned long tcpClTx=0; diff --git a/lib/channel/GwChannelList.cpp b/lib/channel/GwChannelList.cpp index 56f4598..9b68b07 100644 --- a/lib/channel/GwChannelList.cpp +++ b/lib/channel/GwChannelList.cpp @@ -6,6 +6,7 @@ #include "GwSocketServer.h" #include "GwSerial.h" #include "GwTcpClient.h" +#include "GwUdpWriter.h" class SerInit{ public: int serial=-1; @@ -241,6 +242,24 @@ static ChannelParam channelParameters[]={ .maxId=-1, .rxstatus=offsetof(GwApi::Status,GwApi::Status::tcpClRx), .txstatus=offsetof(GwApi::Status,GwApi::Status::tcpClTx) + }, + { + .id=UDPW_CHANNEL_ID, + .baud="", + .receive="", + .send=GwConfigDefinitions::udpwEnabled, + .direction="", + .toN2K="", + .readF="", + .writeF=GwConfigDefinitions::udpwWriteFilter, + .preventLog="", + .readAct="", + .writeAct="", + .sendSeasmart=GwConfigDefinitions::udpwSeasmart, + .name="UDPWriter", + .maxId=-1, + .rxstatus=0, + .txstatus=offsetof(GwApi::Status,GwApi::Status::udpwTx) } }; @@ -425,6 +444,13 @@ void GwChannelList::begin(bool fallbackSerial){ ); } addChannel(createChannel(logger,config,TCP_CLIENT_CHANNEL_ID,client)); + + //udp writer + if (config->getBool(GwConfigDefinitions::udpwEnabled)){ + GwUdpWriter *writer=new GwUdpWriter(config,logger,UDPW_CHANNEL_ID); + writer->begin(); + addChannel(createChannel(logger,config,UDPW_CHANNEL_ID,writer)); + } logger->flush(); } String GwChannelList::getMode(int id){ diff --git a/lib/channel/GwChannelList.h b/lib/channel/GwChannelList.h index ba45c66..956b786 100644 --- a/lib/channel/GwChannelList.h +++ b/lib/channel/GwChannelList.h @@ -18,6 +18,7 @@ #define SERIAL2_CHANNEL_ID 3 #define TCP_CLIENT_CHANNEL_ID 4 #define MIN_TCP_CHANNEL_ID 5 +#define UDPW_CHANNEL_ID 20 #define MIN_USER_TASK 200 class GwSocketServer; diff --git a/lib/socketserver/GwUdpWriter.cpp b/lib/socketserver/GwUdpWriter.cpp new file mode 100644 index 0000000..51a5037 --- /dev/null +++ b/lib/socketserver/GwUdpWriter.cpp @@ -0,0 +1,59 @@ +#include "GwUdpWriter.h" +#include +#include +#include "GwBuffer.h" +#include "GwSocketConnection.h" +#include "GwSocketHelper.h" + +GwUdpWriter::GwUdpWriter(const GwConfigHandler *config, GwLog *logger, int minId) +{ + this->config = config; + this->logger = logger; + this->minId = minId; +} + +void GwUdpWriter::begin() +{ + fd=socket(AF_INET,SOCK_DGRAM,IPPROTO_IP); + if (fd < 0){ + LOG_ERROR("unable to create udp socket"); + return; + } + int enable = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); + setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(int)); + port=config->getInt(GwConfigDefinitions::udpwPort); + //TODO: check port + address=config->getString(GwConfigDefinitions::udpwAddress); + LOG_INFO("UDP writer created, address=%s, port=%d", + address.c_str(),port); + inet_pton(AF_INET, address.c_str(), &destination.sin_addr); + destination.sin_family = AF_INET; + destination.sin_port = htons(port); +} + +void GwUdpWriter::loop(bool handleRead, bool handleWrite) +{ + +} + +void GwUdpWriter::readMessages(GwMessageFetcher *writer) +{ + +} +size_t GwUdpWriter::sendToClients(const char *buf, int source,bool partial) +{ + if (source == minId) return 0; + size_t len=strlen(buf); + ssize_t err = sendto(fd,buf,len,0,(struct sockaddr *)&destination, sizeof(destination)); + if (err < 0){ + LOG_DEBUG(GwLog::DEBUG,"UDP writer error sending: %d",errno); + return 0; + } + return err; +} + + +GwUdpWriter::~GwUdpWriter() +{ +} \ No newline at end of file diff --git a/lib/socketserver/GwUdpWriter.h b/lib/socketserver/GwUdpWriter.h new file mode 100644 index 0000000..e98ea67 --- /dev/null +++ b/lib/socketserver/GwUdpWriter.h @@ -0,0 +1,28 @@ +#ifndef _GWUDPWRITER_H +#define _GWUDPWRITER_H +#include "GWConfig.h" +#include "GwLog.h" +#include "GwBuffer.h" +#include "GwChannelInterface.h" +#include +#include +#include + +class GwUdpWriter: public GwChannelInterface{ + private: + const GwConfigHandler *config; + GwLog *logger; + int fd=-1; + int minId; + int port; + String address; + struct sockaddr_in destination; + public: + GwUdpWriter(const GwConfigHandler *config,GwLog *logger,int minId); + ~GwUdpWriter(); + 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 \ No newline at end of file diff --git a/web/config.json b/web/config.json index 5c21eb5..b4336d6 100644 --- a/web/config.json +++ b/web/config.json @@ -826,6 +826,47 @@ "description": "send NMEA2000 as seasmart to remote TCP server", "category": "TCP client" }, + { + "name": "udpwEnabled", + "label": "enable", + "type": "boolean", + "default": "false", + "description":"enable the UDP writer", + "category":"UDP writer" + }, + { + "name": "udpwPort", + "label": "remote port", + "type": "number", + "default": "10110", + "description": "the UDP port we send to", + "category": "UDP writer" + }, + { + "name": "udpwAddress", + "label": "remote address", + "type": "string", + "default": "", + "check": "checkIpAddress", + "description": "the IP address we connect to in the form 192.168.1.2", + "category": "UDP writer" + }, + { + "name": "udpwWriteFilter", + "label": "NMEA write Filter", + "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" + }, + { + "name": "udpwSeasmart", + "label": "Seasmart out", + "type": "boolean", + "default": "false", + "description": "send NMEA2000 as seasmart to remote UDP server", + "category": "UDP writer" + }, { "name": "wifiClient", "label": "wifi client",