1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-13 05:53:06 +01:00

intermediate, untested: move channel handling out of main

This commit is contained in:
wellenvogel
2022-01-02 14:43:37 +01:00
parent 47fb805ee6
commit d21e497864
10 changed files with 381 additions and 302 deletions

View File

@@ -52,10 +52,12 @@ class GwChannelMessageReceiver : public GwMessageFetcher{
GwChannel::GwChannel(GwLog *logger,
String name,
int sourceId){
int sourceId,
int maxSourceId){
this->logger = logger;
this->name=name;
this->sourceId=sourceId;
this->maxSourceId=sourceId;
this->countIn=new GwCounter<String>(String("count")+name+String("in"));
this->countOut=new GwCounter<String>(String("count")+name+String("out"));
this->impl=NULL;
@@ -206,8 +208,16 @@ void GwChannel::parseActisense(N2kHandler handler){
}
}
void GwChannel::sendActisense(const tN2kMsg &msg){
void GwChannel::sendActisense(const tN2kMsg &msg, int sourceId){
if (!enabled || ! impl || ! writeActisense || ! channelStream) return;
//currently actisense only for channels with a single source id
//so we can check it here
if (isOwnSource(sourceId)) return;
canSendOut(msg.PGN);
msg.SendInActisenseFormat(channelStream);
}
bool GwChannel::isOwnSource(int id){
if (maxSourceId < 0) return id == sourceId;
else return (id >= sourceId && id <= maxSourceId);
}

View File

@@ -26,6 +26,7 @@ class GwChannel{
GwCounter<String> *countOut=NULL;
GwChannelInterface *impl;
int sourceId=0;
int maxSourceId=-1;
GwChannelMessageReceiver *receiver=NULL;
tActisenseReader *actisenseReader=NULL;
Stream *channelStream=NULL;
@@ -34,7 +35,8 @@ class GwChannel{
GwChannel(
GwLog *logger,
String name,
int sourceId);
int sourceId,
int maxSourceId=-1);
void begin(
bool enabled,
bool nmeaOut,
@@ -48,7 +50,7 @@ class GwChannel{
);
void setImpl(GwChannelInterface *impl);
bool isOwnSource(int id);
void enable(bool enabled){
this->enabled=enabled;
}
@@ -70,6 +72,6 @@ class GwChannel{
void sendToClients(const char *buffer, int sourceId);
typedef std::function<void(const tN2kMsg &msg, int sourceId)> N2kHandler ;
void parseActisense(N2kHandler handler);
void sendActisense(const tN2kMsg &msg);
void sendActisense(const tN2kMsg &msg, int sourceId);
};

View File

@@ -0,0 +1,189 @@
#include "GwChannelList.h"
#include "GwApi.h"
#include "GwHardware.h"
#include "GwSocketServer.h"
#include "GwSerial.h"
#include "GwTcpClient.h"
class GwSerialLog : public GwLogWriter{
static const size_t bufferSize=4096;
char *logBuffer=NULL;
int wp=0;
GwSerial *writer;
public:
GwSerialLog(GwSerial *writer){
this->writer=writer;
logBuffer=new char[bufferSize];
wp=0;
}
virtual ~GwSerialLog(){}
virtual void write(const char *data){
int len=strlen(data);
if ((wp+len) >= (bufferSize-1)) return;
strncpy(logBuffer+wp,data,len);
wp+=len;
logBuffer[wp]=0;
}
virtual void flush(){
size_t handled=0;
while (handled < wp){
writer->flush();
size_t rt=writer->sendToClients(logBuffer+handled,-1,true);
handled+=rt;
}
wp=0;
logBuffer[0]=0;
}
};
GwChannelList::GwChannelList(GwLog *logger, GwConfigHandler *config){
this->logger=logger;
this->config=config;
}
void GwChannelList::allChannels(ChannelAction action){
for (auto it=theChannels.begin();it != theChannels.end();it++){
action(*it);
}
}
void GwChannelList::begin(bool fallbackSerial){
LOG_DEBUG(GwLog::DEBUG,"GwChannelList::begin");
GwChannel *channel=NULL;
//usb
if (! fallbackSerial){
GwSerial *usb=new GwSerial(NULL,0,USB_CHANNEL_ID);
usb->setup(config->getInt(config->usbBaud),3,1);
logger->setWriter(new GwSerialLog(usb));
logger->prefix="GWSERIAL:";
channel=new GwChannel(logger,"USB",USB_CHANNEL_ID);
channel->begin(true,
config->getBool(config->sendUsb),
config->getBool(config->receiveUsb),
config->getString(config->usbReadFilter),
config->getString(config->usbWriteFilter),
false,
config->getBool(config->usbToN2k),
config->getBool(config->usbActisense),
config->getBool(config->usbActSend)
);
LOG_DEBUG(GwLog::LOG,"%s",channel->toString().c_str());
}
//TCP server
sockets=new GwSocketServer(config,logger,MIN_TCP_CHANNEL_ID);
sockets->begin();
channel=new GwChannel(logger,"TCP",MIN_TCP_CHANNEL_ID,MIN_TCP_CHANNEL_ID+10);
channel->setImpl(sockets);
channel->begin(
true,
config->getBool(config->sendTCP),
config->getBool(config->readTCP),
config->getString(config->tcpReadFilter),
config->getString(config->tcpWriteFilter),
config->getBool(config->sendSeasmart),
config->getBool(config->tcpToN2k),
false,
false
);
LOG_DEBUG(GwLog::LOG,"%s",channel->toString().c_str());
theChannels.push_back(channel);
//serial 1
bool serCanRead=false;
bool serCanWrite=false;
int serialrx=-1;
int serialtx=-1;
#ifdef GWSERIAL_MODE
#ifdef GWSERIAL_TX
serialtx=GWSERIAL_TX;
#endif
#ifdef GWSERIAL_RX
serialrx=GWSERIAL_RX;
#endif
if (serialrx != -1 && serialtx != -1){
serialMode=GWSERIAL_MODE;
}
#endif
//the serial direction is from the config (only valid for mode UNI)
String serialDirection=config->getString(config->serialDirection);
//we only consider the direction if mode is UNI
if (serialMode != String("UNI")){
serialDirection=String("");
//if mode is UNI it depends on the selection
serCanRead=config->getBool(config->receiveSerial);
serCanWrite=config->getBool(config->sendSerial);
}
if (serialDirection == "receive" || serialDirection == "off" || serialMode == "RX") serCanWrite=false;
if (serialDirection == "send" || serialDirection == "off" || serialMode == "TX") serCanRead=false;
LOG_DEBUG(GwLog::DEBUG,"serial set up: mode=%s,direction=%s,rx=%d,tx=%d",
serialMode.c_str(),serialDirection.c_str(),serialrx,serialtx
);
if (serialtx != -1 || serialrx != -1 ){
LOG_DEBUG(GwLog::LOG,"creating serial interface rx=%d, tx=%d",serialrx,serialtx);
GwSerial *serial=new GwSerial(logger,1,SERIAL1_CHANNEL_ID,serCanRead);
int rt=serial->setup(config->getInt(config->serialBaud,115200),serialrx,serialtx);
LOG_DEBUG(GwLog::LOG,"starting serial returns %d",rt);
channel=new GwChannel(logger,"SER",SERIAL1_CHANNEL_ID);
channel->setImpl(serial);
channel->begin(
serCanRead || serCanWrite,
serCanWrite,
serCanRead,
config->getString(config->serialReadF),
config->getString(config->serialWriteF),
false,
config->getBool(config->serialToN2k),
false,
false
);
LOG_DEBUG(GwLog::LOG,"%s",channel->toString().c_str());
theChannels.push_back(channel);
}
//tcp client
channel=new GwChannel(logger,"TCPClient",TCP_CLIENT_CHANNEL_ID);
channel->begin(
config->getBool(config->tclEnabled),
config->getBool(config->sendTCL),
config->getBool(config->readTCL),
config->getString(config->tclReadFilter),
config->getString(config->tclReadFilter),
config->getBool(config->tclSeasmart),
config->getBool(config->tclToN2k),
false,
false
);
if (channel->isEnabled()){
client=new GwTcpClient(logger);
client->begin(TCP_CLIENT_CHANNEL_ID,
config->getString(config->remoteAddress),
config->getInt(config->remotePort),
channel->shouldRead()
);
channel->setImpl(client);
}
LOG_DEBUG(GwLog::LOG,"%s",channel->toString().c_str());
logger->flush();
}
int GwChannelList::getJsonSize(){
int rt=0;
allChannels([&](GwChannel *c){
rt+=c->getJsonSize();
});
return rt+20;
}
void GwChannelList::toJson(GwJsonDocument &doc){
if (sockets) doc["numClients"]=sockets->numClients();
if (client){
doc["clientCon"]=client->isConnected();
doc["clientErr"]=client->getError();
}
allChannels([&](GwChannel *c){
c->toJson(doc);
});
}
GwChannel *GwChannelList::getChannelById(int sourceId){
for (auto it=theChannels.begin();it != theChannels.end();it++){
if ((*it)->isOwnSource(sourceId)) return *it;
}
return NULL;
}

View File

@@ -0,0 +1,43 @@
#pragma once
#include <functional>
#include <vector>
#include <WString.h>
#include "GwChannel.h"
#include "GwLog.h"
#include "GWConfig.h"
#include "GwJsonDocument.h"
//NMEA message channels
#define N2K_CHANNEL_ID 0
#define USB_CHANNEL_ID 1
#define SERIAL1_CHANNEL_ID 2
#define TCP_CLIENT_CHANNEL_ID 3
#define MIN_TCP_CHANNEL_ID 4
#define MIN_USER_TASK 200
class GwSocketServer;
class GwTcpClient;
class GwChannelList{
private:
GwLog *logger;
GwConfigHandler *config;
typedef std::vector<GwChannel *> ChannelList;
ChannelList theChannels;
GwSocketServer *sockets;
GwTcpClient *client;
String serialMode=F("NONE");
public:
GwChannelList(GwLog *logger, GwConfigHandler *config);
typedef std::function<void(GwChannel *)> ChannelAction;
void allChannels(ChannelAction action);
//initialize
void begin(bool fallbackSerial=false);
//status
int getJsonSize();
void toJson(GwJsonDocument &doc);
//single channel
GwChannel *getChannelById(int sourceId);
};

View File

@@ -29,11 +29,13 @@ uint16_t DaysSince1970 = 0;
class MyAisDecoder : public AIS::AisDecoder
{
public:
int sourceId=-1;
private:
NMEA0183DataToN2K::N2kSender sender;
GwLog *logger;
void send(const tN2kMsg &msg){
(*sender)(msg);
(*sender)(msg,sourceId);
}
AIS::DefaultSentenceParser parser;
public:

View File

@@ -97,26 +97,26 @@ private:
waypointMap[wpName]=newWp;
return newWp.id;
}
bool send(tN2kMsg &msg,String key,unsigned long minDiff){
bool send(tN2kMsg &msg,String key,unsigned long minDiff,int sourceId){
unsigned long now=millis();
unsigned long pgn=msg.PGN;
if (key == "") key=String(msg.PGN);
auto it=lastSends.find(key);
if (it == lastSends.end()){
lastSends[key]=now;
sender(msg);
sender(msg,sourceId);
return true;
}
if ((it->second + minDiff) <= now){
lastSends[key]=now;
sender(msg);
sender(msg,sourceId);
return true;
}
LOG_DEBUG(GwLog::DEBUG+1,"skipped n2k message %d",msg.PGN);
return false;
}
bool send(tN2kMsg &msg, String key=""){
send(msg,key,minSendInterval);
bool send(tN2kMsg &msg, int sourceId,String key=""){
return send(msg,key,minSendInterval,sourceId);
}
bool updateDouble(GwBoatItem<double> *target,double v, int sourceId){
if (v != NMEA0183DoubleNA){
@@ -255,7 +255,7 @@ private:
(tN2kFluidType)(current.selector()),
fields[0],
fields[1]);
send(n2kMsg, buildN2KKey(n2kMsg, current.mapping));
send(n2kMsg,msg.sourceId, buildN2KKey(n2kMsg, current.mapping));
}
break;
case XDRBAT:
@@ -263,7 +263,7 @@ private:
{
SetN2kPGN127508(n2kMsg, current.mapping.instanceId,
fields[0], fields[1], fields[2]);
send(n2kMsg, buildN2KKey(n2kMsg, current.mapping));
send(n2kMsg,msg.sourceId, buildN2KKey(n2kMsg, current.mapping));
}
break;
case XDRTEMP:
@@ -271,7 +271,7 @@ private:
SetN2kPGN130312(n2kMsg,1,current.mapping.instanceId,
(tN2kTempSource)(current.selector()),
fields[0],fields[1]);
send(n2kMsg,buildN2KKey(n2kMsg,current.mapping));
send(n2kMsg,msg.sourceId,buildN2KKey(n2kMsg,current.mapping));
}
break;
case XDRHUMIDITY:
@@ -281,7 +281,7 @@ private:
fields[0],
fields[1]
);
send(n2kMsg,buildN2KKey(n2kMsg,current.mapping));
send(n2kMsg,msg.sourceId,buildN2KKey(n2kMsg,current.mapping));
}
break;
case XDRPRESSURE:
@@ -289,7 +289,7 @@ private:
SetN2kPGN130314(n2kMsg,1,current.mapping.instanceId,
(tN2kPressureSource)(current.selector()),
fields[0]);
send(n2kMsg,buildN2KKey(n2kMsg,current.mapping));
send(n2kMsg,msg.sourceId,buildN2KKey(n2kMsg,current.mapping));
}
break;
case XDRENGINE:
@@ -301,14 +301,14 @@ private:
fields[0], fields[1], fields[2], fields[3], fields[4],
fields[5], fields[6], fields[7], fromDouble(fields[8]), fromDouble(fields[9]),
tN2kEngineDiscreteStatus1(), tN2kEngineDiscreteStatus2());
send(n2kMsg, buildN2KKey(n2kMsg, current.mapping));
send(n2kMsg,msg.sourceId, buildN2KKey(n2kMsg, current.mapping));
}
}
else{
if (fillFieldList(current, fields, 13,10)){
SetN2kPGN127488(n2kMsg,current.mapping.instanceId,
fields[10],fields[11],fromDouble(fields[12]));
send(n2kMsg, buildN2KKey(n2kMsg, current.mapping));
send(n2kMsg,msg.sourceId, buildN2KKey(n2kMsg, current.mapping));
}
}
break;
@@ -334,7 +334,7 @@ private:
mode=xteMode(*modeChar);
}
SetN2kXTE(n2kMsg,1,mode,false,rmb.xte);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
uint8_t destinationId=getWaypointId(rmb.destID);
uint8_t sourceId=getWaypointId(rmb.originID);
@@ -357,10 +357,10 @@ private:
rmb.longitude,
rmb.vmg
);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
SetN2kPGN129285(n2kMsg,sourceId,1,1,true,true,"default");
AppendN2kPGN129285(n2kMsg,destinationId,rmb.destID,rmb.latitude,rmb.longitude);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
}
void convertRMC(const SNMEA0183Msg &msg)
@@ -382,25 +382,26 @@ private:
{
SetN2kSystemTime(n2kMsg, 1, GpsDate, GpsTime);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
if (UD(Latitude) &&
UD(Longitude)){
SetN2kLatLonRapid(n2kMsg,Latitude,Longitude);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
if (UD(COG) && UD(SOG)){
SetN2kCOGSOGRapid(n2kMsg,1,N2khr_true,COG,SOG);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
if (UD(Variation)){
SetN2kMagneticVariation(n2kMsg,1,N2kmagvar_Calc,
getUint32(boatData->GpsDate), Variation);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
}
void convertAIVDX(const SNMEA0183Msg &msg){
aisDecoder->sourceId=msg.sourceId;
aisDecoder->handleMessage(msg.line);
}
void convertMWV(const SNMEA0183Msg &msg){
@@ -434,7 +435,7 @@ private:
}
if (shouldSend){
SetN2kWindSpeed(n2kMsg,1,WindSpeed,WindAngle,n2kRef);
send(n2kMsg,String(n2kMsg.PGN)+String((int)n2kRef));
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)n2kRef));
}
}
void convertVWR(const SNMEA0183Msg &msg)
@@ -475,7 +476,7 @@ private:
if (shouldSend)
{
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, WindAngle, N2kWind_Apparent);
send(n2kMsg,String(n2kMsg.PGN)+String((int)N2kWind_Apparent));
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)N2kWind_Apparent));
}
}
@@ -519,11 +520,11 @@ private:
if (shouldSend)
{
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, WindAngle, N2kWind_True_North);
send(n2kMsg,String(n2kMsg.PGN)+String((int)N2kWind_True_North));
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)N2kWind_True_North));
}
if (WindAngleMagnetic != NMEA0183DoubleNA && shouldSend){
SetN2kWindSpeed(n2kMsg, 1, WindSpeed, WindAngleMagnetic, N2kWind_Magnetic);
send(n2kMsg,String(n2kMsg.PGN)+String((int)N2kWind_Magnetic));
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((int)N2kWind_Magnetic));
}
}
@@ -540,7 +541,7 @@ private:
boatData->Variation->getDataWithDefault(N2kDoubleNA),
boatData->Deviation->getDataWithDefault(N2kDoubleNA)
);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
void convertHDT(const SNMEA0183Msg &msg){
@@ -553,7 +554,7 @@ private:
if (! UD(Heading)) return;
tN2kMsg n2kMsg;
SetN2kTrueHeading(n2kMsg,1,Heading);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
void convertHDG(const SNMEA0183Msg &msg){
double MagneticHeading=NMEA0183DoubleNA;
@@ -584,7 +585,7 @@ private:
UD(Deviation);
tN2kMsg n2kMsg;
SetN2kMagneticHeading(n2kMsg,1,MagneticHeading,Deviation,Variation);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
void convertDPT(const SNMEA0183Msg &msg){
@@ -612,7 +613,7 @@ private:
if (! boatData->DepthTransducer->update(DepthBelowTransducer)) return;
tN2kMsg n2kMsg;
SetN2kWaterDepth(n2kMsg,1,DepthBelowTransducer,Offset);
send(n2kMsg,String(n2kMsg.PGN)+String((Offset != N2kDoubleNA)?1:0));
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String((Offset != N2kDoubleNA)?1:0));
}
typedef enum {
DBS,
@@ -647,7 +648,7 @@ private:
if (! boatData->DepthTransducer->update(Depth,msg.sourceId)) return;
tN2kMsg n2kMsg;
SetN2kWaterDepth(n2kMsg,1,Depth,N2kDoubleNA);
send(n2kMsg,String(n2kMsg.PGN)+String(0));
send(n2kMsg,msg.sourceId,String(n2kMsg.PGN)+String(0));
return;
}
//we can only send if we have a valid depth beloww tranducer
@@ -667,7 +668,7 @@ private:
}
tN2kMsg n2kMsg;
SetN2kWaterDepth(n2kMsg,1,Depth,offset);
send(n2kMsg,String(n2kMsg.PGN)+String((offset != N2kDoubleNA)?1:0));
send(n2kMsg,msg.sourceId,(n2kMsg.PGN)+String((offset != N2kDoubleNA)?1:0));
}
}
}
@@ -694,7 +695,7 @@ private:
tN2kMsg n2kMsg;
if (! UD(RudderPosition)) return;
SetN2kRudder(n2kMsg,RudderPosition);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
}
@@ -711,7 +712,7 @@ private:
if (MagneticHeading == NMEA0183DoubleNA) MagneticHeading=N2kDoubleNA;
tN2kMsg n2kMsg;
SetN2kBoatSpeed(n2kMsg,1,STW);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
void convertVTG(const SNMEA0183Msg &msg){
@@ -727,7 +728,7 @@ private:
tN2kMsg n2kMsg;
//TODO: maybe use MCOG if no COG?
SetN2kCOGSOGRapid(n2kMsg,1,N2khr_true,COG,SOG);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
void convertZDA(const SNMEA0183Msg &msg){
time_t DateTime;
@@ -751,10 +752,10 @@ private:
tN2kMsg n2kMsg;
if (timezoneValid){
SetN2kLocalOffset(n2kMsg,DaysSince1970,GpsTime,Timezone);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
SetN2kSystemTime(n2kMsg,1,DaysSince1970,GpsTime);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
void convertGGA(const SNMEA0183Msg &msg){
double GPSTime=NMEA0183DoubleNA;
@@ -788,7 +789,7 @@ private:
SatelliteCount, HDOP, boatData->PDOP->getDataWithDefault(N2kDoubleNA), 0,
0, N2kGNSSt_GPS, DGPSReferenceStationID,
DGPSAge);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
void convertGSA(const SNMEA0183Msg &msg){
if (msg.FieldCount() < 17)
@@ -819,7 +820,7 @@ private:
if (!updateDouble(boatData->VDOP,VDOP,msg.sourceId)) return;
}
SetN2kGNSSDOPData(n2kMsg,1,rmode,mode,HDOP,VDOP,N2kDoubleNA);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
void convertGSV(const SNMEA0183Msg &msg){
if (msg.FieldCount() < 7){
@@ -867,7 +868,7 @@ private:
}
}
if (hasInfos){
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
}
@@ -885,7 +886,7 @@ private:
if (! updateDouble(boatData->GpsTime,GLL.GPSTime,msg.sourceId)) return;
tN2kMsg n2kMsg;
SetN2kLatLonRapid(n2kMsg,GLL.latitude,GLL.longitude);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
void convertROT(const SNMEA0183Msg &msg){
@@ -897,7 +898,7 @@ private:
if (! updateDouble(boatData->ROT,ROT,msg.sourceId)) return;
tN2kMsg n2kMsg;
SetN2kRateOfTurn(n2kMsg,1,ROT);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
void convertXTE(const SNMEA0183Msg &msg){
if (msg.FieldCount() < 6){
@@ -916,7 +917,7 @@ private:
tN2kMsg n2kMsg;
tN2kXTEMode mode=xteMode(msg.Field(5)[0]);
SetN2kXTE(n2kMsg,1,mode,false,xte);
send(n2kMsg);
send(n2kMsg,msg.sourceId);
}
//shortcut for lambda converters

View File

@@ -7,7 +7,7 @@
class NMEA0183DataToN2K{
public:
typedef bool (*N2kSender)(const tN2kMsg &msg);
typedef bool (*N2kSender)(const tN2kMsg &msg,int sourceId);
protected:
GwLog * logger;
GwBoatData *boatData;

View File

@@ -19,15 +19,22 @@ void GwTcpClient::startConnection()
{
//TODO
state = C_INITIALIZED;
error="";
connectStart=millis();
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
error="unable to create socket";
LOG_DEBUG(GwLog::ERROR,"unable to create socket: %d", errno);
return;
}
fcntl( sockfd, F_SETFL, fcntl( sockfd, F_GETFL, 0 ) | O_NONBLOCK );
uint32_t ip_addr = this->remoteAddress;
IPAddress addr;
if (! addr.fromString(remoteAddress)){
error="invalid ip "+remoteAddress;
LOG_DEBUG(GwLog::ERROR,"%s",error.c_str());
return;
}
uint32_t ip_addr = addr;
struct sockaddr_in serveraddr;
memset((char *) &serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
@@ -36,6 +43,7 @@ void GwTcpClient::startConnection()
int res = lwip_connect_r(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if (res < 0 ) {
if (errno != EINPROGRESS){
error=String("connect error ")+String(strerror(errno));
LOG_DEBUG(GwLog::ERROR,"connect on fd %d, errno: %d, \"%s\"", sockfd, errno, strerror(errno));
close(sockfd);
return;
@@ -56,7 +64,7 @@ void GwTcpClient::checkConnection()
}
if (state == C_INITIALIZED){
if ((now - connectStart) > CON_TIMEOUT){
LOG_DEBUG(GwLog::LOG,"retry connect to %s",remoteAddress.toString().c_str());
LOG_DEBUG(GwLog::LOG,"retry connect to %s",remoteAddress.c_str());
startConnection();
}
return;
@@ -73,13 +81,15 @@ void GwTcpClient::checkConnection()
tv.tv_usec = 0;
int res = select(sockfd + 1, nullptr, &fdset, nullptr, &tv);
if (res < 0) {
error=String("select error ")+String(strerror(errno));
LOG_DEBUG(GwLog::ERROR,"select on fd %d, errno: %d, \"%s\"", sockfd, errno, strerror(errno));
connection->stop();
return;
} else if (res == 0) {
//still connecting
if ((now - connectStart) >= CON_TIMEOUT){
LOG_DEBUG(GwLog::ERROR,"connect timeout to %s, retry",remoteAddress.toString().c_str());
error="connect timeout";
LOG_DEBUG(GwLog::ERROR,"connect timeout to %s, retry",remoteAddress.c_str());
connection->stop();
return;
}
@@ -89,17 +99,19 @@ void GwTcpClient::checkConnection()
res = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &sockerr, &len);
if (res < 0) {
error="getsockopt failed";
LOG_DEBUG(GwLog::ERROR,"getsockopt on fd %d, errno: %d, \"%s\"", sockfd, errno, strerror(errno));
connection->stop();
return;
}
if (sockerr != 0) {
error=String("socket error ")+String(strerror(sockerr));
LOG_DEBUG(GwLog::ERROR,"socket error on fd %d, errno: %d, \"%s\"", sockfd, sockerr, strerror(sockerr));
connection->stop();
return;
}
}
LOG_DEBUG(GwLog::LOG,"connected to %s",remoteAddress.toString().c_str());
LOG_DEBUG(GwLog::LOG,"connected to %s",remoteAddress.c_str());
state=C_CONNECTED;
}
@@ -111,7 +123,7 @@ GwTcpClient::~GwTcpClient(){
if (connection)
delete connection;
}
void GwTcpClient::begin(int sourceId,IPAddress address, uint16_t port,bool allowRead)
void GwTcpClient::begin(int sourceId,String address, uint16_t port,bool allowRead)
{
stop();
this->sourceId=sourceId;
@@ -151,14 +163,18 @@ void GwTcpClient::loop(bool handleRead,bool handleWrite)
}
}
void GwTcpClient::sendToClients(const char *buf,int sourceId){
if (sourceId == this->sourceId) return;
size_t GwTcpClient::sendToClients(const char *buf,int sourceId, bool partialWrite){
if (sourceId == this->sourceId) return 0;
if (state != C_CONNECTED) return 0;
if (! connection->hasClient()) return 0;
size_t len=strlen(buf);
if (connection->enqueue((uint8_t*)buf,len)){
return len;
}
return 0;
}
void GwTcpClient::readMessages(GwMessageFetcher *writer){
if (state != C_CONNECTED) return;
if (! connection->hasClient()) return;
connection->enqueue((uint8_t*)buf,strlen(buf));
}
bool GwTcpClient::readMessages(GwMessageFetcher *writer){
if (state != C_CONNECTED) return false;
if (! connection->hasClient()) return false;
return connection->messagesFromBuffer(writer);
connection->messagesFromBuffer(writer);
}

View File

@@ -1,15 +1,17 @@
#pragma once
#include "GwSocketConnection.h"
class GwTcpClient
#include "GwChannelInterface.h"
class GwTcpClient : public GwChannelInterface
{
static const unsigned long CON_TIMEOUT=10;
GwSocketConnection *connection = NULL;
IPAddress remoteAddress;
String remoteAddress;
uint16_t port = 0;
unsigned long connectStart=0;
GwLog *logger;
int sourceId;
bool configured=false;
String error;
public:
typedef enum
@@ -30,9 +32,10 @@ private:
public:
GwTcpClient(GwLog *logger);
~GwTcpClient();
void begin(int sourceId,IPAddress address, uint16_t port,bool allowRead);
void loop(bool handleRead=true,bool handleWrite=true);
void sendToClients(const char *buf,int sourceId);
bool readMessages(GwMessageFetcher *writer);
void begin(int sourceId,String address, uint16_t port,bool allowRead);
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);
bool isConnected();
String getError(){return error;}
};