UNPKG

@rflafla/motec-ld-reader

Version:

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

120 lines (119 loc) 4.15 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LdChan = void 0; exports.readChannels = readChannels; const utils_js_1 = require("./utils.js"); /** * Channel (meta) data * * Parses and stores the channel meta data of a channel in an ld file. * The actual data is read on demand using the 'data' property. */ class LdChan { constructor(reader, metaPtr, prevMetaPtr, nextMetaPtr, dataPtr, dataLen, dtype, freq, shift, mul, scale, dec, name, shortName, unit) { this._data = null; this.reader = reader; this.metaPtr = metaPtr; this.prevMetaPtr = prevMetaPtr; this.nextMetaPtr = nextMetaPtr; this.dataPtr = dataPtr; this.dataLen = dataLen; this.dtype = dtype; this.freq = freq; this.shift = shift; this.mul = mul; this.scale = scale; this.dec = dec; this.name = name; this.shortName = shortName; this.unit = unit; } /** * Parses and stores the header information of an ld channel in an ld file */ static fromFile(reader, metaPtr) { reader.seek(metaPtr); // Read channel structure // fmt = '<IIII H HHH hhhh 32s 8s 12s 40x' const prevMetaPtr = reader.readUInt32LE(); const nextMetaPtr = reader.readUInt32LE(); const dataPtr = reader.readUInt32LE(); const dataLen = reader.readUInt32LE(); reader.skip(2); // some counter const dtypeA = reader.readUInt16LE(); const dtypeRaw = reader.readUInt16LE(); const freq = reader.readUInt16LE(); const shift = reader.readInt16LE(); const mul = reader.readInt16LE(); const scale = reader.readInt16LE(); const dec = reader.readInt16LE(); const name = (0, utils_js_1.decodeString)(reader.readBytes(32)); const shortName = (0, utils_js_1.decodeString)(reader.readBytes(8)); const unit = (0, utils_js_1.decodeString)(reader.readBytes(12)); reader.skip(40); // padding // Determine data type // dtypeRaw is the number of bytes let dtype = null; if (dtypeA === 0x07) { // Float types if (dtypeRaw === 2) { dtype = 'float16'; } else if (dtypeRaw === 4) { dtype = 'float32'; } } else if ([0, 0x03, 0x05].includes(dtypeA)) { // Integer types if (dtypeRaw === 2) { dtype = 'int16'; } else if (dtypeRaw === 4) { dtype = 'int32'; } } else if (dtypeA === 0x08) { dtype = 'gps'; } else if (dtypeA === 0x06) { dtype = 'timestamp'; } return new LdChan(reader, metaPtr, prevMetaPtr, nextMetaPtr, dataPtr, dataLen, dtype, freq, shift, mul, scale, dec, name, shortName, unit); } /** * Read the data words of the channel (lazy loading) */ get data() { if (this.dtype === null) { throw new Error(`Channel ${this.name} has unknown data type`); } if (this._data === null) { // Read raw data const rawData = this.reader.readNumericArray(this.dataPtr, this.dataLen, this.dtype); // Apply scaling: (raw/scale * 10^(-dec) + shift) * mul this._data = rawData.map(value => (value / this.scale * Math.pow(10, -this.dec) + this.shift) * this.mul); } return this._data; } toString() { return `chan ${this.name} (${this.shortName}) [${this.unit}], ${this.freq} Hz`; } } exports.LdChan = LdChan; /** * Read channel data inside ld file * * Cycles through the channels inside an ld file, * starting with the one where metaPtr points to. * Returns a list of LdChan objects. */ function readChannels(reader, metaPtr) { const channels = []; let currentPtr = metaPtr; while (currentPtr !== 0) { const chan = LdChan.fromFile(reader, currentPtr); channels.push(chan); currentPtr = chan.nextMetaPtr; } return channels; }