intermediate: introduce an abstract channel

This commit is contained in:
wellenvogel 2021-12-31 18:38:11 +01:00
parent 0acb988f31
commit 47fb805ee6
9 changed files with 351 additions and 259 deletions

213
lib/channel/GwChannel.cpp Normal file
View File

@ -0,0 +1,213 @@
#include "GwChannel.h"
#include <ActisenseReader.h>
class GwChannelMessageReceiver : public GwMessageFetcher{
static const int bufferSize=GwBuffer::RX_BUFFER_SIZE+4;
uint8_t buffer[bufferSize];
uint8_t *writePointer=buffer;
GwLog *logger;
GwChannel *channel;
GwChannel::NMEA0183Handler handler;
public:
GwChannelMessageReceiver(GwLog *logger,GwChannel *channel){
this->logger=logger;
this->channel=channel;
}
void setHandler(GwChannel::NMEA0183Handler handler){
this->handler=handler;
}
virtual bool handleBuffer(GwBuffer *gwbuffer){
size_t len=fetchMessageToBuffer(gwbuffer,buffer,bufferSize-4,'\n');
writePointer=buffer+len;
if (writePointer == buffer) return false;
uint8_t *p;
for (p=writePointer-1;p>=buffer && *p <= 0x20;p--){
*p=0;
}
if (p > buffer){
p++;
*p=0x0d;
p++;
*p=0x0a;
p++;
*p=0;
}
for (p=buffer; *p != 0 && p < writePointer && *p <= 0x20;p++){}
//very simple NMEA check
if (*p != '!' && *p != '$'){
LOG_DEBUG(GwLog::DEBUG,"unknown line [%d] - ignore: %s",id,(const char *)p);
}
else{
LOG_DEBUG(GwLog::DEBUG,"NMEA[%d]: %s",id,(const char *)p);
if (channel->canReceive((const char *)p)){
handler((const char *)p,id);
}
}
writePointer=buffer;
return true;
}
};
GwChannel::GwChannel(GwLog *logger,
String name,
int sourceId){
this->logger = logger;
this->name=name;
this->sourceId=sourceId;
this->countIn=new GwCounter<String>(String("count")+name+String("in"));
this->countOut=new GwCounter<String>(String("count")+name+String("out"));
this->impl=NULL;
this->receiver=new GwChannelMessageReceiver(logger,this);
this->actisenseReader=NULL;
}
void GwChannel::begin(
bool enabled,
bool nmeaOut,
bool nmeaIn,
String readFilter,
String writeFilter,
bool seaSmartOut,
bool toN2k,
bool readActisense,
bool writeActisense)
{
this->enabled = enabled;
this->NMEAout = nmeaOut;
this->NMEAin = nmeaIn;
this->readFilter=readFilter.isEmpty()?
NULL:
new GwNmeaFilter(readFilter);
this->writeFilter=writeFilter.isEmpty()?
NULL:
new GwNmeaFilter(writeFilter);
this->seaSmartOut=seaSmartOut;
this->toN2k=toN2k;
this->readActisense=readActisense;
this->writeActisense=writeActisense;
if (readActisense|| writeActisense){
channelStream=impl->getStream(false);
if (! channelStream) {
this->readActisense=false;
this->writeActisense=false;
LOG_DEBUG(GwLog::ERROR,"unable to read actisnse on %s",name.c_str());
}
else{
if (readActisense){
this->actisenseReader= new tActisenseReader();
actisenseReader->SetReadStream(channelStream);
}
}
}
}
void GwChannel::setImpl(GwChannelInterface *impl){
this->impl=impl;
}
void GwChannel::updateCounter(const char *msg, bool out)
{
char key[6];
if (msg[0] == '$')
{
strncpy(key, &msg[3], 3);
key[3] = 0;
}
else if (msg[0] == '!')
{
strncpy(key, &msg[1], 5);
key[5] = 0;
}
else{
return;
}
if (out){
countOut->add(key);
}
else{
countIn->add(key);
}
}
bool GwChannel::canSendOut(unsigned long pgn){
if (! enabled) return false;
if (! NMEAout) return false;
countOut->add(String(pgn));
return true;
}
bool GwChannel::canReceive(unsigned long pgn){
if (!enabled) return false;
if (!NMEAin) return false;
countIn->add(String(pgn));
return true;
}
bool GwChannel::canSendOut(const char *buffer){
if (! enabled) return false;
if (! NMEAout) return false;
if (writeFilter && ! writeFilter->canPass(buffer)) return false;
updateCounter(buffer,true);
return true;
}
bool GwChannel::canReceive(const char *buffer){
if (! enabled) return false;
if (! NMEAin) return false;
if (readFilter && ! readFilter->canPass(buffer)) return false;
updateCounter(buffer,false);
return true;
}
int GwChannel::getJsonSize(){
if (! enabled) return 0;
int rt=2;
if (countIn) rt+=countIn->getJsonSize();
if (countOut) rt+=countOut->getJsonSize();
return rt;
}
void GwChannel::toJson(GwJsonDocument &doc){
if (! enabled) return;
if (countOut) countOut->toJson(doc);
if (countIn) countIn->toJson(doc);
}
String GwChannel::toString(){
String rt="CH:"+name;
rt+=enabled?"[ena]":"[dis]";
rt+=NMEAin?"in,":"";
rt+=NMEAout?"out,":"";
rt+=String("RF:") + (readFilter?readFilter->toString():"[]");
rt+=String("WF:") + (writeFilter?writeFilter->toString():"[]");
rt+=String(",")+ (toN2k?"n2k":"");
rt+=String(",")+ (seaSmartOut?"SM":"");
return rt;
}
void GwChannel::loop(bool handleRead, bool handleWrite){
if (! enabled || ! impl) return;
impl->loop(handleRead,handleWrite);
}
void GwChannel::readMessages(GwChannel::NMEA0183Handler handler){
if (! enabled || ! impl) return;
if (readActisense || ! NMEAin) return;
receiver->id=sourceId;
receiver->setHandler(handler);
impl->readMessages(receiver);
}
void GwChannel::sendToClients(const char *buffer, int sourceId){
if (! impl) return;
if (canSendOut(buffer)){
impl->sendToClients(buffer,sourceId);
}
}
void GwChannel::parseActisense(N2kHandler handler){
if (!enabled || ! impl || ! readActisense || ! actisenseReader) return;
tN2kMsg N2kMsg;
while (actisenseReader->GetMessageFromStream(N2kMsg)) {
canReceive(N2kMsg.PGN);
handler(N2kMsg,sourceId);
}
}
void GwChannel::sendActisense(const tN2kMsg &msg){
if (!enabled || ! impl || ! writeActisense || ! channelStream) return;
canSendOut(msg.PGN);
msg.SendInActisenseFormat(channelStream);
}

