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:
213
lib/channel/GwChannel.cpp
Normal file
213
lib/channel/GwChannel.cpp
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
9
lib/channel/GwChannelInterface.h
Normal file
9
lib/channel/GwChannelInterface.h
Normal 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;}
|
||||
};
|
||||
@@ -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(){
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user