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

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
#include "GwChannelInterface.h"
#include "GwConfigItem.h"
#include "GwLog.h"
#include "GWConfig.h"
#include "GwCounter.h"
#include "GwJsonDocument.h"
#include <N2kMsg.h>
#include <functional>
class GwChannelConfig{
class GwChannelMessageReceiver;
class tActisenseReader;
class GwChannel{
bool enabled=false;
bool NMEAout=false;
bool NMEAin=false;
@@ -13,15 +18,23 @@ class GwChannelConfig{
GwNmeaFilter* writeFilter=NULL;
bool seaSmartOut=false;
bool toN2k=false;
bool readActisense=false;
bool writeActisense=false;
GwLog *logger;
String name;
GwCounter<String> *countIn=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);
public:
GwChannelConfig(
GwChannel(
GwLog *logger,
String name);
String name,
int sourceId);
void begin(
bool enabled,
bool nmeaOut,
@@ -29,9 +42,13 @@ class GwChannelConfig{
String readFilter,
String writeFilter,
bool seaSmartOut,
bool toN2k
bool toN2k,
bool readActisense=false,
bool writeActisense=false
);
void setImpl(GwChannelInterface *impl);
void enable(bool enabled){
this->enabled=enabled;
}
@@ -46,5 +63,13 @@ class GwChannelConfig{
int getJsonSize();
void toJson(GwJsonDocument &doc);
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;
}
void GwSerial::loop(bool handleRead){
void GwSerial::loop(bool handleRead,bool handleWrite){
write();
if (! isInitialized()) return;
if (! handleRead) return;
@@ -116,10 +116,10 @@ void GwSerial::loop(bool handleRead){
serial->readBytes(buffer,available);
}
}
bool GwSerial::readMessages(GwMessageFetcher *writer){
if (! isInitialized()) return false;
if (! allowRead) return false;
return writer->handleBuffer(readBuffer);
void GwSerial::readMessages(GwMessageFetcher *writer){
if (! isInitialized()) return;
if (! allowRead) return;
writer->handleBuffer(readBuffer);
}
void GwSerial::flush(){

View File

@@ -3,8 +3,9 @@
#include "HardwareSerial.h"
#include "GwLog.h"
#include "GwBuffer.h"
#include "GwChannelInterface.h"
class GwSerialStream;
class GwSerial{
class GwSerial : public GwChannelInterface{
private:
GwBuffer *buffer;
GwBuffer *readBuffer=NULL;
@@ -23,11 +24,11 @@ class GwSerial{
~GwSerial();
int setup(int baud,int rxpin,int txpin);
bool isInitialized();
size_t sendToClients(const char *buf,int sourceId,bool partial=false);
void loop(bool handleRead=true);
bool readMessages(GwMessageFetcher *writer);
virtual size_t sendToClients(const char *buf,int sourceId,bool partial=false);
virtual void loop(bool handleRead=true,bool handleWrite=true);
virtual void readMessages(GwMessageFetcher *writer);
void flush();
Stream *getStream(bool partialWrites);
virtual Stream *getStream(bool partialWrites);
friend GwSerialStream;
};
#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)
return false;
bool hasMessages = false;
return;
for (int i = 0; i < maxClients; i++)
{
writer->id = minId + i;
if (!clients[i]->hasClient())
continue;
if (clients[i]->messagesFromBuffer(writer))
hasMessages = true;
clients[i]->messagesFromBuffer(writer);
}
return hasMessages;
return;
}
void GwSocketServer::sendToClients(const char *buf, int source)
size_t GwSocketServer::sendToClients(const char *buf, int source,bool partial)
{
if (!clients)
return;
return 0;
int len = strlen(buf);
int sourceIndex = source - minId;
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);
}
}
return len;
}
int GwSocketServer::numClients()

View File

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