@foxglove/ulog
Version:
PX4 ULog file reader
309 lines • 15.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const ULog_1 = require("./ULog");
const enums_1 = require("./enums");
const FileReader_1 = require("./node/FileReader");
jest.setTimeout(1000 * 30);
describe("ULog sample.ulg", () => {
const sampleFixture = path_1.default.join(__dirname, "..", "tests", "sample.ulg");
it("open()", async () => {
const reader = new FileReader_1.FileReader(sampleFixture);
const ulog = new ULog_1.ULog(reader);
await ulog.open();
const header = ulog.header;
expect(header.version).toBe(0);
expect(header.timestamp).toBe(112500176n);
expect(header.flagBits).toBeUndefined();
expect(header.information.size).toBe(4);
expect(header.information.get("ver_sw")).toBe("fd483321a5cf50ead91164356d15aa474643aa73");
expect(header.information.get("ver_hw")).toBe("AUAV_X21");
expect(header.information.get("sys_name")).toBe("PX4");
expect(header.information.get("time_ref_utc")).toBe(0);
expect(header.parameters.size).toEqual(493);
expect(header.parameters.get("RC12_TRIM")).toEqual({ defaultTypes: 0, value: 1500 });
expect(header.parameters.get("SENS_BARO_QNH")).toEqual({ defaultTypes: 0, value: 1013.25 });
expect(header.definitions.size).toEqual(103);
const esc_status = header.definitions.get("esc_status");
expect(esc_status).toBeDefined();
expect(esc_status.name).toBe("esc_status");
expect(esc_status.fields).toHaveLength(6);
const timestamp = esc_status.fields[0];
expect(timestamp.name).toBe("timestamp");
expect(timestamp.isComplex).toBe(false);
expect(timestamp.type).toBe("uint64_t");
const counter = esc_status.fields[1];
expect(counter.name).toBe("counter");
expect(counter.isComplex).toBe(false);
expect(counter.type).toBe("uint16_t");
const esc_count = esc_status.fields[2];
expect(esc_count.name).toBe("esc_count");
expect(esc_count.isComplex).toBe(false);
expect(esc_count.type).toBe("uint8_t");
const esc_connectiontype = esc_status.fields[3];
expect(esc_connectiontype.name).toBe("esc_connectiontype");
expect(esc_connectiontype.isComplex).toBe(false);
expect(esc_connectiontype.type).toBe("uint8_t");
const padding0 = esc_status.fields[4];
expect(padding0.name).toBe("_padding0");
expect(padding0.isComplex).toBe(false);
expect(padding0.type).toBe("uint8_t");
expect(padding0.arrayLength).toBe(4);
const esc = esc_status.fields[5];
expect(esc.name).toBe("esc");
expect(esc.isComplex).toBe(true);
expect(esc.type).toBe("esc_report");
expect(esc.arrayLength).toBe(8);
void reader.close();
});
it("readMessages()", async () => {
const reader = new FileReader_1.FileReader(sampleFixture);
const ulog = new ULog_1.ULog(reader);
await ulog.open();
let prevTimestamp = 0n;
for await (const msg of ulog.readMessages()) {
if (msg.type === enums_1.MessageType.Data) {
// eslint-disable-next-line jest/no-conditional-expect
expect(msg.value.timestamp).toBeGreaterThanOrEqual(prevTimestamp);
prevTimestamp = msg.value.timestamp;
}
else if (msg.type === enums_1.MessageType.Log || msg.type === enums_1.MessageType.LogTagged) {
// eslint-disable-next-line jest/no-conditional-expect
expect(msg.timestamp).toBeGreaterThanOrEqual(prevTimestamp);
prevTimestamp = msg.timestamp;
}
}
void reader.close();
});
it("readMessages() reverse", async () => {
const reader = new FileReader_1.FileReader(sampleFixture);
const ulog = new ULog_1.ULog(reader);
await ulog.open();
let prevTimestamp = BigInt(Number.MAX_SAFE_INTEGER);
for await (const msg of ulog.readMessages({ reverse: true })) {
if (msg.type === enums_1.MessageType.Data) {
// eslint-disable-next-line jest/no-conditional-expect
expect(msg.value.timestamp).toBeLessThanOrEqual(prevTimestamp);
prevTimestamp = msg.value.timestamp;
}
else if (msg.type === enums_1.MessageType.Log || msg.type === enums_1.MessageType.LogTagged) {
// eslint-disable-next-line jest/no-conditional-expect
expect(msg.timestamp).toBeLessThanOrEqual(prevTimestamp);
prevTimestamp = msg.timestamp;
}
}
void reader.close();
});
it("MessageAddLogged", async () => {
const reader = new FileReader_1.FileReader(sampleFixture);
const ulog = new ULog_1.ULog(reader);
await ulog.open();
let subscribe;
for await (const msg of ulog.readMessages()) {
if (msg.type === enums_1.MessageType.AddLogged) {
subscribe = msg;
break;
}
}
expect(subscribe).toBeDefined();
expect(subscribe.type).toBe(enums_1.MessageType.AddLogged);
expect(subscribe.size).toBe(19);
expect(subscribe.multiId).toBe(0);
expect(subscribe.msgId).toBe(0);
expect(subscribe.messageName).toBe("vehicle_attitude");
void reader.close();
});
it("MessageDataParsed", async () => {
const reader = new FileReader_1.FileReader(sampleFixture);
const ulog = new ULog_1.ULog(reader);
await ulog.open();
let data;
for await (const msg of ulog.readMessages()) {
if (msg.type === enums_1.MessageType.Data && msg.msgId === 0) {
data = msg;
break;
}
}
expect(data).toBeDefined();
expect(data.type).toBe(enums_1.MessageType.Data);
expect(data.size).toBe(38);
expect(data.msgId).toBe(0);
expect(data.data.byteLength).toBe(36);
expect(data.data[0]).toBe(99);
expect(data.data[data.data.byteLength - 1]).toBe(190);
expect(data.value).toEqual({
timestamp: 112574307n,
rollspeed: -0.0004259266424924135,
pitchspeed: 0.000473720021545887,
yawspeed: 0.0008371851872652769,
q: [0.9545906186103821, 0.041478633880615234, 0.048174899071455, -0.2910595238208771],
});
void reader.close();
});
});
describe("ULog sample_appended.ulg", () => {
const sampleFixture = path_1.default.join(__dirname, "..", "tests", "sample_appended.ulg");
it("open()", async () => {
const reader = new FileReader_1.FileReader(sampleFixture);
const ulog = new ULog_1.ULog(reader);
await ulog.open();
const header = ulog.header;
expect(header.version).toBe(1);
expect(header.timestamp).toBe(5115156n);
expect(header.flagBits).toEqual({
appendedOffsets: [4530735n, 0n, 0n],
compatibleFlags: [0, 0, 0, 0, 0, 0, 0, 0],
incompatibleFlags: [1, 0, 0, 0, 0, 0, 0, 0],
size: 40,
type: 66,
});
expect(header.information.size).toBe(47);
expect(Object.fromEntries(header.information)).toEqual({
ver_sw: "f54a6c2999e1e2fcbf56dd89de06b615b4186a6e",
ver_sw_release: 17170432,
ver_hw: "PX4FMU_V4",
sys_name: "PX4",
sys_os_name: "NuttX",
ver_sw_branch: "ulog_crash_dump",
sys_os_ver: "8b81cf5c7ece0c228eaaea3e9d8e667fc4d21a06",
sys_os_ver_release: 192,
sys_toolchain: "GNU GCC",
sys_toolchain_ver: "5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496]",
sys_mcu: "STM32F42x, rev. 3",
sys_uuid: "004F00413335510D30383336",
time_ref_utc: 0,
"perf_counter_preflight-00": "navigator: 3 events, 80us elapsed, 26us avg, min 25us max 28us 1.528us rms",
"perf_counter_preflight-01": "mc_att_control: 766 events, 38087us elapsed, 49us avg, min 23us max 395us 32.174us rms",
"perf_counter_preflight-02": "logger_sd_fsync: 0 events, 0us elapsed, 0us avg, min 0us max 0us 0.000us rms",
"perf_counter_preflight-03": "logger_sd_write: 3 events, 72442us elapsed, 24147us avg, min 10us max 36356us 20904.014us rms",
"perf_counter_preflight-04": "mavlink_txe: 226 events",
"perf_counter_preflight-05": "mavlink_el: 1016 events, 163693us elapsed, 161us avg, min 84us max 2478us 191.598us rms",
"perf_counter_preflight-06": "mavlink_txe: 0 events",
"perf_counter_preflight-07": "mavlink_el: 286 events, 33394us elapsed, 116us avg, min 46us max 1851us 166.045us rms",
"perf_counter_preflight-08": "mavlink_txe: 0 events",
"perf_counter_preflight-09": "mavlink_el: 318 events, 48587us elapsed, 152us avg, min 66us max 2327us 259.293us rms",
"perf_counter_preflight-10": "mavlink_txe: 0 events",
"perf_counter_preflight-11": "mavlink_el: 1030 events, 214017us elapsed, 207us avg, min 79us max 4163us 310.871us rms",
"perf_counter_preflight-12": "ctl_lat: 321 events, 13187us elapsed, 41us avg, min 38us max 111us 11.183us rms",
"perf_counter_preflight-13": "stack_check: 7 events, 69us elapsed, 9us avg, min 2us max 16us 4.488us rms",
"perf_counter_preflight-14": "sensors: 826 events, 93853us elapsed, 113us avg, min 65us max 5118us 179.764us rms",
"perf_counter_preflight-15": "ctrl_latency: 321 events, 40037us elapsed, 124us avg, min 103us max 3022us 166.815us rms",
"perf_counter_preflight-16": "mpu9250_dupe: 898 events",
"perf_counter_preflight-17": "mpu9250_reset: 0 events",
"perf_counter_preflight-18": "mpu9250_good_trans: 3443 events",
"perf_counter_preflight-19": "mpu9250_bad_reg: 0 events",
"perf_counter_preflight-20": "mpu9250_bad_trans: 0 events",
"perf_counter_preflight-21": "mpu9250_read: 4342 events, 269357us elapsed, 62us avg, min 41us max 91us 13.632us rms",
"perf_counter_preflight-22": "mpu9250_gyro_read: 0 events",
"perf_counter_preflight-23": "mpu9250_acc_read: 2 events",
"perf_counter_preflight-24": "mpu9250_mag_duplicates: 3066 events",
"perf_counter_preflight-25": "mpu9250_mag_overflows: 0 events",
"perf_counter_preflight-26": "mpu9250_mag_overruns: 51 events",
"perf_counter_preflight-27": "mpu9250_mag_errors: 0 events",
"perf_counter_preflight-28": "mpu9250_mag_reads: 0 events",
"perf_counter_preflight-29": "adc_samples: 3024 events, 8046us elapsed, 2us avg, min 2us max 3us 0.474us rms",
"perf_counter_preflight-30": "ms5611_com_err: 0 events",
"perf_counter_preflight-31": "ms5611_measure: 321 events, 5603us elapsed, 17us avg, min 8us max 679us 54.355us rms",
"perf_counter_preflight-32": "ms5611_read: 320 events, 23168us elapsed, 72us avg, min 13us max 543us 49.197us rms",
"perf_counter_preflight-33": "dma_alloc: 4 events",
});
expect(header.parameters.size).toEqual(713);
expect(header.parameters.get("RC12_TRIM")).toEqual({ defaultTypes: 0, value: 1500 });
expect(header.parameters.get("SENS_BARO_QNH")).toEqual({ defaultTypes: 0, value: 1013.25 });
expect(header.definitions.size).toEqual(110);
const esc_status = header.definitions.get("esc_status");
expect(esc_status).toBeDefined();
expect(esc_status.name).toBe("esc_status");
expect(esc_status.fields).toHaveLength(6);
const timestamp = esc_status.fields[0];
expect(timestamp.name).toBe("timestamp");
expect(timestamp.isComplex).toBe(false);
expect(timestamp.type).toBe("uint64_t");
const counter = esc_status.fields[1];
expect(counter.name).toBe("counter");
expect(counter.isComplex).toBe(false);
expect(counter.type).toBe("uint16_t");
const esc_count = esc_status.fields[2];
expect(esc_count.name).toBe("esc_count");
expect(esc_count.isComplex).toBe(false);
expect(esc_count.type).toBe("uint8_t");
const esc_connectiontype = esc_status.fields[3];
expect(esc_connectiontype.name).toBe("esc_connectiontype");
expect(esc_connectiontype.isComplex).toBe(false);
expect(esc_connectiontype.type).toBe("uint8_t");
const padding0 = esc_status.fields[4];
expect(padding0.name).toBe("_padding0");
expect(padding0.isComplex).toBe(false);
expect(padding0.type).toBe("uint8_t");
expect(padding0.arrayLength).toBe(4);
const esc = esc_status.fields[5];
expect(esc.name).toBe("esc");
expect(esc.isComplex).toBe(true);
expect(esc.type).toBe("esc_report");
expect(esc.arrayLength).toBe(8);
void reader.close();
});
});
describe("log_6_2021-7-20-11-41-56.ulg", () => {
const sampleFixture = path_1.default.join(__dirname, "..", "tests", "log_6_2021-7-20-11-41-56.ulg");
it("should parse", async () => {
const reader = new FileReader_1.FileReader(sampleFixture);
const ulog = new ULog_1.ULog(reader);
await ulog.open();
expect(ulog.messageCount()).toBe(1023911);
await reader.close();
});
});
describe("truncated.ulg", () => {
const sampleFixture = path_1.default.join(__dirname, "..", "tests", "truncated.ulg");
it("should parse", async () => {
const reader = new FileReader_1.FileReader(sampleFixture);
const ulog = new ULog_1.ULog(reader);
await ulog.open();
expect(ulog.messageCount()).toBe(187433);
await reader.close();
});
});
describe("README.md", () => {
const sampleFixture = path_1.default.join(__dirname, "..", "tests", "sample.ulg");
it("example code works", async () => {
const reader = new FileReader_1.FileReader(sampleFixture);
const ulog = new ULog_1.ULog(reader);
await ulog.open(); // required before any other operations
expect(ulog.messageCount()).toBe(64599); // ex: 64599
expect(ulog.timeRange()).toEqual([0n, 181493506n]); // ex: [ 0n, 181493506n ]
const msgIdCounts = new Map();
for await (const msg of ulog.readMessages()) {
if (msg.type === enums_1.MessageType.Data) {
// NOTE: `msg.value` holds the deserialized message
msgIdCounts.set(msg.msgId, (msgIdCounts.get(msg.msgId) ?? 0) + 1);
}
}
const msgCounts = Object.fromEntries(Array.from(msgIdCounts.entries()).map(([id, count]) => [
ulog.subscriptions.get(id).name,
count,
]));
expect(msgCounts).toEqual({
vehicle_attitude: 6461,
actuator_outputs: 1311,
telemetry_status: 70,
vehicle_status: 294,
commander_state: 678,
vehicle_attitude_setpoint: 3272,
vehicle_rates_setpoint: 6448,
actuator_controls_0: 3269,
vehicle_local_position: 678,
ekf2_innovations: 3271,
sensor_preflight: 17072,
sensor_combined: 17070,
control_state: 3268,
estimator_status: 1311,
cpuload: 69,
});
await reader.close();
});
});
//# sourceMappingURL=ULog.test.js.map