UNPKG

@rflafla/motec-ld-reader

Version:

A Node.js library for reading MoTeC .ld telemetry files

181 lines (180 loc) 6.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LdHead = exports.LdEvent = exports.LdVenue = exports.LdVehicle = void 0; const utils_js_1 = require("./utils.js"); /** * Vehicle information */ class LdVehicle { constructor(id, weight, type, comment) { this.id = id; this.weight = weight; this.type = type; this.comment = comment; } static fromFile(reader) { // fmt = '<64s 128x I 32s 32s' const id = (0, utils_js_1.decodeString)(reader.readBytes(64)); reader.skip(128); const weight = reader.readUInt32LE(); const type = (0, utils_js_1.decodeString)(reader.readBytes(32)); const comment = (0, utils_js_1.decodeString)(reader.readBytes(32)); return new LdVehicle(id, weight, type, comment); } toString() { return `${this.id} (type: ${this.type}, weight: ${this.weight}, ${this.comment})`; } } exports.LdVehicle = LdVehicle; /** * Venue information */ class LdVenue { constructor(name, vehiclePtr, vehicle) { this.name = name; this.vehiclePtr = vehiclePtr; this.vehicle = vehicle; } static fromFile(reader) { // fmt = '<64s 1034x H' const name = (0, utils_js_1.decodeString)(reader.readBytes(64)); reader.skip(1034); const vehiclePtr = reader.readUInt16LE(); let vehicle = null; if (vehiclePtr > 0) { const currentPos = reader.tell(); reader.seek(vehiclePtr); vehicle = LdVehicle.fromFile(reader); reader.seek(currentPos); } return new LdVenue(name, vehiclePtr, vehicle); } toString() { return `${this.name}; vehicle: ${this.vehicle}`; } } exports.LdVenue = LdVenue; /** * Event information */ class LdEvent { constructor(name, session, comment, venuePtr, venue) { this.name = name; this.session = session; this.comment = comment; this.venuePtr = venuePtr; this.venue = venue; } static fromFile(reader) { // fmt = '<64s 64s 1024s H' const name = (0, utils_js_1.decodeString)(reader.readBytes(64)); const session = (0, utils_js_1.decodeString)(reader.readBytes(64)); const comment = (0, utils_js_1.decodeString)(reader.readBytes(1024)); const venuePtr = reader.readUInt16LE(); let venue = null; if (venuePtr > 0) { const currentPos = reader.tell(); reader.seek(venuePtr); venue = LdVenue.fromFile(reader); reader.seek(currentPos); } return new LdEvent(name, session, comment, venuePtr, venue); } toString() { return `${this.name}; venue: ${this.venue}`; } } exports.LdEvent = LdEvent; /** * Header information of an ld file */ class LdHead { constructor(metaPtr, dataPtr, eventPtr, event, driver, vehicleId, venue, datetime, shortComment) { this.metaPtr = metaPtr; this.dataPtr = dataPtr; this.eventPtr = eventPtr; this.event = event; this.driver = driver; this.vehicleId = vehicleId; this.venue = venue; this.datetime = datetime; this.shortComment = shortComment; } static fromFile(reader) { reader.seek(0); // Read header structure // fmt = '<I 4x II 20x I 24x HHH I 8s H H I 4x 16s 16x 16s 16x 64s 64s 64x 64s 64x 1024x I 66x 64s 126x' reader.skip(4); // ldmarker reader.skip(4); // padding const metaPtr = reader.readUInt32LE(); const dataPtr = reader.readUInt32LE(); reader.skip(20); // unknown const eventPtr = reader.readUInt32LE(); reader.skip(24); // unknown reader.skip(2 + 2 + 2); // unknown static numbers reader.skip(4); // device serial reader.skip(8); // device type reader.skip(2); // device version reader.skip(2); // unknown static number reader.skip(4); // num_channs reader.skip(4); // padding const dateStr = (0, utils_js_1.decodeString)(reader.readBytes(16)); reader.skip(16); // padding const timeStr = (0, utils_js_1.decodeString)(reader.readBytes(16)); reader.skip(16); // padding const driver = (0, utils_js_1.decodeString)(reader.readBytes(64)); const vehicleId = (0, utils_js_1.decodeString)(reader.readBytes(64)); reader.skip(64); // padding const venue = (0, utils_js_1.decodeString)(reader.readBytes(64)); reader.skip(64); // padding reader.skip(1024); // padding reader.skip(4); // pro logging magic number reader.skip(66); // padding const shortComment = (0, utils_js_1.decodeString)(reader.readBytes(64)); reader.skip(126); // padding // Parse datetime let datetime; try { // Try with seconds first: "dd/mm/yyyy HH:MM:SS" const dateTimeParts = `${dateStr} ${timeStr}`.match(/(\d{2})\/(\d{2})\/(\d{4})\s+(\d{2}):(\d{2}):(\d{2})/); if (dateTimeParts) { const [, day, month, year, hour, minute, second] = dateTimeParts; datetime = new Date(parseInt(year), parseInt(month) - 1, parseInt(day), parseInt(hour), parseInt(minute), parseInt(second)); } else { // Try without seconds: "dd/mm/yyyy HH:MM" const dateTimePartsNoSec = `${dateStr} ${timeStr}`.match(/(\d{2})\/(\d{2})\/(\d{4})\s+(\d{2}):(\d{2})/); if (dateTimePartsNoSec) { const [, day, month, year, hour, minute] = dateTimePartsNoSec; datetime = new Date(parseInt(year), parseInt(month) - 1, parseInt(day), parseInt(hour), parseInt(minute), 0); } else { datetime = new Date(); } } } catch (e) { datetime = new Date(); } // Read event if present let event = null; if (eventPtr > 0) { const currentPos = reader.tell(); reader.seek(eventPtr); event = LdEvent.fromFile(reader); reader.seek(currentPos); } return new LdHead(metaPtr, dataPtr, eventPtr, event, driver, vehicleId, venue, datetime, shortComment); } toString() { return [ `driver: ${this.driver}`, `vehicleid: ${this.vehicleId}`, `venue: ${this.venue}`, `event: ${this.event?.name || 'N/A'}`, `session: ${this.event?.session || 'N/A'}`, `short_comment: ${this.shortComment}` ].join('\n'); } } exports.LdHead = LdHead;