Repository navigation
add label 76401 parsing #546
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
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,85 @@ | ||
| import { MessageDecoder } from '../MessageDecoder'; | ||
| import { Label_H1_76401 } from './Label_H1_76401'; | ||
|
|
||
| describe('Label H1 Preamble 76401', () => { | ||
| let plugin: Label_H1_76401; | ||
| const message = { label: 'H1', text: '' }; | ||
|
|
||
| beforeEach(() => { | ||
| const decoder = new MessageDecoder(); | ||
| plugin = new Label_H1_76401(decoder); | ||
| }); | ||
| test('matches qualifiers', () => { | ||
| expect(plugin.decode).toBeDefined(); | ||
| expect(plugin.name).toBe('label-h1-76401'); | ||
| expect(plugin.qualifiers).toBeDefined(); | ||
| expect(plugin.qualifiers()).toEqual({ | ||
| labels: ['H1'], | ||
| preambles: ['76401\r\n'], | ||
| }); | ||
| }); | ||
|
|
||
| test('decodes variant 1', () => { | ||
| // https://app.airframes.io/messages/7903362642 | ||
| message.text = | ||
| '76401\r\n02E23KDJTKBWI\r\nN35551W07767100084099M050276030G1801230030YY,\r\n'; | ||
| const decodeResult = plugin.decode(message); | ||
|
|
||
| expect(decodeResult.decoded).toBe(true); | ||
| expect(decodeResult.decoder.decodeLevel).toBe('partial'); | ||
| expect(decodeResult.raw.departure_icao).toBe('KDJT'); | ||
| expect(decodeResult.raw.arrival_icao).toBe('KBWI'); | ||
| expect(decodeResult.raw.position?.latitude).toBe(35.551); | ||
| expect(decodeResult.raw.position?.longitude).toBe(-77.671); | ||
| expect(decodeResult.raw.message_timestamp).toBe(520); // 00:08:40 | ||
| expect(decodeResult.remaining.text).toBe( | ||
| '76401\r\n02E23\r\n99M050276030G1801230030YY,\r\n', | ||
| ); | ||
| }); | ||
|
|
||
| test('decodes variant 2', () => { | ||
| // https://app.airframes.io/messages/7903363689 | ||
| message.text = | ||
| '76401\r\n02E23KBWIKBDL\r\nN39831W07515900082500M032334018B000025003005Z\r\n'; | ||
| const decodeResult = plugin.decode(message); | ||
|
|
||
| expect(decodeResult.decoded).toBe(true); | ||
| expect(decodeResult.decoder.decodeLevel).toBe('partial'); | ||
| expect(decodeResult.raw.departure_icao).toBe('KBWI'); | ||
| expect(decodeResult.raw.arrival_icao).toBe('KBDL'); | ||
| expect(decodeResult.raw.route?.waypoints?.length).toBe(1); | ||
| expect(decodeResult.raw.position?.latitude).toBe(39.831); | ||
| expect(decodeResult.raw.position?.longitude).toBe(-75.159); | ||
| expect(decodeResult.raw.message_timestamp).toBe(505); // 00:08:25 | ||
| expect(decodeResult.remaining.text).toBe( | ||
| '76401\r\n02E23\r\n00M032334018B000025003005Z\r\n', | ||
| ); | ||
| }); | ||
|
|
||
| test('decodes multiple positions', () => { | ||
| // https://app.airframes.io/messages/7903359093 | ||
| message.text = | ||
| '76401\r\n02E23KPHXKBUR\r\nN34550W11842100030787M001223021G000025::Q030;\r\nN34499W11847100040641P003227022G000025::2HGMY\r\nN34443W11851500050596P004225020G000025::B0YY,\r\nN34386W11855900060596P004227017G000025::B0G'; | ||
| const decodeResult = plugin.decode(message); | ||
|
|
||
| expect(decodeResult.decoded).toBe(true); | ||
| expect(decodeResult.decoder.decodeLevel).toBe('partial'); | ||
| expect(decodeResult.raw.departure_icao).toBe('KPHX'); | ||
| expect(decodeResult.raw.arrival_icao).toBe('KBUR'); | ||
| expect(decodeResult.raw.route?.waypoints?.length).toBe(4); | ||
| expect(decodeResult.raw.position?.latitude).toBe(34.386); | ||
| expect(decodeResult.raw.position?.longitude).toBe(-118.559); | ||
| expect(decodeResult.raw.message_timestamp).toBe(365); // 00:06:05 | ||
| expect(decodeResult.remaining.text).toBe( | ||
| '76401\r\n02E23\r\n87M001223021G000025::Q030;\r\n41P003227022G000025::2HGMY\r\n96P004225020G000025::B0YY,\r\n96P004227017G000025::B0G', | ||
| ); | ||
| }); | ||
| test('does not decode invalid', () => { | ||
| message.text = '76401\r\n<Invalid text>'; | ||
| const decodeResult = plugin.decode(message); | ||
|
|
||
| expect(decodeResult.decoded).toBe(false); | ||
| expect(decodeResult.decoder.decodeLevel).toBe('none'); | ||
| expect(decodeResult.formatted.description).toBe('Position Report'); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,78 @@ | ||||||||||||||
| import { DateTimeUtils } from '../DateTimeUtils'; | ||||||||||||||
| import { DecoderPlugin } from '../DecoderPlugin'; | ||||||||||||||
| import { DecodeResult, Message, Options } from '../DecoderPluginInterface'; | ||||||||||||||
| import { Waypoint } from '../types/waypoint'; | ||||||||||||||
| import { CoordinateUtils } from '../utils/coordinate_utils'; | ||||||||||||||
| import { ResultFormatter } from '../utils/result_formatter'; | ||||||||||||||
|
|
||||||||||||||
| export class Label_H1_76401 extends DecoderPlugin { | ||||||||||||||
| name = 'label-h1-76401'; | ||||||||||||||
|
|
||||||||||||||
| qualifiers() { | ||||||||||||||
| return { | ||||||||||||||
| labels: ['H1'], | ||||||||||||||
| preambles: ['76401\r\n'], | ||||||||||||||
| }; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| decode(message: Message, options: Options = {}): DecodeResult { | ||||||||||||||
| const decodeResult = this.initResult(message, 'Position Report'); | ||||||||||||||
|
|
||||||||||||||
| const lines = message.text.split('\r\n'); | ||||||||||||||
|
|
||||||||||||||
| if (lines.length < 3) { | ||||||||||||||
| return decodeResult; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| ResultFormatter.unknown(decodeResult, lines[0], '\r\n'); | ||||||||||||||
|
|
||||||||||||||
| ResultFormatter.unknown(decodeResult, lines[1].substring(0, 5), '\r\n'); | ||||||||||||||
| ResultFormatter.departureAirport(decodeResult, lines[1].substring(5, 9)); | ||||||||||||||
| ResultFormatter.arrivalAirport(decodeResult, lines[1].substring(9, 13)); | ||||||||||||||
| ResultFormatter.unknown(decodeResult, lines[1].substring(13), ''); // should have nothing left on line 1 | ||||||||||||||
|
|
||||||||||||||
| const waypoints: Waypoint[] = []; | ||||||||||||||
| for (const line of lines.slice(2)) { | ||||||||||||||
| const position = CoordinateUtils.decodeStringCoordinates( | ||||||||||||||
| line.substring(0, 13), | ||||||||||||||
| ); | ||||||||||||||
| if (position) { | ||||||||||||||
|
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. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis
Reject non-numeric coordinate fields before adding a waypoint.
Checking the numeric fields with 🐛 Suggested fix
📝 Committable suggestion
🤖 Prompt for AI Agents
|
||||||||||||||
| waypoints.push({ | ||||||||||||||
| name: CoordinateUtils.coordinateString(position), | ||||||||||||||
| latitude: position.latitude, | ||||||||||||||
| longitude: position.longitude, | ||||||||||||||
| time: DateTimeUtils.convertHHMMSSToTod(line.substring(13, 19)), | ||||||||||||||
| }); | ||||||||||||||
| } else { | ||||||||||||||
| ResultFormatter.unknown(decodeResult, line.substring(0, 19), ''); | ||||||||||||||
| } | ||||||||||||||
| ResultFormatter.unknown(decodeResult, line.substring(19), '\r\n'); | ||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| ResultFormatter.route(decodeResult, { waypoints: waypoints }); | ||||||||||||||
| // add position from the last waypoint for fun mapping | ||||||||||||||
| if (waypoints.length > 0) { | ||||||||||||||
| const lastWaypoint = waypoints[waypoints.length - 1]; | ||||||||||||||
| // should be true, making typescript happy | ||||||||||||||
| if ( | ||||||||||||||
| lastWaypoint.latitude !== undefined && | ||||||||||||||
| lastWaypoint.longitude !== undefined | ||||||||||||||
| ) { | ||||||||||||||
| ResultFormatter.position(decodeResult, { | ||||||||||||||
| latitude: lastWaypoint.latitude, | ||||||||||||||
| longitude: lastWaypoint.longitude, | ||||||||||||||
| }); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // should be true, making typescript happy | ||||||||||||||
| if (lastWaypoint.time !== undefined) { | ||||||||||||||
| ResultFormatter.timestamp(decodeResult, lastWaypoint.time); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| decodeResult.decoded = true; | ||||||||||||||
| decodeResult.decoder.decodeLevel = 'partial'; | ||||||||||||||
|
|
||||||||||||||
| return decodeResult; | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
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.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: airframesio/acars-decoder-typescript
Length of output: 1990
🏁 Script executed:
Repository: airframesio/acars-decoder-typescript
Length of output: 32457
Register
Label_H1_76401in the default dispatch path.MessageDecoderconstructs and dispatches only plugins frompluginClasses. AddLabel_H1_76401to that list and export it from the official plugin index.Suggested fix
🤖 Prompt for AI Agents