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