Comparing version 2.0.1 to 2.1.0
@@ -8,3 +8,4 @@ { | ||
"description": "A SocketCAN abstraction layer for NodeJS.", | ||
"version": "2.0.1", | ||
"version": "2.1.0", | ||
"license": "MIT", | ||
"repository": { | ||
@@ -14,9 +15,17 @@ "type": "git", | ||
}, | ||
"scripts" : { | ||
"preinstall" : "node-gyp configure && node-gyp build", | ||
"preuninstall" : "rm -rf build/*" | ||
"scripts": { | ||
"configure": "node-gyp configure", | ||
"build": "node-gyp build" | ||
}, | ||
"dependencies": { "xml2js": ">=0.2.0" }, | ||
"devDependencies": { | ||
"nan": "^2.0.9", | ||
"node-gyp": ">=1.0.0" | ||
}, | ||
"dependencies": { | ||
"xml2js": ">=0.2.0" | ||
}, | ||
"main": "socketcan.js", | ||
"os": [ "linux" ] | ||
"os": [ | ||
"linux" | ||
] | ||
} |
113
parse_kcd.js
@@ -30,3 +30,3 @@ /* Copyright Sebastian Haas <sebastian$sebastianhaas.info>. All rights reserved. | ||
var data = fs.readFileSync(file) | ||
var data = fs.readFileSync(file); | ||
@@ -44,4 +44,29 @@ var parser = new xml2js.Parser({explicitArray: true}); | ||
result.nodes[node['id']] = {}; | ||
result.nodes[node['id']].name = node['name']; | ||
result.nodes[node['id']].buses = {}; | ||
result.nodes[node['id']].name = node['name']; | ||
result.nodes[node['id']].buses = {}; | ||
result.nodes[node['id']].device = node['device']; | ||
result.nodes[node['id']].J1939 = { | ||
'AAC' : node['J1939AAC'], | ||
'Function' : node['J1939Function'], | ||
'Vehicle' : node['J1939Vehicle'], | ||
'Identity' : node['J1939IdentityNumber'], | ||
'Industry' : node['J1939IndustryGroup'], | ||
'System' : node['J1939System'], | ||
'Manufacture': node['J1939ManufacturerCode'], | ||
getName : function(){ | ||
var name = new Buffer(8); | ||
name[7] = ((this.AAC & 0x1) << 7) | ((this.Industry & 0x7) << 4) | (this.Vehicle & 0xF); | ||
name[6] = (this.System) << 1 & 0xFE; | ||
name[5] = this.Function & 0xFF; | ||
name[4] = 0; // function Instance & ECU instance | ||
name[3] = (this.Manufacture >> 3) & 0xFF ; | ||
name[2] = ((this.Manufacture & 0x7) << 5) | ( (this.Identity >> 16) & 0x1F ); | ||
name[1] = (this.Identity >> 8 ) & 0xFF; | ||
name[0] = this.Identity & 0xFF; | ||
return name; | ||
}, | ||
} | ||
} | ||
@@ -62,2 +87,4 @@ | ||
var multiplex = d['Bus'][b]['Message'][m]['Multiplex']; | ||
var _m = { | ||
@@ -68,6 +95,8 @@ name: message.name, | ||
triggered: message.triggered == 'true', | ||
length: message.length, | ||
interval: parseInt(message.interval) | ||
length: message.length ? parseInt(message.length) : 0, | ||
interval: message.interval ? parseInt(message.interval) : 0, | ||
muxed : (multiplex != undefined ), | ||
}; | ||
// Add messages going out and from whom. | ||
for (p in producers) { | ||
@@ -86,3 +115,3 @@ for (n in producers[p]['NodeRef']) { | ||
} | ||
// Add listeners / targets for the message. | ||
for (c in consumers) { | ||
@@ -111,2 +140,52 @@ for (n in consumers[c]['NodeRef']) { | ||
// look for multiplexed messages | ||
for ( mux in multiplex ){ | ||
for (mg in multiplex[mux]['MuxGroup'] ){ | ||
var muxmsg = multiplex[mux]['MuxGroup'][mg]['$']; | ||
for (s in multiplex[mux]['MuxGroup'][mg]['Signal']) { | ||
var signal = multiplex[mux]['MuxGroup'][mg]['Signal'][s]['$']; | ||
var value = multiplex[mux]['MuxGroup'][mg]['Signal'][s]['Value']; | ||
var _s = { | ||
name: signal.name, | ||
mux : parseInt(muxmsg['count'],16), | ||
bitLength: signal.length ? parseInt(signal.length) : 1, | ||
endianess: signal.endianess ? signal.endianess : 'little', | ||
spn : signal.spn, | ||
labels : {}, | ||
}; | ||
// add Values from the database | ||
if (Array.isArray(value)) { | ||
_s.slope = value[0]['$'].slope ? parseFloat(value[0]['$'].slope) : 1.0; | ||
_s.intercept = value[0]['$'].intercept ? parseFloat(value[0]['$'].intercept) : 0.0; | ||
_s.units = value[0]['$'].units ? value[0]['$'].units : ""; | ||
_s.minValue = value[0]['$'].min ? value[0]['$'].min : undefined; | ||
_s.maxValue = value[0]['$'].max ? value[0]['$'].max : undefined; | ||
_s.type = value[0]['$'].type ? value[0]['$'].type : "unsigned"; | ||
_s.defaultValue = value[0]['$'].defaultValue ? parseFloat(value[0]['$'].defaultValue) : 0.0 ; | ||
// add label sets from the database. | ||
if( Array.isArray( value[0].LabelSet )){ | ||
var labels = value[0].LabelSet[0]['Label']; | ||
for ( var i =0 ; i < labels.length; i++ ){ | ||
_s.labels[labels[i]['$'].value] = labels[i]['$'].name ; | ||
} | ||
} | ||
} | ||
var offset_num = parseInt(signal.offset) + _s.bitLength; | ||
if (offset_num > maxOffset) | ||
maxOffset = offset_num; | ||
_s.bitOffset = parseInt(signal.offset); | ||
_m.signals.push(_s); | ||
} | ||
} | ||
} | ||
for (s in d['Bus'][b]['Message'][m]['Signal']) { | ||
@@ -120,13 +199,23 @@ var signal = d['Bus'][b]['Message'][m]['Signal'][s]['$']; | ||
endianess: signal.endianess ? signal.endianess : 'little', | ||
spn : signal.spn, | ||
labels : {}, | ||
}; | ||
// add Values from the database | ||
if (Array.isArray(value)) { | ||
_s.scale = value[0]['$'].slope ? parseFloat(value[0]['$'].slope) : 1.0; | ||
_s.offset = value[0]['$'].intercept ? parseFloat(value[0]['$'].intercept) : 0.0; | ||
_s.unit = value[0]['$'].unit ? value[0]['$'].unit : ""; | ||
_s.slope = value[0]['$'].slope ? parseFloat(value[0]['$'].slope) : 1.0; | ||
_s.intercept = value[0]['$'].intercept ? parseFloat(value[0]['$'].intercept) : 0.0; | ||
_s.units = value[0]['$'].units ? value[0]['$'].units : ""; | ||
_s.minValue = value[0]['$'].min ? value[0]['$'].min : undefined; | ||
_s.maxValue = value[0]['$'].max ? value[0]['$'].max : undefined; | ||
_s.type = value[0]['$'].type ? value[0]['$'].type : "unsigned"; | ||
_s.defaultValue = value[0]['$'].defaultValue ? parseFloat(value[0]['$'].defaultValue) : 0.0 ; | ||
// add label sets from the database. | ||
if( Array.isArray( value[0].LabelSet )){ | ||
var labels = value[0].LabelSet[0]['Label']; | ||
for ( var i =0 ; i < labels.length; i++ ){ | ||
_s.labels[labels[i]['$'].value] = labels[i]['$'].name ; | ||
} | ||
} | ||
} | ||
var offset_num = parseInt(signal.offset) + _s.bitLength; | ||
@@ -141,3 +230,3 @@ | ||
} | ||
if (!_m.length) { | ||
@@ -144,0 +233,0 @@ _m.length = parseInt(maxOffset / 8); |
@@ -34,3 +34,3 @@ node-can | ||
var channel = can.createRawChannel("vcan0"); | ||
var db = new can.DatabaseService(channel, network.buses["Motor"].messages); | ||
var db = new can.DatabaseService(channel, network.buses["Motor"]); | ||
@@ -42,3 +42,3 @@ channel.start(); | ||
console.log("SpeedKm " + s.value); | ||
} | ||
}); | ||
@@ -60,6 +60,12 @@ // Update tank temperature | ||
node-gyp configure && node-gyp build | ||
```shell | ||
$ npm i | ||
$ npm run configure | ||
$ npm run build | ||
``` | ||
2. Install via npm: | ||
npm install socketcan | ||
```shell | ||
$ npm install socketcan | ||
``` |
@@ -14,4 +14,4 @@ var can = require('socketcan'); | ||
var c = can.createRawChannel("vcan" + i++); | ||
var d = new can.DatabaseService(c, network.buses[b].messages); | ||
var d = new can.DatabaseService(c, network.buses[b]); | ||
c.start(); | ||
@@ -24,3 +24,3 @@ | ||
var msg = node.buses[b].produces[m]; | ||
if (msg.interval) | ||
@@ -27,0 +27,0 @@ setInterval(function(name) { d.send(name); }, msg.interval, msg.name); |
189
socketcan.js
@@ -59,3 +59,4 @@ /* Copyright Sebastian Haas <sebastian@sebastianhaas.info>. All rights reserved. | ||
this.name = desc['name']; | ||
this.spn = desc['spn']; | ||
this.bitOffset = desc['bitOffset']; | ||
@@ -65,18 +66,31 @@ this.bitLength = desc['bitLength']; | ||
this.type = desc['type']; | ||
this.offset = desc['offset']; | ||
this.factor = desc['factor']; | ||
this.intercept = desc['intercept']; | ||
this.slope = desc['slope']; | ||
this.minValue = desc['minValue']; | ||
this.maxValue = desc['maxValue']; | ||
/** | ||
* Current value | ||
* @attribute value | ||
* @final | ||
*/ | ||
this.units = desc['units']; | ||
/** | ||
* Label set for defined states of the signal. | ||
*/ | ||
this.labels = desc['labels']; | ||
/** | ||
* this will allow triggering on mux'ed message ids. | ||
*/ | ||
this.muxGroup = [ desc['mux'] ]; | ||
/** | ||
* Current value | ||
* | ||
* @attribute value | ||
* @final | ||
*/ | ||
this.value = desc['defaultValue']; | ||
if (!this.value) | ||
this.value = 0; | ||
this.listeners = []; | ||
@@ -105,5 +119,12 @@ } | ||
// Nothing changed | ||
if (this.value == newValue) | ||
if (this.value == newValue) { | ||
return; | ||
} else if (newValue > this.maxValue) { | ||
console.error("ERROR : " + this.name + " value= " + newValue | ||
+ " is outof bounds > " + this.maxValue); | ||
} else if (newValue < this.minValue) { | ||
console.error("ERROR : " + this.name + " value= " + newValue | ||
+ " is outof bounds < " + this.minValue); | ||
} | ||
this.value = newValue; | ||
@@ -130,3 +151,3 @@ | ||
this.id = desc.id; | ||
/** | ||
@@ -138,3 +159,3 @@ * Extended Frame Format used | ||
this.ext = desc.ext; | ||
/** | ||
@@ -146,11 +167,28 @@ * Symbolic name | ||
this.name = desc.name; | ||
/** | ||
* Length in bytes of resulting CAN message | ||
* @attribute length | ||
* @final | ||
*/ | ||
this.length = desc.length; | ||
/** | ||
* | ||
* @attribute len | ||
* @final | ||
*/ | ||
this.len = desc.length; | ||
/** | ||
* This is the time frame that the message gets generated | ||
* | ||
* @attribute interval | ||
* @final | ||
*/ | ||
this.interval = desc.interval; | ||
/** | ||
* This is tells us the message is mutliplexed. | ||
* | ||
* @attribute muxed | ||
* @final | ||
*/ | ||
this.muxed = desc.muxed; | ||
/** | ||
* Named array of signals within this message. Accessible via index and name. | ||
@@ -161,6 +199,10 @@ * @attribute {Signal} signals | ||
this.signals = []; | ||
for (i in desc['signals']) { | ||
var s = desc['signals'][i]; | ||
this.signals[s.name] = new Signal(s); | ||
if (this.signals[s.name] && this.signals[s.name].muxGroup) { | ||
this.signals[s.name].muxGroup.push(s.mux); | ||
} else { | ||
this.signals[s.name] = new Signal(s); | ||
} | ||
} | ||
@@ -182,3 +224,3 @@ } | ||
this.channel = channel; | ||
/** | ||
@@ -190,4 +232,4 @@ * Named array of known messages. Accessible via index and name. | ||
for (i in db_desc) { | ||
var m = db_desc[i]; | ||
for (i in db_desc['messages']) { | ||
var m = db_desc['messages'][i]; | ||
var id = m.id | (m.ext ? 1 : 0) << 31; | ||
@@ -199,3 +241,3 @@ | ||
} | ||
// Subscribe to any incoming messages | ||
@@ -207,9 +249,11 @@ channel.addListener("onMessage", this.onMessage, this); | ||
DatabaseService.prototype.onMessage = function (msg) { | ||
if (msg == undefined) | ||
return; | ||
if (msg.rtr) | ||
return; | ||
id = msg.id | (msg.ext ? 1 : 0) << 31; | ||
var m = this.messages[id]; | ||
if (!m) | ||
@@ -220,14 +264,27 @@ { | ||
} | ||
// this is the possible multiplexor for the signals coming in. | ||
var b1mux = _signals.decode_signal(msg.data, 0, 8, true, false); | ||
// Let the C-Portition extract and convert the signal | ||
for (i in m.signals) { | ||
var s = m.signals[i]; | ||
var val = _signals.decode_signal(msg.data, s.bitOffset, s.bitLength, s.endianess == 'little', s.type == 'signed'); | ||
if (s.factor) | ||
val *= s.factor; | ||
if (s.offset) | ||
val += s.offset; | ||
if (s.value === undefined) | ||
continue; | ||
// if this is a mux signal and the muxor isnt in my list... | ||
if (m.muxed && s.muxGroup && s.muxGroup.indexOf(b1mux) == -1) { | ||
continue; | ||
} | ||
var val = _signals.decode_signal(msg.data, s.bitOffset, s.bitLength, | ||
s.endianess == 'little', s.type == 'signed'); | ||
if (s.slope) | ||
val *= s.slope; | ||
if (s.intercept) | ||
val += s.intercept; | ||
s.update(val); | ||
@@ -245,7 +302,10 @@ } | ||
DatabaseService.prototype.send = function (msg_name) { | ||
var m = this.messages[msg_name] | ||
var args = msg_name.split("."); // allow for mux'ed messages sent. | ||
var m = this.messages[args[0]]; | ||
var mux = (args.length > 1) ? args[1] : undefined; | ||
if (!m) | ||
throw msg_name + " not defined"; | ||
var canmsg = { | ||
@@ -255,26 +315,43 @@ id: m.id, | ||
rtr: false, | ||
data: new Buffer(m.length) | ||
data : (m.len > 0 && m.len < 8) ? new Buffer(m.len) : new Buffer(8) | ||
}; | ||
canmsg.data.fill(0); // should be 0xFF for j1939 message def. | ||
if (mux) { | ||
_signals.encode_signal(canmsg.data, 0, 8, true, false, | ||
parseInt(mux, 16)); | ||
} | ||
for (var i = 0; i < m.length; i++) | ||
canmsg.data[i] = 0; | ||
for (i in m.signals) { | ||
var s = m.signals[i]; | ||
if (s.value == undefined) | ||
continue; | ||
if (mux) { | ||
if (s.muxGroup.indexOf(parseInt(mux, 16)) === -1) { | ||
continue; | ||
} | ||
} | ||
var val = s.value; | ||
// Apply factor/offset and convert to Integer | ||
if (s.offset) | ||
val -= s.offset; | ||
if (s.factor) | ||
val /= s.factor; | ||
// Apply factor/intercept and convert to Integer | ||
if (s.intercept) | ||
val -= s.intercept; | ||
if (s.slope) | ||
val /= s.slope; | ||
if (typeof(val) == 'double') | ||
val = parseInt(Math.round(val)); | ||
_signals.encode_signal(canmsg.data, s.bitOffset, s.bitLength, s.endianess == 'little', s.type == 'signed', val); | ||
if (m.len == 0) { | ||
return; | ||
} | ||
_signals.encode_signal(canmsg.data, s.bitOffset, s.bitLength, | ||
s.endianess == 'little', s.type == 'signed', val); | ||
} | ||
this.channel.send(canmsg); | ||
@@ -281,0 +358,0 @@ } |
@@ -6,36 +6,34 @@ var signals = require('../build/Release/can_signals'); | ||
data = new Buffer([0, 0, 0, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 0, 1, true, false, 1); | ||
console.log(data); | ||
signals.encode_signal(data, 1, 1, true, false, 1); | ||
console.log(data); | ||
signals.encode_signal(data, 2, 1, true, false, 0 /* set zero */); | ||
console.log(data); | ||
signals.encode_signal(data, 3, 1, true, false, 1); | ||
test.deepEqual(data, new Buffer([0x0b, 0x00, 0x00, 0, 0, 0, 0, 0])); | ||
signals.encode_signal(data, 4, 8, true, false, 0xEA); | ||
console.log(data); | ||
test.deepEqual(data, [0xD0, 0x00, 0x00, 0, 0, 0, 0, 0]); | ||
/* | ||
signals.encode_signal(data, 4, 8, true, false, 0xEA); | ||
test.deepEqual(data, [0xDE, 0xA0, 0x00, 0, 0, 0, 0, 0]); | ||
test.deepEqual(data, new Buffer([0x0B, 0x0E, 0xA0, 0, 0, 0, 0, 0])); | ||
signals.encode_signal(data, 12, 12, true, false, 0xEDB); | ||
test.deepEqual(data, [0xDE, 0xAD, 0xBE, 0, 0, 0, 0, 0]); | ||
test.deepEqual(data, new Buffer([0xDE, 0xAD, 0xBE, 0, 0, 0, 0, 0])); | ||
signals.encode_signal(data, 12, 12, true, false, 0); | ||
test.deepEqual(data, [0xDE, 0xA0, 0x00, 0, 0, 0, 0, 0], "Overwriting signal value failed"); | ||
*/ | ||
test.deepEqual(data, new Buffer([0xDE, 0xA0, 0x00, 0, 0, 0, 0, 0]), "Overwriting signal value failed"); | ||
test.done(); | ||
} | ||
exports['little_endian_decode'] = function(test) { | ||
data = new Buffer([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE]); | ||
test.equals(signals.decode_signal(data, 0, 8, true, false), 0xDE); | ||
test.equals(signals.decode_signal(data, 0, 12, true, false), 0xADE); | ||
test.equals(signals.decode_signal(data, 0, 16, true, false), 0xADDE); | ||
test.equals(signals.decode_signal(data, 12, 8, true, false), 0xDB); | ||
test.equals(signals.decode_signal(data, 12, 12, true, false), 0xEDB); | ||
test.equals(signals.decode_signal(data, 12, 20, true, false), 0xFEEDB); | ||
test.equals(signals.decode_signal(data, 0, 1, true, false), 1); | ||
@@ -45,3 +43,3 @@ test.equals(signals.decode_signal(data, 1, 1, true, false), 1); | ||
test.equals(signals.decode_signal(data, 3, 1, true, false), 1); | ||
test.done(); | ||
@@ -52,7 +50,7 @@ } | ||
data = new Buffer([0xFE, 0xFF, 0x80]); | ||
test.equals(signals.decode_signal(data, 8, 8, true, true), -1); | ||
test.equals(signals.decode_signal(data, 0, 16, true, true), -2); | ||
test.equals(signals.decode_signal(data, 16, 8, true, true), -128); | ||
test.done(); | ||
@@ -63,12 +61,12 @@ } | ||
data = new Buffer([0, 0, 0, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 0, 8, true, true, -1); | ||
test.deepEqual(data, [0xFF, 0x00, 0x00, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 0, 16, true, true, -2); | ||
test.deepEqual(data, [0xFE, 0xFF, 0x00, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 16, 8, true, true, -128); | ||
test.deepEqual(data, [0xFE, 0xFF, 0x80, 0, 0, 0, 0, 0]); | ||
test.done(); | ||
@@ -79,3 +77,3 @@ } | ||
data = new Buffer([0, 0, 0, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 0, 1, false, false, 1); | ||
@@ -86,12 +84,12 @@ signals.encode_signal(data, 1, 1, false, false, 1); | ||
test.deepEqual(data, [0xD0, 0x00, 0x00, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 11, 8, false, false, 0xEA); | ||
test.deepEqual(data, [0xDE, 0xA0, 0x00, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 23, 12, false, false, 0xDBE); | ||
test.deepEqual(data, [0xDE, 0xAD, 0xBE, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 23, 12, false, false, 0); | ||
test.deepEqual(data, [0xDE, 0xA0, 0x00, 0, 0, 0, 0, 0], "Overwriting signal value failed"); | ||
test.done(); | ||
@@ -102,6 +100,6 @@ } | ||
data = new Buffer([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE]); | ||
test.equals(signals.decode_signal(data, 7, 8, false, false), 0xDE); | ||
test.equals(signals.decode_signal(data, 15, 16, false, false), 0xDEAD); | ||
test.equals(signals.decode_signal(data, 0, 1, false, false), 1); | ||
@@ -111,3 +109,3 @@ test.equals(signals.decode_signal(data, 1, 1, false, false), 1); | ||
test.equals(signals.decode_signal(data, 3, 1, false, false), 1); | ||
test.done(); | ||
@@ -118,12 +116,12 @@ } | ||
data = new Buffer([0, 0, 0, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 7, 8, false, true, -1); | ||
test.deepEqual(data, [0xFF, 0x00, 0x00, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 15, 16, false, true, -2); | ||
test.deepEqual(data, [0xFF, 0xFE, 0x00, 0, 0, 0, 0, 0]); | ||
signals.encode_signal(data, 23, 8, false, true, -128); | ||
test.deepEqual(data, [0xFF, 0xFE, 0x80, 0, 0, 0, 0, 0]); | ||
test.done(); | ||
@@ -134,9 +132,9 @@ } | ||
data = new Buffer([0xFF, 0xFE, 0x80 ]); | ||
test.equals(signals.decode_signal(data, 7, 8, false, true), -1); | ||
test.equals(signals.decode_signal(data, 15, 16, false, true), -2); | ||
test.equals(signals.decode_signal(data, 23, 8, false, true), -128); | ||
test.done(); | ||
} | ||
@@ -10,3 +10,3 @@ var can = require('socketcan'); | ||
var gen_channel = can.createRawChannel("vcan0"); | ||
var db = new can.DatabaseService(channel, network.buses["Motor"].messages); | ||
var db = new can.DatabaseService(channel, network.buses["Motor"]); | ||
@@ -58,4 +58,4 @@ channel.start(); | ||
var rx_db = new can.DatabaseService(channel, network.buses["Motor"].messages); | ||
var tx_db = new can.DatabaseService(gen_channel, network.buses["Motor"].messages); | ||
var rx_db = new can.DatabaseService(channel, network.buses["Motor"]); | ||
var tx_db = new can.DatabaseService(gen_channel, network.buses["Motor"]); | ||
@@ -62,0 +62,0 @@ channel.start(); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
258538
49
2416
69
2