add some memory diagnostics
This commit is contained in:
		
							parent
							
								
									56aaf595b4
								
							
						
					
					
						commit
						e7b2c6e756
					
				|  | @ -1,7 +1,7 @@ | |||
| #include "GwBoatData.h" | ||||
| 
 | ||||
| GwBoatData::GwBoatData(GwLog *logger){ | ||||
|      | ||||
|     this->logger=logger; | ||||
| } | ||||
| GwBoatData::~GwBoatData(){ | ||||
|     GwBoatItemBase::GwBoatItemMap::iterator it; | ||||
|  |  | |||
|  | @ -63,13 +63,14 @@ template<class T> class GwBoatItem : public GwBoatItemBase{ | |||
|             (*doc)[name]=getData(true); | ||||
|         } | ||||
|         private: | ||||
|         static GwBoatItem<T> *findOrCreate(GwBoatItemMap *values, String name,bool doCreate=true,  | ||||
|         static GwBoatItem<T> *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<T> *)it->second; | ||||
|             } | ||||
|             if (! doCreate) return NULL; | ||||
|             LOG_DEBUG(GwLog::DEBUG,"creating boat data item %s",name.c_str()); | ||||
|             GwBoatItem<T> *ni=new GwBoatItem<T>(invalidTime,fmt); | ||||
|             (*values)[name]=ni; | ||||
|             return ni;  | ||||
|  | @ -83,7 +84,7 @@ template<class T> class GwBoatItem : public GwBoatItemBase{ | |||
|  * */ | ||||
| #define GWBOATDATA_IMPL_ITEM(type,name) GwBoatItem<type> *get##name##Item(String iname,bool doCreate=true, \ | ||||
|                 long invalidTime=GwBoatItemBase::INVALID_TIME, GwBoatItem<type>::Formatter fmt=NULL){ \ | ||||
|                 return GwBoatItem<type>::findOrCreate(&values,iname, doCreate, \ | ||||
|                 return GwBoatItem<type>::findOrCreate(logger,&values,iname, doCreate, \ | ||||
|                 invalidTime,fmt);\ | ||||
|             } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  | @ -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); | ||||
| } | ||||
| //*****************************************************************************
 | ||||
|  |  | |||
|  | @ -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; | ||||
| }; | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -51,6 +51,7 @@ const char Prefix='!'; | |||
| 
 | ||||
| std::vector<ship *> 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<ship *>::iterator it=vships.begin(); | ||||
|     delete *it; | ||||
|     vships.erase(it); | ||||
|   } | ||||
| 
 | ||||
|   // AIS Type 24 Message
 | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
| #include <vector> | ||||
| #include <string> | ||||
| 
 | ||||
| #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<ship *> 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) | ||||
|  |  | |||
|  | @ -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]; | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
|  | @ -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;i<maxClients;i++){ | ||||
|         clients[i]=gwClientPtr(new GwClient(wiFiClientPtr(NULL),logger,allowReceive)); | ||||
|     } | ||||
| } | ||||
| void GwSocketServer::begin(){ | ||||
|     server=new WiFiServer(config->getInt(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++; | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ class GwSocketServer{ | |||
|     private: | ||||
|         const GwConfigHandler *config; | ||||
|         GwLog *logger; | ||||
|         gwClientPtr *clients; | ||||
|         gwClientPtr *clients=NULL; | ||||
|         WiFiServer *server=NULL; | ||||
|         bool allowReceive; | ||||
|         int maxClients; | ||||
|  |  | |||
|  | @ -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 | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										23
									
								
								src/main.cpp
								
								
								
								
							
							
						
						
									
										23
									
								
								src/main.cpp
								
								
								
								
							|  | @ -25,6 +25,7 @@ | |||
| #include <ArduinoJson.h> | ||||
| #include <ESPmDNS.h> | ||||
| #include <map> | ||||
| #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
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 andreas
						andreas