From c6f601377ca3babb437242779fc604a91041744c Mon Sep 17 00:00:00 2001 From: andreas Date: Sun, 3 Nov 2024 16:15:52 +0100 Subject: [PATCH] intermediate,untested: reorganize channel handling --- lib/channel/GwChannel.cpp | 17 +- lib/channel/GwChannel.h | 7 +- lib/channel/GwChannelInterface.h | 1 + lib/channel/GwChannelList.cpp | 325 ++++++++++++++----------------- lib/channel/GwChannelList.h | 5 +- lib/hardware/GwHardware.h | 1 + lib/serial/GwSerial.cpp | 38 +++- lib/serial/GwSerial.h | 79 +++++--- 8 files changed, 249 insertions(+), 224 deletions(-) diff --git a/lib/channel/GwChannel.cpp b/lib/channel/GwChannel.cpp index 93a2da3..069b5ae 100644 --- a/lib/channel/GwChannel.cpp +++ b/lib/channel/GwChannel.cpp @@ -218,14 +218,23 @@ 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; + if (maxSourceId < 0 && this->sourceId == sourceId) return; + if (sourceId >= this->sourceId && sourceId <= maxSourceId) 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); +bool GwChannel::overlaps(const GwChannel *other) const{ + if (maxSourceId < 0){ + if (other->maxSourceId < 0) return sourceId == other->sourceId; + return (other->sourceId <= sourceId && other->maxSourceId >= sourceId); + } + if (other->maxSourceId < 0){ + return other->sourceId >= sourceId && other->sourceId <= maxSourceId; + } + if (other->maxSourceId < sourceId) return false; + if (other->sourceId > maxSourceId) return false; + return true; } unsigned long GwChannel::countRx(){ diff --git a/lib/channel/GwChannel.h b/lib/channel/GwChannel.h index 77af597..951290b 100644 --- a/lib/channel/GwChannel.h +++ b/lib/channel/GwChannel.h @@ -50,7 +50,7 @@ class GwChannel{ ); void setImpl(GwChannelInterface *impl); - bool isOwnSource(int id); + bool overlaps(const GwChannel *) const; void enable(bool enabled){ this->enabled=enabled; } @@ -73,5 +73,10 @@ class GwChannel{ void sendActisense(const tN2kMsg &msg, int sourceId); unsigned long countRx(); unsigned long countTx(); + bool isOwnSource(int source){ + if (maxSourceId < 0) return source == sourceId; + return (source >= sourceId && source <= maxSourceId); + } + String getMode(){return impl->getMode();} }; diff --git a/lib/channel/GwChannelInterface.h b/lib/channel/GwChannelInterface.h index f9b076c..68f519b 100644 --- a/lib/channel/GwChannelInterface.h +++ b/lib/channel/GwChannelInterface.h @@ -6,4 +6,5 @@ class GwChannelInterface{ 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;} + virtual String getMode(){return "UNKNOWN";} }; \ No newline at end of file diff --git a/lib/channel/GwChannelList.cpp b/lib/channel/GwChannelList.cpp index 58b96b5..c09966c 100644 --- a/lib/channel/GwChannelList.cpp +++ b/lib/channel/GwChannelList.cpp @@ -18,16 +18,53 @@ class SerInit{ }; std::vector serialInits; +static int typeFromMode(const char *mode){ + if (strcmp(mode,"UNI") == 0) return GWSERIAL_TYPE_UNI; + if (strcmp(mode,"BI") == 0) return GWSERIAL_TYPE_BI; + if (strcmp(mode,"RX") == 0) return GWSERIAL_TYPE_RX; + if (strcmp(mode,"TX") == 0) return GWSERIAL_TYPE_TX; + return GWSERIAL_TYPE_UNK; +} + #define CFG_SERIAL(ser,...) \ __MSG("serial config " #ser); \ static GwInitializer __serial ## ser ## _init \ (serialInits,SerInit(ser,__VA_ARGS__)); #ifdef _GWI_SERIAL1 - CFG_SERIAL(1,_GWI_SERIAL1) + CFG_SERIAL(0,_GWI_SERIAL1) #endif #ifdef _GWI_SERIAL2 - CFG_SERIAL(2,_GWI_SERIAL2) + CFG_SERIAL(1,_GWI_SERIAL2) #endif +//handle separate defines + //serial 1 + #ifndef GWSERIAL_TX + #define GWSERIAL_TX -1 + #endif + #ifndef GWSERIAL_RX + #define GWSERIAL_RX -1 + #endif + #ifdef GWSERIAL_TYPE + CFG_SERIAL(0,GWSERIAL_RX,GWSERIAL_TX,GWSERIAL_TYPE) + #else + #ifdef GWSERIAL_MODE + CFG_SERIAL(0,GWSERIAL_RX,GWSERIAL_TX,typeFromMode(GWSERIAL_MODE)) + #endif + #endif + //serial 2 + #ifndef GWSERIAL2_TX + #define GWSERIAL2_TX -1 + #endif + #ifndef GWSERIAL2_RX + #define GWSERIAL2_RX -1 + #endif + #ifdef GWSERIAL2_TYPE + CFG_SERIAL(1,GWSERIAL2_RX,GWSERIAL2_TX,GWSERIAL2_TYPE) + #else + #ifdef GWSERIAL2_MODE + CFG_SERIAL(1,GWSERIAL2_RX,GWSERIAL2_TX,typeFromMode(GWSERIAL2_MODE)) + #endif + #endif class GwSerialLog : public GwLogWriter { static const size_t bufferSize = 4096; @@ -35,13 +72,11 @@ class GwSerialLog : public GwLogWriter int wp = 0; GwSerial *writer; bool disabled = false; - long flushTimeout=200; public: - GwSerialLog(GwSerial *writer, bool disabled,long flushTimeout=200) + GwSerialLog(GwSerial *writer, bool disabled) { this->writer = writer; this->disabled = disabled; - this->flushTimeout=flushTimeout; logBuffer = new char[bufferSize]; wp = 0; } @@ -64,7 +99,7 @@ public: { while (handled < wp) { - if ( !writer->flush(flushTimeout)) break; + if ( !writer->flush()) break; size_t rt = writer->sendToClients(logBuffer + handled, -1, true); handled += rt; } @@ -82,44 +117,6 @@ public: } }; -template - class SerialWrapper : public GwSerial::SerialWrapperBase{ - private: - template - void beginImpl(C *s,unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1){} - void beginImpl(HardwareSerial *s,unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1){ - s->begin(baud,config,rxPin,txPin); - } - template - void setError(C* s, GwLog *logger){} - void setError(HardwareSerial *s,GwLog *logger){ - LOG_DEBUG(GwLog::LOG,"enable serial errors for channel %d",id); - s->onReceiveError([logger,this](hardwareSerial_error_t err){ - LOG_DEBUG(GwLog::ERROR,"serial error on id %d: %d",this->id,(int)err); - }); - } - #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 - void beginImpl(HWCDC *s,unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1){ - s->begin(baud); - } - #endif - T *serial; - int id; - public: - SerialWrapper(T* s,int i):serial(s),id(i){} - virtual void begin(GwLog* logger,unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1) override{ - beginImpl(serial,baud,config,rxPin,txPin); - setError(serial,logger); - }; - virtual Stream *getStream() override{ - return serial; - } - virtual int getId() override{ - return id; - } - - }; - GwChannelList::GwChannelList(GwLog *logger, GwConfigHandler *config){ this->logger=logger; @@ -139,10 +136,27 @@ typedef struct { const char *toN2K; const char *readF; const char *writeF; + const char *preventLog; + const char *readAct; + const char *writeAct; const char *name; } SerialParam; static SerialParam serialParameters[]={ + { + .id=USB_CHANNEL_ID, + .baud=GwConfigDefinitions::usbBaud, + .receive=GwConfigDefinitions::receiveUsb, + .send=GwConfigDefinitions::sendUsb, + .direction="", + .toN2K=GwConfigDefinitions::usbToN2k, + .readF=GwConfigDefinitions::usbReadFilter, + .writeF=GwConfigDefinitions::usbWriteFilter, + .preventLog=GwConfigDefinitions::usbActisense, + .readAct=GwConfigDefinitions::usbActisense, + .writeAct=GwConfigDefinitions::usbActSend, + .name="USB" + }, { .id=SERIAL1_CHANNEL_ID, .baud=GwConfigDefinitions::serialBaud, @@ -152,6 +166,9 @@ static SerialParam serialParameters[]={ .toN2K=GwConfigDefinitions::serialToN2k, .readF=GwConfigDefinitions::serialReadF, .writeF=GwConfigDefinitions::serialWriteF, + .preventLog="", + .readAct="", + .writeAct="", .name="Serial" }, { @@ -163,81 +180,38 @@ static SerialParam serialParameters[]={ .toN2K=GwConfigDefinitions::serial2ToN2k, .readF=GwConfigDefinitions::serial2ReadF, .writeF=GwConfigDefinitions::serial2WriteF, + .preventLog="", + .readAct="", + .writeAct="", .name="Serial2" } }; -static SerialParam *getSerialParam(int id){ - for (size_t idx=0;idx(&Serial1,SERIAL1_CHANNEL_ID),type,rx,tx); - return; - } - if (id == 2){ - addSerial(new SerialWrapper(&Serial2,SERIAL2_CHANNEL_ID),type,rx,tx); - return; - } - LOG_DEBUG(GwLog::ERROR,"invalid serial config with id %d",id); -} -void GwChannelList::addSerial(GwSerial::SerialWrapperBase *stream,int type,int rx,int tx){ - const char *mode=nullptr; - switch (type) - { - case GWSERIAL_TYPE_UNI: - mode="UNI"; - break; - case GWSERIAL_TYPE_BI: - mode="BI"; - break; - case GWSERIAL_TYPE_RX: - mode="RX"; - break; - case GWSERIAL_TYPE_TX: - mode="TX"; - break; - } - if (mode == nullptr) { - LOG_DEBUG(GwLog::ERROR,"unknown serial type %d",type); - return; - } - addSerial(stream,mode,rx,tx); -} -void GwChannelList::addSerial(GwSerial::SerialWrapperBase *serialStream,const String &mode,int rx,int tx){ - int id=serialStream->getId(); - for (auto &&it:theChannels){ - if (it->isOwnSource(id)){ - LOG_DEBUG(GwLog::ERROR,"trying to re-add serial id=%d, ignoring",id); - return; - } - } - SerialParam *param=getSerialParam(id); - if (param == nullptr){ - logger->logDebug(GwLog::ERROR,"trying to set up an unknown serial channel: %d",id); - return; - } - if (rx < 0 && tx < 0){ - logger->logDebug(GwLog::ERROR,"useless config for serial %d: both rx/tx undefined"); - return; - } - modes[id]=String(mode); +template +GwSerial* createSerial(GwLog *logger, T* s,int id, bool canRead=true){ + return new GwSerialImpl(logger,s,id,canRead); +} + +static GwChannel * createSerialChannel(GwConfigHandler *config,GwLog *logger, int idx,int type,int rx,int tx, bool setLog=false){ + if (idx < 0 || idx >= sizeof(serialParameters)/sizeof(SerialParam*)) return nullptr; + SerialParam *param=&serialParameters[idx]; bool canRead=false; bool canWrite=false; - if (mode == "BI"){ + bool validType=false; + if (type == GWSERIAL_TYPE_BI){ canRead=config->getBool(param->receive); canWrite=config->getBool(param->send); + validType=true; } - if (mode == "TX"){ + if (type == GWSERIAL_TYPE_TX){ canWrite=true; + validType=true; } - if (mode == "RX"){ + if (type == GWSERIAL_TYPE_RX){ canRead=true; + validType=true; } - if (mode == "UNI"){ + if (type == GWSERIAL_TYPE_UNI ){ String cfgMode=config->getString(param->direction); if (cfgMode == "receive"){ canRead=true; @@ -245,16 +219,41 @@ void GwChannelList::addSerial(GwSerial::SerialWrapperBase *serialStream,const St if (cfgMode == "send"){ canWrite=true; } + validType=true; + } + if (! validType){ + LOG_DEBUG(GwLog::ERROR,"invalid type for serial channel %d: %d",param->id,type); + return nullptr; } if (rx < 0) canRead=false; if (tx < 0) canWrite=false; - LOG_DEBUG(GwLog::DEBUG,"serial set up: mode=%s,rx=%d,canRead=%d,tx=%d,canWrite=%d", - mode.c_str(),rx,(int)canRead,tx,(int)canWrite); - serialStream->begin(logger,config->getInt(param->baud,115200),SERIAL_8N1,rx,tx); - GwSerial *serial = new GwSerial(logger, serialStream, canRead); - LOG_DEBUG(GwLog::LOG, "starting serial %d ", id); - GwChannel *channel = new GwChannel(logger, param->name, id); - channel->setImpl(serial); + LOG_DEBUG(GwLog::DEBUG,"serial set up: type=%d,rx=%d,canRead=%d,tx=%d,canWrite=%d", + type,rx,(int)canRead,tx,(int)canWrite); + GwSerial *serialStream=nullptr; + GwLog *streamLog=setLog?nullptr:logger; + switch(param->id){ + case USB_CHANNEL_ID: + serialStream=createSerial(streamLog,&USBSerial,param->id); + break; + case SERIAL1_CHANNEL_ID: + serialStream=createSerial(streamLog,&Serial1,param->id); + break; + case SERIAL2_CHANNEL_ID: + serialStream=createSerial(streamLog,&Serial2,param->id); + break; + } + if (serialStream == nullptr){ + LOG_DEBUG(GwLog::ERROR,"invalid serial config with id %d",param->id); + return nullptr; + } + serialStream->begin(config->getInt(param->baud,115200),SERIAL_8N1,rx,tx); + if (setLog){ + logger->setWriter(new GwSerialLog(serialStream,config->getBool(param->preventLog,false))); + logger->prefix="GWSERIAL:"; + } + LOG_DEBUG(GwLog::LOG, "starting serial %d ", param->id); + GwChannel *channel = new GwChannel(logger, param->name,param->id); + channel->setImpl(serialStream); channel->begin( canRead || canWrite, canWrite, @@ -263,9 +262,20 @@ void GwChannelList::addSerial(GwSerial::SerialWrapperBase *serialStream,const St config->getString(param->writeF), false, config->getBool(param->toN2K), - false, - false); - LOG_DEBUG(GwLog::LOG, "%s", channel->toString().c_str()); + config->getBool(param->readAct), + config->getBool(param->writeAct)); + return channel; +} +void GwChannelList::addChannel(GwChannel * channel){ + for (auto &&it:theChannels){ + if (it->overlaps(channel)){ + LOG_DEBUG(GwLog::ERROR,"trying to add channel with overlapping ids %s (%s), ignoring", + channel->toString().c_str(), + it->toString().c_str()); + return; + } + } + LOG_DEBUG(GwLog::LOG, "adding channel %s", channel->toString().c_str()); theChannels.push_back(channel); } void GwChannelList::preinit(){ @@ -290,38 +300,20 @@ void GwChannelList::preinit(){ } } } -template -long getFlushTimeout(S &s){ - return 200; -} -template<> -long getFlushTimeout(HardwareSerial &s){ - return 2000; -} +#ifndef GWUSB_TX + #define GWUSB_TX -1 +#endif +#ifndef GWUSB_RX + #define GWUSB_RX -1 +#endif + void GwChannelList::begin(bool fallbackSerial){ LOG_DEBUG(GwLog::DEBUG,"GwChannelList::begin"); GwChannel *channel=NULL; //usb if (! fallbackSerial){ - GwSerial::SerialWrapperBase *usbWrapper=new SerialWrapper(&USBSerial,USB_CHANNEL_ID); - usbWrapper->begin(NULL,config->getInt(config->usbBaud)); - GwSerial *usb=new GwSerial(NULL,usbWrapper); - logger->setWriter(new GwSerialLog(usb,config->getBool(config->usbActisense),getFlushTimeout(USBSerial))); - logger->prefix="GWSERIAL:"; - channel=new GwChannel(logger,"USB",USB_CHANNEL_ID); - channel->setImpl(usb); - 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) - ); - theChannels.push_back(channel); - LOG_DEBUG(GwLog::LOG,"%s",channel->toString().c_str()); + GwChannel *usb=createSerialChannel(config, logger,0,GWSERIAL_TYPE_BI,GWUSB_RX,GWUSB_TX,true); + addChannel(usb); } //TCP server sockets=new GwSocketServer(config,logger,MIN_TCP_CHANNEL_ID); @@ -339,42 +331,13 @@ void GwChannelList::begin(bool fallbackSerial){ false, false ); - LOG_DEBUG(GwLog::LOG,"%s",channel->toString().c_str()); - theChannels.push_back(channel); + addChannel(channel); //new serial config handling for (auto &&init:serialInits){ - addSerial(init.serial,init.rx,init.tx,init.mode); + (logger,init.serial,init.rx,init.tx,init.mode); } - //handle separate defines - //serial 1 - #ifndef GWSERIAL_TX - #define GWSERIAL_TX -1 - #endif - #ifndef GWSERIAL_RX - #define GWSERIAL_RX -1 - #endif - #ifdef GWSERIAL_TYPE - addSerial(new SerialWrapper(&Serial1,SERIAL1_CHANNEL_ID),GWSERIAL_TYPE,GWSERIAL_RX,GWSERIAL_TX); - #else - #ifdef GWSERIAL_MODE - addSerial(new SerialWrapper(&Serial1,SERIAL1_CHANNEL_ID),GWSERIAL_MODE,GWSERIAL_RX,GWSERIAL_TX); - #endif - #endif - //serial 2 - #ifndef GWSERIAL2_TX - #define GWSERIAL2_TX -1 - #endif - #ifndef GWSERIAL2_RX - #define GWSERIAL2_RX -1 - #endif - #ifdef GWSERIAL2_TYPE - addSerial(new SerialWrapper(&Serial2,SERIAL2_CHANNEL_ID),GWSERIAL2_TYPE,GWSERIAL2_RX,GWSERIAL2_TX); - #else - #ifdef GWSERIAL2_MODE - addSerial(new SerialWrapper(&Serial2,SERIAL2_CHANNEL_ID),GWSERIAL2_MODE,GWSERIAL2_RX,GWSERIAL2_TX); - #endif - #endif + //tcp client bool tclEnabled=config->getBool(config->tclEnabled); channel=new GwChannel(logger,"TCPClient",TCP_CLIENT_CHANNEL_ID); @@ -398,13 +361,13 @@ void GwChannelList::begin(bool fallbackSerial){ false, false ); - theChannels.push_back(channel); - LOG_DEBUG(GwLog::LOG,"%s",channel->toString().c_str()); + addChannel(channel); logger->flush(); } String GwChannelList::getMode(int id){ - auto it=modes.find(id); - if (it != modes.end()) return it->second; + for (auto && c: theChannels){ + if (c->isOwnSource(id)) return c->getMode(); + } return "UNKNOWN"; } int GwChannelList::getJsonSize(){ @@ -429,8 +392,8 @@ void GwChannelList::toJson(GwJsonDocument &doc){ }); } GwChannel *GwChannelList::getChannelById(int sourceId){ - for (auto it=theChannels.begin();it != theChannels.end();it++){ - if ((*it)->isOwnSource(sourceId)) return *it; + for (auto && it: theChannels){ + if (it->isOwnSource(sourceId)) return it; } return NULL; } diff --git a/lib/channel/GwChannelList.h b/lib/channel/GwChannelList.h index 6ca20f8..ba45c66 100644 --- a/lib/channel/GwChannelList.h +++ b/lib/channel/GwChannelList.h @@ -28,13 +28,10 @@ class GwChannelList{ GwConfigHandler *config; typedef std::vector ChannelList; ChannelList theChannels; - std::map modes; GwSocketServer *sockets; GwTcpClient *client; - void addSerial(GwSerial::SerialWrapperBase *stream,const String &mode,int rx,int tx); - void addSerial(GwSerial::SerialWrapperBase *stream,int type,int rx,int tx); public: - void addSerial(int id, int rx, int tx, int type); + void addChannel(GwChannel *); GwChannelList(GwLog *logger, GwConfigHandler *config); typedef std::function ChannelAction; void allChannels(ChannelAction action); diff --git a/lib/hardware/GwHardware.h b/lib/hardware/GwHardware.h index 8306409..0b14ab3 100644 --- a/lib/hardware/GwHardware.h +++ b/lib/hardware/GwHardware.h @@ -24,6 +24,7 @@ #define GWSERIAL_TYPE_BI 2 #define GWSERIAL_TYPE_RX 3 #define GWSERIAL_TYPE_TX 4 +#define GWSERIAL_TYPE_UNK 0 #include #include #include "GwAppInfo.h" diff --git a/lib/serial/GwSerial.cpp b/lib/serial/GwSerial.cpp index 28c8d34..c0fb06e 100644 --- a/lib/serial/GwSerial.cpp +++ b/lib/serial/GwSerial.cpp @@ -1,4 +1,5 @@ #include "GwSerial.h" +#include "GwHardware.h" class GwSerialStream: public Stream{ private: @@ -40,11 +41,13 @@ class GwSerialStream: public Stream{ -GwSerial::GwSerial(GwLog *logger, GwSerial::SerialWrapperBase *s, bool allowRead):serial(s) +GwSerial::GwSerial(GwLog *logger, Stream * stream,int id,int type,bool allowRead) { LOG_DEBUG(GwLog::DEBUG,"creating GwSerial %p id %d",this,id); - this->id=s->getId(); this->logger = logger; + this->id=id; + this->stream=stream; + this->type=type; String bufName="Ser("; bufName+=String(id); bufName+=")"; @@ -62,6 +65,20 @@ GwSerial::~GwSerial() if (readBuffer) delete readBuffer; } +String GwSerial::getMode(){ + switch (type){ + case GWSERIAL_TYPE_UNI: + return "UNI"; + case GWSERIAL_TYPE_BI: + return "BI"; + case GWSERIAL_TYPE_RX: + return "RX"; + case GWSERIAL_TYPE_TX: + return "TX"; + } + return "UNKNOWN"; +} + bool GwSerial::isInitialized() { return initialized; } size_t GwSerial::enqueue(const uint8_t *data, size_t len, bool partial) { @@ -70,9 +87,9 @@ size_t GwSerial::enqueue(const uint8_t *data, size_t len, bool partial) } GwBuffer::WriteStatus GwSerial::write(){ if (! isInitialized()) return GwBuffer::ERROR; - size_t numWrite=serial->availableForWrite(); + size_t numWrite=availableForWrite(); size_t rt=buffer->fetchData(numWrite,[](uint8_t *buffer,size_t len, void *p){ - return ((GwSerial *)p)->serial->write(buffer,len); + return ((GwSerial *)p)->stream->write(buffer,len); },this); if (rt != 0){ LOG_DEBUG(GwLog::DEBUG+1,"Serial %d write %d",id,rt); @@ -93,11 +110,11 @@ void GwSerial::loop(bool handleRead,bool handleWrite){ write(); if (! isInitialized()) return; if (! handleRead) return; - size_t available=serial->available(); + size_t available=stream->available(); if (! available) return; if (allowRead){ size_t rd=readBuffer->fillData(available,[](uint8_t *buffer, size_t len, void *p)->size_t{ - return ((GwSerial *)p)->serial->readBytes(buffer,len); + return ((GwSerial *)p)->stream->readBytes(buffer,len); },this); if (rd != 0){ LOG_DEBUG(GwLog::DEBUG+2,"GwSerial %d read %d bytes",id,rd); @@ -106,7 +123,7 @@ void GwSerial::loop(bool handleRead,bool handleWrite){ else{ uint8_t buffer[10]; if (available > 10) available=10; - serial->readBytes(buffer,available); + stream->readBytes(buffer,available); } } void GwSerial::readMessages(GwMessageFetcher *writer){ @@ -115,10 +132,11 @@ void GwSerial::readMessages(GwMessageFetcher *writer){ writer->handleBuffer(readBuffer); } -bool GwSerial::flush(long max){ +bool GwSerial::flush(){ if (! isInitialized()) return false; + long max=getFlushTimeout(); if (! availableWrite) { - if ( serial->availableForWrite() < 1){ + if ( availableForWrite() < 1){ return false; } availableWrite=true; @@ -128,7 +146,7 @@ bool GwSerial::flush(long max){ if (write() != GwBuffer::AGAIN) return true; vTaskDelay(1); } - availableWrite=(serial->availableForWrite() > 0); + availableWrite=(availableForWrite() > 0); return false; } Stream * GwSerial::getStream(bool partialWrite){ diff --git a/lib/serial/GwSerial.h b/lib/serial/GwSerial.h index f50149e..8e37974 100644 --- a/lib/serial/GwSerial.h +++ b/lib/serial/GwSerial.h @@ -6,10 +6,11 @@ #include "GwChannelInterface.h" class GwSerialStream; class GwSerial : public GwChannelInterface{ - private: + protected: GwBuffer *buffer; GwBuffer *readBuffer=NULL; GwLog *logger; + Stream *stream; bool initialized=false; bool allowRead=true; GwBuffer::WriteStatus write(); @@ -17,36 +18,66 @@ class GwSerial : public GwChannelInterface{ int overflows=0; size_t enqueue(const uint8_t *data, size_t len,bool partial=false); bool availableWrite=false; //if this is false we will wait for availabkleWrite until we flush again + virtual long getFlushTimeout(){return 2000;} + virtual int availableForWrite()=0; + int type=0; public: - class SerialWrapperBase{ - public: - virtual void begin(GwLog* logger,unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1)=0; - virtual int getId()=0; - virtual int available(){return getStream()->available();} - size_t readBytes(uint8_t *buffer, size_t length){ - return getStream()->readBytes(buffer,length); - } - virtual int availableForWrite(void){ - return getStream()->availableForWrite(); - } - size_t write(const uint8_t *buffer, size_t size){ - return getStream()->write(buffer,size); - } - private: - virtual Stream *getStream()=0; - }; - static const int bufferSize=200; - GwSerial(GwLog *logger,SerialWrapperBase *stream,bool allowRead=true); - ~GwSerial(); + GwSerial(GwLog *logger,Stream *stream,int id,int type,bool allowRead=true); + virtual ~GwSerial(); bool isInitialized(); 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); - bool flush(long millis=200); + bool flush(); virtual Stream *getStream(bool partialWrites); bool getAvailableWrite(){return availableWrite;} + virtual void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1)=0; + virtual String getMode() override; friend GwSerialStream; - private: - SerialWrapperBase *serial; }; + +template + class GwSerialImpl : public GwSerial{ + private: + template + void beginImpl(C *s,unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1){} + void beginImpl(HardwareSerial *s,unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1){ + s->begin(baud,config,rxPin,txPin); + } + template + void setError(C* s, GwLog *logger){} + void setError(HardwareSerial *s,GwLog *logger){ + LOG_DEBUG(GwLog::LOG,"enable serial errors for channel %d",id); + s->onReceiveError([logger,this](hardwareSerial_error_t err){ + LOG_DEBUG(GwLog::ERROR,"serial error on id %d: %d",this->id,(int)err); + }); + } + #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 + void beginImpl(HWCDC *s,unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1){ + s->begin(baud); + } + #endif + template + long getFlushTimeoutImpl(const C*){return 2000;} + long getFlushTimeoutImpl(HWCDC *){return 200;} + + T *serial; + protected: + virtual long getFlushTimeout() override{ + return getFlushTimeoutImpl(serial); + } + virtual int availableForWrite(){ + return serial->availableForWrite(); + } + public: + GwSerialImpl(GwLog* logger,T* s,int i,int type,bool allowRead=true): GwSerial(logger,s,i,type,allowRead),serial(s){} + virtual ~GwSerialImpl(){} + virtual void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1) override{ + beginImpl(serial,baud,config,rxPin,txPin); + setError(serial,logger); + }; + + }; + + #endif \ No newline at end of file