-
-
Notifications
You must be signed in to change notification settings - Fork 15
pull up c-band prefix decoding #174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5e8d511
00ce6ed
fe1cdc7
269b8ad
bb74b0f
c78110c
de30f33
7ba6a90
ae9655e
a448c33
9bdea5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| import { MessageDecoder } from '../MessageDecoder'; | ||
| import { CBand } from './CBand'; | ||
|
|
||
| describe('CBand', () => { | ||
| let plugin: CBand; | ||
|
|
||
| beforeEach(() => { | ||
| const decoder = new MessageDecoder(); | ||
| plugin = new CBand(decoder); | ||
| }); | ||
|
|
||
| test('matches qualifiers', () => { | ||
| expect(plugin.decode).toBeDefined(); | ||
| expect(plugin.name).toBe('c-band'); | ||
| expect(plugin.qualifiers).toBeDefined(); | ||
| expect(plugin.qualifiers()).toEqual({ | ||
| labels: ['*'], | ||
| }); | ||
| }); | ||
|
|
||
| test('decodes Label 4A', () => { | ||
| // https://app.airframes.io/messages/3461407615 | ||
| const text = | ||
| 'M60ALH0752N22456E077014OSE35 ,192027370VEX36 ,192316,M46,275043309,85220111'; | ||
| const decodeResult = plugin.decode({ label: '4A', text: text }); | ||
|
|
||
| expect(decodeResult.decoded).toBe(true); | ||
| expect(decodeResult.decoder.decodeLevel).toBe('partial'); | ||
| expect(decodeResult.decoder.name).toBe('c-band-label-4a'); | ||
| expect(decodeResult.formatted.description).toBe('Latest New Format'); | ||
| expect(decodeResult.raw.flight_number).toBe('LH752'); | ||
| expect(decodeResult.raw.position.latitude).toBe(22.456); | ||
| expect(decodeResult.raw.position.longitude).toBe(77.014); | ||
| expect(decodeResult.raw.route.waypoints.length).toBe(2); | ||
| expect(decodeResult.raw.route.waypoints[0].name).toBe('OSE35'); | ||
| expect(decodeResult.raw.route.waypoints[1].name).toBe('VEX36'); | ||
| expect(decodeResult.raw.outside_air_temperature).toBe(-46); | ||
| expect(decodeResult.formatted.items.length).toBe(5); | ||
| expect(decodeResult.remaining.text).toBe('275043309,85220111'); | ||
| }); | ||
|
|
||
| test('decodes Label 4N variant 2C (C-band)', () => { | ||
| // https://app.airframes.io/messages/3422221702 | ||
| const text = | ||
| 'M85AUP0109285,C,,10/12,,,,,NRT,ANC,ANC,07R/,33/,0,0,,,,,,0,0,0,0,1,0,,0,0,709.8,048.7,758.5,75F3'; | ||
| const decodeResult = plugin.decode({ label: '4N', text: text }); | ||
|
|
||
| expect(decodeResult.decoded).toBe(true); | ||
| expect(decodeResult.decoder.decodeLevel).toBe('partial'); | ||
| expect(decodeResult.decoder.name).toBe('c-band-label-4n'); | ||
| expect(decodeResult.formatted.description).toBe('Airline Defined'); | ||
| expect(decodeResult.raw.flight_number).toBe('UP109'); | ||
| expect(decodeResult.raw.date).toBe('10/12'); | ||
| expect(decodeResult.raw.departure_icao).toBe('NRT'); | ||
| expect(decodeResult.raw.arrival_icao).toBe('ANC'); | ||
| expect(decodeResult.raw.alternate_icao).toBe('ANC'); | ||
| expect(decodeResult.raw.arrival_runway).toBe('07R'); | ||
| expect(decodeResult.raw.alternate_runway).toBe('33'); | ||
| expect(decodeResult.raw.checksum).toBe(30195); | ||
| expect(decodeResult.remaining.text).toBe( | ||
| 'C,0,0,0,0,0,0,1,0,0,0,709.8,048.7,758.5', | ||
| ); | ||
| expect(decodeResult.formatted.items.length).toBe(7); | ||
| }); | ||
|
|
||
| test('decodes Label 83 variant 1 (C-band)', () => { | ||
| // https://app.airframes.io/messages/3413113024 | ||
| const text = | ||
| 'M05AUA0007KIAH,RJAA,110012, 39.12,-175.10,39001,265,-107.6, 64900'; | ||
| const decodeResult = plugin.decode({ label: '83', text: text }); | ||
|
|
||
| expect(decodeResult.decoded).toBe(true); | ||
| expect(decodeResult.decoder.decodeLevel).toBe('partial'); | ||
| expect(decodeResult.decoder.name).toBe('c-band-label-83'); | ||
| expect(decodeResult.formatted.description).toBe('Airline Defined'); | ||
| expect(decodeResult.raw.flight_number).toBe('UA7'); | ||
| expect(decodeResult.raw.departure_icao).toBe('KIAH'); | ||
| expect(decodeResult.raw.arrival_icao).toBe('RJAA'); | ||
| expect(decodeResult.raw.day).toBe('11'); | ||
| expect(decodeResult.raw.position.latitude).toBe(39.12); | ||
| expect(decodeResult.raw.position.longitude).toBe(-175.1); | ||
| expect(decodeResult.raw.altitude).toBe(39001); | ||
| expect(decodeResult.raw.groundspeed).toBe(265); | ||
| expect(decodeResult.raw.heading).toBe(-107.6); | ||
| expect(decodeResult.remaining.text).toBe('64900'); | ||
| expect(decodeResult.formatted.items.length).toBe(7); | ||
| }); | ||
|
|
||
| test('decodes Label 83 variant 3 (C-band)', () => { | ||
| // https://app.airframes.io/messages/3413346742 | ||
| const text = 'M09AXA0001001PR11013423N0556.6E11603.0000000----'; | ||
| const decodeResult = plugin.decode({ label: '83', text: text }); | ||
|
|
||
| expect(decodeResult.decoded).toBe(true); | ||
| expect(decodeResult.decoder.decodeLevel).toBe('partial'); | ||
| expect(decodeResult.decoder.name).toBe('c-band-label-83'); | ||
| expect(decodeResult.formatted.description).toBe('Airline Defined'); | ||
| expect(decodeResult.raw.flight_number).toBe('XA1'); | ||
| expect(decodeResult.raw.day).toBe('11'); | ||
| expect(decodeResult.raw.position.latitude).toBe(5.943333333333333); | ||
| expect(decodeResult.raw.position.longitude).toBe(116.05); | ||
| expect(decodeResult.raw.altitude).toBe(0); | ||
| expect(decodeResult.remaining.text).toBe('0----'); | ||
| expect(decodeResult.formatted.items.length).toBe(3); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import { DecoderPlugin } from '../DecoderPlugin'; | ||
| import { DecodeResult, Message, Options } from '../DecoderPluginInterface'; | ||
| import { MIAMCoreUtils } from '../utils/miam'; | ||
| import { ResultFormatter } from '../utils/result_formatter'; | ||
|
|
||
| export class CBand extends DecoderPlugin { | ||
| name = 'c-band'; | ||
| qualifiers() { | ||
| return { | ||
| labels: ['*'], | ||
| }; | ||
| } | ||
|
|
||
| decode(message: Message, options: Options = {}): DecodeResult { | ||
| let decodeResult = this.defaultResult(); | ||
| decodeResult.decoder.name = this.name; | ||
| decodeResult.message = message; | ||
|
|
||
| // C-Band puts a 10 char header in front of some message types | ||
| // First 4 chars are some kind of message number | ||
| // Last 6 chars are the flight number | ||
| let cband = message.text.match( | ||
| /^(?<msgno>[A-Z]\d{2}[A-Z])(?<airline>[A-Z0-9]{2})(?<number>[0-9]{4})/, | ||
| ); | ||
| if (cband?.groups) { | ||
| const messageText = message.text.substring(10); | ||
| const decoded = this.decoder.decode( | ||
| { | ||
| label: message.label, | ||
| sublabel: message.sublabel, | ||
| text: messageText, | ||
| }, | ||
| options, | ||
| ); | ||
| if (decoded.decoded) { | ||
| ResultFormatter.flightNumber( | ||
| decodeResult, | ||
| cband.groups.airline + Number(cband.groups.number), | ||
| ); | ||
| decodeResult.decoded = true; | ||
| decodeResult.decoder.decodeLevel = decoded.decoder.decodeLevel; | ||
| decodeResult.decoder.name = this.name + '-' + decoded.decoder.name; | ||
| decodeResult.raw = { ...decodeResult.raw, ...decoded.raw }; | ||
| decodeResult.formatted.description = decoded.formatted.description; | ||
| decodeResult.formatted.items.push(...decoded.formatted.items); | ||
| decodeResult.remaining = decoded.remaining; | ||
| } | ||
| } | ||
| return decodeResult; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,18 +20,8 @@ export class Label_4A extends DecoderPlugin { | |
| decodeResult.message = message; | ||
| decodeResult.formatted.description = 'Latest New Format'; | ||
|
|
||
| // Inmarsat C-band seems to prefix normal messages with a message number and flight number | ||
| let text = message.text; | ||
| if (text.match(/^M\d{2}A\w{6}/)) { | ||
| ResultFormatter.flightNumber( | ||
| decodeResult, | ||
| message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, '$1'), | ||
| ); | ||
| text = text.substring(10); | ||
| } | ||
|
|
||
| decodeResult.decoded = true; | ||
| const fields = text.split(','); | ||
| const fields = message.text.split(','); | ||
| if (fields.length === 11) { | ||
| // variant 1 | ||
| ResultFormatter.time_of_day( | ||
|
|
@@ -42,10 +32,7 @@ export class Label_4A extends DecoderPlugin { | |
| if (fields[3]) ResultFormatter.callsign(decodeResult, fields[3]); | ||
| ResultFormatter.departureAirport(decodeResult, fields[4]); | ||
| ResultFormatter.arrivalAirport(decodeResult, fields[5]); | ||
| const alt = text.substring(48, 51); | ||
| if (alt !== '') { | ||
| ResultFormatter.altitude(decodeResult, Number(alt) * 100); | ||
| } | ||
| // ResultFormatter.altitude(decodeResult, Number(alt) * 100); | ||
| ResultFormatter.unknownArr(decodeResult, fields.slice(8)); | ||
|
Comment on lines
+35
to
36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Altitude extraction removed for variant 1 — this is a regression. The previous code extracted altitude from the text (likely via substring slicing on the prefix-stripped text). Commenting it out means variant 1 of Label 4A silently drops altitude from the decode result. If the altitude data is still present in one of the 🤖 Prompt for AI Agents
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was straight up wrong - it needs to be fixed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain
🏁 Script executed: Length of output: 979 🏁 Script executed: Length of output: 8053 🏁 Script executed: Length of output: 3618 🏁 Script executed: Length of output: 4791 🏁 Script executed: Length of output: 6478 🏁 Script executed: Length of output: 469
Current situation:
Analysis:
What should the fix be?
Can you clarify whether variant 1 should extract altitude, and if so, from which field? 🧬 Code Graph Analysis Resultslib/DecoderPluginInterface.ts
lib/types/waypoint.ts
lib/DateTimeUtils.ts
lib/utils/coordinate_utils.ts
lib/utils/result_formatter.ts
lib/utils/result_formatter.ts
|
||
| } else if (fields.length === 6) { | ||
| if (fields[0].match(/^[NS]/)) { | ||
|
|
@@ -92,7 +79,7 @@ export class Label_4A extends DecoderPlugin { | |
| } | ||
| } else { | ||
| decodeResult.decoded = false; | ||
| ResultFormatter.unknown(decodeResult, text); | ||
| ResultFormatter.unknown(decodeResult, message.text); | ||
| } | ||
|
|
||
| if (decodeResult.decoded) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CBand wildcard plugin can recurse infinitely through
MessageDecoder.decode.CBandis always eligible (wildcard*), and itsdecodemethod callsthis.decoder.decode(...)with the stripped text. If the stripped text also matches the C-band regex (/^[A-Z]\d{2}[A-Z][A-Z0-9]{2}\d{4}/), the innerdecodecall will again selectCBand, strip another 10 characters, and recurse — potentially until a stack overflow.Consider either:
optionslike{ skipCBand: true }), orMessageDecoder.decode.🤖 Prompt for AI Agents