add some memory diagnostics

This commit is contained in:
andreas 2021-10-30 12:01:50 +02:00
parent 56aaf595b4
commit e7b2c6e756
14 changed files with 54 additions and 20 deletions

View File

@ -1,7 +1,7 @@
#include "GwBoatData.h"
GwBoatData::GwBoatData(GwLog *logger){
this->logger=logger;
}
GwBoatData::~GwBoatData(){
GwBoatItemBase::GwBoatItemMap::iterator it;

View File

@ -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);\
}

View File

@ -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

View File

@ -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);
}
//*****************************************************************************

View File

@ -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;
};

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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];

View File

@ -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;
}

View File

@ -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++;

View File

@ -13,7 +13,7 @@ class GwSocketServer{
private:
const GwConfigHandler *config;
GwLog *logger;
gwClientPtr *clients;
gwClientPtr *clients=NULL;
WiFiServer *server=NULL;
bool allowReceive;
int maxClients;

View File

@ -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

View File

@ -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