Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 18 additions & 30 deletions lib/plugins/Label_4J_POS.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ describe('Label 4J POS', () => {
});
});

// Disabled due to checksum mismatch. Possibly non-ascii characters in message?
test.skip('decodes msg 1', () => {
test('decodes inmarsat', () => {
// https://app.airframes.io/messages/2434848463
message.text =
'POS/ID91459S,BANKR31,/DC03032024,142813/MR64,0/ET31539/PSN39277W077359,142800,240,N39300W077110,031430,N38560W077150,M28,27619,MT370/CG311,160,350/FB732/VR329071';
Expand All @@ -31,35 +30,24 @@ describe('Label 4J POS', () => {
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.formatted.description).toBe('Position Report');
expect(decodeResult.raw.message_timestamp).toBe(1709476093);
expect(decodeResult.raw.tail).toBe('91459S');
expect(decodeResult.raw.flight_number).toBe('BANKR31');
expect(decodeResult.raw.mission_number).toBe('');
expect(decodeResult.formatted.items.length).toBe(9);
expect(decodeResult.formatted.items[0].label).toBe('Tail');
expect(decodeResult.formatted.items[0].value).toBe('91459S');
expect(decodeResult.formatted.items[1].label).toBe('Flight Number');
expect(decodeResult.formatted.items[1].value).toBe('BANKR31');
expect(decodeResult.formatted.items[2].label).toBe('Day of Month');
expect(decodeResult.formatted.items[2].value).toBe('3');
expect(decodeResult.formatted.items[3].label).toBe(
'Estimated Time of Arrival',
);
expect(decodeResult.formatted.items[3].value).toBe('15:39:00');
expect(decodeResult.formatted.items[4].label).toBe('Aircraft Position');
expect(decodeResult.formatted.items[4].value).toBe('39.462 N, 77.598 W');
expect(decodeResult.formatted.items[5].label).toBe('Aircraft Route');
expect(decodeResult.formatted.items[5].value).toBe(
'(39.500 N, 77.183 W)@14:28:00 > (38.933 N, 77.250 W)@03:14:30 > ?',
);
expect(decodeResult.formatted.items[6].label).toBe('Altitude');
expect(decodeResult.formatted.items[6].value).toBe('24000 feet');
expect(decodeResult.formatted.items[7].label).toBe(
'Outside Air Temperature (C)',
);
expect(decodeResult.formatted.items[7].value).toBe('-28 degrees');
expect(decodeResult.formatted.items[8].label).toBe('Message Checksum');
expect(decodeResult.formatted.items[8].value).toBe('0x9071');
expect(decodeResult.remaining.text).toBe(
'MR64,0,27619,MT370/CG311,160,350/FB732/VR32',
);
expect(decodeResult.raw.message_date).toBe('03032024');
expect(decodeResult.raw.day).toBe(3);
expect(decodeResult.raw.eta_time).toBe(56340);
expect(decodeResult.raw.position.latitude).toBeCloseTo(39.462, 3);
expect(decodeResult.raw.position.longitude).toBeCloseTo(-77.598, 3);
expect(decodeResult.raw.altitude).toBe(24000);
expect(decodeResult.raw.route.waypoints.length).toBe(3);
expect(decodeResult.raw.outside_air_temperature).toBe(-28);
expect(decodeResult.raw.center_of_gravity).toBe(31.1);
expect(decodeResult.raw.cg_lower_limit).toBe(16);
expect(decodeResult.raw.cg_upper_limit).toBe(35);
expect(decodeResult.raw.fuel_on_board).toBe(732);
expect(decodeResult.raw.version).toBe(3.2);
expect(decodeResult.formatted.items.length).toBe(14);
expect(decodeResult.remaining.text).toBe('MR64,0,27619,MT370');
});

test('decodes <invalid>', () => {
Expand Down
2 changes: 1 addition & 1 deletion lib/plugins/Label_4N.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class Label_4N extends DecoderPlugin {
if (fields[12].length > 1) {
ResultFormatter.alternateRunway(decodeResult, fields[12].split('/')[0]);
}
ResultFormatter.checksum(decodeResult, fields[32]);
ResultFormatter.checksum(decodeResult, parseInt(fields[32], 16));
ResultFormatter.unknownArr(
decodeResult,
[...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter(
Expand Down
3 changes: 2 additions & 1 deletion lib/plugins/Label_H1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export class Label_H1 extends DecoderPlugin {
} else if (parts.length === 1) {
decoded = H1Helper.decodeH1Message(decodeResult, msg);
} else if (parts.length == 2) {
const offset = isNaN(parseInt(parts[1][1])) ? 3 : 4;
// need a better way to figure this out
const offset = parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4;
Comment on lines +39 to +40
Copy link

@coderabbitai coderabbitai bot Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the actual code in Label_H1.ts around lines 39-40
find . -type f -name "Label_H1.ts" | head -5

Repository: airframesio/acars-decoder-typescript

Length of output: 105


🏁 Script executed:

# Search for test files related to H1 or Label_H1
find . -type f -name "*test*" -o -name "*spec*" | grep -i h1

Repository: airframesio/acars-decoder-typescript

Length of output: 723


🏁 Script executed:

# Let's also look for fixture or example data files
find . -type f \( -name "*.json" -o -name "*.txt" -o -name "*.fixture*" \) | xargs grep -l "^-\s*#M" 2>/dev/null | head -10

Repository: airframesio/acars-decoder-typescript

Length of output: 62


🏁 Script executed:

# Let's examine the actual code in Label_H1.ts around lines 39-40
cat -n ./lib/plugins/Label_H1.ts | sed -n '30,50p'

Repository: airframesio/acars-decoder-typescript

Length of output: 1329


🏁 Script executed:

# Let's look at the test file to see what message formats are tested
cat -n ./lib/plugins/Label_H1.test.ts | head -100

Repository: airframesio/acars-decoder-typescript

Length of output: 744


🏁 Script executed:

# Let's look at H1_FTX test file for actual message examples
cat -n ./lib/plugins/Label_H1_FTX.test.ts | head -150

Repository: airframesio/acars-decoder-typescript

Length of output: 4285


🏁 Script executed:

# Let's also check H1_FPN test file
cat -n ./lib/plugins/Label_H1_FPN.test.ts | head -150

Repository: airframesio/acars-decoder-typescript

Length of output: 9786


🏁 Script executed:

# Search for all message text patterns in test files to identify actual message formats
rg "message\.text\s*=" ./lib/plugins/Label_H1*.test.ts -A 1 | grep -oE "'[^']*'" | head -30

Repository: airframesio/acars-decoder-typescript

Length of output: 2431


🏁 Script executed:

# Specifically search for any '- `#M`' patterns with digits
rg "'\s*-\s*#M[0-9]" ./lib/plugins/ -r '$0' 2>/dev/null

Repository: airframesio/acars-decoder-typescript

Length of output: 62


🏁 Script executed:

# Let's check if there are any patterns like '- `#T1B`' or similar
rg "'\s*-\s*#[MT][0-9]" ./lib/plugins/ -r '$0' 2>/dev/null

Repository: airframesio/acars-decoder-typescript

Length of output: 62


🏁 Script executed:

# Let's check the H1_helper to understand the message structure better
cat -n ./lib/utils/h1_helper.ts | head -100

Repository: airframesio/acars-decoder-typescript

Length of output: 4289


🏁 Script executed:

# Look for any comments or documentation about H1 message formats
rg -i "message.*format|format.*message" ./lib/ -B 2 -A 2 | head -80

Repository: airframesio/acars-decoder-typescript

Length of output: 4625


🏁 Script executed:

# Check if there are any other references to parts[1][1] or offset logic
rg "parts\[1\]\[1\]" ./lib/ -B 3 -A 3

Repository: airframesio/acars-decoder-typescript

Length of output: 593


🏁 Script executed:

# Check if there's any git history showing when this condition was added
git log --oneline --all -S "parts[0] === '- '" -- ./lib/plugins/Label_H1.ts | head -5

Repository: airframesio/acars-decoder-typescript

Length of output: 110


🏁 Script executed:

# Let's also verify the complete split logic by looking at what the msg variable contains
cat -n ./lib/plugins/Label_H1.ts | sed -n '25,50p'

Repository: airframesio/acars-decoder-typescript

Length of output: 1532


🏁 Script executed:

# Let's check the git commit to see what was changed
git show 3c8ed5b --stat | head -20

Repository: airframesio/acars-decoder-typescript

Length of output: 879


🏁 Script executed:

# Let's verify the complete logic by examining what `msg` is before the split
cat -n ./lib/plugins/Label_H1.ts | sed -n '1,25p'

Repository: airframesio/acars-decoder-typescript

Length of output: 1064


🏁 Script executed:

# Let's check the exact change that introduced the parts[0] === '- ' condition
git show 3c8ed5b -- lib/plugins/Label_H1.ts | grep -A 10 -B 10 "parts\[0\]"

Repository: airframesio/acars-decoder-typescript

Length of output: 1502


🏁 Script executed:

# Let's also check if there are any other tests that might use '- `#M1`' or similar patterns
rg "- #" ./lib/plugins/*.test.ts -n | head -20

Repository: airframesio/acars-decoder-typescript

Length of output: 484


🏁 Script executed:

# Search for test patterns with escaped characters
rg '\- #' ./lib/plugins/*.test.ts -n | head -20

Repository: airframesio/acars-decoder-typescript

Length of output: 841


🏁 Script executed:

# Let's check all test cases in the H1 tests that use the "- #" prefix
grep -rn "- #" ./lib/plugins/Label_H1*.test.ts | head -30

Repository: airframesio/acars-decoder-typescript

Length of output: 190


🏁 Script executed:

# Let's trace through the logic with concrete examples
# For '- `#MDFTX/ID77170A`,...':
# - msg = '- `#MDFTX/ID77170A`,...'
# - parts = msg.split('#') = ['- ', 'MDFTX/ID77170A,...']
# - parts[0] = '- ' (length 2)
# - parts[1][1] = 'D'
# Let's verify the exact message format in the test
cat -n ./lib/plugins/Label_H1_FTX.test.ts | sed -n '37,65p'

Repository: airframesio/acars-decoder-typescript

Length of output: 1853


🏁 Script executed:

# Let's verify what the offset calculation should be for '- `#MDFTX`' format
python3 << 'EOF'
msg = '- `#MDFTX/ID77170A`,RCH836,ABZ01G6XH273/MR2,/FXIRAN IS LAUNCHING MISSILES'
parts = msg.split('#')
print(f"msg = '{msg}'")
print(f"parts[0] = '{parts[0]}' (length {len(parts[0])})")
print(f"parts[1] = '{parts[1]}'")
print(f"parts[1][1] = '{parts[1][1]}'")

# Current logic
offset_current = 3 if (parts[0] == '- ' or int(parts[1][1]) != int(parts[1][1])) else 4
# Simulating: parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4
import math
is_nan = math.isnan(float(parts[1][1])) if parts[1][1] not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' else True
offset_current = 3 if (parts[0] == '- ' or is_nan) else 4
print(f"\nFor '- `#MDFTX`' (D is non-numeric):")
print(f"  isNaN(parseInt('D')) = True")
print(f"  offset = 3")
print(f"  msg.slice({len(parts[0])} + 3) = msg.slice({len(parts[0]) + 3})")
print(f"  Result: '{msg[len(parts[0]) + 3:]}'")

# Hypothetical '- `#M1B`' message
msg2 = '- `#M1BFTX/ID77170A`,RCH836'
parts2 = msg2.split('#')
print(f"\nFor hypothetical '- `#M1BFTX`' (1 is numeric):")
print(f"  parts[1][1] = '{parts2[1][1]}'")
print(f"  isNaN(parseInt('1')) = False")
print(f"  WITH parts[0] === '- ': offset = 3, msg.slice({len(parts2[0]) + 3}) = '{msg2[len(parts2[0]) + 3:]}'")
print(f"  WITHOUT parts[0] === '- ': offset = 4, msg.slice({len(parts2[0]) + 4}) = '{msg2[len(parts2[0]) + 4:]}'")
EOF

Repository: airframesio/acars-decoder-typescript

Length of output: 729


Remove the redundant parts[0] === '- ' condition that introduces a latent offset bug.

For all currently tested '- #MD...' messages, the second character is 'D' (non-numeric), so isNaN(parseInt('D')) already returns true and produces the correct offset = 3. The new parts[0] === '- ' clause adds no value for known cases.

However, it creates a latent bug: if a '- #M1B...' or '- #T1B...' message is ever encountered, the condition forces offset = 3 (incorrect) instead of the proper 4. For example, with '- #M1BFTX/...', slicing at 2 + 3 = 5 yields 'BFTX/...' (includes trailing B), while correct offset of 4 would yield 'FTX/...'.

The inline comment already acknowledges this approach is fragile. Remove the redundant clause:

♻️ Suggested simplification
-      // need a better way to figure this out
-      const offset = parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4;
+      // offset: 3 for '#MD...' style (non-numeric 2nd char), 4 for '#M1B...' style
+      const offset = isNaN(parseInt(parts[1][1])) ? 3 : 4;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// need a better way to figure this out
const offset = parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4;
// offset: 3 for '#MD...' style (non-numeric 2nd char), 4 for '#M1B...' style
const offset = isNaN(parseInt(parts[1][1])) ? 3 : 4;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/plugins/Label_H1.ts` around lines 39 - 40, The ternary that computes
offset in Label_H1.ts currently includes a redundant parts[0] === '- ' check
which can force an incorrect offset for messages like '- `#M1B`...' — replace the
expression const offset = parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3
: 4; with a simpler check that only uses the numeric test (e.g., const offset =
isNaN(parseInt(parts[1][1])) ? 3 : 4;) so offset is 3 when the second char is
non-numeric and 4 when numeric; keep or update the inline comment to note
fragility around slicing logic in the function that uses parts/offset.

Copy link
Collaborator Author

@makrsmark makrsmark Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the suggestion does not work for the example that is - #M1FPN...

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for test messages that contain the '- `#M1`' pattern
rg "- `#M1`" lib/plugins/Label_H1*.test.ts -n -C3

Length of output: 404


🏁 Script executed:

#!/bin/bash
# Search for test messages that contain the '- `#M1`' pattern (properly escaped)
rg '- `#M1`' lib/plugins/Label_H1*.test.ts -n -C3

Length of output: 404


🏁 Script executed:

#!/bin/bash
# Search for test messages containing '- `#M1`' pattern using -e flag
rg -e '- `#M1`' lib/plugins/Label_H1*.test.ts -n -C3

# Also search for messages starting with '- `#M`' more broadly
rg -e '- `#M`' lib/plugins/Label_H1*.test.ts -n -C2

# Look at the actual H1_FPN test file to see the inmarsat test
cat lib/plugins/Label_H1_FPN.test.ts | grep -A5 -B5 "inmarsat"

Length of output: 3158


🏁 Script executed:

#!/bin/bash
# Search for messages containing M1 in test files
rg 'M1' lib/plugins/Label_H1*.test.ts -n -B2 -A2 | head -80

# Also look for the specific pattern in the FPN test file since user mentioned M1FPN
cat lib/plugins/Label_H1_FPN.test.ts

Length of output: 27333


@makrsmark, you're absolutely right—thank you for the correction! My analysis was incorrect.

For a message like '- #M1FPN/...':

  • parts[0] = '- ' and parts[1][1] = '1' (numeric)
  • Current code: parts[0] === '- ' returns trueoffset = 3msg.slice(2+3) skips '- #M1' → correctly decodes 'FPN/...'
  • My suggestion: isNaN(parseInt('1')) returns falseoffset = 4msg.slice(2+4) skips '- #M1F' → incorrectly decodes 'PN/...'

The current logic is correct: when the prefix is '- ', the offset should always be 3 (to skip the 3 characters after #), regardless of whether parts[1][1] is numeric. My suggestion would break this case.

I apologize for the confusion! The parts[0] === '- ' condition is necessary, not redundant.

  /\_/\
 ( o.o )
  > ^ <
(Sorry!)

🧬 Code Graph Analysis Results
  • File: lib/utils/result_formatter.ts

    • Snippet:
      static flightNumber(decodeResult: DecodeResult, value: string) {
      if (value.length === 0) {
      return;
      }
      decodeResult.raw.flight_number = value;
      decodeResult.formatted.items.push({
      type: 'flight_number',
      code: 'FLIGHT',
      label: 'Flight Number',
      value: decodeResult.raw.flight_number,
      });
      }
    • This snippet is relevant because Label_H1 uses ResultFormatter.flightNumber(...) when parsing an H1 message that starts with a flight number prefix (as seen in the code path handling parts[0]). Understanding this function helps interpret how flight numbers get recorded in the decode result.
  • File: lib/utils/h1_helper.ts

    • Summary (docstring-style description):
      Class: H1Helper
      • Method: static decodeH1Message(decodeResult: DecodeResult, message: string)
        • Parameters:
          • decodeResult: the DecodeResult object being populated.
          • message: the H1 data payload (excluding the trailing checksum).
        • Returns: boolean indicating whether decoding succeeded.
        • Behavior:
          • Computes checksum from the last 4 hex characters of the message; validates using CRC16 IBM SDLC reversed or GENIBUS algorithms on the data portion.
          • If checksum is valid, splits data into fields (by '/'), validates message type (via parseMessageType), and processes each field key/data pair (AF, AK, CG, DC, DI, DT, DQ, ET, etc.) by invoking corresponding processing/formatter routines.
          • For each known key, it delegates to specialized handlers (e.g., processPS, processPosition, processDateCode, processETA, etc.) or records unknowns via ResultFormatter.unknown.
          • After processing all fields, it records the checksum algorithm and checksum itself.
        • Exceptions/Error handling:
          • If checksum validation fails or message type parsing fails, sets decodeResult.decoded = false and decodeResult.decoder.decodeLevel = 'none', and returns false.
        • Important implementation notes:
          • Handles many H1 field types by dispatching to helper functions (e.g., processPS, processCenterOfGravity, processDateCode, etc.).
          • On success, returns true; on failure, returns false and adjusts decode state accordingly.
        • This function is central to interpreting H1 payloads and is directly invoked by Label_H1 for various message formats.
  • File: lib/DecoderPluginInterface.ts

    • Snippet: Message interface
      export interface Message {
      label: string;
      sublabel?: string;
      text: string;
      }
    • Snippet: Options interface
      export interface Options {
      debug?: boolean;
      }
    • Snippet: DecodeResult interface
      export interface DecodeResult {
      decoded: boolean;
      decoder: {
      name: string;
      type: 'pattern-match' | 'none';
      decodeLevel: 'none' | 'partial' | 'full';
      };
      error?: string;
      formatted: {
      description: string;
      items: {
      type: string;
      code: string;
      label: string;
      value: string;
      }[];
      };
      message?: Message;
      raw: any; // eslint-disable-line @typescript-eslint/no-explicit-any
      remaining: {
      text?: string;
      };
      }
    • These interfaces define the core structures used by Label_H1.ts (Message, DecodeResult, and Options), and help explain how text messages are represented, how decoding state is tracked, and how results are formatted.
  • File: lib/DecoderPluginInterface.ts

    • Rationale: The Label_H1.ts decoder interacts with the DecodeResult, Message, and Options types defined here. Understanding the fields of DecodeResult (especially remaining.text, decoded, decoder.decodeLevel, and formatted.items) is important for diagnosing why certain inputs like "- #M1FPN..." might not be parsed as expected.

✏️ Learnings added
Learnt from: makrsmark
Repo: airframesio/acars-decoder-typescript PR: 332
File: lib/plugins/Label_H1.ts:39-40
Timestamp: 2026-02-21T01:32:00.829Z
Learning: In lib/plugins/Label_H1.ts, when parsing two-part H1 messages (split by '#'), the offset logic `parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4` is correct. The `parts[0] === '- '` condition ensures that messages like '- `#M1FPN/`...' use offset=3 to skip 3 characters after '#' ('M1' + next char), whereas messages like 'F37AKL0767#M1BFPN/...' use offset=4 to skip 4 characters ('M1B' + '/'). Removing the `parts[0] === '- '` check would break '- `#M1`...' messages where parts[1][1] is numeric.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: makrsmark
Repo: airframesio/acars-decoder-typescript PR: 309
File: lib/utils/h1_helper.ts:12-19
Timestamp: 2026-01-30T02:52:39.855Z
Learning: In H1 message decoding (lib/utils/h1_helper.ts), the checksum in incoming messages is always uppercase, so case normalization is not required when comparing against calculateChecksum() output.

decoded = H1Helper.decodeH1Message(
decodeResult,
msg.slice(parts[0].length + offset),
Expand Down
21 changes: 20 additions & 1 deletion lib/plugins/Label_H1_FPN.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ describe('Label_H1 FPN', () => {
expect(decodeResult.formatted.items[8].label).toBe('Message Checksum');
expect(decodeResult.formatted.items[8].value).toBe('0x156d');
expect(decodeResult.remaining.text).toBe(
':WS:N61000W030000,370..N61000W040000..N60000W050000..URTAK:WS:URTAK,380..LAKES:WS:LAKES,400..N57000W070000..N54300W080000..N49000W090000..DLH..COLDD/PR4356,344,360,1060,,,13,,,30,,,P50,M40,36090,,3296,292,KMSP,30L,172,215117',
':WS:N61000W030000,370..N61000W040000..N60000W050000..URTAK:WS:URTAK,380..LAKES:WS:LAKES,400..N57000W070000..N54300W080000..N49000W090000..DLH..COLDD/PR4356,344,360,1060,,,13,,,30,,,P50,M40,36090,,3296,292',
);
});

Expand Down Expand Up @@ -339,4 +339,23 @@ describe('Label_H1 FPN', () => {
expect(decodeResult.raw.checksum).toBe(0xeee6);
expect(decodeResult.formatted.items.length).toBe(1);
});

test('decodes inmarsat', () => {
message.text =
'FPN/ID80094S,RCH411,8JZ41NG3S048/MR3,5/RP:DA:KMCF:AA:LBSF:F:PIE..BRUTS.Q109.CAMJO.Q109.YURCK.Q97.PAACK.Q97.BLENO.Q97.FRIAR..TOPPS..FROSS..RIKAL..N53000W050000..N55000W040000..N56000W030000..N56000W020000..PIKIL..SOVED..MIMKU..MAC..BELOX.L603.DOLAS..NAVPI..MAVAS..SOGPO..TIVUN..ESAMA..OSBIT..KOMIB..SULUS.Z650.VEMUT..PEPIK..BERVA..ERGOM..TEGRI..OSTOV..GOL:V:CAMJO,301,AT3100,,:V:PAACK,282,AT3300,,:V:BLENO,258,AT3700,,:V:N53000W050000,256,AT3700,,:V:N55000W040000,260,AT3700,,:V:SOVED,303,AT2700,,:V:MIMKU,302,AT2700,,:V:DOLAS,290,AT2900,,:V:PEPIK,242,AT3700,,:V:BERVA,260,AT3700,,7147/WD,,,,C850';
const decodeResult = plugin.decode(message);

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.raw.tail).toBe('80094S');
expect(decodeResult.raw.flight_number).toBe('RCH411');
expect(decodeResult.raw.mission_number).toBe('8JZ41NG3S048');
expect(decodeResult.raw.route_status).toBe('RP');
expect(decodeResult.raw.departure_icao).toBe('KMCF');
expect(decodeResult.raw.arrival_icao).toBe('LBSF');
expect(decodeResult.raw.route.waypoints.length).toBe(69); //nice
expect(decodeResult.raw.checksum).toBe(0xc850);
expect(decodeResult.formatted.description).toBe('Flight Plan');
expect(decodeResult.formatted.items.length).toBe(7);
});
});
3 changes: 1 addition & 2 deletions lib/plugins/Label_H1_FTX.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ describe('Label_H1 FTX', () => {
plugin = new Label_H1(decoder);
});

// disabled due to checksum failure. could be hidden characters in the source message
test.skip('decodes Label H1 Preamble FTX valid', () => {
test('decodes inmarsat', () => {
// https://app.airframes.io/messages/3402014738
message.text =
'FTX/ID23544S,HIFI21,7VZ007B1S276/MR2,/FXFYI .. TAF KSUX 021720Z 0218 0318 20017G28KT P6SM SKC FM022200 22012G18KT P6SM SKC .. PUTS YOUR CXWIND AT 26KT ON RWY 13 .. REDUCES TO 18KT AT 22Z4FEF';
Expand Down
78 changes: 78 additions & 0 deletions lib/plugins/Label_H1_LDI.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { MessageDecoder } from '../MessageDecoder';
import { Label_H1 } from './Label_H1';

describe('Label H1 LDI', () => {
let plugin: Label_H1;
const message = { label: 'H1', text: '' };

beforeEach(() => {
const decoder = new MessageDecoder();
plugin = new Label_H1(decoder);
});

test('decodes variant 2', () => {
message.text =
'LDI/RW27R,,,,,M160,1676,,,,202003,2,,,,P8,137147150,0,,M160,,146149150,P48,2,2.27L,,,,,M160,1676,,,,202003,2,,,,P8,137147150,0,,M160,,147150151,P52,2,2.35O,,,,,M160,1676,,,,202003,2,,,,P8,127133138,0,,,,,,3:KPHL,H1007,1036,1036,1036/CG225/SN69EAE8';
const decodeResult = plugin.decode(message);

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.raw.departure_icao).toBe('KPHL');
expect(decodeResult.raw.departure_runway).toBe('27R');
expect(decodeResult.raw.center_of_gravity).toBe(22.5);
expect(decodeResult.raw.checksum).toBe(0xeae8);
expect(decodeResult.formatted.description).toBe(
'Load Distribution Information',
);
expect(decodeResult.formatted.items.length).toBe(4);
expect(decodeResult.remaining.text).toBe(
',,,,M160,1676,,,,202003,2,,,,P8,137147150,0,,M160,,146149150,P48,2,2.27L,,,,,M160,1676,,,,202003,2,,,,P8,137147150,0,,M160,,147150151,P52,2,2.35O,,,,,M160,1676,,,,202003,2,,,,P8,127133138,0,,,,,,3,H1007,1036,1036,1036',
);
});

test('decodes variant 1', () => {
message.text =
'LDI/RW16L,,,,,,1552,,P4,D7,164008,1,1,0,,P60,155159161:,,800,800,800/CG2356485';
const decodeResult = plugin.decode(message);

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.raw.departure_runway).toBe('16L');
expect(decodeResult.raw.center_of_gravity).toBe(23.5);
expect(decodeResult.raw.checksum).toBe(0x6485);
expect(decodeResult.formatted.description).toBe(
'Load Distribution Information',
);
expect(decodeResult.formatted.items.length).toBe(4);
expect(decodeResult.remaining.text).toBe(
',,,,,1552,,P4,D7,164008,1,1,0,,P60,155159161.,,800,800,800',
);
});

test('decodes response', () => {
message.text = 'RESLDI/AK,7151B9';
const decodeResult = plugin.decode(message);

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.raw.checksum).toBe(0x51b9);
expect(decodeResult.formatted.description).toBe(
'Response for Load Distribution Information',
);
expect(decodeResult.formatted.items.length).toBe(1);
expect(decodeResult.remaining.text).toBe('AK,71');
});

test('decodes request', () => {
message.text = '#MDREQLDI57CC';
const decodeResult = plugin.decode(message);

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('full');
expect(decodeResult.raw.checksum).toBe(0x57cc);
expect(decodeResult.formatted.description).toBe(
'Request for Load Distribution Information',
);
expect(decodeResult.formatted.items.length).toBe(1);
});
});
1 change: 1 addition & 0 deletions lib/plugins/Label_H1_OHMA.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ describe('Label H1 Preamble OHMA', () => {
expect(decodeResult.formatted.items[0].value).toBe('undefined');
});

// disabled because parser currently does not handle before OHMA, but here as an example.
test.skip('decodes Label H1 Preamble OHMA partial', () => {
// https://app.airframes.io/messages/3126673935
message.text =
Expand Down
40 changes: 1 addition & 39 deletions lib/plugins/Label_H1_POS.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,44 +270,6 @@ describe('Label_H1 POS', () => {
expect(decodeResult.remaining.text).toBe('272100,157');
});

// broken as there is no checksum
test.skip('# long variant', () => {
// https://app.airframes.io/messages/2366921571
message.text =
'#M1BPOSN29510W098448,RW04,140407,188,TATAR,4,140445,ALISS,M12,246048,374K,282K,1223,133,KSAT,KELP,,70,151437,415,73/PR1223,222,240,133,,44,40,252074,M22,180,P0,P0/RI:DA:KSAT:AA:KELP..TATAR:D:ALISS6:F:ALISS..FST';
const decodeResult = plugin.decode(message);

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.formatted.description).toBe('Position Report');
expect(decodeResult.formatted.items.length).toBe(10);
expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position');
expect(decodeResult.formatted.items[0].value).toBe('29.510 N, 98.448 W');
expect(decodeResult.formatted.items[1].label).toBe('Arrival Runway');
expect(decodeResult.formatted.items[1].value).toBe('04');
expect(decodeResult.formatted.items[2].label).toBe('Aircraft Groundspeed');
expect(decodeResult.formatted.items[2].value).toBe('415');
expect(decodeResult.formatted.items[3].label).toBe('Altitude');
expect(decodeResult.formatted.items[3].value).toBe('24000 feet');
expect(decodeResult.formatted.items[4].label).toBe('Route Status');
expect(decodeResult.formatted.items[4].value).toBe('Route Inactive');
expect(decodeResult.formatted.items[5].label).toBe('Origin');
expect(decodeResult.formatted.items[5].value).toBe('KSAT');
expect(decodeResult.formatted.items[6].label).toBe('Destination');
expect(decodeResult.formatted.items[6].value).toBe('KELP..TATAR'); // FIXME- should be just kelp
expect(decodeResult.formatted.items[7].label).toBe('Departure Procedure');
expect(decodeResult.formatted.items[7].value).toBe('ALISS6');
expect(decodeResult.formatted.items[8].label).toBe('Aircraft Route');
expect(decodeResult.formatted.items[8].value).toBe('ALISS >> FST');
expect(decodeResult.formatted.items[9].label).toBe('Aircraft Route');
expect(decodeResult.formatted.items[9].value).toBe(
'TATAR@14:04:07 > ALISS@14:04:45 > ?',
); // FIXME - ? should be FST
expect(decodeResult.remaining.text).toBe(
'188,4,M12,246048,374K,282K,1223,133,,70,151437,73/PR1223,222,133,,44,40,252074,M22,180,P0',
);
});

test('# variant 7', () => {
// https://app.airframes.io/messages/2434835903
message.text =
Expand Down Expand Up @@ -484,7 +446,7 @@ describe('Label_H1 POS', () => {
expect(decodeResult.formatted.items[11].label).toBe('Message Checksum');
expect(decodeResult.formatted.items[11].value).toBe('0x53b2');
expect(decodeResult.remaining.text).toBe(
'290016,191/PR1496,150,370,191,,55,10,248028,M47,30,P19,P0/FHCIV,105208,273K,3226,175,M41,252027,450,N,221,62.MEDIL,105411,267K,3439,172,M44,250028,459,N,203,15.PITHI,105533,259K,3584,170,M47,249028,456,N,203,10.LESDO,105859,252K,3700,167,M47,248028,456,N,203,25.KOVIN,110153,252K,3700,164,M47,248028,456,N,203,21.DUCRA,110705,252K,3700,160,M47,248028,456,N,213,37.RESMI,111101,251K,3700,156,M47,248028,455,N,213,28.DEKOD,111325,251K,3700,154,M47,248028,455,N,192,17.DISAK,111438,251K,3700,153,M47,248028,454,N,172,9.DIRMO,112306,251K,3700,145,M47,248028,454,N,178,63.ETAMO,112514,250K,3700,143,M47,248028,453,N,158,16.ADEKA,113339,250K,3700,136,M47,248028,454,N,147,64.MOKDI,114139,251K,3700,129,M47,248028,454,N,181,59.MEN,114429,251K,3700,127,M47,248028,454,N,181,21.BADAM,114843,251K,3700,123,M47,248028,454,N,179,31.KANIG,120154,250K,3700,111,M47,248028,453,N,185,97.KENAS,121800,250K,3700,98,M47,248028,453,N,177,119.POS,122257,250K,3018,96,M45,248023,395,N,182,34.LEIB,124503,150K,2,89,P15,000000,161,N,231,103,LEIB,,89,124503,73',
'290016,191/PR1496,150,370,191,,55,10,248028,M47,30,P19,P0/FHCIV,105208,273K,3226,175,M41,252027,450,N,221,62.MEDIL,105411,267K,3439,172,M44,250028,459,N,203,15.PITHI,105533,259K,3584,170,M47,249028,456,N,203,10.LESDO,105859,252K,3700,167,M47,248028,456,N,203,25.KOVIN,110153,252K,3700,164,M47,248028,456,N,203,21.DUCRA,110705,252K,3700,160,M47,248028,456,N,213,37.RESMI,111101,251K,3700,156,M47,248028,455,N,213,28.DEKOD,111325,251K,3700,154,M47,248028,455,N,192,17.DISAK,111438,251K,3700,153,M47,248028,454,N,172,9.DIRMO,112306,251K,3700,145,M47,248028,454,N,178,63.ETAMO,112514,250K,3700,143,M47,248028,453,N,158,16.ADEKA,113339,250K,3700,136,M47,248028,454,N,147,64.MOKDI,114139,251K,3700,129,M47,248028,454,N,181,59.MEN,114429,251K,3700,127,M47,248028,454,N,181,21.BADAM,114843,251K,3700,123,M47,248028,454,N,179,31.KANIG,120154,250K,3700,111,M47,248028,453,N,185,97.KENAS,121800,250K,3700,98,M47,248028,453,N,177,119.POS,122257,250K,3018,96,M45,248023,395,N,182,34.LEIB,124503,150K,2,89,P15,000000,161,N,231,103',
);
});

Expand Down
8 changes: 4 additions & 4 deletions lib/plugins/Label_H1_PRG.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,7 @@ describe('Label H1 Preamble PRG', () => {
);
});

// TODO Fix this test
test.skip('decodes named runway', () => {
test('decodes named runway inmarsat', () => {
message.text = 'PRG/DT,KMDW,31R,62,031854,524,N38584W077333,171,732B3C';
const decodeResult = plugin.decode(message);

Expand All @@ -142,9 +141,10 @@ describe('Label H1 Preamble PRG', () => {
expect(decodeResult.raw.arrival_runway).toBe('31R');
expect(decodeResult.raw.position.latitude).toBe(38.584);
expect(decodeResult.raw.position.longitude).toBe(-77.333);

expect(decodeResult.raw.fuel_on_board).toBe(62);
expect(decodeResult.raw.checksum).toBe(0x2b3c);
expect(decodeResult.formatted.description).toBe('Progress Report');
expect(decodeResult.formatted.items.length).toBe(0);
expect(decodeResult.formatted.items.length).toBe(6);
});

test('decodes Label H1 Preamble PRG <invalid>', () => {
Expand Down
16 changes: 16 additions & 0 deletions lib/plugins/Label_H1_REQ.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ describe('Label H1 preamble REQ', () => {
expect(decodeResult.remaining.text).toBeUndefined();
});

test('decodes REQ POS inmarsat', () => {
message.text = '#MDREQPOS/ID55150A,RCH892,LVZF1185C049/MR1,/AU39310';
const decodeResult = plugin.decode(message);

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.raw.tail).toBe('55150A');
expect(decodeResult.raw.flight_number).toBe('RCH892');
expect(decodeResult.raw.checksum).toBe(0x9310);
expect(decodeResult.formatted.description).toBe(
'Request for Position Report',
);
expect(decodeResult.formatted.items.length).toBe(3);
expect(decodeResult.remaining.text).toBe('MR1,/AU3');
});

test('decodes FPN', () => {
message.text = 'REQFPN/RN10001/RS:FP:Z5585 9736';
const decodeResult = plugin.decode(message);
Expand Down
Loading