Skip to content

Commit

Permalink
Enhanced schedule function. Robustness improvement E3List. Version is…
Browse files Browse the repository at this point in the history
… buggy!
  • Loading branch information
MyHomeMyData committed Dec 2, 2023
1 parent c64ab41 commit 0f6b404
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 40 deletions.
81 changes: 71 additions & 10 deletions lib/canUds.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}

Expand Down Expand Up @@ -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: {
Expand All @@ -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);
Expand All @@ -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);
}
Expand All @@ -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));
Expand All @@ -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':
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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;
Expand Down
10 changes: 7 additions & 3 deletions lib/codecs.js
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,13 @@ class O3EList {
if (('subTypes' in subT)) {
// O3EComplexType
result[subT.id] = [];
for (let i=0; i<count; i++) {
result[subT.id].push(subT.decode(string_bin.slice(index,index+subT.string_len)));
index += subT.string_len;
if (count <= 100) {
for (let i=0; i<count; i++) {
result[subT.id].push(subT.decode(string_bin.slice(index,index+subT.string_len)));
index += subT.string_len;
}
} else {
result[subT.id] = ['Implausible number of elements. Decoding aborted.'];
}
} else {
result[subT.id] = subT.decode(string_bin.slice(index,index+subT.string_len));
Expand Down
27 changes: 16 additions & 11 deletions lib/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,31 @@ class storage {
},
native: {},
});
ctx.log.debug(String(stateId)+': '+JSON.stringify(obj));
//await ctx.setStateAsync(stateId, JSON.stringify(obj), true);
ctx.log.silly(String(stateId)+': '+JSON.stringify(obj));
await ctx.setStateAsync(stateId, JSON.stringify(obj), true);
}
async function storeObjectTree(ctx, stateId, obj) {
if (typeof(obj) == 'object') {
for (const [key, itm] of Object.entries(obj)) {
storeObjectTree(ctx, String(stateId)+'.'+String(key),itm);
if (Object.keys(obj).length <= 100) {
for (const [key, itm] of Object.entries(obj)) {
await storeObjectTree(ctx, String(stateId)+'.'+String(key),itm);
}
} else {
ctx.log.error('Evaluation aborted. Too many members ('+String(Object.keys(obj).length)+') for Did '+stateId);
}
} else {
//ctx.log.debug(String(stateId)+': '+JSON.stringify(obj));
storeObjectJson(ctx, stateId, obj);
await storeObjectJson(ctx, stateId, obj);
}
}
const idStr = didsDict[this.config.device][did].id;
const val = didsDict[this.config.device][did].decode(data);
const didStr = '000'+String(did);
const stateIdJson = this.config.stateBase+'.json.'+didStr.slice(-4)+'_'+idStr;
const stateIdTree = this.config.stateBase+'.tree.'+didStr.slice(-4)+'_'+idStr;
if (this.config.doTree) { storeObjectTree(ctx, stateIdTree, val); }
if (this.config.doJson) { storeObjectJson(ctx, stateIdJson, val); }
if (val) {
const didStr = '000'+String(did);
const stateIdJson = this.config.stateBase+'.json.'+didStr.slice(-4)+'_'+idStr;
const stateIdTree = this.config.stateBase+'.tree.'+didStr.slice(-4)+'_'+idStr;
if (this.config.doTree) { await storeObjectTree(ctx, stateIdTree, val); }
if (this.config.doJson) { await storeObjectJson(ctx, stateIdJson, val); }
}
}

}
Expand Down
44 changes: 28 additions & 16 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class E3oncan extends utils.Adapter {
this.E3CollectInt = []; // List of collect devices on internal bus
this.E3CollectExt = []; // List of collect devices on external bus
this.E3Uds = []; // List of uds devices on external bus
this.udsDevices = {}; // Uds devices-addresses

this.channelExt = null;
this.channelInt = null;
Expand Down Expand Up @@ -120,18 +121,25 @@ class E3oncan extends utils.Adapter {
// Setup all configured devices for UDS:
for (const dev of Object.values(this.config.table_uds)) {
if ( (dev.uds_tree_states) || (dev.uds_json_states) ) {
const Uds = new uds.uds(
{ 'canID': [Number(dev.uds_dev_addr)],
'stateBase': dev.uds_dev_name,
'device': 'common',
'delay': 0,
'doTree': dev.uds_tree_states,
'doJSON': dev.uds_json_states,
'channel': this.channelExt,
'timeout': 2 // Commuication timeout (s)
});
this.E3Uds.push(Uds);
await Uds.initStates(this); }
if (!(dev.uds_dev_addr in Object.keys(this.udsDevices))) {
const Uds = new uds.uds(
{ 'canID': [Number(dev.uds_dev_addr)],
'stateBase': dev.uds_dev_name,
'device': 'common',
'delay': 0,
'doTree': dev.uds_tree_states,
'doJSON': dev.uds_json_states,
'channel': this.channelExt,
'timeout': 2 // Commuication timeout (s)
});
this.E3Uds.push(Uds);
this.udsDevices[dev.uds_dev_addr] = Uds;
await Uds.initStates(this);
await Uds.addSchedule(this, dev.uds_schedule, dev.uds_dids);
} else {
await this.udsDevices[dev.uds_dev_addr].Uds.addSchedule(this,dev.uds_schedule, dev.uds_dids);
}
}
}

// Evaluate configuration for internal CAN bus
Expand Down Expand Up @@ -180,10 +188,14 @@ class E3oncan extends utils.Adapter {
this.setState('info.connection', true, true);
}

if (this.E3Uds[0]) {
await this.E3Uds[0].pushCmnd(this, 'read', [256]);
await this.E3Uds[0].pushCmnd(this, 'read', [256,269,2346]);
this.E3Uds[0].cmndLoop(this);
// Startup UDS communications if configured
// ========================================

for (const dev of Object.values(this.E3Uds)) {
if (dev) {
dev.cmndLoop(this);
dev.schedulesLoop(this);
}
}

this.log.debug('onReady(): All done.');
Expand Down

0 comments on commit 0f6b404

Please sign in to comment.