diff --git a/lib/boatData/GwBoatData.cpp b/lib/boatData/GwBoatData.cpp index fba0bee..47cffbf 100644 --- a/lib/boatData/GwBoatData.cpp +++ b/lib/boatData/GwBoatData.cpp @@ -1,7 +1,7 @@ #include "GwBoatData.h" GwBoatData::GwBoatData(GwLog *logger){ - + this->logger=logger; } GwBoatData::~GwBoatData(){ GwBoatItemBase::GwBoatItemMap::iterator it; diff --git a/lib/boatData/GwBoatData.h b/lib/boatData/GwBoatData.h index 8eaf3c3..7ff64ac 100644 --- a/lib/boatData/GwBoatData.h +++ b/lib/boatData/GwBoatData.h @@ -63,13 +63,14 @@ template class GwBoatItem : public GwBoatItemBase{ (*doc)[name]=getData(true); } private: - static GwBoatItem *findOrCreate(GwBoatItemMap *values, String name,bool doCreate=true, + static GwBoatItem *findOrCreate(GwLog *logger,GwBoatItemMap *values, String name,bool doCreate=true, long invalidTime=GwBoatItemBase::INVALID_TIME, Formatter fmt=NULL){ GwBoatItemMap::iterator it; if ((it=values->find(name)) != values->end()){ return (GwBoatItem *)it->second; } if (! doCreate) return NULL; + LOG_DEBUG(GwLog::DEBUG,"creating boat data item %s",name.c_str()); GwBoatItem *ni=new GwBoatItem(invalidTime,fmt); (*values)[name]=ni; return ni; @@ -83,7 +84,7 @@ template class GwBoatItem : public GwBoatItemBase{ * */ #define GWBOATDATA_IMPL_ITEM(type,name) GwBoatItem *get##name##Item(String iname,bool doCreate=true, \ long invalidTime=GwBoatItemBase::INVALID_TIME, GwBoatItem::Formatter fmt=NULL){ \ - return GwBoatItem::findOrCreate(&values,iname, doCreate, \ + return GwBoatItem::findOrCreate(logger,&values,iname, doCreate, \ invalidTime,fmt);\ } diff --git a/lib/log/GwLog.h b/lib/log/GwLog.h index 5a24858..1433aa0 100644 --- a/lib/log/GwLog.h +++ b/lib/log/GwLog.h @@ -24,6 +24,6 @@ class GwLog{ void logDebug(int level, const char *fmt,...); int isActive(int level){return level <= logLevel;}; }; -#define LOG_DEBUG(level,...){ if (logger->isActive(level)) logger->logDebug(level,__VA_ARGS__);} +#define LOG_DEBUG(level,...){ if (logger != NULL && logger->isActive(level)) logger->logDebug(level,__VA_ARGS__);} #endif \ No newline at end of file diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp index 039184e..20232fe 100644 --- a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp +++ b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp @@ -52,6 +52,7 @@ void N2kDataToNMEA0183::SendMessage(const tNMEA0183Msg &NMEA0183Msg) { N2kDataToNMEA0183* N2kDataToNMEA0183::create(GwLog *logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, tNMEA0183 *NMEA0183, int sourceId){ + LOG_DEBUG(GwLog::LOG,"creating N2kToNMEA0183"); return new N2kToNMEA0183Functions(logger,boatData,NMEA2000,NMEA0183, sourceId); } //***************************************************************************** diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.h b/lib/nmea2kto0183/N2kDataToNMEA0183.h index 8207ae5..32727e7 100644 --- a/lib/nmea2kto0183/N2kDataToNMEA0183.h +++ b/lib/nmea2kto0183/N2kDataToNMEA0183.h @@ -53,7 +53,7 @@ public: } virtual void loop(); virtual ~N2kDataToNMEA0183(){} - virtual const unsigned long* handledPgns()=0; + virtual unsigned long* handledPgns()=0; virtual int numPgns()=0; virtual void toJson(JsonDocument &json)=0; }; diff --git a/lib/nmea2kto0183/N2kToNMEA0183Functions.h b/lib/nmea2kto0183/N2kToNMEA0183Functions.h index 3e36991..cf509d8 100644 --- a/lib/nmea2kto0183/N2kToNMEA0183Functions.h +++ b/lib/nmea2kto0183/N2kToNMEA0183Functions.h @@ -112,7 +112,7 @@ private: ConverterEntry e(converter); converters[pgn] = e; } - virtual const unsigned long *handledPgns() + virtual unsigned long *handledPgns() { logger->logString("CONV: # %d handled PGNS", (int)converters.size()); unsigned long *rt = new unsigned long[converters.size() + 1]; @@ -145,6 +145,7 @@ private: { json["cnv"][String(it->first)] = it->second.count; } + json["aisTargets"]=numShips(); } virtual int numPgns() { @@ -897,11 +898,14 @@ public: registerConverter(128275UL, &N2kToNMEA0183Functions::HandleLog); registerConverter(127245UL, &N2kToNMEA0183Functions::HandleRudder); registerConverter(130310UL, &N2kToNMEA0183Functions::HandleWaterTemp); +#define HANDLE_AIS 1 +#ifdef HANDLE_AIS registerConverter(129038UL, &N2kToNMEA0183Functions::HandleAISClassAPosReport); // AIS Class A Position Report, Message Type 1 registerConverter(129039UL, &N2kToNMEA0183Functions::HandleAISClassBMessage18); // AIS Class B Position Report, Message Type 18 registerConverter(129794UL, &N2kToNMEA0183Functions::HandleAISClassAMessage5); // AIS Class A Ship Static and Voyage related data, Message Type 5 registerConverter(129809UL, &N2kToNMEA0183Functions::HandleAISClassBMessage24A); // AIS Class B "CS" Static Data Report, Part A registerConverter(129810UL, &N2kToNMEA0183Functions::HandleAISClassBMessage24B); // AIS Class B "CS" Static Data Report, Part B +#endif } virtual void loop() diff --git a/lib/nmea2ktoais/NMEA0183AISMessages.cpp b/lib/nmea2ktoais/NMEA0183AISMessages.cpp index a7b4ed7..aa2c45b 100644 --- a/lib/nmea2ktoais/NMEA0183AISMessages.cpp +++ b/lib/nmea2ktoais/NMEA0183AISMessages.cpp @@ -51,6 +51,7 @@ const char Prefix='!'; std::vector vships; +int numShips(){return vships.size();} // ************************ Helper for AIS *********************************** static bool AddMessageType(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType); static bool AddRepeat(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Repeat); @@ -250,7 +251,9 @@ bool SetAISClassBMessage24(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, } } if ( i > MAX_SHIP_IN_VECTOR ) { - vships.erase(vships.begin()); + std::vector::iterator it=vships.begin(); + delete *it; + vships.erase(it); } // AIS Type 24 Message diff --git a/lib/nmea2ktoais/NMEA0183AISMessages.h b/lib/nmea2ktoais/NMEA0183AISMessages.h index 0c32ac8..e7910cb 100644 --- a/lib/nmea2ktoais/NMEA0183AISMessages.h +++ b/lib/nmea2ktoais/NMEA0183AISMessages.h @@ -36,7 +36,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include -#define MAX_SHIP_IN_VECTOR 200 +#define MAX_SHIP_IN_VECTOR 5 class ship { public: uint32_t _userID; @@ -45,7 +45,6 @@ public: ship(uint32_t UserID, std::string ShipName) : _userID(UserID), _shipName(ShipName) {} }; -extern std::vector vships; // Types 1, 2 and 3: Position Report Class A or B bool SetAISClassABMessage1(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType, uint8_t Repeat, @@ -78,6 +77,7 @@ bool SetAISClassBMessage24(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint32_t UserID, uint8_t VesselType, char *VendorID, char *Callsign, double Length, double Beam, double PosRefStbd, double PosRefBow, uint32_t MothershipID ); +int numShips(); inline int32_t aRoundToInt(double x) { return x >= 0 ? (int32_t) floor(x + 0.5) diff --git a/lib/queue/GwBuffer.cpp b/lib/queue/GwBuffer.cpp index fc2e83e..d60a3ee 100644 --- a/lib/queue/GwBuffer.cpp +++ b/lib/queue/GwBuffer.cpp @@ -8,6 +8,7 @@ void GwBuffer::lp(const char *fkt, int p) GwBuffer::GwBuffer(GwLog *logger,size_t bufferSize) { + LOG_DEBUG(GwLog::DEBUG,"creating new buffer %p of size %d",this,(int)bufferSize); this->logger = logger; this->bufferSize=bufferSize; this->buffer=new uint8_t[bufferSize]; diff --git a/lib/serial/GwSerial.cpp b/lib/serial/GwSerial.cpp index e6c5c1f..ca9444e 100644 --- a/lib/serial/GwSerial.cpp +++ b/lib/serial/GwSerial.cpp @@ -15,6 +15,7 @@ class SerialWriter : public GwBufferWriter{ }; GwSerial::GwSerial(GwLog *logger, uart_port_t num, int id,bool allowRead) { + LOG_DEBUG(GwLog::DEBUG,"creating GwSerial %p port %d",this,(int)num); this->id=id; this->logger = logger; this->num = num; @@ -79,6 +80,7 @@ void GwSerial::sendToClients(const char *buf,int sourceId){ } void GwSerial::loop(bool handleRead){ write(); + if (! isInitialized()) return; if (! handleRead) return; char buffer[10]; int rt=uart_read_bytes(num,(uint8_t *)(&buffer),10,0); @@ -87,6 +89,7 @@ void GwSerial::loop(bool handleRead){ } } bool GwSerial::readMessages(GwBufferWriter *writer){ + if (! isInitialized()) return false; if (! allowRead) return false; return readBuffer->fetchMessage(writer,'\n',true) == GwBuffer::OK; } \ No newline at end of file diff --git a/lib/socketserver/GwSocketServer.cpp b/lib/socketserver/GwSocketServer.cpp index 024d041..9231ec3 100644 --- a/lib/socketserver/GwSocketServer.cpp +++ b/lib/socketserver/GwSocketServer.cpp @@ -68,6 +68,7 @@ class GwClient{ overflows=0; if (client != NULL){ writer=new Writer(client); + LOG_DEBUG(GwLog::DEBUG,"creating SocketWriter %p",writer); remoteIp=client->remoteIP().toString(); } } @@ -76,10 +77,14 @@ class GwClient{ buffer->reset(); if (readBuffer) readBuffer->reset(); overflows=0; - if (writer) delete writer; + if (writer) { + LOG_DEBUG(GwLog::DEBUG,"deleting SocketWriter %p",writer); + delete writer; + } writer=NULL; if (client){ writer=new Writer(client); + LOG_DEBUG(GwLog::DEBUG,"creating SocketWriter %p",writer); remoteIp=client->remoteIP().toString(); } else{ @@ -162,12 +167,12 @@ GwSocketServer::GwSocketServer(const GwConfigHandler *config,GwLog *logger,int m this->minId=minId; maxClients=config->getInt(config->maxClients); allowReceive=config->getBool(config->readTCP); +} +void GwSocketServer::begin(){ clients=new gwClientPtr[maxClients]; for (int i=0;igetInt(config->serverPort),maxClients); server->begin(); logger->logString("Socket server created, port=%d", @@ -177,6 +182,7 @@ void GwSocketServer::begin(){ } void GwSocketServer::loop(bool handleRead) { + if (! clients) return; WiFiClient client = server->available(); // listen for incoming clients if (client) @@ -234,7 +240,7 @@ void GwSocketServer::loop(bool handleRead) } bool GwSocketServer::readMessages(GwBufferWriter *writer){ - if (! allowReceive) return false; + if (! allowReceive || ! clients) return false; bool hasMessages=false; for (int i = 0; i < maxClients; i++){ writer->id=minId+i; @@ -244,6 +250,7 @@ bool GwSocketServer::readMessages(GwBufferWriter *writer){ return hasMessages; } void GwSocketServer::sendToClients(const char *buf,int source){ + if (! clients) return; int len=strlen(buf); int sourceIndex=source-minId; for (int i = 0; i < maxClients; i++) @@ -262,6 +269,7 @@ void GwSocketServer::sendToClients(const char *buf,int source){ } int GwSocketServer::numClients(){ + if (! clients) return 0; int num=0; for (int i = 0; i < maxClients; i++){ if (clients[i]->hasClient()) num++; diff --git a/lib/socketserver/GwSocketServer.h b/lib/socketserver/GwSocketServer.h index 38bc001..61166c1 100644 --- a/lib/socketserver/GwSocketServer.h +++ b/lib/socketserver/GwSocketServer.h @@ -13,7 +13,7 @@ class GwSocketServer{ private: const GwConfigHandler *config; GwLog *logger; - gwClientPtr *clients; + gwClientPtr *clients=NULL; WiFiServer *server=NULL; bool allowReceive; int maxClients; diff --git a/platformio.ini b/platformio.ini index e1f3321..9a53355 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,7 +20,7 @@ lib_deps = board_build.embed_files = generated/index.html.gz generated/config.json.gz -extra_scripts = extra_script.py +extra_scripts = pre:extra_script.py build_flags= -Igenerated diff --git a/src/main.cpp b/src/main.cpp index 5861af5..a209c6c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,7 @@ #include #include #include +#include "esp_heap_caps.h" #include "N2kDataToNMEA0183.h" @@ -65,7 +66,7 @@ Preferences preferences; // Nonvolatile storage on ESP32 - To store bool SendNMEA0183Conversion = true; // Do we send NMEA2000 -> NMEA0183 conversion bool SendSeaSmart = false; // Do we send NMEA2000 messages in SeaSmart format -N2kDataToNMEA0183 *nmea0183Converter=N2kDataToNMEA0183::create(&logger, &boatData,&NMEA2000, 0, N2K_CHANNEL_ID); +N2kDataToNMEA0183 *nmea0183Converter=NULL; // Set the information for other bus devices, which messages we support const unsigned long TransmitMessages[] PROGMEM = {127489L, // Engine dynamic @@ -193,7 +194,7 @@ GwConfigInterface *sendTCP=NULL; GwConfigInterface *sendSeasmart=NULL; GwConfigInterface *systemName=NULL; -GwSerial usbSerial(&logger, UART_NUM_0, USB_CHANNEL_ID); +GwSerial usbSerial(NULL, UART_NUM_0, USB_CHANNEL_ID); class GwSerialLog : public GwLogWriter{ public: virtual ~GwSerialLog(){} @@ -357,6 +358,7 @@ void setup() { MDNS.addService("_http","_tcp",80); + nmea0183Converter= N2kDataToNMEA0183::create(&logger, &boatData,&NMEA2000, 0, N2K_CHANNEL_ID); // Reserve enough buffer for sending all messages. This does not work on small memory devices like Uno or Mega NMEA2000.SetN2kCANMsgBufSize(8); @@ -493,9 +495,21 @@ class NMEAMessageReceiver : public GwBufferWriter{ writePointer=buffer; } }; +NMEAMessageReceiver receiver; +unsigned long lastHeapReport=0; +const unsigned long HEAP_REPORT_TIME=2000; void loop() { gwWifi.loop(); - + unsigned long now=millis(); + if (now > (lastHeapReport+HEAP_REPORT_TIME)){ + lastHeapReport=now; + if (logger.isActive(GwLog::DEBUG)){ + logger.logDebug(GwLog::DEBUG,"Heap free=%ld, minFree=%ld", + (long)xPortGetFreeHeapSize(), + (long)xPortGetMinimumEverFreeHeapSize() + ); + } + } handleSendAndRead(true); NMEA2000.ParseMessages(); @@ -512,11 +526,10 @@ void loop() { //handle messages from the async web server Message *msg=NULL; if (xQueueReceive(queue,&msg,0)){ - logger.logDebug(GwLog::DEBUG+1,"main message"); + logger.logDebug(GwLog::DEBUG,"main message"); msg->process(); msg->unref(); } - NMEAMessageReceiver receiver; socketServer.readMessages(&receiver); //read channels