@canboat/canboatjs
Version:
Native javascript version of canboat
245 lines • 8.34 kB
JavaScript
;
/**
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.filterPGN = exports.setupFilters = exports.byteStringArray = exports.byteString = exports.hexByte = exports.arrBuff = exports.rmChecksum = exports.trimWrap = exports.createDebug = void 0;
exports.getPlainPGNs = getPlainPGNs;
exports.isPGNProprietary = isPGNProprietary;
exports.compute0183Checksum = compute0183Checksum;
exports.binToActisense = binToActisense;
const debug_1 = require("debug");
const fp_1 = require("lodash/fp");
const createDebug = (name, appOptions = undefined) => {
if (appOptions !== undefined && appOptions.createDebug !== undefined) {
return appOptions.createDebug(name);
}
else {
return (0, debug_1.debug)(name);
}
};
exports.createDebug = createDebug;
function getPlainPGNs(buffer) {
const res = [];
let bucket = 0x40; // 64
const first = Buffer.alloc(8);
first.writeUInt8(bucket++, 0);
first.writeUInt8(buffer.length, 1);
buffer.copy(first, 2, 0, 6);
res.push(first);
for (let index = 6; index < buffer.length; index += 7) {
const next = Buffer.alloc(8);
next.writeUInt8(bucket++, 0);
let end = index + 7;
let fill = 0;
if (end > buffer.length) {
fill = end - buffer.length;
end = buffer.length;
}
buffer.copy(next, 1, index, end);
if (fill > 0) {
for (let i = end - index + 1; i < 8; i++) {
next.writeUInt8(0xff, i);
}
}
res.push(next);
}
return res;
}
// NMEA 2000 proprietary PGN ranges:
// - 61184, 61440: PDU1 single-frame proprietary
// - 65280–65535: PDU1 proprietary
// - 126720–126975: PDU2 proprietary fast-packet
function isPGNProprietary(pgn) {
return (pgn === 61184 ||
pgn === 61440 ||
(pgn >= 65280 && pgn <= 65535) ||
(pgn >= 126720 && pgn <= 126975));
}
const m_hex = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'
];
function toHexString(v) {
const msn = (v >> 4) & 0x0f;
const lsn = (v >> 0) & 0x0f;
return m_hex[msn] + m_hex[lsn];
}
function compute0183Checksum(sentence) {
// skip the $
let i = 1;
// init to first character
let c1 = sentence.charCodeAt(i);
// process rest of characters, zero delimited
for (i = 2; i < sentence.length; ++i) {
c1 = c1 ^ sentence.charCodeAt(i);
}
return '*' + toHexString(c1);
}
function binToActisense(pgn, timestamp, data, length) {
const arr = [];
return (timestamp +
`,${pgn.prio},${pgn.pgn},${pgn.src},${pgn.dst},${length},` +
new Uint32Array(data)
.reduce(function (acc, i) {
acc.push(i.toString(16));
return acc;
}, arr)
.map((x) => (x.length === 1 ? '0' + x : x))
.join(','));
}
exports.trimWrap = (0, fp_1.trimChars)('()<>[]');
const rmChecksum = (str) => str.includes('*') ? str.split('*', 1)[0] : str;
exports.rmChecksum = rmChecksum;
const arrBuff = (arr, encoding = 'hex') => Buffer.from(arr.join(''), encoding);
exports.arrBuff = arrBuff;
const hexByte = (x) => (0, fp_1.padCharsStart)('0', 2, Number(x).toString(16));
exports.hexByte = hexByte;
const byteString = (data, separator = ',') =>
// Uint32Array map method doesn't work as expect. _.map does.
(0, fp_1.map)(exports.hexByte, new Uint32Array(data)).join(separator);
exports.byteString = byteString;
const byteStringArray = (data) =>
// Uint32Array map method doesn't work as expect. _.map does.
(0, fp_1.map)(exports.hexByte, new Uint8Array(data));
exports.byteStringArray = byteStringArray;
const setupFilters = (filterOptions) => {
let pgn_filter = undefined;
if (filterOptions.pgn !== undefined) {
if (Array.isArray(filterOptions.pgn)) {
pgn_filter = filterOptions.pgn.map((p) => typeof p === 'string' ? Number(p) : p);
}
else {
pgn_filter = [
typeof filterOptions.pgn === 'string'
? Number(filterOptions.pgn)
: filterOptions.pgn
];
}
}
let src_filter = undefined;
if (filterOptions.src !== undefined) {
if (Array.isArray(filterOptions.src)) {
src_filter = filterOptions.src.map((s) => typeof s === 'string' ? Number(s) : s);
}
else {
src_filter = [
typeof filterOptions.src === 'string'
? Number(filterOptions.src)
: filterOptions.src
];
}
}
let dst_filter = undefined;
if (filterOptions.dst !== undefined) {
if (Array.isArray(filterOptions.dst)) {
dst_filter = filterOptions.dst.map((d) => typeof d === 'string' ? Number(d) : d);
}
else {
dst_filter = [
typeof filterOptions.dst === 'string'
? Number(filterOptions.dst)
: filterOptions.dst
];
}
}
let manufacturer_filter = undefined;
if (filterOptions.manufacturer !== undefined) {
if (Array.isArray(filterOptions.manufacturer)) {
manufacturer_filter = filterOptions.manufacturer;
}
else {
manufacturer_filter = [filterOptions.manufacturer];
}
}
let id_filter = undefined;
if (filterOptions.id !== undefined) {
if (Array.isArray(filterOptions.id)) {
id_filter = filterOptions.id;
}
else {
id_filter = [filterOptions.id];
}
}
let js_filter = undefined;
const filter = filterOptions.filter;
if (filter !== undefined && filter.length > 0) {
try {
js_filter = new Function('pgn', `return ${filter}`);
}
catch (e) {
console.error(`Invalid filter expression: ${e.message}`);
//process.exit(1)
}
}
return {
pgn_filter,
manufacturer_filter,
src_filter,
dst_filter,
js_filter,
id_filter
};
};
exports.setupFilters = setupFilters;
const filterPGN = (pgn, filter) => {
if ((filter.src_filter === undefined ||
filter.src_filter.length === 0 ||
filter.src_filter.find((s) => pgn.src === s)) &&
(filter.dst_filter === undefined ||
filter.dst_filter.length === 0 ||
filter.dst_filter.find((d) => pgn.dst === d)) &&
(filter.manufacturer_filter === undefined ||
filter.manufacturer_filter.length === 0 ||
filter.manufacturer_filter.find((m) => pgn.fields?.manufacturerCode === m))) {
// Check if PGN passes either filter (when filters are defined)
const hasPgnFilter = filter.pgn_filter !== undefined && filter.pgn_filter.length > 0;
const hasIdFilter = filter.id_filter !== undefined && filter.id_filter.length > 0;
if (hasPgnFilter || hasIdFilter) {
const passesNumberFilter = hasPgnFilter && filter.pgn_filter.includes(pgn.pgn);
const passesIdFilter = hasIdFilter && filter.id_filter.includes(pgn.id);
if (!passesNumberFilter && !passesIdFilter) {
return false;
}
}
if (filter.js_filter !== undefined) {
try {
return filter.js_filter(pgn);
}
catch (e) {
console.error(`Error evaluating filter on PGN ${pgn.pgn}: ${e.message}`);
return false;
}
}
return true;
}
return false;
};
exports.filterPGN = filterPGN;
//# sourceMappingURL=utilities.js.map