222 lines
6.2 KiB
C++
222 lines
6.2 KiB
C++
#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,
|
|
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;
|
|
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 (impl && readActisense){
|
|
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{
|
|
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(const char *buffer, bool isSeasmart){
|
|
if (! enabled || ! impl) return false;
|
|
if (readActisense) return false;
|
|
if (! isSeasmart && ! NMEAout) return false;
|
|
if (isSeasmart && ! seaSmartOut) return false;
|
|
if (writeFilter && ! writeFilter->canPass(buffer)) return false;
|
|
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(){
|
|
int rt=2;
|
|
if (countIn) rt+=countIn->getJsonSize();
|
|
if (countOut) rt+=countOut->getJsonSize();
|
|
return rt;
|
|
}
|
|
void GwChannel::toJson(GwJsonDocument &doc){
|
|
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":"");
|
|
rt+=String(",")+(readActisense?"AR":"");
|
|
rt+=String(",")+(writeActisense?"AW":"");
|
|
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, bool isSeasmart){
|
|
if (! impl) return;
|
|
if (canSendOut(buffer,isSeasmart)){
|
|
if(impl->sendToClients(buffer,sourceId)){
|
|
updateCounter(buffer,true);
|
|
}
|
|
}
|
|
}
|
|
void GwChannel::parseActisense(N2kHandler handler){
|
|
if (!enabled || ! impl || ! readActisense || ! actisenseReader) return;
|
|
tN2kMsg N2kMsg;
|
|
|
|
while (actisenseReader->GetMessageFromStream(N2kMsg)) {
|
|
countIn->add(String(N2kMsg.PGN));
|
|
handler(N2kMsg,sourceId);
|
|
}
|
|
}
|
|
|
|
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;
|
|
countOut->add(String(msg.PGN));
|
|
msg.SendInActisenseFormat(channelStream);
|
|
}
|
|
|
|
bool GwChannel::isOwnSource(int id){
|
|
if (maxSourceId < 0) return id == sourceId;
|
|
else return (id >= sourceId && id <= maxSourceId);
|
|
}
|
|
|
|
unsigned long GwChannel::countRx(){
|
|
if (! countIn) return 0UL;
|
|
return countIn->getGlobal();
|
|
}
|
|
unsigned long GwChannel::countTx(){
|
|
if (! countOut) return 0UL;
|
|
return countOut->getGlobal();
|
|
}
|