UNPKG

obd-raw-data-parser

Version:

A lightweight TypeScript library for parsing OBD-II raw data into human readable format. Based on the excellent work of obd-utils by Nishkalkashyap.

121 lines (120 loc) 4.59 kB
import { BaseDecoder } from "./BaseDecoder.js"; import { byteArrayToString, parseHexInt, formatMessage } from "../../utils.js"; import { hexToDTC } from "../utils/dtcConverter.js"; export class NonCanDecoder extends BaseDecoder { _determineFrameType(frame) { const colonIndex = frame.indexOf(58); return colonIndex !== -1 ? "colon" : "no-colon"; } _extractBytesFromColonFrame(frame, colonIndex) { let dataStartIndex = colonIndex + 1; while (dataStartIndex < frame.length && frame[dataStartIndex] === 32) { dataStartIndex++; } return this._extractBytesFromData(frame.slice(dataStartIndex)); } _extractBytesFromNoColonFrame(frame) { let dataStartIndex = 0; while (dataStartIndex < frame.length && frame[dataStartIndex] === 32) { dataStartIndex++; } return this._extractBytesFromData(frame.slice(dataStartIndex)); } _extractBytesFromData(dataArray) { const bytes = []; const hexString = byteArrayToString(dataArray).replace(/[\s\x00-\x1F]/g, ""); for (let i = 0; i < hexString.length; i += 2) { const pair = hexString.substr(i, 2); if (pair.length === 2) { bytes.push(pair); } } this._log("debug", formatMessage("Converted ASCII to bytes:", "", JSON.stringify(bytes))); return bytes; } decodeDTCs(rawResponseBytes) { try { this.reset(); const dtcs = new Set(); for (let frameIndex = 0; frameIndex < rawResponseBytes.length; frameIndex++) { const frame = rawResponseBytes[frameIndex]; if (!Array.isArray(frame) || frame.length === 0) continue; const frameType = this._determineFrameType(frame); let bytes; if (frameType === "colon") { bytes = this._extractBytesFromColonFrame(frame, frame.indexOf(58)); } else { bytes = this._extractBytesFromNoColonFrame(frame); } if (!bytes || bytes.length === 0) continue; if (frameIndex === 0) { const modeResponse = parseHexInt(bytes[0]); if (modeResponse === this.getModeResponseByte()) { bytes = bytes.slice(1); } } for (let i = 0; i < bytes.length; i += 2) { if (i + 1 >= bytes.length) { this.leftoverByte = bytes[i]; break; } const dtc = this._decodeDTC(bytes[i], bytes[i + 1]); if (dtc) { this.rawDtcObjects.push(dtc); const dtcString = this._dtcToString(dtc); if (dtcString) { dtcs.add(dtcString); this.setDTC(dtcString); } } } } return Array.from(dtcs); } catch (error) { this._log("error", formatMessage("Failed to parse response:", "", String(error))); return []; } } // eslint-disable-next-line @typescript-eslint/no-unused-vars _log(_level, ..._message) { // Implementation provided by parent } // eslint-disable-next-line @typescript-eslint/no-unused-vars setDTC(_dtc) { // Implementation provided by parent } getModeResponseByte() { // Implementation provided by parent return 0; } setModeResponse(modeResponse) { Object.defineProperty(this, "getModeResponseByte", { value: () => modeResponse, }); } // eslint-disable-next-line @typescript-eslint/no-unused-vars _getDTCInfo(_dtcLevel, _dtcMessage) { return undefined; } _decodeDTC(byte1, byte2) { try { // Skip null, undefined, or "00" bytes if (!byte1 || !byte2 || (byte1 === "00" && byte2 === "00")) { return null; } const combinedHex = byte1.padStart(2, '0') + byte2.padStart(2, '0'); return hexToDTC(combinedHex); } catch (error) { this._log("error", "Failed to decode DTC:", error); return null; } } _dtcToString(dtc) { return dtc; // Already in the correct format from hexToDTC } }