add NMEA and NSk counter
This commit is contained in:
parent
2425006d7c
commit
3c4920d104
|
@ -0,0 +1,61 @@
|
|||
#ifndef _GWCOUNTER_H
|
||||
#define _GWCOUNTER_H
|
||||
#include <map>
|
||||
#include "ArduinoJson.h"
|
||||
template<class T> class GwCounter{
|
||||
private:
|
||||
typedef std::map<T,unsigned long> CounterMap;
|
||||
CounterMap okCounter;
|
||||
CounterMap failCounter;
|
||||
unsigned long globalOk=0;
|
||||
unsigned long globalFail=0;
|
||||
String name;
|
||||
public:
|
||||
GwCounter(String name){
|
||||
this->name=name;
|
||||
};
|
||||
void reset(){
|
||||
okCounter.clear();
|
||||
failCounter.clear();
|
||||
globalFail=0;
|
||||
globalOk=0;
|
||||
}
|
||||
void add(T key){
|
||||
globalOk++;
|
||||
auto it=okCounter.find(key);
|
||||
if (it == okCounter.end()){
|
||||
okCounter[key]=1;
|
||||
}
|
||||
else{
|
||||
it->second++;
|
||||
}
|
||||
}
|
||||
void addFail(T key){
|
||||
globalFail++;
|
||||
auto it=failCounter.find(key);
|
||||
if (it == failCounter.end()){
|
||||
failCounter[key]=1;
|
||||
}
|
||||
else{
|
||||
it->second++;
|
||||
}
|
||||
}
|
||||
int getJsonSize(){
|
||||
return JSON_OBJECT_SIZE(4)+JSON_OBJECT_SIZE(okCounter.size()+1)+
|
||||
JSON_OBJECT_SIZE(failCounter.size()+1);
|
||||
}
|
||||
void toJson(JsonDocument &json){
|
||||
JsonObject jo=json.createNestedObject(name);
|
||||
jo["sumOk"]=globalOk;
|
||||
jo["sumFail"]=globalFail;
|
||||
JsonObject jok=jo.createNestedObject("ok");
|
||||
for (auto it=okCounter.begin();it!=okCounter.end();it++){
|
||||
jok[String(it->first)]=it->second;
|
||||
}
|
||||
JsonObject jfail=jo.createNestedObject("fail");
|
||||
for (auto it=failCounter.begin();it!=failCounter.end();it++){
|
||||
jfail[String(it->first)]=it->second;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
69
src/main.cpp
69
src/main.cpp
|
@ -46,6 +46,7 @@ const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
|
|||
#include "GwApi.h"
|
||||
#include "GwButtons.h"
|
||||
#include "GwLeds.h"
|
||||
#include "GwCounter.h"
|
||||
|
||||
|
||||
//NMEA message channels
|
||||
|
@ -72,10 +73,6 @@ GwSocketServer socketServer(&config,&logger,MIN_TCP_CHANNEL_ID);
|
|||
GwBoatData boatData(&logger);
|
||||
|
||||
|
||||
//counter
|
||||
int numCan=0;
|
||||
|
||||
|
||||
int NodeAddress; // To store last Node Address
|
||||
|
||||
Preferences preferences; // Nonvolatile storage on ESP32 - To store LastDeviceAddress
|
||||
|
@ -88,6 +85,41 @@ void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg,int id);
|
|||
GwRequestQueue mainQueue(&logger,20);
|
||||
GwWebServer webserver(&logger,&mainQueue,80);
|
||||
|
||||
GwCounter<unsigned long> countNMEA2KIn("count2Kin");
|
||||
GwCounter<unsigned long> countNMEA2KOut("count2kout");
|
||||
|
||||
GwCounter<String> countUSBIn("countUSBin");
|
||||
GwCounter<String> countUSBOut("countUSBout");
|
||||
GwCounter<String> countTCPIn("countTCPin");
|
||||
GwCounter<String> countTCPOut("countTCPout");
|
||||
GwCounter<String> countSerialIn("countSerialIn");
|
||||
GwCounter<String> countSerialOut("countSerialOut");
|
||||
|
||||
void updateNMEACounter(int id,const char *msg,bool incoming,bool fail=false){
|
||||
//we rely on the msg being long enough
|
||||
char key[6];
|
||||
if (msg[0] == '$') {
|
||||
strncpy(key,&msg[3],3);
|
||||
key[3]=0;
|
||||
}
|
||||
else if(msg[0] == '!'){
|
||||
strncpy(key,&msg[1],5);
|
||||
key[5]=0;
|
||||
}
|
||||
else return;
|
||||
GwCounter<String> *counter=NULL;
|
||||
if (id == USB_CHANNEL_ID) counter=incoming?&countUSBIn:&countUSBOut;
|
||||
if (id == SERIAL1_CHANNEL_ID) counter=incoming?&countSerialIn:&countSerialOut;
|
||||
if (id >= MIN_TCP_CHANNEL_ID) counter=incoming?&countTCPIn:&countTCPOut;
|
||||
if (! counter) return;
|
||||
if (fail){
|
||||
counter->addFail(key);
|
||||
}
|
||||
else{
|
||||
counter->add(key);
|
||||
}
|
||||
}
|
||||
|
||||
//configs that we need in main
|
||||
|
||||
|
||||
|
@ -211,14 +243,30 @@ protected:
|
|||
virtual void processRequest()
|
||||
{
|
||||
int numPgns = nmea0183Converter->numPgns();
|
||||
DynamicJsonDocument status(256 + numPgns * 50);
|
||||
status["numcan"] = numCan;
|
||||
DynamicJsonDocument status(256 +
|
||||
countNMEA2KIn.getJsonSize()+
|
||||
countNMEA2KOut.getJsonSize() +
|
||||
countUSBIn.getJsonSize()+
|
||||
countUSBOut.getJsonSize()+
|
||||
countSerialIn.getJsonSize()+
|
||||
countSerialOut.getJsonSize()+
|
||||
countTCPIn.getJsonSize()+
|
||||
countTCPOut.getJsonSize()
|
||||
);
|
||||
status["version"] = VERSION;
|
||||
status["wifiConnected"] = gwWifi.clientConnected();
|
||||
status["clientIP"] = WiFi.localIP().toString();
|
||||
status["numClients"] = socketServer.numClients();
|
||||
status["apIp"] = gwWifi.apIP();
|
||||
nmea0183Converter->toJson(status);
|
||||
//nmea0183Converter->toJson(status);
|
||||
countNMEA2KIn.toJson(status);
|
||||
countNMEA2KOut.toJson(status);
|
||||
countUSBIn.toJson(status);
|
||||
countUSBOut.toJson(status);
|
||||
countSerialIn.toJson(status);
|
||||
countSerialOut.toJson(status);
|
||||
countTCPIn.toJson(status);
|
||||
countTCPOut.toJson(status);
|
||||
serializeJson(status, result);
|
||||
}
|
||||
};
|
||||
|
@ -444,6 +492,7 @@ void setup() {
|
|||
|
||||
toN2KConverter= NMEA0183DataToN2K::create(&logger,&boatData,[](const tN2kMsg &msg)->bool{
|
||||
logger.logDebug(GwLog::DEBUG+2,"send N2K %ld",msg.PGN);
|
||||
countNMEA2KOut.add(msg.PGN);
|
||||
NMEA2000.SendMsg(msg);
|
||||
return true;
|
||||
});
|
||||
|
@ -494,7 +543,7 @@ void setup() {
|
|||
NMEA2000.ExtendTransmitMessages(pgns);
|
||||
NMEA2000.ExtendReceiveMessages(nmea0183Converter->handledPgns());
|
||||
NMEA2000.SetMsgHandler([](const tN2kMsg &n2kMsg){
|
||||
numCan++;
|
||||
countNMEA2KIn.add(n2kMsg.PGN);
|
||||
if ( sendSeasmart->asBoolean() ) {
|
||||
char buf[MAX_NMEA2000_MESSAGE_SEASMART_SIZE];
|
||||
if ( N2kToSeasmart(n2kMsg, millis(), buf, MAX_NMEA2000_MESSAGE_SEASMART_SIZE) == 0 ) return;
|
||||
|
@ -519,12 +568,15 @@ void setup() {
|
|||
void sendBufferToChannels(const char * buffer, int sourceId){
|
||||
if (sendTCP->asBoolean() && checkFilter(buffer,MIN_TCP_CHANNEL_ID,false)){
|
||||
socketServer.sendToClients(buffer,sourceId);
|
||||
updateNMEACounter(MIN_TCP_CHANNEL_ID,buffer,false);
|
||||
}
|
||||
if (sendUsb->asBoolean() && checkFilter(buffer,USB_CHANNEL_ID,false)){
|
||||
usbSerial->sendToClients(buffer,sourceId);
|
||||
updateNMEACounter(USB_CHANNEL_ID,buffer,false);
|
||||
}
|
||||
if (serial1 && serCanWrite && checkFilter(buffer,SERIAL1_CHANNEL_ID,false)){
|
||||
serial1->sendToClients(buffer,sourceId);
|
||||
updateNMEACounter(SERIAL1_CHANNEL_ID,buffer,false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,6 +595,7 @@ void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId) {
|
|||
}
|
||||
|
||||
void handleReceivedNmeaMessage(const char *buf, int sourceId){
|
||||
updateNMEACounter(sourceId,buf,true);
|
||||
if (! checkFilter(buf,sourceId,true)) return;
|
||||
if ((sourceId == USB_CHANNEL_ID && n2kFromUSB->asBoolean())||
|
||||
(sourceId >= MIN_TCP_CHANNEL_ID && n2kFromTCP->asBoolean())||
|
||||
|
|
158
web/index.html
158
web/index.html
|
@ -15,6 +15,12 @@
|
|||
if (parent)parent.appendChild(el);
|
||||
return el;
|
||||
}
|
||||
function forEl(query,callback){
|
||||
let all=document.querySelectorAll(query);
|
||||
for (let i=0;i<all.length;i++){
|
||||
callback(all[i]);
|
||||
}
|
||||
}
|
||||
function alertRestart(){
|
||||
reloadConfig=true;
|
||||
alert("Board reset triggered, reconnect WLAN if necessary");
|
||||
|
@ -41,8 +47,18 @@
|
|||
getJson('/api/status')
|
||||
.then(function(jsonData){
|
||||
for (let k in jsonData){
|
||||
if (k == 'cnv'){
|
||||
updateCanDetails(jsonData[k]);
|
||||
if (typeof(jsonData[k]) === 'object'){
|
||||
for (let sk in jsonData[k]){
|
||||
let key=k+"."+sk;
|
||||
if (typeof(jsonData[k][sk]) === 'object'){
|
||||
//msg details
|
||||
updateMsgDetails(key,jsonData[k][sk]);
|
||||
}
|
||||
else{
|
||||
let el=document.getElementById(key);
|
||||
if (el) el.textContent=jsonData[k][sk];
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
let el=document.getElementById(k);
|
||||
|
@ -131,35 +147,23 @@
|
|||
alertRestart();
|
||||
})
|
||||
}
|
||||
function showCanDetails(on){
|
||||
let el=document.getElementById('canDetails');
|
||||
if (!el) return;
|
||||
if (on) el.classList.add('visible');
|
||||
else(el.classList).remove('visible');
|
||||
}
|
||||
function updateCanDetails(details){
|
||||
let frame=document.getElementById('canDetails');
|
||||
if (! frame) return;
|
||||
|
||||
function updateMsgDetails(key, details) {
|
||||
forEl('.msgDetails', function (frame) {
|
||||
if (frame.getAttribute('id') !== key) return;
|
||||
for (let k in details) {
|
||||
let el = frame.querySelector("[data-id=\"" + k + "\"] ");
|
||||
if (!el) {
|
||||
el=document.createElement('div');
|
||||
el.classList.add('row');
|
||||
let cv=document.createElement('span');
|
||||
cv.classList.add('label');
|
||||
cv.textContent="PGN"+k;
|
||||
el.appendChild(cv);
|
||||
cv=document.createElement('span');
|
||||
cv.classList.add('value');
|
||||
el = addEl('div','row',frame);
|
||||
let cv = addEl('span','label',el,k);
|
||||
cv = addEl('span','value',el,details[k]);
|
||||
cv.setAttribute('data-id', k);
|
||||
cv.textContent=details[k];
|
||||
el.appendChild(cv);
|
||||
frame.appendChild(el);
|
||||
}
|
||||
else {
|
||||
el.textContent = details[k];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function showOverlay(text,isHtml){
|
||||
let el=document.getElementById('overlayContent');
|
||||
|
@ -451,9 +455,15 @@
|
|||
let be=buttons[i];
|
||||
be.onclick=window[be.id]; //assume a function with the button id
|
||||
}
|
||||
let cd=document.getElementById("showCanDetails");
|
||||
forEl('.showMsgDetails',function(cd){
|
||||
cd.addEventListener('change',function(ev){
|
||||
showCanDetails(ev.target.checked);
|
||||
let key=ev.target.getAttribute('data-key');
|
||||
if (! key) return;
|
||||
let el=document.getElementById(key);
|
||||
if (!el) return;
|
||||
if (ev.target.checked) el.classList.remove('hidden');
|
||||
else(el.classList).add('hidden');
|
||||
});
|
||||
});
|
||||
let tabs=document.querySelectorAll('.tab');
|
||||
for (let i=0;i<tabs.length;i++){
|
||||
|
@ -544,13 +554,13 @@ button.infoButton {
|
|||
.hidden{
|
||||
display: none !important;
|
||||
}
|
||||
#canDetails{
|
||||
display:none;
|
||||
.msgDetails .value {
|
||||
width: 5em;
|
||||
text-align: right;
|
||||
}
|
||||
#canDetails.visible{
|
||||
display: block;
|
||||
.msgDetails .label {
|
||||
width: 5em;
|
||||
}
|
||||
|
||||
.overlayContainer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
@ -670,28 +680,96 @@ div#dashboardPage {
|
|||
<span class="value" id="apIp">---</span>
|
||||
</div>
|
||||
<div class="row ">
|
||||
<span class="label"># NMEA2000 messages</span>
|
||||
<span class="value" id="numcan">---</span>
|
||||
<span class="label">wifi client connected</span>
|
||||
<span class="value" id="wifiConnected">---</span>
|
||||
</div>
|
||||
<div class="row even">
|
||||
<span class="label">NMEA2000 details</span>
|
||||
<input type="checkbox" id="showCanDetails"></span>
|
||||
<span class="label">wifi client IP</span>
|
||||
<span class="value" id="clientIP">---</span>
|
||||
</div>
|
||||
|
||||
<div class="row even" id="canDetails">
|
||||
|
||||
<div class="row">
|
||||
<span class="label"># NMEA2000 in</span>
|
||||
<span class="value" id="count2Kin.sumOk">---</span>
|
||||
</div>
|
||||
<div class="row even">
|
||||
<span class="label">NMEA2000 in details</span>
|
||||
<input type="checkbox" class="showMsgDetails" data-key="count2Kin.ok"></span>
|
||||
</div>
|
||||
<div class="row even msgDetails hidden" id="count2Kin.ok" >
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="label"># NMEA2000 out</span>
|
||||
<span class="value" id="count2Kout.sumOk">---</span>
|
||||
</div>
|
||||
<div class="row even">
|
||||
<span class="label">NMEA2000 out details</span>
|
||||
<input type="checkbox" class="showMsgDetails" data-key="count2Kout.ok"></span>
|
||||
</div>
|
||||
<div class="row even msgDetails hidden" id="count2Kout.ok" >
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="label"># TCP clients</span>
|
||||
<span class="value" id="numClients">---</span>
|
||||
</div>
|
||||
<div class="row even">
|
||||
<span class="label">wifi client connected</span>
|
||||
<span class="value" id="wifiConnected">---</span>
|
||||
<span class="label"># TCP in</span>
|
||||
<span class="value" id="countTCPin.sumOk">---</span>
|
||||
</div>
|
||||
<div class="row ">
|
||||
<span class="label">wifi client IP</span>
|
||||
<span class="value" id="clientIP">---</span>
|
||||
<span class="label">TCP in details</span>
|
||||
<input type="checkbox" class="showMsgDetails" data-key="countTCPin.ok"></span>
|
||||
</div>
|
||||
<div class="row msgDetails hidden" id="countTCPin.ok" >
|
||||
</div>
|
||||
<div class="row even">
|
||||
<span class="label"># TCP out</span>
|
||||
<span class="value" id="countTCPout.sumOk">---</span>
|
||||
</div>
|
||||
<div class="row ">
|
||||
<span class="label">TCP out details</span>
|
||||
<input type="checkbox" class="showMsgDetails" data-key="countTCPout.ok"></span>
|
||||
</div>
|
||||
<div class="row msgDetails hidden" id="countTCPout.ok" >
|
||||
</div>
|
||||
<div class="row even">
|
||||
<span class="label"># USB in</span>
|
||||
<span class="value" id="countUSBin.sumOk">---</span>
|
||||
</div>
|
||||
<div class="row ">
|
||||
<span class="label">USB in details</span>
|
||||
<input type="checkbox" class="showMsgDetails" data-key="countUSBin.ok"></span>
|
||||
</div>
|
||||
<div class="row msgDetails hidden" id="countUSBin.ok" >
|
||||
</div>
|
||||
<div class="row even">
|
||||
<span class="label"># USB out</span>
|
||||
<span class="value" id="countUSBout.sumOk">---</span>
|
||||
</div>
|
||||
<div class="row ">
|
||||
<span class="label">USB out details</span>
|
||||
<input type="checkbox" class="showMsgDetails" data-key="countUSBout.ok"></span>
|
||||
</div>
|
||||
<div class="row msgDetails hidden" id="countUSBout.ok" >
|
||||
</div>
|
||||
<div class="row even">
|
||||
<span class="label"># Serial in</span>
|
||||
<span class="value" id="countSerialin.sumOk">---</span>
|
||||
</div>
|
||||
<div class="row ">
|
||||
<span class="label">Serial in details</span>
|
||||
<input type="checkbox" class="showMsgDetails" data-key="countSerialin.ok"></span>
|
||||
</div>
|
||||
<div class="row msgDetails hidden" id="countSerialin.ok" >
|
||||
</div>
|
||||
<div class="row even">
|
||||
<span class="label"># Serial out</span>
|
||||
<span class="value" id="countSerialout.sumOk">---</span>
|
||||
</div>
|
||||
<div class="row ">
|
||||
<span class="label">Serial out details</span>
|
||||
<input type="checkbox" class="showMsgDetails" data-key="countSerialout.ok"></span>
|
||||
</div>
|
||||
<div class="row msgDetails hidden" id="countSerialout.ok" >
|
||||
</div>
|
||||
<button id="reset" >Reset</button>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue