'use strict'; const assert = require('assert'), bitUtil = require('bit-util'); const GPS_13 = 0x13; /** * RAPParser is responsible for parsing RAP binary records */ class RAPParser { constructor() { // Using these local vars to avoid GC for more memory efficency this._hour = 0; this._minute = 0; this._second = 0; this._year = 0; this._month = 0; this._day = 0; this._byte = 0; } /** * Parse RAP binary response package * @param {*} rapPkg The binary package data in Buffer. Structure: , Cmd = 0x13 * @returns a GPS data object */ parse(rapPkg) { let record; if (rapPkg && rapPkg[0] >= GPS_13) { assert.ok(Buffer.isBuffer(rapPkg), 'rapPkg argument must be an instance of Buffer'); // prettier-ignore // Byte 19th, if bit 4 is set -> has GPS Fix if (rapPkg[18] && bitUtil.isBitOn(rapPkg[18], 4)) { record = {}; let offset = 2; // Add 2 to skip the data package header to read the data record.lat = rapPkg.readInt32LE(offset) * 1e-5; offset += 4; record.lon = rapPkg.readInt32LE(offset) * 1e-5; offset += 4; record.speed = rapPkg.readUInt8(offset); offset += 1; // GPS Direction in 2 Degree Increasements record.head = rapPkg.readUInt8(offset) << 1; offset += 1; this._hour = rapPkg.readUInt8(offset); offset += 1; this._minute = rapPkg.readUInt8(offset); offset += 1; this._second = rapPkg.readUInt8(offset); offset += 1; this._year = 2000 + rapPkg.readUInt8(offset); offset += 1; this._month = rapPkg.readUInt8(offset); offset += 1; this._day = rapPkg.readUInt8(offset); offset += 1; // Month in JS 0 => 11 record.gdt = new Date(Date.UTC(this._year, this._month - 1, this._day, this._hour, this._minute, this._second)); record.inputs = 0; // Cmd 0x13. Byte 19th this._byte = rapPkg.readUInt8(offset); offset += 1; // Cmd 0x13. Byte 19th. Bits 0-3: numbers of GPS setellites record.sats = bitUtil.extractBits(this._byte, 4, 0); // Cmd 0x13. Byte 20th this._byte = rapPkg.readUInt8(offset); // Cmd 0x13. Byte 20th. Bit 3: Inputs+ if (bitUtil.isBitOn(this._byte, 3)) { // Cmd 0x13. Byte 20th. Bit 0: 1 => extra inputs (21-24) offset += bitUtil.isBitOn(this._byte, 0) ? 4 : 1; // Skip reading Odometer data // Cmd 0x13. Byte 21th/25th this._byte = rapPkg.readUInt8(offset); offset += 1; if (bitUtil.isBitOn(this._byte, 0)) { // Cmd 0x13. Byte 22th/25th: Whether Digital input state present this._byte = rapPkg.readUInt8(offset); offset += 1; // Digital inputs (Up to 5, use only input 1 for Spray on/off, 0: spray on and 1 is off) // Check Input 1 (bit 0) for spray on/off record.inputs = bitUtil.isBitOn(this._byte, 0) ? 0 : 1; } } } } return record; } } module.exports = RAPParser;