Skip to content

Commit

Permalink
More improvemets for Collecting. Introduced comm. statistics.
Browse files Browse the repository at this point in the history
  • Loading branch information
MyHomeMyData committed Dec 17, 2023
1 parent a34dd9e commit 7da1ae0
Show file tree
Hide file tree
Showing 6 changed files with 281 additions and 116 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ admin/i18n/*/flat.txt
admin/jsonConfigDemo.json5
admin/jsonConfig.testTab.json
README.org.md
todo.md
6 changes: 3 additions & 3 deletions lib/callback.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class udsCallback {
}
break;
case 'timeout':
if (ctxAgent.cntCommTimeout < ctx.udsMaxTrialsDevScan) {
if (ctxAgent.stat.cntCommTimeout < ctx.udsMaxTrialsDevScan) {
await ctxAgent.pushCmnd(ctx, 'read', [ctx.udsDidForScan]);
ctx.udsScanDidsCntRetries += 1;
}
Expand Down Expand Up @@ -98,8 +98,8 @@ class udsCallback {
case 'did mismatch MF':
case 'bad frame':
if (response == 'timeout') {
//ctx.log.debug('UDS did scan: Timeout on '+String(ctxAgent.canIDhex)+'.'+String(ctxAgent.data.did)+' cnt: '+String(ctxAgent.cntCommTimeoutPerDid[ctxAgent.data.did]));
if (ctxAgent.cntCommTimeoutPerDid[ctxAgent.data.did] < ctx.udsMaxTrialsDidScan) {
//ctx.log.debug('UDS did scan: Timeout on '+String(ctxAgent.canIDhex)+'.'+String(ctxAgent.data.did)+' cnt: '+String(ctxAgent.stat.cntCommTimeoutPerDid[ctxAgent.data.did]));
if (ctxAgent.stat.cntCommTimeoutPerDid[ctxAgent.data.did] < ctx.udsMaxTrialsDidScan) {
ctxAgent.pushCmnd(ctx, 'read', [ctxAgent.data.did]);
ctx.udsScanDidsCntRetries += 1;
}
Expand Down
201 changes: 154 additions & 47 deletions lib/canCollect.js
Original file line number Diff line number Diff line change
@@ -1,88 +1,195 @@

const storageCol = require('./storage');
const storage = require('./storage');

class collect {
constructor(config) {
this.config = config;
this.storage = new storageCol.storage(this.config);
this.config.statName = 'statCollect';
this.storage = new storage.storage(this.config);
this.ts = {};
this.didwatch = 7777;
this.msDelay = config.delay*1000;
this.timeoutHandle = null;
this.maxDid = 3500;
this.commBusy = false; // Communication routine running
this.data = {
'len' : 0,
'timestamp' : 0,
'databytes' : [],
'did' : 0,
'collecting': false,
'D0' : 0x21
'D0expected': 0x21
};
this.stat = {
cntCommTotal : 0, // Number collected dids
cntCommOk : 0, // Number of ok
cntCommStored : 0, // Number of dids stored
cntCommTimeout : 0, // Number of timeouts
cntCommBadProt : 0, // Number of bad communications
cntTooBusy : 0, // Number of conflicting calls of msgCollect()
};
}

async initStates(ctx) {
await this.storage.initStates(ctx);
await this.storage.storeStatistics(ctx, this);
}

async onTimeout(ctxGlobal, ctxLocal) {
ctxGlobal.log.error('Collect timeout on 0x'+Number(ctxLocal.config.canID[0]).toString(16)+'.'+String(ctxLocal.data.did));
ctxLocal.stat.cntCommTimeout += 1;
ctxLocal.data.collecting = false;
}

async startup(ctx) {
await this.storage.storeStatistics(ctx, this);
this.data.collecting = false;
await this.storage.setOpMode('normal');
await ctx.log.debug('Collect agent started on '+this.config.stateBase);
}

async stop(ctx) {
// Stop Timeout:
if (this.timeoutHandle) await clearTimeout(this.timeoutHandle);
this.timeoutHandle = null;

// Wait till possibly running communication has finished:
const tsAbort = await new Date().getTime() + this.config.timeout;
while ( (this.commBusy) && (new Date().getTime() < tsAbort) ) {
await this.sleep(50);
}

await this.storage.storeStatistics(ctx, this);

// Stop agent:
this.data.collecting = false;
await this.storage.setOpMode('standby');
await ctx.log.debug('Collect agent stopped on '+this.config.stateBase);
}

sleep(milliseconds) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}

async msgCollect(ctx, msg) {

if (this.commBusy) {
this.stat.cntTooBusy += 1;
if (this.stat.cntTooBusy == 1) ctx.log.warn('Collect: Evaluation of messages overloaded on '+String(this.config.stateBase));
return;
}

this.commBusy = true;
const candata = msg.data.toJSON().data;

const canid = msg.id;
const msgDlc = candata.length;
const tsNow = new Date().getTime();

if (this.config.device == 'e380') {
if (!(canid in this.ts)) { this.ts[canid] = 0; }
if ( (this.config.delay > 0) && ((tsNow-this.ts[canid]) < this.config.delay*1000) ) { return; }
this.storage.decodeDataCAN(ctx,msg.id,candata);
this.ts[canid] = tsNow;
// Energy meter
this.stat.cntCommTotal += 1;
this.stat.cntCommOk += 1;
if (!(canid in this.ts)) { this.ts[canid] = tsNow; }
if ( (this.config.delay == 0) || ((tsNow >= this.ts[canid])) ) {
this.stat.cntCommStored += 1;
this.storage.decodeDataCAN(ctx,this,msg.id,candata);
this.ts[canid] = tsNow+this.msDelay;
}
} else {
//ctx.log.debug(JSON.stringify(candata));
// E3 device
//await ctx.log.debug(this.storage.arr2Hex(candata));
if (this.data.collecting) {
this.data.D0 += 1;
if (this.data.D0 > 0x2f) {
this.data.D0 = 0x20;
}
if (candata[0] == this.data.D0) {
if (candata[0] == this.data.D0expected) {
// append next part of data
this.data.databytes = this.data.databytes.concat(candata.slice(1));
if (this.data.did == this.didwatch) { ctx.log.debug('D0='+String(this.data.D0)+'; candata='+JSON.stringify(this.data.databytes)); }
} else {
// no more data
if ((this.config.dids == null) || (this.data.did in this.config.dids) ) {
if (this.data.did == this.didwatch) {
ctx.log.debug(JSON.stringify(this.data));
if (this.data.databytes.length >= this.data.len) {
// All data received
if (this.timeoutHandle) await clearTimeout(this.timeoutHandle);
//await ctx.log.debug('Done did MF '+String(this.data.did));
this.stat.cntCommOk += 1;
if (!(this.data.did in this.ts)) { this.ts[this.data.did] = tsNow; }
if ( (this.config.delay == 0) || ((tsNow >= this.ts[this.data.did])) ) {
this.stat.cntCommStored += 1;
this.storage.decodeDataCAN(ctx, this, this.data.did, this.data.databytes.slice(0,this.data.len));
this.ts[this.data.did] = tsNow+this.msDelay;
}
this.data.collecting = false;
await this.storage.decodeDataCAN(ctx, this.data.did, this.data.databytes.slice(0,this.data.len));
this.ts[this.data.did] = tsNow;
} else {
// More data to come
//await ctx.log.debug('Ongoing did MF '+String(this.data.did)+' len '+String(this.data.databytes.length));
this.data.D0expected += 1;
if (this.data.D0expected > 0x2f) {
this.data.D0expected = 0x20;
}
}
}
}

if ( (!this.data.collecting) && (candata.length > 4) && (candata[0] == 0x21) && (candata[3] >= 0xb0) && (candata[3] < 0xc0)) {
this.data.D0 = candata[0];
const D3 = candata[3];
if (D3 == 0xb0) {
this.data.len = candata[4];
if (candata[5]==0xb5) {
this.data.databytes = candata.slice(6);
} else {
this.data.databytes = candata.slice(5);
}
} else {
this.data.len = D3-0xb0;
this.data.databytes = candata.slice(4);
}
const D3 = candata[3];
if ( (!this.data.collecting) && (msgDlc > 4) && (candata[0] == 0x21) && (D3 >= 0xb0) && (D3 < 0xc0)) {
this.data.D0expected = candata[0];
this.data.did = candata[1]+256*candata[2];
if (this.data.did == this.didwatch) {
ctx.log.debug('Start did '+String(this.didwatch));
ctx.log.debug(JSON.stringify(this.data));
}
if ( (this.data.did > 0) && (this.data.did < 10000) ) {
if (!(this.data.did in this.ts)) { this.ts[this.data.did] = 0; }
if ( (this.config.delay > 0) && ((tsNow-this.ts[this.data.did]) < this.config.delay*1000) ) { return; }
this.data.timestamp = msg.ts_sec*1000+Math.round(msg.ts_usec/1000);
this.data.collecting = true;
this.data.timestamp = msg.ts_sec*1000+Math.round(msg.ts_usec/1000);
if ( (this.data.did > 0) && (this.data.did < this.maxDid) ) {
switch (D3) {
case 0xb1:
case 0xb2:
case 0xb3:
case 0xb4:
// Single Frame B1,B2,B3,B4
this.data.len = D3-0xb0;
//await ctx.log.debug('Start did B1..B4 '+String(this.data.did)+String(this.data.len));
this.data.databytes = candata.slice(4);
this.stat.cntCommTotal += 1;
this.stat.cntCommOk += 1;
if (!(this.data.did in this.ts)) { this.ts[this.data.did] = tsNow; }
if ( (this.config.delay == 0) || ((tsNow >= this.ts[this.data.did])) ) {
this.stat.cntCommStored += 1;
this.storage.decodeDataCAN(ctx, this, this.data.did, this.data.databytes.slice(0,this.data.len));
this.ts[this.data.did] = tsNow+this.msDelay;
}
//await ctx.log.debug('Done did B1..B4 '+String(this.data.did));
break;
case 0xb0:
// Multi Frame B0
this.data.D0expected = candata[0]+1;
this.stat.cntCommTotal += 1;
if (candata[4]==0xc1) {
this.data.databytes = candata.slice(6);
this.data.len = candata[5];
//await ctx.log.debug('Start did B0..B5 '+String(this.data.did)+' len '+String(this.data.len));
} else {
this.data.databytes = candata.slice(5);
this.data.len = candata[4];
//await ctx.log.debug('Start did B0 '+String(this.data.did)+String(this.data.len));
}
this.timeoutHandle = setTimeout(this.onTimeout, this.config.timeout, ctx, this);
this.data.collecting = true;
break;
case 0xb6:
case 0xb7:
case 0xb8:
case 0xb9:
case 0xba:
case 0xbb:
case 0xbc:
case 0xbd:
case 0xbe:
case 0xbf:
// Multi Frame B6 .. BF
this.stat.cntCommTotal += 1;
this.data.D0expected = candata[0]+1;
this.data.databytes = candata.slice(4);
this.data.len = D3-0xb0;
this.timeoutHandle = setTimeout(this.onTimeout, this.config.timeout, ctx, this);
//await ctx.log.debug('Start did B6B7 '+String(this.data.did)+String(this.data.len));
this.data.collecting = true;
break;
default:
ctx.log.debug('Collect: D3=0x'+Number(D3).toString(16));
}
}
}
}
this.commBusy = false;
}
}

Expand Down
Loading

0 comments on commit 7da1ae0

Please sign in to comment.