This GitHub repository contains an ICAO ATS and OLDI Message Parser. The ICAO ATS and OLDI Message Parser is implemented using Python version 3.10.7. A more recent version of Python must be used in order to support switch statements used in the source code.
An acronym list is provided at the end of this readme for readers unfamiliar with ATC acronyms.
The open source GitHub repository for the ICAO ATS and OLDI Message Parser can be found here.
The ICAO ATS and OLDI Message Parser uses a standalone ICAO Field 15 Parser that is also available as an open source GitHub project that can be found here.
All software on both the ICAO ATS and OLDI Message Parser and ICAO Field 15 Parser GitHub repositories has been written by Peter Venton (user pventon on GitHub).
Full source code documentation can be found here.
This repository is used in a complete AFTN Terminal Application uploaded to my third GitHub repository that can be found here.
The project has been built using the PyCharm 2022.2.2 (Professional Edition) IDE running on a Linux Mint OS. Installing Python 3.x and the PyCharm IDE was straightforward with everything working as expected. Please donate and support Linux Mint if your able to do so, its a great OS!
ICAO ATS and OLDI messages conform to the syntax and semantic standards described in ICAO DOC 4444.
ATS messages contain an application header described in the ICAO Annex 10, Volume II document. OLDI messages do not have an application header. Both types of message have additional header information that is processed by the appropriate protocol handler, this parser does not deal with the protocol handler header.
The ICAO ATS and OLDI Message Parser is able to process the following:
- Messages with or without the application header;
- Messages with or without an application header, with or without the open and closed brackets;
The ICAO ATS and OLDI Message Parser automatically determines if messages have the header and/or brackets.
All fields are parsed and copied to an FPR for the caller to process further. ICAO field 15 is processed using a dedicated Field 15 Parser (available here).
Message content is defined in configuration data; each message title consists of a finite set of ICAO fields. This is the same for OLDI messages although the OLDI messages have some additional fields defined, however, the principle is the same.
OLDI messages have one further difference when compared to ATS messages; in addition to the content defined for a given title, the field content varies depending on the adjacent unit OLDI messages are exchanged on. The ICAO ATS and OLDI Message Parser determines the adjacent unit identifier from a message and selects the field content using a combination of the message title and adjacent unit name.
Route extraction is performed on field 15 and the extracted route stored in the FPR. For details on Field 15 parsing refer to the ICAO Field 15 Parser repository.
Each field and its subfield(s) are parsed for correct syntax and semantics; should an error be detected, accurate error messages are generated describing an error found in a particular field. The zero based index of a field and subfield are stored with all fields and subfields; these indices can be used for highlighting errors in a GUI.
The current implementation parses all the 'basic' ICAO fields F3, F5, F7, F8, F9, F10, F13, F14, F15, F16, F17, F20 and F21. The ICAO fields F18, F19 and F22 are 'compound' fields made up of numerous subfields. This parser fully parses F18, F19 and F22 and all their subfields. The flight plan record stores a complete F22 flight plan that is populated by F22 subfields. Theoretically, F22 is able to specify all the fields for a complete flight plan, hence an F22 flight plan is stored within the flight plan proper. Any errors reported for F22 subfields are copied to the main flight plan record for convenience to the caller. Duplicated F22 subfield errors are also reported.
Fields F18 and F19 are parsed for correct keyword/data format with all subfields copied to the flight plan. Errors are reported if the keyword/data format is found to be incorrect or text is found outside a keyword/data subfield. All F18 and F19 subfields are fully parsed.
OLDI define two extra fields 80 and 81, the parser fully supports these two fields with appropriate error messages etc. These fields are an addition to the ICAO F22 suite of subfields.
A parsed message can be output as an XML string by calling FlightPlanRecord.as_xml()
The ICAO ATS and OLDI Message Parser performs consistency checking between various fields once a flight plan has been parsed. The consistency checking can only be carried out on messages that contain the required fields, the message titles subject to consistency checking are:
- AFP
- ALR
- APL
- CPL
- FPL
The consistency checks carried out are:
- Flight rules between F8a and the flight rules derived by the F15 parsing and route extraction process; these must match.
- If F10a contains the letter 'Z' then one or more of the F18 subfields 'COM', 'NAV' or 'DAT' must be present;
- If F10a contains the letter 'R' then the F18 'PBN' subfield must be present and contain one or more of the indicators 'B1', 'B2', 'B3', 'B4' or 'B5';
- If F18 contains the subfield 'PBN', F10a must contain an 'R';
- If F18 'PBN' contains one or more of the indicators 'B1', 'B2', 'C1', 'C2', 'D1', 'D2', 'O1' or 'O2', then F10a must contain the letter 'G';
- If F18 'PBN' contains one or more of the indicators 'B1', 'B3', 'C1', 'C3', 'D1', 'D3', 'O1' or 'O3', then F10a must contain the letter 'D';
- If F18 'PBN' contains one or more of the indicators 'B1' or 'B4', then F10a must contain either an 'O' or 'S' and a 'D';
- If F18 'PBN' contains one or more of the indicators 'B1', 'B5', 'C1', 'C4', 'D1', 'D4', 'O1' or 'O4', then F10a must contain the letter 'I';
- If F18 'PBN' contains one or more of the indicators 'C1', 'C4', 'D1', 'D4', 'O1' or 'O4', then F10a must contain the letter 'D';
- If F9b contains ZZZZ then field 18 must contain the TYP subfield;
- If F13a contains ZZZZ then field 18 must contain the DEP subfield;
- If F16a contains ZZZZ then field 18 must contain the DEST subfield;
None as 23rd October 2022 that the author is currently aware of;
No modifications pending as of 23rd October 2022;
Although every attempt has been made to reduce the number of software coding errors and resulting chaos that can ensue as a result of such errors, it is highly likely that this early release will have a few bugs. The possible combinations of message structure and semantics run into millions of combinations, and it's impossible to test them all. There are a lot of unit tests that check the individual field parsers and messages in their entirety, but even with so many tests, there may still be some bugs in the software.
Should any use be made of this software and errors found, do not hesitate to contact me at peter.venton@flightatm.com, so I may attempt to fix/correct any issues, or alternatively post any errors on the discussion page or bug tracker that I believe is supplied as part of GitHub.
Good luck!
In the root directory of the repository there is a class called IcaoAtsMessageParser that is the calling interface to the ICAO ATS and OLDI Message Parser.
Example usage of the ICAO ATS and OLDI Message Parser;
# The following example ATS FPL message will be used for the discussions that follow...
# icao_message: str = "(FPL-TEST01-IS-B737/M-S/C-LOWW0800-N0450f350 PNT B9 LNZ1A-EGLL0200-0)"
# Instantiate the parser...
icao_message_parser: IcaoAtsMessageParser = IcaoAtsMessageParser()
# Parse the message...
flight_plan_record: FlightPlanRecord = icao_message_parser.parse_message_p1(icao_message)
# Check if any errors were reported in the basic field processing...
if flight_plan_record.errors_detected():
# For fields other than field 15 call the following method, this returns a list of ErrorRecord's...
basic_field_errors: [ErrorRecord] = flight_plan_record.get_erroneous_fields()
# For field 15, get the Extracted Route Sequence and get the errors, returns a list of Tokens...
if flight_plan_record.get_extracted_route_sequence().get_number_of_errors() > 0:
field_15_errors: [Token] = flight_plan_record.get_extracted_route_sequence().get_all_errors()
# To extract fields and / or subfields use the methods in the following example code...
self.assertEqual(
# Get the complete ICAO Field 9
"B737/M",
flight_plan_record.get_icao_field(FieldIdentifiers.F9).get_field_text())
self.assertEqual(
# Get the ICAO field 9 WTC (Field 9 'c')
"M",
flight_plan_record.get_icao_subfield(FieldIdentifiers.F9, SubFieldIdentifiers.F9c).get_field_text())
# Instantiate a FlightPlanRecord, the output is written into this class instance.
flight_plan_record: FlightPlanRecord = FlightPlanRecord()
# Instantiate the parser...
icao_message_parser = IcaoAtsMessageParser()
# Parse the message...
# result = icao_message_parser.parse_message_p2(flight_plan_record, icao_message)
# If errors were detected, result will be False; to get the error records do the following...
if not result:
# For fields other than field 15 call the following method, this returns a list of ErrorRecord's...
basic_field_errors: [ErrorRecord] = flight_plan_record.get_erroneous_fields()
# For field 15, get the Extracted Route Sequence and get the errors, returns a list of Tokens...
if flight_plan_record.get_extracted_route_sequence().get_number_of_errors() > 0:
field_15_errors: [Token] = flight_plan_record.get_extracted_route_sequence().get_all_errors()
# To extract fields and / or subfields use the methods in the following example code...
self.assertEqual(
# Get the complete ICAO Field 13
"LOWW0800",
flight_plan_record.get_icao_field(FieldIdentifiers.F13).get_field_text())
self.assertEqual(
# Get the ICAO field 16 EET (Field 16 'b')
"0200",
flight_plan_record.get_icao_subfield(FieldIdentifiers.F16, SubFieldIdentifiers.F16b).get_field_text())
- ABI OLDI Advanced Boundary Information
- ACH ATS ATC Change Message
- ACT OLDI Activation Message
- ACP ATS Advanced Coordination Procedure Message
- ACP OLDI Advanced Coordination Procedure Message
- ADEP Aerodrome of Departure (Given as an ICAO Location Indicator)
- ADES Aerodrome of Destination (Given as an ICAO Location Indicator)
- AFP ATS ATC Flightplan Proposal Message
- AIP Aeronautical Information Publication
- ALR ATS ATC Alerting Message
- AMA OLDI Arrival Management Message
- APL ATS ATC Flight Plan Message
- ARR ATS Arrival Message
- ATC Air Traffic Control
- ATS Air Traffic Service
- CDN ATS Change Message
- CDN OLDI Coordination Message
- CFMU Central Flow Management Unit
- CNL ATS Cancel Message
- COD OLDI Advanced Coordination Procedure
- CPL OLDI Current Flight Plan Message
- CPL ATS Current Flight Plan Message
- DCT Direct (used to specify direct routing between points)
- DEP ATS Departure Message
- DLA ATS Delay Message
- ERS Extracted Route Sequence
- EST ATS Estimate Message
- ETO Estimated Time Over
- FPL ATS Flight Plan Message
- FPR Flight Plan Record
- FNM Gander Oceanic Message
- GAT General Air Traffic
- GUI Graphical User Interface
- ICAO International Civil Aviation Organisation
- IFR Instrument Flight Rules
- IFPS Initial Flight Planing System
- IFPSTOP Indicates end of IFR routing (used by the CFMU IFPS)
- IFPSTART Indicates start of IFR routing (used by the CFMU IFPS)
- INF OLDI Information Message
- LAM OLDI Logical Acknowledgement
- MAC OLDI Message for the Abrogation of Coordination
- MFS Oceanic Centre Message
- OAT Operational Air Traffic (typically military)
- OCM OLDI Oceanic Clearance Message
- PAC OLDI Preliminary Activation Message
- PRP Published Route Points
- RAP OLDI Referred Activate Proposal Message
- RCF ATS Radio communication failure
- REJ OLDI Reject Message
- REV OLDI Revision Message
- RJC OLDI Reject Coordination Message
- ROC OLDI Request Oceanic Clearance Message
- RRV OLDI Referred Revision Proposal Message
- RQP ATS Request Flight Plan Message
- RQS ATS Request Supplementary Flight Plan Information Message
- SBY OLDI Standby Message
- SI Metric measurement system
- SID Standard Instrument Departure
- SPL ATS Supplementary Flight Plan Message
- STAR Standard Arrival Route
- VFR Visual Flight Rules