|
- /**
- * @license
- * Copyright 2021- anjingyu <anjingyu@navinfo.com>
- * SPDX-License-Identifier: WTFPL 2
- */
-
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.DBCC = {}));
- })(this, (function (exports) {
- 'use strict';
-
- const VERSION = '1.0.0';
-
- const MSG_REGEXP = /BO_\s+([0-9]+)\s+([^\s]+):\s*([0-9]{1,2})\s+(.*)?/;
- const SIG_REGEXP = /\s+SG_\s+([^\s]+)\s*:\s*([0-9]{1,2})\|([0-9]{1,2})@([0-1])([+-])\s+\((.*)?,(.*)?\)\s+\[(.*)?\|(.*)?\]\s+"(.*)?"\s{1,2}(.*)?/;
-
- const ByteOrder = {
- Motorola: 0, ///< 0 big-endbian
- Intel: 1 ///< 1 little-endbian
- };
-
- const Sign = {
- Unsigned: 0,
- Signed: 1
- };
-
- const ShiftDirection = {
- Left: 0,
- Right: 1
- };
-
- Object.freeze(ByteOrder);
- Object.freeze(Sign);
- Object.freeze(ShiftDirection);
-
- class Message {
- #name;
- #id;
- #dlc;
- #from;
- #to;
-
- #signals;
- #indexes;
-
- constructor(name, id, dlc, from) {
- this.#name = name;
- this.#id = id;
- this.#dlc = dlc
- this.#from = from
- this.#to = [];
-
- this.#signals = [];
- this.#indexes = {};
- }
-
- get name() {
- return this.#name;
- }
-
- get id() {
- return this.#id;
- }
-
- get dlc() {
- return this.#dlc;
- }
-
- get from() {
- return this.#from;
- }
-
- get to() {
- if (!this.#to.length) {
- let toMap = new Map();
- for (let sig in this.#signals) {
- for (let t in sig.to) {
- toMap.set(t, '');
- }
- }
-
- this.#to = Array.from(toMap.keys());
- }
-
- return this.#to;
- }
-
- [Symbol.iterator]() {
- let index = -1;
- let signals = this.#signals;
-
- return {
- next: () => ({value: signals[++index], done: index == signals.length})
- };
- }
-
- append(signal) {
- this.#signals.push(signal);
- this.#indexes[signal.name] = this.#signals.length - 1;
- }
-
- static fromLineString(lineString) {
- let items = lineString.match(MSG_REGEXP);
-
- if (items) {
- return new Message(items[2], parseInt(items[1]), parseInt(items[3]), items[4]);
- } else {
- return null;
- }
- }
- }
-
- class CompiledSignalParameter {
- #index;
- #shift; ///< TODO(donkey): Optimization, use the highest bit to indicate the shift direction.
- #mask;
- #direction; ///< 0: left shift, 1: right shift
-
- constructor(index, shift, mask, direction) {
- this.#index = index;
- this.#shift = shift;
- this.#mask = mask;
- this.#direction = direction;
- }
-
- get index() {
- return this.#index;
- }
-
- get mask() {
- return this.#mask;
- }
-
- get shift() {
- return this.#shift;
- }
-
- get direction() {
- return this.#direction;
- }
- }
-
- class Signal {
- #name;
- #byteOrder;
- #startBit;
- #length;
- #sign;
- #minimum;
- #maximum;
- #factor;
- #offset;
- #unit;
- #to;
- #isFloat;
-
- #compiled;
- #signedLengthMask;
-
- constructor(name, startBit, length, byteOrder, sign, factor, offset, minimum, maximum, unit, to) {
- this.#name = name;
- this.#startBit = startBit;
- this.#length = length;
- this.#byteOrder = byteOrder;
- this.#sign = sign;
- this.#factor = factor;
- this.#offset = offset;
- this.#minimum = minimum;
- this.#maximum = maximum;
- this.#unit = unit;
- this.#to = to;
-
- let f = (x) => (~~x == x);
- if (f(minimum) && f(maximum) && f(factor) && f(offset)) {
- this.#isFloat = false;
- } else {
- this.#isFloat = true;
- }
-
- this.#compiled = this.#segments(true);
-
- this.#signedLengthMask = 0;
- if (this.#sign == Sign.Signed)
- {
- let mask = ((1 << (this.#typeLength() - this.#length)) - 1);
-
- if (mask != 0) {
- mask <<= this.#length;
- this.#signedLengthMask = mask;
- }
- }
- }
-
- #typeLength() {
- let len = this.#length;
-
- if (len <= 8) {
- return 8;
- } else if (len <= 16) {
- return 16;
- } else if (len <= 32) {
- return 32;
- }
-
- return 64;
- }
-
- #segments(invertShift) {
- invertShift = invertShift || false;
-
- let segs = [];
- let index = parseInt(this.#startBit / 8);
- let pos = this.#startBit % 8;
- let left = this.#length;
-
- let length = 0;
- let tmpShift = 0, tmpMask = 0, tmpDirection = 0, tmpIndex = 0;
-
- while (left > 0) {
- if (this.#byteOrder == ByteOrder.Motorola) {
- if (left >= (pos + 1)) {
- length = (pos + 1);
- pos = 7;
- tmpShift = -(left - length);
- tmpMask = ((1 << length) - 1);
- } else {
- length = left;
- tmpShift = (pos - length + 1);
- tmpMask = ((1 << length) - 1);
- tmpMask <<= (pos - length + 1);
- }
- } else {
- tmpShift = (left - this.#length) + pos;
-
- if (left >= (8 - pos)) {
- length = (8 - pos);
- tmpMask = ((1 << length) - 1);
- tmpMask <<= pos;
- pos = 0;
- }
- else {
- length = left;
- tmpMask = ((1 << length) - 1);
- tmpMask <<= pos;
- }
- }
-
- if (invertShift) {
- if (tmpShift < 0) {
- tmpShift = -tmpShift;
- tmpDirection = ShiftDirection.Left;
- }
- else {
- tmpDirection = ShiftDirection.Right;
- }
- } else {
- if (tmpShift < 0) {
- tmpShift = -tmpShift;
- tmpDirection = ShiftDirection.Right;
- }
- else {
- tmpDirection = ShiftDirection.Left;
- }
- }
- tmpIndex = index;
- segs.push(new CompiledSignalParameter(tmpIndex, tmpShift, tmpMask, tmpDirection));
-
- left -= length;
- index += 1;
- }
-
- return segs;
- }
-
- #packLeftShift(value, shift, mask) {
- return ((value << shift) & mask) & 0xff;
- }
-
- #packRightShift(value, shift, mask) {
- return ((value >> shift) & mask) & 0xff;
- }
-
- #unpackLeftShift(value, shift, mask) {
- return ((value & mask) << shift);
- }
-
- #unpackRightShift(value, shift, mask) {
- return ((value & mask) >> shift);
- }
-
- // Return ArrayBuffer<Uint8>
- encode(value) {
- let temp = 0;
- let data = new Uint8Array(8);
-
- if (!this.#isFloat) {
- temp = ((parseInt(value) - this.#offset) / this.#factor);
- } else {
- temp = ((value - this.#offset) / this.#factor);
- }
-
- for (let i = 0; i < this.#compiled.length; ++i) {
- let p = this.#compiled[i];
-
- // NOTE(anjingyu): Here we encode the data, so the direction
- // is reversed.
- if (p.direction == ShiftDirection.Left) {
- data[p.index] |= this.#packRightShift(temp, p.shift, p.mask);
- } else {
- data[p.index] |= this.#packLeftShift(temp, p.shift, p.mask);
- }
- }
-
- return data;
- }
-
- // Return a double value
- decode(data) {
- let result = 0;
-
- for (let i = 0; i < this.#compiled.length; ++i) {
- let p = this.#compiled[i];
-
- if (p.direction == ShiftDirection.Left) {
- result |= this.#unpackLeftShift(data[p.index], p.shift, p.mask);
- } else {
- result |= this.#unpackRightShift(data[p.index], p.shift, p.mask);
- }
- }
-
- if (this.#signedLengthMask != 0) {
- if ((result & (1 << (this.#length - 1))) != 0) {
- result |= this.#signedLengthMask;
- }
- }
-
- return (result * this.#factor + this.#offset);
- }
-
- get name() {
- return this.#name;
- }
-
- get startBit() {
- return this.#startBit;
- }
-
- get length() {
- return this.#length;
- }
-
- get byteOrder() {
- return this.#byteOrder;
- }
-
- get sign() {
- return this.#sign;
- }
-
- get minimum() {
- return this.#minimum;
- }
-
- get maximum() {
- return this.#maximum;
- }
-
- get factor() {
- return this.#factor;
- }
-
- get offset() {
- return this.#offset;
- }
-
- get unit() {
- return this.#unit;
- }
-
- get to() {
- return this.#to;
- }
-
- get isFloat() {
- return this.#isFloat;
- }
-
- static fromLineString(lineString) {
- let items = lineString.match(SIG_REGEXP);
-
- if (items) {
- return new Signal(items[1], ///< name
- parseInt(items[2]), ///< startBit
- parseInt(items[3]), ///< length
- parseInt(items[4]), ///< byteOrder
- items[5] === '+' ? Sign.Unsigned : Sign.Signed, ///< sign
- parseFloat(items[6]), ///< factor
- parseFloat(items[7]), ///< offset
- parseFloat(items[8]), ///< minimum
- parseFloat(items[9]), ///< maximum
- items[10], ///< unit string
- items[11].split(",")); ///< to list
- } else {
- return null;
- }
- }
- }
-
- class DbcParser {
- #messages;
- #indexes;
-
- constructor() {
- this.#messages = [];
- this.#indexes = {};
- }
-
- [Symbol.iterator]() {
- let index = -1;
- let msgs = this.#messages;
-
- return {
- next: () => ({value: msgs[++index], done: index == msgs.length})
- };
- }
-
- parse(contentString) {
- // Traverse the contentString line by line,
- // BO_ and SG_ are the interested lines(Message and Signal).
- let lines = contentString.split(/\n/);
-
- for (let i = 0; i < lines.length; ++i) {
- let line = lines[i];
- let signature = line.trim().split(" ")[0];
-
- if (signature != "BO_") {
- continue;
- } else {
- // Parse the Message Object and corresponding Signal Objects
- let message = Message.fromLineString(line.trim());
-
- this.#messages.push(message);
- this.#indexes[message.name] = {};
-
- for (let j = i + 1; j < lines.length; j = i + 1) {
- let subline = lines[j];
- signature = subline.trim().split(" ")[0];
-
- if (signature != "SG_") {
- --i;
- break;
- } else {
- let sig = Signal.fromLineString(subline.trimEnd());
- message.append(sig);
- ++i;
- }
- }
- }
- }
- }
- }
-
- class SignalProcessor {
-
- #dbcParser;
- #msgs;
- #handlers;
-
- constructor(contentString) {
- this.#dbcParser = new DbcParser();
- this.#msgs = new Map();
-
- this.#dbcParser.parse(contentString);
-
- for (let msg of this.#dbcParser) {
- if (msg.dlc == 0) {
- continue;
- }
-
- let msgEntity = [msg, {}];
-
- for (let sig of msg) {
- msgEntity[1][sig.name] = sig;
- }
- this.#msgs.set(msg.id, msgEntity);
- }
-
- this.#handlers = new Map();
- }
-
- // Register the delegate to encode/decode the message
- // the delegate should contains two methods, onEncode/onDecode
- registerDelegate(msgId, sigName, delegate) {
- if (this.#msgs.has(msgId) && sigName in this.#msgs.get(msgId)[1]) {
- if (!this.#handlers.has(msgId)) {
- this.#handlers.set(msgId, {});
- }
- this.#handlers.get(msgId)[sigName] = delegate;
- return true;
- }
- return false;
- }
-
- unregisterDelegate(msgId, sigName) {
- if (this.#handlers.has(msgId) && sigName in this.#handlers.get(msgId)) {
- delete this.#handlers.get(msgId)[sigName];
-
- if (Object.keys(this.#handlers.get(msgId)).length == 0) {
- this.#handlers.delete(msgId);
- }
- }
- }
-
- decodeMessage(msgId, data) {
- if (this.#handlers.has(msgId)) {
- let sigs = this.#handlers.get(msgId);
- for (let sigName in sigs) {
- let sig = this.#msgs.get(msgId)[1][sigName];
- let r = sig.decode(data);
- sigs[sigName].onDecoded(msgId, sigName, r);
- }
- }
- }
-
- encodeMessage(msgId, values) {
- if (this.#handlers.has(msgId)) {
- let sigs = this.#handlers.get(msgId);
- for (let sigName in values) {
- let data = undefined;
-
- if (sigName in sigs) {
- let sig = this.#msgs.get(msgId)[1][sigName];
- data = sig.encode(values[sigName]);
- } else {
- console.warn(`Did not register handler for signal (#{msgId}).{sigName}`)
- }
- sigs[sigName].onEncoded(msgId, data);
- }
- }
- }
- }
-
- exports.VERSION = VERSION;
-
- exports.Message = Message;
- exports.Signal = Signal;
- exports.DbcParser = DbcParser;
- exports.SignalProcessor = SignalProcessor;
- exports.ByteOrder = ByteOrder;
- exports.Sign = Sign;
-
- Object.defineProperty(exports, '__esModule', { value: true });
- }));
|