@canboat/canboatjs
Version:
Native javascript version of canboat
261 lines • 9.36 kB
JavaScript
"use strict";
/**
* Copyright 2018 Scott Bender (scott@scottbender.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CanbusStream = CanbusStream;
const utilities_1 = require("./utilities");
const stream_1 = require("stream");
const toPgn_1 = require("./toPgn");
const lodash_1 = __importDefault(require("lodash"));
const candevice_1 = require("./candevice");
const utilities_2 = require("./utilities");
const canId_1 = require("./canId");
const stringMsg_1 = require("./stringMsg");
const util_1 = __importDefault(require("util"));
function CanbusStream(options) {
if (this === undefined) {
return new CanbusStream(options);
}
this.debug = (0, utilities_1.createDebug)('canboatjs:canbus', options);
stream_1.Transform.call(this, {
objectMode: true
});
this.plainText = false;
this.options = options;
this.start();
this.setProviderStatus =
options.app && options.app.setProviderStatus
? (msg) => {
options.app.setProviderStatus(options.providerId, msg);
}
: () => { };
this.setProviderError =
options.app && options.app.setProviderError
? (msg) => {
options.app.setProviderError(options.providerId, msg);
}
: () => { };
if (options.fromStdIn) {
return;
}
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
this.socketcan = require('socketcan');
}
catch (err) {
console.error(err);
const msg = 'unable to load native socketcan interface';
console.error(msg);
}
// eslint-disable-next-line @typescript-eslint/no-this-alias
const that = this;
if (options.app) {
options.app.on(options.outEvent || 'nmea2000out', (msg) => {
that.sendPGN(msg);
});
options.app.on(options.jsonOutEvent || 'nmea2000JsonOut', (msg) => {
that.sendPGN(msg);
});
}
if (this.connect() == false) {
return;
}
const noDataReceivedTimeout = typeof options.noDataReceivedTimeout !== 'undefined'
? options.noDataReceivedTimeout
: -1;
if (noDataReceivedTimeout > 0) {
this.noDataInterval = setInterval(() => {
if (this.channel &&
this.lastDataReceived &&
Date.now() - this.lastDataReceived > noDataReceivedTimeout * 1000) {
const channel = this.channel;
delete this.channel;
try {
channel.stop();
}
catch (_error) { }
this.setProviderError('No data received, retrying...');
if (this.options.app) {
console.error('No data received, retrying...');
}
this.connect();
}
}, noDataReceivedTimeout * 1000);
}
}
CanbusStream.prototype.connect = function () {
const canDevice = this.options.canDevice || 'can0';
try {
if (this.socketcan === undefined) {
this.setProviderError('unable to load native socketcan interface');
return false;
}
// eslint-disable-next-line @typescript-eslint/no-this-alias
const that = this;
this.channel = this.socketcan.createRawChannelWithOptions(canDevice, {
non_block_send: true
});
this.channel.addListener('onStopped', () => {
if (this.channel) {
// stoped by us?
delete this.channel;
this.setProviderError('Stopped, Retrying...');
if (this.options.app) {
console.error('socketcan stopped, retrying...');
}
setTimeout(() => {
this.setProviderError('Reconnecting...');
this.connect();
}, 2000);
}
});
this.channel.addListener('onMessage', (msg) => {
const pgn = (0, canId_1.parseCanId)(msg.id);
if (this.noDataInterval) {
this.lastDataReceived = Date.now();
}
//always send address claims through
if (pgn.pgn != 60928 &&
that.candevice &&
that.candevice.cansend &&
pgn.src == that.candevice.address) {
return;
}
const timestamp = new Date().toISOString();
if (that.plainText) {
this.push((0, utilities_2.binToActisense)(pgn, timestamp, msg.data, msg.data.length));
}
else {
that.push({ pgn, length: msg.data.length, data: msg.data });
}
});
this.channel.start();
this.setProviderStatus('Connected to socketcan');
this.candevice = new candevice_1.CanDevice(this, this.options);
this.candevice.start();
return true;
}
catch (e) {
console.error(`unable to open canbus ${canDevice}: ${e}`);
console.error(e.stack);
this.setProviderError(e.message);
return false;
}
};
util_1.default.inherits(CanbusStream, stream_1.Transform);
CanbusStream.prototype.start = function () { };
CanbusStream.prototype.sendPGN = function (msg, force) {
if (this.candevice) {
//if ( !this.candevice.cansend && (_.isString(msg) || msg.pgn !== 59904) ) {
if (!this.candevice.cansend && force !== true) {
//we have not completed address claim yet
return;
}
this.debug('sending %j', msg);
if (this.options.app) {
this.options.app.emit('connectionwrite', {
providerId: this.options.providerId
});
}
const src = msg.pgn === 59904 || msg.forceSrc ? msg.src : this.candevice.address;
if (lodash_1.default.isString(msg)) {
const split = msg.split(',');
split[3] = src;
msg = split.join(',');
}
else {
msg.src = src;
if (lodash_1.default.isUndefined(msg.prio)) {
msg.prio = 3;
}
if (lodash_1.default.isUndefined(msg.dst)) {
msg.dst = 255;
}
}
if (this.socketCanWriter) {
if (lodash_1.default.isString(msg)) {
this.socketCanWriter.stdin.write(msg + '\n');
}
else {
const str = (0, stringMsg_1.toActisenseSerialFormat)(msg.pgn, (0, toPgn_1.toPgn)(msg), msg.dst, msg.src);
this.socketCanWriter.stdin.write(str + '\n');
}
}
else if (this.channel) {
let canid;
let buffer;
let pgn;
if (lodash_1.default.isObject(msg)) {
canid = (0, canId_1.encodeCanId)(msg);
buffer = (0, toPgn_1.toPgn)(msg);
pgn = msg;
}
else {
pgn = (0, stringMsg_1.parseActisense)(msg);
canid = (0, canId_1.encodeCanId)(pgn);
buffer = pgn.data;
}
if (this.debug.enabled) {
const str = (0, stringMsg_1.toActisenseSerialFormat)(pgn.pgn, buffer, pgn.dst, pgn.src);
this.debug(str);
}
if (buffer === undefined) {
this.debug("can't convert %j", msg);
return;
}
//seems as though 126720 should always be encoded this way
if (buffer.length > 8 || pgn.pgn == 126720) {
const pgns = (0, utilities_2.getPlainPGNs)(buffer);
pgns.forEach((pbuffer) => {
this.channel.send({ id: canid, ext: true, data: pbuffer });
});
}
else {
this.channel.send({ id: canid, ext: true, data: buffer });
}
}
}
};
CanbusStream.prototype._transform = function (chunk, encoding, done) {
done();
};
CanbusStream.prototype.end = function () {
if (this.channel) {
const channel = this.channel;
delete this.channel;
channel.stop();
}
if (this.noDataInterval) {
clearInterval(this.noDataInterval);
}
};
CanbusStream.prototype.pipe = function (pipeTo) {
if (!pipeTo.fromPgn) {
this.plainText = true;
}
/*
pipeTo.fromPgn.on('pgn', (pgn) => {
if ( this.candevice ) {
this.candevice.n2kMessage(pgn)
}
})
*/
return CanbusStream.super_.prototype.pipe.call(this, pipeTo);
};
//# sourceMappingURL=canbus.js.map