@rflafla/motec-ld-reader
Version:
A Node.js library for reading MoTeC .ld telemetry files
181 lines (180 loc) • 6.74 kB
JavaScript
;
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;