View File

@ -1,11 +1,16 @@
#pragma once #pragma once
#include "GwChannelInterface.h"
#include "GwConfigItem.h" #include "GwConfigItem.h"
#include "GwLog.h" #include "GwLog.h"
#include "GWConfig.h" #include "GWConfig.h"
#include "GwCounter.h" #include "GwCounter.h"
#include "GwJsonDocument.h" #include "GwJsonDocument.h"
#include <N2kMsg.h>
#include <functional>
class GwChannelConfig{ class GwChannelMessageReceiver;
class tActisenseReader;
class GwChannel{
bool enabled=false; bool enabled=false;
bool NMEAout=false; bool NMEAout=false;
bool NMEAin=false; bool NMEAin=false;
@ -13,15 +18,23 @@ class GwChannelConfig{
GwNmeaFilter* writeFilter=NULL; GwNmeaFilter* writeFilter=NULL;
bool seaSmartOut=false; bool seaSmartOut=false;
bool toN2k=false; bool toN2k=false;
bool readActisense=false;
bool writeActisense=false;
GwLog *logger; GwLog *logger;
String name; String name;
GwCounter<String> *countIn=NULL; GwCounter<String> *countIn=NULL;
GwCounter<String> *countOut=NULL; GwCounter<String> *countOut=NULL;
GwChannelInterface *impl;
int sourceId=0;
GwChannelMessageReceiver *receiver=NULL;
tActisenseReader *actisenseReader=NULL;
Stream *channelStream=NULL;
void updateCounter(const char *msg, bool out); void updateCounter(const char *msg, bool out);
public: public:
GwChannelConfig( GwChannel(
GwLog *logger, GwLog *logger,
String name); String name,
int sourceId);
void begin( void begin(
bool enabled, bool enabled,
bool nmeaOut, bool nmeaOut,
@ -29,9 +42,13 @@ class GwChannelConfig{
String readFilter, String readFilter,
String writeFilter, String writeFilter,
bool seaSmartOut, bool seaSmartOut,
bool toN2k bool toN2k,
bool readActisense=false,
bool writeActisense=false
); );
void setImpl(GwChannelInterface *impl);
void enable(bool enabled){ void enable(bool enabled){
this->enabled=enabled; this->enabled=enabled;
} }
@ -46,5 +63,13 @@ class GwChannelConfig{
int getJsonSize(); int getJsonSize();
void toJson(GwJsonDocument &doc); void toJson(GwJsonDocument &doc);
String toString(); String toString();
void loop(bool handleRead, bool handleWrite);
typedef std::function<void(const char *buffer, int sourceid)> NMEA0183Handler;
void readMessages(NMEA0183Handler handler);
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);
}; };

View File

@ -1,104 +0,0 @@
#include "GwChannelConfig.h"
GwChannelConfig::GwChannelConfig(GwLog *logger,String name){
this->logger = logger;
this->name=name;
this->countIn=new GwCounter<String>(String("count")+name+String("in"));
this->countOut=new GwCounter<String>(String("count")+name+String("out"));
}
void GwChannelConfig::begin(
bool enabled,
bool nmeaOut,
bool nmeaIn,
String readFilter,
String writeFilter,
bool seaSmartOut,
bool toN2k)
{
this->enabled = enabled;
this->NMEAout = nmeaOut;
this->NMEAin = nmeaIn;
this->readFilter=readFilter.isEmpty()?
NULL:
new GwNmeaFilter(readFilter);
this->writeFilter=writeFilter.isEmpty()?
NULL:
new GwNmeaFilter(writeFilter);
this->seaSmartOut=seaSmartOut;
this->toN2k=toN2k;
}
void GwChannelConfig::updateCounter(const char *msg, bool out)
{
char key[6];
if (msg[0] == '$')
{
strncpy(key, &msg[3], 3);
key[3] = 0;
}
else if (msg[0] == '!')
{
strncpy(key, &msg[1], 5);
key[5] = 0;
}
else{
return;
}
if (out){
countOut->add(key);
}
else{
countIn->add(key);
}
}
bool GwChannelConfig::canSendOut(unsigned long pgn){
if (! enabled) return false;
if (! NMEAout) return false;
countOut->add(String(pgn));
return true;
}
bool GwChannelConfig::canReceive(unsigned long pgn){
if (!enabled) return false;
if (!NMEAin) return false;
countIn->add(String(pgn));
return true;
}
bool GwChannelConfig::canSendOut(const char *buffer){
if (! enabled) return false;
if (! NMEAout) return false;
if (writeFilter && ! writeFilter->canPass(buffer)) return false;
updateCounter(buffer,true);
return true;
}
bool GwChannelConfig::canReceive(const char *buffer){
if (! enabled) return false;
if (! NMEAin) return false;
if (readFilter && ! readFilter->canPass(buffer)) return false;
updateCounter(buffer,false);
return true;
}
int GwChannelConfig::getJsonSize(){
if (! enabled) return 0;
int rt=2;
if (countIn) rt+=countIn->getJsonSize();
if (countOut) rt+=countOut->getJsonSize();
return rt;
}
void GwChannelConfig::toJson(GwJsonDocument &doc){
if (! enabled) return;
if (countOut) countOut->toJson(doc);
if (countIn) countIn->toJson(doc);
}
String GwChannelConfig::toString(){
String rt="CH:"+name;
rt+=enabled?"[ena]":"[dis]";
rt+=NMEAin?"in,":"";
rt+=NMEAout?"out,":"";
rt+=String("RF:") + (readFilter?readFilter->toString():"[]");
rt+=String("WF:") + (writeFilter?writeFilter->toString():"[]");
rt+=String(",")+ (toN2k?"n2k":"");
rt+=String(",")+ (seaSmartOut?"SM":"");
return rt;
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "GwBuffer.h"
class GwChannelInterface{
public:
virtual void loop(bool handleRead,bool handleWrite)=0;
virtual void readMessages(GwMessageFetcher *writer)=0;
virtual size_t sendToClients(const char *buffer, int sourceId, bool partial=false)=0;
virtual Stream * getStream(bool partialWrites){ return NULL;}
};

View File

@ -96,7 +96,7 @@ size_t GwSerial::sendToClients(const char *buf,int sourceId,bool partial){
} }
return enqueued; return enqueued;
} }
void GwSerial::loop(bool handleRead){ void GwSerial::loop(bool handleRead,bool handleWrite){
write(); write();
if (! isInitialized()) return; if (! isInitialized()) return;
if (! handleRead) return; if (! handleRead) return;
@ -116,10 +116,10 @@ void GwSerial::loop(bool handleRead){
serial->readBytes(buffer,available); serial->readBytes(buffer,available);
} }
} }
bool GwSerial::readMessages(GwMessageFetcher *writer){ void GwSerial::readMessages(GwMessageFetcher *writer){
if (! isInitialized()) return false; if (! isInitialized()) return;
if (! allowRead) return false; if (! allowRead) return;
return writer->handleBuffer(readBuffer); writer->handleBuffer(readBuffer);
} }
void GwSerial::flush(){ void GwSerial::flush(){

View File

@ -3,8 +3,9 @@
#include "HardwareSerial.h" #include "HardwareSerial.h"
#include "GwLog.h" #include "GwLog.h"
#include "GwBuffer.h" #include "GwBuffer.h"
#include "GwChannelInterface.h"
class GwSerialStream; class GwSerialStream;
class GwSerial{ class GwSerial : public GwChannelInterface{
private: private:
GwBuffer *buffer; GwBuffer *buffer;
GwBuffer *readBuffer=NULL; GwBuffer *readBuffer=NULL;
@ -23,11 +24,11 @@ class GwSerial{
~GwSerial(); ~GwSerial();
int setup(int baud,int rxpin,int txpin); int setup(int baud,int rxpin,int txpin);
bool isInitialized(); bool isInitialized();
size_t sendToClients(const char *buf,int sourceId,bool partial=false); virtual size_t sendToClients(const char *buf,int sourceId,bool partial=false);
void loop(bool handleRead=true); virtual void loop(bool handleRead=true,bool handleWrite=true);
bool readMessages(GwMessageFetcher *writer); virtual void readMessages(GwMessageFetcher *writer);
void flush(); void flush();
Stream *getStream(bool partialWrites); virtual Stream *getStream(bool partialWrites);
friend GwSerialStream; friend GwSerialStream;
}; };
#endif #endif

View File

@ -133,25 +133,23 @@ void GwSocketServer::loop(bool handleRead, bool handleWrite)
} }
} }
bool GwSocketServer::readMessages(GwMessageFetcher *writer) void GwSocketServer::readMessages(GwMessageFetcher *writer)
{ {
if (!allowReceive || !clients) if (!allowReceive || !clients)
return false; return;
bool hasMessages = false;
for (int i = 0; i < maxClients; i++) for (int i = 0; i < maxClients; i++)
{ {
writer->id = minId + i; writer->id = minId + i;
if (!clients[i]->hasClient()) if (!clients[i]->hasClient())
continue; continue;
if (clients[i]->messagesFromBuffer(writer)) clients[i]->messagesFromBuffer(writer);
hasMessages = true;
} }
return hasMessages; return;
} }
void GwSocketServer::sendToClients(const char *buf, int source) size_t GwSocketServer::sendToClients(const char *buf, int source,bool partial)
{ {
if (!clients) if (!clients)
return; return 0;
int len = strlen(buf); int len = strlen(buf);
int sourceIndex = source - minId; int sourceIndex = source - minId;
for (int i = 0; i < maxClients; i++) for (int i = 0; i < maxClients; i++)
@ -166,6 +164,7 @@ void GwSocketServer::sendToClients(const char *buf, int source)
client->enqueue((uint8_t *)buf, len); client->enqueue((uint8_t *)buf, len);
} }
} }
return len;
} }
int GwSocketServer::numClients() int GwSocketServer::numClients()

