From 0f6b40495838f61946339babfeeb691ebdd50414 Mon Sep 17 00:00:00 2001 From: MyHomeMyData Date: Sat, 2 Dec 2023 19:23:36 +0100 Subject: [PATCH] Enhanced schedule function. Robustness improvement E3List. Version is buggy! --- lib/canUds.js | 81 +++++++++++++++++++++++++++++++++++++++++++------- lib/codecs.js | 10 +++++-- lib/storage.js | 27 ++++++++++------- main.js | 44 +++++++++++++++++---------- 4 files changed, 122 insertions(+), 40 deletions(-) diff --git a/lib/canUds.js b/lib/canUds.js index 0b24424..c74ab10 100644 --- a/lib/canUds.js +++ b/lib/canUds.js @@ -27,6 +27,7 @@ class uds { this.canIDhex = '0x'+Number(this.config.canID).toString(16); this.cmndQueueId = 'admin.uds.'+this.canIDhex+'.cmndQueue'; this.timeoutId = 'admin.uds.'+this.canIDhex+'.timeout'; + this.schedulesId = 'admin.uds.'+this.canIDhex+'.schedules'; this.userDidsToReadId = 'uds.'+this.canIDhex+'.didsToRead'; } @@ -57,6 +58,18 @@ class uds { }); await ctx.setStateAsync(this.timeoutId, { val: false, ack: true }); ctx.subscribeStates(this.timeoutId); + await ctx.setObjectNotExistsAsync(this.schedulesId, { + type: 'state', + common: { + name: 'List schedules to be read via UDS ReadByDid according to adapter configuration.', + type: 'json', + role: 'state', + read: true, + write: true, + }, + native: {}, + }); + await ctx.setStateAsync(this.schedulesId, { val: JSON.stringify({}), ack: true }); await ctx.setObjectNotExistsAsync(this.userDidsToReadId, { type: 'state', common: { @@ -72,6 +85,20 @@ class uds { ctx.subscribeStates(this.userDidsToReadId); } + async addSchedule(ctx, schedule, dids) { + // x + const obj = await ctx.getStateAsync(this.schedulesId); + const schedules = JSON.parse(obj.val); + if (!Object.keys(schedules).includes(schedule)) { + const didsArr = dids.replace(' ','').split(','); + schedules[schedule] = didsArr.map(function(str) { return parseInt(str); }); + ctx.log.debug('addSchedule: '+String(schedule)+' '+JSON.stringify(schedules[schedule])); + await ctx.setStateAsync(this.schedulesId, {val: JSON.stringify(schedules), ack: true}); + } else { + ctx.log.warn('Multiple definiton of schedule: Dev='+this.config.stateBase+'; Schedule='+String(schedule)); + } + } + async pushCmnd(ctx, mode, dids) { const obj = await ctx.getStateAsync(this.cmndQueueId); const cmnds = JSON.parse(obj.val); @@ -94,9 +121,11 @@ class uds { for (const did of Object.values(cmnd.dids)) { // Do ReadByDid for each did await this.readByDid(ctx,did); - ctx.log.silly('cmndLoop()->ReadByDid: '+String(did)); + await ctx.log.debug('cmndLoop()->ReadByDid: '+String(did)); + await this.sleep(100); while (this.data.state != this.states[0]) { - await this.sleep(10); + await ctx.log.debug('cmndLoop()->ReadByDid: Waiting.'); + await this.sleep(100); } await this.sleep(10); } @@ -109,6 +138,30 @@ class uds { } } + async schedulesLoop(ctx) { + const obj = await ctx.getStateAsync(this.schedulesId); + const schedules = JSON.parse(obj.val); + if (Object.keys(schedules).includes('0')) { + // One time schedule + ctx.log.silly('scheduleLoop() one time: '+JSON.stringify(schedules[0])); + await this.pushCmnd(ctx, 'read', schedules[0]); + } + let secsLast = -1; + // eslint-disable-next-line no-constant-condition + while (true) { + const secs = Math.floor(new Date().getTime() / 1000); + if (secs != secsLast) { + secsLast = secs; + for (const [sched, dids] of Object.entries(schedules)) { + if ( (Number(sched) > 0) && ((secs % Number(sched)) == 0) ) { + ctx.log.silly('scheduleLoop(): '+JSON.stringify(dids)); + await this.pushCmnd(ctx, 'read', dids); } + } + } + await this.sleep(100); + } + } + async onTimeoutChange(ctx, obj) { if (!obj) { ctx.log.error('UDS timeout on device '+this.canIDhex+'. Did='+String(this.data.did)); @@ -135,21 +188,28 @@ class uds { return { id: canID,ext: false, rtr: false,data: Buffer.from(frame) }; } - async sendFrame(frame) { - await this.config.channel.send(this.canMessage(this.config.canID,frame)); + async sendFrame(ctx, frame) { + ctx.log.debug(JSON.stringify(frame)); + const myFrame = this.canMessage(this.config.canID,frame); + ctx.log.debug(JSON.stringify(myFrame)); + await this.config.channel.send(myFrame); } async readByDid(ctx, did) { + await ctx.log.debug('ReadByDid(): state='+String(this.data.state)); + if (this.data.state != this.states[0]) { + await ctx.log.error('ReadByDid(): state != standBy when called! Aborting.'); + return; + } this.data.state = this.states[1]; // 'waitForFF' await ctx.setStateAsync(this.timeoutId, { val: false, ack: true, expire: this.config.timeout }); // Start Timeout monitoring this.data.did = did; - await this.sendFrame(this.initialRequestSF(did)); + await this.sendFrame(ctx, this.initialRequestSF(did)); } async msgUds(ctx, msg) { const candata = msg.data.toJSON().data; - const canid = msg.id; switch (this.data.state) { case 'waitForFF': @@ -168,9 +228,9 @@ class uds { ctx.log.silly('msgUds SF: '+this.canIDhex+' '+JSON.stringify(candata)); this.data.len = candata[0]-3; this.data.databytes = candata.slice(4,4+this.data.len); + await ctx.setStateAsync(this.timeoutId, { val: false, ack: true }); // Stop timeout monitoring await this.storage.decodeDataCAN(ctx, this.data.did, this.data.databytes.slice(0,this.data.len)); this.data.state = this.states[0]; // 'standby' - await ctx.setStateAsync(this.timeoutId, { val: false, ack: true }); // Stop timeout monitoring break; } else { // Did does not match @@ -190,7 +250,7 @@ class uds { ctx.log.silly('msgUds FF: data.len='+String(this.data.len)); this.data.databytes = candata.slice(5,4+this.data.len); this.data.D0 = 0x21; - await this.sendFrame(this.frameFC); // Send request for Consecutive Frames + await this.sendFrame(this, this.frameFC); // Send request for Consecutive Frames this.data.state = this.states[2]; // 'waitForCF' break; } else { @@ -213,9 +273,10 @@ class uds { this.data.databytes = this.data.databytes.concat(candata.slice(1)); if (this.data.databytes.length >= this.data.len) { // All data received - this.storage.decodeDataCAN(ctx, this.data.did, this.data.databytes.slice(0,this.data.len)); - this.data.state = this.states[0]; + ctx.log.silly('msgUds multi frame completed: '+this.canIDhex+' '+JSON.stringify(this.data)); await ctx.setStateAsync(this.timeoutId, { val: false, ack: true }); // Stop timeout monitoring + await this.storage.decodeDataCAN(ctx, this.data.did, this.data.databytes.slice(0,this.data.len)); + this.data.state = this.states[0]; } else { // More data to come this.data.D0 += 1; diff --git a/lib/codecs.js b/lib/codecs.js index 960ce62..ba2ad96 100644 --- a/lib/codecs.js +++ b/lib/codecs.js @@ -506,9 +506,13 @@ class O3EList { if (('subTypes' in subT)) { // O3EComplexType result[subT.id] = []; - for (let i=0; i