diff --git a/lib/channel/GwChannel.cpp b/lib/channel/GwChannel.cpp index 1b09859..93a2da3 100644 --- a/lib/channel/GwChannel.cpp +++ b/lib/channel/GwChannel.cpp @@ -173,7 +173,7 @@ void GwChannel::toJson(GwJsonDocument &doc){ if (countIn) countIn->toJson(doc); } String GwChannel::toString(){ - String rt="CH:"+name; + String rt="CH"+name+"("+sourceId+"):"; rt+=enabled?"[ena]":"[dis]"; rt+=NMEAin?"in,":""; rt+=NMEAout?"out,":""; diff --git a/lib/channel/GwChannelList.cpp b/lib/channel/GwChannelList.cpp index bf7817a..fed0332 100644 --- a/lib/channel/GwChannelList.cpp +++ b/lib/channel/GwChannelList.cpp @@ -35,12 +35,13 @@ class GwSerialLog : public GwLogWriter int wp = 0; GwSerial *writer; bool disabled = false; - + long flushTimeout=200; public: - GwSerialLog(GwSerial *writer, bool disabled) + GwSerialLog(GwSerial *writer, bool disabled,long flushTimeout=200) { this->writer = writer; this->disabled = disabled; + this->flushTimeout=flushTimeout; logBuffer = new char[bufferSize]; wp = 0; } @@ -63,16 +64,63 @@ public: { while (handled < wp) { - writer->flush(); + if ( !writer->flush(flushTimeout)) break; size_t rt = writer->sendToClients(logBuffer + handled, -1, true); handled += rt; } + if (handled < wp){ + if (handled > 0){ + memmove(logBuffer,logBuffer+handled,wp-handled); + wp-=handled; + logBuffer[handled]=0; + } + return; + } } wp = 0; logBuffer[0] = 0; } }; +template + class SerialWrapper : public GwChannelList::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; this->config=config; @@ -127,16 +175,16 @@ static SerialParam *getSerialParam(int id){ } void GwChannelList::addSerial(int id, int rx, int tx, int type){ if (id == 1){ - addSerial(&Serial1,SERIAL1_CHANNEL_ID,type,rx,tx); + addSerial(new SerialWrapper(&Serial1,SERIAL1_CHANNEL_ID),type,rx,tx); return; } if (id == 2){ - addSerial(&Serial2,SERIAL2_CHANNEL_ID,type,rx,tx); + 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(HardwareSerial *stream,int id,int type,int rx,int tx){ +void GwChannelList::addSerial(GwChannelList::SerialWrapperBase *stream,int type,int rx,int tx){ const char *mode=nullptr; switch (type) { @@ -157,9 +205,10 @@ void GwChannelList::addSerial(HardwareSerial *stream,int id,int type,int rx,int LOG_DEBUG(GwLog::ERROR,"unknown serial type %d",type); return; } - addSerial(stream,id,mode,rx,tx); + addSerial(stream,mode,rx,tx); } -void GwChannelList::addSerial(HardwareSerial *serialStream,int id,const String &mode,int rx,int tx){ +void GwChannelList::addSerial(GwChannelList::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); @@ -201,8 +250,8 @@ void GwChannelList::addSerial(HardwareSerial *serialStream,int id,const String & 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(config->getInt(param->baud,115200),SERIAL_8N1,rx,tx); - GwSerial *serial = new GwSerial(logger, serialStream, id, canRead); + serialStream->begin(logger,config->getInt(param->baud,115200),SERIAL_8N1,rx,tx); + GwSerial *serial = new GwSerial(logger, serialStream->getStream(), id, canRead); LOG_DEBUG(GwLog::LOG, "starting serial %d ", id); GwChannel *channel = new GwChannel(logger, param->name, id); channel->setImpl(serial); @@ -241,6 +290,14 @@ void GwChannelList::preinit(){ } } } +template +long getFlushTimeout(S &s){ + return 200; +} +template<> +long getFlushTimeout(HardwareSerial &s){ + return 2000; +} void GwChannelList::begin(bool fallbackSerial){ LOG_DEBUG(GwLog::DEBUG,"GwChannelList::begin"); GwChannel *channel=NULL; @@ -248,7 +305,7 @@ void GwChannelList::begin(bool fallbackSerial){ if (! fallbackSerial){ GwSerial *usb=new GwSerial(NULL,&USBSerial,USB_CHANNEL_ID); USBSerial.begin(config->getInt(config->usbBaud)); - logger->setWriter(new GwSerialLog(usb,config->getBool(config->usbActisense))); + 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); @@ -297,10 +354,12 @@ void GwChannelList::begin(bool fallbackSerial){ #define GWSERIAL_RX -1 #endif #ifdef GWSERIAL_TYPE - addSerial(&Serial1,SERIAL1_CHANNEL_ID,GWSERIAL_TYPE,GWSERIAL_RX,GWSERIAL_TX); + setSerialError(&Serial1,SERIAL1_CHANNEL_ID,this->logger); + addSerial(new SerialWrapper(&Serial1,SERIAL1_CHANNEL_ID),GWSERIAL_TYPE,GWSERIAL_RX,GWSERIAL_TX); #else #ifdef GWSERIAL_MODE - addSerial(&Serial1,SERIAL1_CHANNEL_ID,GWSERIAL_MODE,GWSERIAL_RX,GWSERIAL_TX); + setSerialError(&Serial1,SERIAL1_CHANNEL_ID,this->logger); + addSerial(new SerialWrapper(&Serial1,SERIAL1_CHANNEL_ID),GWSERIAL_MODE,GWSERIAL_RX,GWSERIAL_TX); #endif #endif //serial 2 @@ -311,10 +370,10 @@ void GwChannelList::begin(bool fallbackSerial){ #define GWSERIAL2_RX -1 #endif #ifdef GWSERIAL2_TYPE - addSerial(&Serial2,SERIAL2_CHANNEL_ID,GWSERIAL2_TYPE,GWSERIAL2_RX,GWSERIAL2_TX); + addSerial(new SerialWrapper(&Serial2,SERIAL2_CHANNEL_ID),GWSERIAL2_TYPE,GWSERIAL2_RX,GWSERIAL2_TX); #else #ifdef GWSERIAL2_MODE - addSerial(&Serial2,SERIAL2_CHANNEL_ID,GWSERIAL2_MODE,GWSERIAL2_RX,GWSERIAL2_TX); + addSerial(new SerialWrapper(&Serial2,SERIAL2_CHANNEL_ID),GWSERIAL2_MODE,GWSERIAL2_RX,GWSERIAL2_TX); #endif #endif //tcp client diff --git a/lib/channel/GwChannelList.h b/lib/channel/GwChannelList.h index ed11e06..373dc6a 100644 --- a/lib/channel/GwChannelList.h +++ b/lib/channel/GwChannelList.h @@ -23,6 +23,12 @@ class GwSocketServer; class GwTcpClient; class GwChannelList{ private: + 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 Stream *getStream()=0; + virtual int getId()=0; + }; GwLog *logger; GwConfigHandler *config; typedef std::vector ChannelList; @@ -30,8 +36,8 @@ class GwChannelList{ std::map modes; GwSocketServer *sockets; GwTcpClient *client; - void addSerial(HardwareSerial *stream,int id,const String &mode,int rx,int tx); - void addSerial(HardwareSerial *stream,int id,int type,int rx,int tx); + void addSerial(SerialWrapperBase *stream,const String &mode,int rx,int tx); + void addSerial(SerialWrapperBase *stream,int type,int rx,int tx); public: void addSerial(int id, int rx, int tx, int type); GwChannelList(GwLog *logger, GwConfigHandler *config); diff --git a/lib/serial/GwSerial.cpp b/lib/serial/GwSerial.cpp index 640d340..c810e58 100644 --- a/lib/serial/GwSerial.cpp +++ b/lib/serial/GwSerial.cpp @@ -40,7 +40,7 @@ class GwSerialStream: public Stream{ -GwSerial::GwSerial(GwLog *logger, HardwareSerial *s, int id,bool allowRead):serial(s) +GwSerial::GwSerial(GwLog *logger, Stream *s, int id,bool allowRead):serial(s) { LOG_DEBUG(GwLog::DEBUG,"creating GwSerial %p id %d",this,id); this->id=id; @@ -54,10 +54,6 @@ GwSerial::GwSerial(GwLog *logger, HardwareSerial *s, int id,bool allowRead):seri this->readBuffer=new GwBuffer(logger, GwBuffer::RX_BUFFER_SIZE,bufName+"rd"); } buffer->reset("init"); - serial->onReceiveError([this](hardwareSerial_error_t err){ - GwLog *logger=this->logger; - LOG_DEBUG(GwLog::ERROR,"serial error on id %d: %d",this->id,(int)err); - }); initialized=true; } GwSerial::~GwSerial() @@ -119,11 +115,21 @@ void GwSerial::readMessages(GwMessageFetcher *writer){ writer->handleBuffer(readBuffer); } -void GwSerial::flush(){ - if (! isInitialized()) return; - while (write() == GwBuffer::AGAIN){ - vTaskDelay(1); +bool GwSerial::flush(long max){ + if (! isInitialized()) return false; + if (! availableWrite) { + if ( serial->availableForWrite() < 1){ + return false; + } + availableWrite=true; } + auto start=millis(); + while (millis() < (start+max)){ + if (write() != GwBuffer::AGAIN) return true; + vTaskDelay(1); + } + availableWrite=(serial->availableForWrite() > 0); + return false; } Stream * GwSerial::getStream(bool partialWrite){ return new GwSerialStream(this,partialWrite); diff --git a/lib/serial/GwSerial.h b/lib/serial/GwSerial.h index 1cf1920..5298bc6 100644 --- a/lib/serial/GwSerial.h +++ b/lib/serial/GwSerial.h @@ -16,17 +16,19 @@ class GwSerial : public GwChannelInterface{ int id=-1; int overflows=0; size_t enqueue(const uint8_t *data, size_t len,bool partial=false); - HardwareSerial *serial; + Stream *serial; + bool availableWrite=false; //if this is false we will wait for availabkleWrite until we flush again public: static const int bufferSize=200; - GwSerial(GwLog *logger,HardwareSerial *stream,int id,bool allowRead=true); + GwSerial(GwLog *logger,Stream *stream,int id,bool allowRead=true); ~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); - void flush(); + bool flush(long millis=200); virtual Stream *getStream(bool partialWrites); + bool getAvailableWrite(){return availableWrite;} friend GwSerialStream; }; #endif \ No newline at end of file