View File

@ -3,10 +3,11 @@
#include "GWConfig.h" #include "GWConfig.h"
#include "GwLog.h" #include "GwLog.h"
#include "GwBuffer.h" #include "GwBuffer.h"
#include "GwChannelInterface.h"
#include <memory> #include <memory>
class GwSocketConnection; class GwSocketConnection;
class GwSocketServer{ class GwSocketServer: public GwChannelInterface{
private: private:
const GwConfigHandler *config; const GwConfigHandler *config;
GwLog *logger; GwLog *logger;
@ -22,9 +23,9 @@ class GwSocketServer{
GwSocketServer(const GwConfigHandler *config,GwLog *logger,int minId); GwSocketServer(const GwConfigHandler *config,GwLog *logger,int minId);
~GwSocketServer(); ~GwSocketServer();
void begin(); void begin();
void loop(bool handleRead=true,bool handleWrite=true); virtual void loop(bool handleRead=true,bool handleWrite=true);
void sendToClients(const char *buf,int sourceId); virtual size_t sendToClients(const char *buf,int sourceId, bool partialWrite=false);
int numClients(); int numClients();
bool readMessages(GwMessageFetcher *writer); virtual void readMessages(GwMessageFetcher *writer);
}; };
#endif #endif

View File

@ -62,7 +62,7 @@ const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
#include "GwStatistics.h" #include "GwStatistics.h"
#include "GwUpdate.h" #include "GwUpdate.h"
#include "GwTcpClient.h" #include "GwTcpClient.h"
#include "GwChannelConfig.h" #include "GwChannel.h"
//NMEA message channels //NMEA message channels
@ -122,8 +122,6 @@ int NodeAddress; // To store last Node Address
Preferences preferences; // Nonvolatile storage on ESP32 - To store LastDeviceAddress Preferences preferences; // Nonvolatile storage on ESP32 - To store LastDeviceAddress
N2kDataToNMEA0183 *nmea0183Converter=NULL; N2kDataToNMEA0183 *nmea0183Converter=NULL;
NMEA0183DataToN2K *toN2KConverter=NULL; NMEA0183DataToN2K *toN2KConverter=NULL;
tActisenseReader *actisenseReader=NULL;
Stream *usbStream=NULL;
SemaphoreHandle_t mainLock; SemaphoreHandle_t mainLock;
@ -133,13 +131,15 @@ GwWebServer webserver(&logger,&mainQueue,80);
GwCounter<unsigned long> countNMEA2KIn("count2Kin"); GwCounter<unsigned long> countNMEA2KIn("count2Kin");
GwCounter<unsigned long> countNMEA2KOut("count2Kout"); GwCounter<unsigned long> countNMEA2KOut("count2Kout");
GwChannelConfig usbChannel(&logger,"USB"); GwChannel usbChannel(&logger,"USB",USB_CHANNEL_ID);
GwChannelConfig actisenseChannel(&logger,"USB"); GwChannel tcpChannel(&logger,"TCPServer",MIN_TCP_CHANNEL_ID);
GwChannelConfig tcpChannel(&logger,"TCPServer"); GwChannel serialChannel(&logger,"SER",SERIAL1_CHANNEL_ID);
GwChannelConfig serialChannel(&logger,"SER"); GwChannel tclChannel(&logger,"TCPClient",TCP_CLIENT_CHANNEL_ID);
GwChannelConfig tclChannel(&logger,"TCPClient");
GwChannelConfig * channelFromSource(int source){ GwChannel *allChannels[]={&usbChannel,&tcpChannel,&serialChannel,&tclChannel};
const int numChannels=sizeof(allChannels)/sizeof(GwChannel*);
GwChannel * channelFromSource(int source){
if (source == USB_CHANNEL_ID) return &usbChannel; if (source == USB_CHANNEL_ID) return &usbChannel;
if (source == SERIAL1_CHANNEL_ID) return &serialChannel; if (source == SERIAL1_CHANNEL_ID) return &serialChannel;
if (source == TCP_CLIENT_CHANNEL_ID) return &tclChannel; if (source == TCP_CLIENT_CHANNEL_ID) return &tclChannel;
@ -204,17 +204,6 @@ bool serCanRead=true;
GwSerial *usbSerial = new GwSerial(NULL, 0, USB_CHANNEL_ID); GwSerial *usbSerial = new GwSerial(NULL, 0, USB_CHANNEL_ID);
GwSerial *serial1=NULL; GwSerial *serial1=NULL;
void sendBufferToChannels(const char * buffer, int sourceId){
if (tcpChannel.canSendOut(buffer)){
socketServer.sendToClients(buffer,sourceId);
}
if (sourceId != USB_CHANNEL_ID && usbChannel.canSendOut(buffer)){
usbSerial->sendToClients(buffer,sourceId);
}
if (serial1 && sourceId != SERIAL1_CHANNEL_ID && serialChannel.canSendOut(buffer)){
serial1->sendToClients(buffer,sourceId);
}
}
typedef enum { typedef enum {
N2KT_MSGIN, //from CAN N2KT_MSGIN, //from CAN
N2KT_MSGINT, //from internal source N2KT_MSGINT, //from internal source
@ -228,18 +217,26 @@ void handleN2kMessage(const tN2kMsg &n2kMsg,N2K_MsgDirection direction)
if (direction == N2KT_MSGIN){ if (direction == N2KT_MSGIN){
countNMEA2KIn.add(n2kMsg.PGN); countNMEA2KIn.add(n2kMsg.PGN);
} }
if (tcpChannel.sendSeaSmart() || tclChannel.sendSeaSmart()) char buf[MAX_NMEA2000_MESSAGE_SEASMART_SIZE];
{ bool messageCreated=false;
char buf[MAX_NMEA2000_MESSAGE_SEASMART_SIZE]; for (int i=0;i<numChannels;i++){
if (N2kToSeasmart(n2kMsg, millis(), buf, MAX_NMEA2000_MESSAGE_SEASMART_SIZE) == 0) if (allChannels[i]->sendSeaSmart()){
return; if (! messageCreated){
if (tcpChannel.sendSeaSmart()){ if (N2kToSeasmart(n2kMsg, millis(), buf, MAX_NMEA2000_MESSAGE_SEASMART_SIZE) != 0) {
socketServer.sendToClients(buf, N2K_CHANNEL_ID); messageCreated=true;
}
}
if (messageCreated){
allChannels[i]->sendToClients(buf,N2K_CHANNEL_ID);
}
} }
} }
if (actisenseReader && direction != N2KT_MSGACT && usbStream && actisenseChannel.canSendOut(n2kMsg.PGN))
if (direction != N2KT_MSGACT)
{ {
n2kMsg.SendInActisenseFormat(usbStream); for (int i=0;i<numChannels;i++){
allChannels[i]->sendActisense(n2kMsg);
}
} }
if (direction != N2KT_MSGOUT){ if (direction != N2KT_MSGOUT){
nmea0183Converter->HandleMsg(n2kMsg); nmea0183Converter->HandleMsg(n2kMsg);
@ -250,14 +247,6 @@ void handleN2kMessage(const tN2kMsg &n2kMsg,N2K_MsgDirection direction)
} }
}; };
void handleReceivedNmeaMessage(const char *buf, int sourceId){
GwChannelConfig *channel=channelFromSource(sourceId);
if (channel && ! channel->canReceive(buf)) return;
if (! channel || channel->sendToN2K()){
toN2KConverter->parseAndSend(buf,sourceId);
}
sendBufferToChannels(buf,sourceId);
}
//***************************************************************************** //*****************************************************************************
void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId,bool convert=false) { void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId,bool convert=false) {
@ -272,7 +261,9 @@ void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId,bool conv
buf[len]=0x0d; buf[len]=0x0d;
buf[len+1]=0x0a; buf[len+1]=0x0a;
buf[len+2]=0; buf[len+2]=0;
sendBufferToChannels(buf,sourceId); for (int i=0;i< numChannels;i++){
allChannels[i]->sendToClients(buf,sourceId);
}
} }
class GwSerialLog : public GwLogWriter{ class GwSerialLog : public GwLogWriter{
@ -431,7 +422,6 @@ protected:
usbChannel.getJsonSize()+ usbChannel.getJsonSize()+
tcpChannel.getJsonSize()+ tcpChannel.getJsonSize()+
serialChannel.getJsonSize()+ serialChannel.getJsonSize()+
actisenseChannel.getJsonSize()+
tclChannel.getJsonSize() tclChannel.getJsonSize()
); );
status["version"] = VERSION; status["version"] = VERSION;
@ -449,7 +439,6 @@ protected:
countNMEA2KIn.toJson(status); countNMEA2KIn.toJson(status);
countNMEA2KOut.toJson(status); countNMEA2KOut.toJson(status);
usbChannel.toJson(status); usbChannel.toJson(status);
actisenseChannel.toJson(status);
serialChannel.toJson(status); serialChannel.toJson(status);
tcpChannel.toJson(status); tcpChannel.toJson(status);
tclChannel.toJson(status); tclChannel.toJson(status);
@ -715,33 +704,28 @@ void setup() {
if (serial1){ if (serial1){
int rt=serial1->setup(config.getInt(config.serialBaud,115200),serialrx,serialtx); int rt=serial1->setup(config.getInt(config.serialBaud,115200),serialrx,serialtx);
logger.logDebug(GwLog::LOG,"starting serial returns %d",rt); logger.logDebug(GwLog::LOG,"starting serial returns %d",rt);
serialChannel.setImpl(serial1);
} }
#endif #endif
usbChannel.setImpl(usbSerial);
MDNS.begin(config.getConfigItem(config.systemName)->asCString()); MDNS.begin(config.getConfigItem(config.systemName)->asCString());
gwWifi.setup(); gwWifi.setup();
// Start TCP server // Start TCP server
socketServer.begin(); socketServer.begin();
tcpChannel.setImpl(&socketServer);
logger.flush(); logger.flush();
usbChannel.begin(!config.getBool(config.usbActisense), usbChannel.begin(true,
config.getBool(config.sendUsb), config.getBool(config.sendUsb),
config.getBool(config.receiveUsb), config.getBool(config.receiveUsb),
config.getString(config.usbReadFilter), config.getString(config.usbReadFilter),
config.getString(config.usbWriteFilter), config.getString(config.usbWriteFilter),
false, false,
config.getBool(config.usbToN2k)); config.getBool(config.usbToN2k),
logger.logDebug(GwLog::LOG,"%s",usbChannel.toString().c_str());
actisenseChannel.begin(
config.getBool(config.usbActisense), config.getBool(config.usbActisense),
config.getBool(config.usbActSend), config.getBool(config.usbActSend)
true, );
"", logger.logDebug(GwLog::LOG,"%s",usbChannel.toString().c_str());
"",
false,
true
);
logger.logDebug(GwLog::LOG,"ACT:%s",actisenseChannel.toString().c_str());
tcpChannel.begin( tcpChannel.begin(
true, true,
config.getBool(config.sendTCP), config.getBool(config.sendTCP),
@ -749,7 +733,9 @@ void setup() {
config.getString(config.tcpReadFilter), config.getString(config.tcpReadFilter),
config.getString(config.tcpWriteFilter), config.getString(config.tcpWriteFilter),
config.getBool(config.sendSeasmart), config.getBool(config.sendSeasmart),
config.getBool(config.tcpToN2k) config.getBool(config.tcpToN2k),
false,
false
); );
logger.logDebug(GwLog::LOG,"%s",tcpChannel.toString().c_str()); logger.logDebug(GwLog::LOG,"%s",tcpChannel.toString().c_str());
serialChannel.begin( serialChannel.begin(
@ -759,7 +745,9 @@ void setup() {
config.getString(config.serialReadF), config.getString(config.serialReadF),
config.getString(config.serialWriteF), config.getString(config.serialWriteF),
false, false,
config.getBool(config.serialToN2k) config.getBool(config.serialToN2k),
false,
false
); );
logger.logDebug(GwLog::LOG,"%s",serialChannel.toString().c_str()); logger.logDebug(GwLog::LOG,"%s",serialChannel.toString().c_str());
tclChannel.begin( tclChannel.begin(
@ -769,7 +757,9 @@ void setup() {
config.getString(config.tclReadFilter), config.getString(config.tclReadFilter),
config.getString(config.tclReadFilter), config.getString(config.tclReadFilter),
config.getBool(config.tclSeasmart), config.getBool(config.tclSeasmart),
config.getBool(config.tclToN2k) config.getBool(config.tclToN2k),
false,
false
); );
logger.logDebug(GwLog::LOG,"%s",tclChannel.toString().c_str()); logger.logDebug(GwLog::LOG,"%s",tclChannel.toString().c_str());
logger.flush(); logger.flush();
@ -890,15 +880,6 @@ void setup() {
} }
NMEA2000.ExtendTransmitMessages(pgns); NMEA2000.ExtendTransmitMessages(pgns);
NMEA2000.ExtendReceiveMessages(nmea0183Converter->handledPgns()); NMEA2000.ExtendReceiveMessages(nmea0183Converter->handledPgns());
if (config.getBool(config.usbActisense)){
actisenseReader=new tActisenseReader();
usbStream=usbSerial->getStream(false);
actisenseReader->SetReadStream(usbStream);
actisenseReader->SetMsgHandler([](const tN2kMsg &msg){
actisenseChannel.canReceive(msg.PGN); //count only
handleN2kMessage(msg,N2KT_MSGACT);
});
}
NMEA2000.SetMsgHandler([](const tN2kMsg &n2kMsg){ NMEA2000.SetMsgHandler([](const tN2kMsg &n2kMsg){
handleN2kMessage(n2kMsg,N2KT_MSGIN); handleN2kMessage(n2kMsg,N2KT_MSGIN);
}); });
@ -918,49 +899,12 @@ void setup() {
} }
//***************************************************************************** //*****************************************************************************
void handleSendAndRead(bool handleRead){ void handleSendAndRead(bool handleRead){
socketServer.loop(handleRead); for (int i=0;i<numChannels;i++){
usbSerial->loop(handleRead); allChannels[i]->loop(handleRead,true);
if (serial1) serial1->loop(handleRead); }
} }
class NMEAMessageReceiver : public GwMessageFetcher{
static const int bufferSize=GwBuffer::RX_BUFFER_SIZE+4;
uint8_t buffer[bufferSize];
uint8_t *writePointer=buffer;
public:
virtual bool handleBuffer(GwBuffer *gwbuffer){
size_t len=fetchMessageToBuffer(gwbuffer,buffer,bufferSize-4,'\n');
writePointer=buffer+len;
if (writePointer == buffer) return false;
uint8_t *p;
for (p=writePointer-1;p>=buffer && *p <= 0x20;p--){
*p=0;
}
if (p > buffer){
p++;
*p=0x0d;
p++;
*p=0x0a;
p++;
*p=0;
}
for (p=buffer; *p != 0 && p < writePointer && *p <= 0x20;p++){}
//very simple NMEA check
if (*p != '!' && *p != '$'){
logger.logDebug(GwLog::DEBUG,"unknown line [%d] - ignore: %s",id,(const char *)p);
}
else{
logger.logDebug(GwLog::DEBUG,"NMEA[%d]: %s",id,(const char *)p);
handleReceivedNmeaMessage((const char *)p,id);
//trigger sending to empty buffers
handleSendAndRead(false);
}
writePointer=buffer;
return true;
}
};
TimeMonitor monitor(20,0.2); TimeMonitor monitor(20,0.2);
NMEAMessageReceiver receiver;
unsigned long lastHeapReport=0; unsigned long lastHeapReport=0;
void loop() { void loop() {
monitor.reset(); monitor.reset();
@ -981,20 +925,18 @@ void loop() {
} }
} }
monitor.setTime(3); monitor.setTime(3);
//read sockets for (int i=0;i<numChannels;i++){
socketServer.loop(true,false); allChannels[i]->loop(true,false);
}
//reads
monitor.setTime(4); monitor.setTime(4);
//write sockets for (int i=0;i<numChannels;i++){
socketServer.loop(false,true); allChannels[i]->loop(false,true);
}
//writes
monitor.setTime(5); monitor.setTime(5);
usbSerial->loop(true);
monitor.setTime(6);
if (serial1) serial1->loop(true);
monitor.setTime(7);
handleSendAndRead(true);
monitor.setTime(8);
NMEA2000.ParseMessages(); NMEA2000.ParseMessages();
monitor.setTime(9); monitor.setTime(6);
int SourceAddress = NMEA2000.GetN2kSource(); int SourceAddress = NMEA2000.GetN2kSource();
if (SourceAddress != NodeAddress) { // Save potentially changed Source Address to NVS memory if (SourceAddress != NodeAddress) { // Save potentially changed Source Address to NVS memory
@ -1005,21 +947,27 @@ void loop() {
logger.logDebug(GwLog::LOG,"Address Change: New Address=%d\n", SourceAddress); logger.logDebug(GwLog::LOG,"Address Change: New Address=%d\n", SourceAddress);
} }
nmea0183Converter->loop(); nmea0183Converter->loop();
monitor.setTime(10); monitor.setTime(7);
//read channels //read channels
if (tcpChannel.shouldRead()) socketServer.readMessages(&receiver); for (int i=0;i<numChannels;i++){
monitor.setTime(11); allChannels[i]->readMessages([&](const char * buffer, int sourceId){
receiver.id=USB_CHANNEL_ID; for (int j=0;j<numChannels;j++){
if (usbChannel.shouldRead()) usbSerial->readMessages(&receiver); allChannels[j]->sendToClients(buffer,sourceId);
monitor.setTime(12); allChannels[j]->loop(false,true);
receiver.id=SERIAL1_CHANNEL_ID; }
if (serial1 && serialChannel.shouldRead() ) serial1->readMessages(&receiver); if (allChannels[i]->sendToN2K()){
monitor.setTime(13); toN2KConverter->parseAndSend(buffer, sourceId);
if (actisenseReader){ }
actisenseReader->ParseMessages(); });
} }
monitor.setTime(14); monitor.setTime(8);
for (int i=0;i<numChannels;i++){
allChannels[i]->parseActisense([](const tN2kMsg &msg,int source){
handleN2kMessage(msg,N2KT_MSGACT);
});
}
monitor.setTime(9);
//handle message requests //handle message requests
GwMessage *msg=mainQueue.fetchMessage(0); GwMessage *msg=mainQueue.fetchMessage(0);
@ -1027,5 +975,5 @@ void loop() {
msg->process(); msg->process();
msg->unref(); msg->unref();
} }
monitor.setTime(15); monitor.setTime(10);
} }