From b6e4ad88834689e1c086f92d715e9f944aa0bbcf Mon Sep 17 00:00:00 2001 From: Mark Bumiller Date: Fri, 2 Aug 2024 09:00:41 -0400 Subject: [PATCH] adding OHMA decoding used on 737 MAX --- lib/plugins/Label_H1_OHMA.test.ts | 53 +++++++++++++++++++++++++++ lib/plugins/Label_H1_OHMA.ts | 59 +++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 lib/plugins/Label_H1_OHMA.test.ts create mode 100644 lib/plugins/Label_H1_OHMA.ts diff --git a/lib/plugins/Label_H1_OHMA.test.ts b/lib/plugins/Label_H1_OHMA.test.ts new file mode 100644 index 0000000..022e0d7 --- /dev/null +++ b/lib/plugins/Label_H1_OHMA.test.ts @@ -0,0 +1,53 @@ +import { MessageDecoder } from '../MessageDecoder'; +import { Label_H1_OHMA } from './Label_H1_OHMA'; + +test('matches Label H1 Preamble OHMA qualifiers', () => { + const decoder = new MessageDecoder(); + const decoderPlugin = new Label_H1_OHMA(decoder); + + expect(decoderPlugin.decode).toBeDefined(); + expect(decoderPlugin.name).toBe('label-h1-ohma'); + expect(decoderPlugin.qualifiers).toBeDefined(); + expect(decoderPlugin.qualifiers()).toEqual({ + labels: ['H1'], + preambles: ['OHMA'], + }); +}); + +test('decodes Label H1 Preamble OHMA valid', () => { + const decoder = new MessageDecoder(); + const decoderPlugin = new Label_H1_OHMA(decoder); + + // https://app.airframes.io/messages/3126721669 + const text = 'OHMAeJy1Ul2PojAU/SubPiuhlA/ljQHMkAElgDuTXTakqx2nCaAp1WQz8b/vFXTGEcw+LX26veece88p7+jARMO3NbKRpqhohCrWNHTDoH7P0arkrJbBOkd2jhaPkZOjUX6BeFSytqGpmj5WJ2NVyzC2ydTWiWJN9B8teE0lBRSIUS52Ja1ZA+VPqCXl5Xxf/WaiVZkTyzD0bsB2zcr2si1fS755kxfamu2okHvBHNDbCukCuMU+PSzSFk+F4Ada9vqLxLvSuxq9dELDtK56IdukEqZkvOpbVG0VXIJFYnYW2QFCuqzXFm5Jm+YcG2xLKyYFX32CB3V70XXQPzv2EX8R+Vn3BrxuJK1XH2HW9KxYyRgWv5gDJCSx72CnOH8dR1/RLhXl9+4f6MF1xRhgJPuSNUzeI1nE+hY5L7ZtO4/RmFjRQwj+4MNqCJf4pNhp/reosggXbhjEke8Fzrxwk2WQ+kUSZ8U/wgNi5kcxhpy9G2PENBVtqt+kcSZoQ4QJViyTDBO8YDYb4GBDwQTfUOIIx4mfpsvEH1xMhzHmfc7gbkTR1R7HcZ9m4eL53m5YmeAhTjA/jbrDMhULT08P3p0jOv4FG0dfvQ=='; + const decodeResult = decoderPlugin.decode({ text: text }); + console.log(JSON.stringify(decodeResult, null, 2)); + + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe('full'); + expect(decodeResult.decoder.name).toBe('label-h1-ohma'); + expect(decodeResult.formatted.description).toBe('OHMA Message'); + expect(decodeResult.message.text).toBe(text); + expect(decodeResult.raw.ohma).toBe('{\"version\":\"2.0\",\"message\":\"{\\\"clientId\\\":\\\"OHMA\\\",\\\"messageDate\\\":\\\"2024-08-02T11:39:43.784Z\\\",\\\"data\\\":{\\\"airplanes\\\":[{\\\"tailNumber\\\":\\\"N37554\\\",\\\"model\\\":\\\"\\\",\\\"flights\\\":[{\\\"departureAirportCode\\\":\\\"KBOS\\\",\\\"arrivalAirportCode\\\":\\\"KORD\\\",\\\"flightNumber\\\":\\\"UAL567\\\",\\\"flightLegStartTime\\\":\\\"2024-08-02T10:01:33.736Z\\\",\\\"events\\\":[{\\\"eventClassId\\\":\\\"parametric\\\",\\\"eventTime\\\":\\\"2024-08-02T11:39:43.784Z\\\",\\\"eventType\\\":\\\"OHMA_META\\\",\\\"instances\\\":[{\\\"name\\\":\\\"mtPartNumber\\\",\\\"values\\\":[\\\"\\\"]},{\\\"name\\\":\\\"mtCarlVersion\\\",\\\"values\\\":[\\\"4.5\\\"]},{\\\"name\\\":\\\"mtRulesetVersion\\\",\\\"values\\\":[\\\"737 MAX:::AHM-37MBL8-000010L:::1\\\"]}]},{\\\"eventClassId\\\":\\\"parametric\\\",\\\"eventTime\\\":\\\"2024-08-02T11:39:43.784Z\\\",\\\"eventType\\\":\\\"TM1_CLIPMEDIAN_CRUISE_RPT_A\\\",\\\"instances\\\":[{\\\"name\\\":\\\"TM1TEMP1_MED\\\",\\\"values\\\":[366.294]},{\\\"name\\\":\\\"TM1TEMP2_MED\\\",\\\"values\\\":[381.763]},{\\\"name\\\":\\\"TM1TEMPDIFF_MED\\\",\\\"values\\\":[15.131]},{\\\"name\\\":\\\"PM1PRESSURE1_MED\\\",\\\"values\\\":[34.766]},{\\\"name\\\":\\\"PM1PRESSURE2_MED\\\",\\\"values\\\":[33.406]},{\\\"name\\\":\\\"PACKFLOWDIFF_MED\\\",\\\"values\\\":[11.816]},{\\\"name\\\":\\\"PACKINPRESDIFF_MED\\\",\\\"values\\\":[6.719]}]}]}]}]}}\"}'); + expect(decodeResult.formatted.items.length).toBe(1); + expect(decodeResult.formatted.items[0].type).toBe('ohma'); + expect(decodeResult.formatted.items[0].code).toBe('OHMA'); + expect(decodeResult.formatted.items[0].label).toBe('OHMA Downlink'); + expect(decodeResult.formatted.items[0].value.length).toBe(2658)}); // instead of comparing to a giant json obj + + +test('decodes Label H1 Preamble OHMA invalid', () => { + const decoder = new MessageDecoder(); + const decoderPlugin = new Label_H1_OHMA(decoder); + + const text = 'OHMA '; + const decodeResult = decoderPlugin.decode({ text: text }); + console.log(JSON.stringify(decodeResult, null, 2)); + + expect(decodeResult.decoded).toBe(false); + expect(decodeResult.decoder.decodeLevel).toBe('none'); + expect(decodeResult.decoder.name).toBe('label-h1-ohma'); + expect(decodeResult.formatted.description).toBe('OHMA Message'); + expect(decodeResult.message.text).toBe(text); + expect(decodeResult.remaining.text).toBe(text); +}); \ No newline at end of file diff --git a/lib/plugins/Label_H1_OHMA.ts b/lib/plugins/Label_H1_OHMA.ts new file mode 100644 index 0000000..7bd7f91 --- /dev/null +++ b/lib/plugins/Label_H1_OHMA.ts @@ -0,0 +1,59 @@ +import { DecoderPlugin } from '../DecoderPlugin'; +import { DecodeResult, Message, Options } from '../DecoderPluginInterface'; + +import * as zlib from "minizlib"; + +export class Label_H1_OHMA extends DecoderPlugin { + name = 'label-h1-ohma'; + + qualifiers() { // eslint-disable-line class-methods-use-this + return { + labels: ["H1"], + preambles: ['OHMA'], //TODO - support data before # + }; + } + + decode(message: Message, options: Options = {}) : DecodeResult { + let decodeResult: any = this.defaultResult; + decodeResult.decoder.name = this.name; + decodeResult.formatted.description = 'OHMA Message'; + decodeResult.message = message; + decodeResult.remaining.text = ''; + + const data = message.text.slice(4); + + try { + const compressedBuffer = Buffer.from(data, 'base64'); + const decompress = new zlib.Inflate({windowBits: 15}); + decompress.write(compressedBuffer); + decompress.flush(zlib.constants.Z_SYNC_FLUSH); + const result = decompress.read(); + const jsonText = result.toString(); + const json = JSON.parse(jsonText); + const ohmaMsg = JSON.parse(json.message); + + decodeResult.decoded = true; + decodeResult.decoder.decodeLevel = 'full'; + decodeResult.raw.ohma = jsonText; + decodeResult.formatted.items.push({ + type: 'ohma', + code: 'OHMA' , + label: 'OHMA Downlink', + value: JSON.stringify(ohmaMsg, null, 2) + }); + } catch { + // Unknown + if (options.debug) { + console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`); + } + decodeResult.remaining.text += message.text; + decodeResult.decoded = false; + decodeResult.decoder.decodeLevel = 'none'; + } + + return decodeResult; + } +} + +export default {}; +