This repository contains an ICAO Field 15 Parser implemented using Python version 3.10.7. A more recent version of Python must be used in order to support match statements used in the source code (switch statements in other languages).
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!
An acronym list is provided at the end of this readme for readers unfamiliar with ATC acronyms.
As of 4th October 2022 implementation is ongoing on a Python project for a complete ICAO message parser that will parse all ICAO ATS and OLDI messages in the ICAO format. The ICAO message parser should be uploaded within a few weeks, say end of October 2022. The list of supported message titles will be:
- ICAO ATS -> ACH, ACP, AFP, APL, ARR, CDN, CHG, CNL, CPL, DEP, DLA, EST, FPL, FNM, MFS, RQP, RQS, SPL
- OLDI -> ABI, ACP, ACT, AMA, CDN, COD, CPL, INF, LAM, MAC, OCM, PAC, RAP, REJ, REV, RJC, ROC, RRV, SBY
Eventually there will be a fully data driven ADEXP parser also; no work in progress at the moment. I have a complete Java implementation of this and need to translate it to Python. It will come, but this will take time. The upcoming ICAO message parser has already been implemented to recognise ADEXP messages and the stub is in place to call a dedicated ADEXP parser. The initial release will be for the ICAO format only.
ICAO Field 15 is a string containing an arbitrary number of tokens that together describe a route filed by a pilot describing the route to be flown. Individual token syntax is described in ICAO DOC 4444; this parser implements these descriptions in order to identify tokens based on their syntax. ICAO Field 15 can be treated as a simple language comprised of three basic token types:
- Points - These can be AIP PRPs, Latitude / Longitude, Point / Bearing / Distance or Aerodrome tokens;
- Connectors - These can be AIP published ATS routes, SID, STAR, DCT and / or special connectors indicating non-IFR routing, (e.g. VFR sections);
- Modifiers - These consist of Speed and Level tokens that have to be applied at a point where they are specified;
The parser starts by tokenizing the string representing ICAO Field 15; whitespace is removed and all tokens placed into a list with two identifiers, one identifying a tokens base type (e.g. point, connector or modifier) and a subtype that identifies a token in more detail, (e.g. a Latitude longitude point). The token type and subtype are derived from a tokens syntax.
In addition, the zero based start and end index of a tokens location in the ICAO Field 15 string are stored; this can be used to highlight tokens in a GUI to identify erroneous tokens to users. Once the token list is established, a class instance representing an empty ERS is created and both the token list (input) and ERS (output) are passed as arguments to the parser.
The parser iterates through the tokens checking for correct semantics (and some limited syntax checking not picked up during tokenization) populating the ERS with an ERS record for each token processed.
The ERS contains the speed and altitude at all points in both imperial units as extracted from field 15 and SI units. SI altitudes are in meters and SI speed in meters / second. Flight rules are applied at each ERS item. Latitude and Longitude values are converted to decimal values and stored in the ERS. The azimuth and distance from one point to another are derived and stored; this can only be done where the latitude and longitude are known. The azimuth and distance between points are calculated using an oblate spheroid Earth model (geographicslib Python library).
This parser performs no lookup into an AIP database to obtain latitude and longitude values for PRPs, although this could be done as a separate 'pass' over the ERS. All the methods for assigning coordinates and calculating azimuth / distance values are available in the F15Parse class.
Flight rule changes accepted by the parser are:
- IFR / VFR - Flight plan Field 15 descriptions can change the flight rules between IFR -> VFR and VFR -> IFR at any point along a route;
- OAT / GAT - Flight plan Field 15 descriptions can change the flight rules between OAT -> GAT and GAT -> OAT at any point along a route;
- IFPSTOP / IFPSTART - These are CFMU IFPS specials to 'stop' IFR handling / processing between these designators. They are included in this implementation for completeness and may not be seen outside the CFMU IFPS.
Example usage of the ICAO field 15 parser.
# A sample Field 15 string...
token_string = "N0450M0825 00N000E B9 00N001E VFR IFR 00N001W/N0350F100 01N001W 01S001W 02S001W180060"
# Instantiate the tokenizer; the 'Tokenize()' class stores a copy of the field 15 string.
# If parallel processing is required using multiple threads, a new instance is
# required for each thread / field 15 string; individual field 15 strings must be
# assigned to each instance of the Tokenize class.
tokenize = Tokenize()
# Set the string to be tokenized...
tokenize.set_string_to_tokenize(token_string)
# Set the white space to tokenize the ICAO field 15, these are a space (ASCII 20),
# a newline (\n), a tab (\t), a carriage return (\r) and the forward slash (/).
# The forward slash is always saved as a token, the remaining whitespace characters
# are discarded.
tokenize.set_whitespace(" \n\t\r/")
# Tokenize the Field 15 string
tokenize.tokenize()
# The tokenized list of tokens is stored in a list of Token class instances which can be
# retrieved as follows:
tokens = tokenize.get_tokens()
# Instantiate an Extracted Route Record instance, the parser 'output' will be stored
# in this class. Multi-threaded applications should also instantiate this class for each thread.
ers = ExtractedRouteSequence()
# Pass the input tokens and output ERS storage as parameters to the parser.
# If the parser return value is greater than zero then errors exist.
# It is a callers responsibility to retrieve the erroneous tokens with
# ers.get_all_errors() which returns a list of tokens (Token classes) containing all
# erroneous tokens along with their respective error messages.
# The erroneous tokens have their zero based start and end index describing
# their location in field 15; the zero based indices can be
# used to highlight erroneous tokens in a GUI.
# The Parse15 class is stateless and therefore only has to be instantiated once
# for multi-threaded applications.
num_errors = ParseF15().parse_f15(ers, tokens)
# An ERS can be examined with the following print command...
ers.print_ers()
- ADEP Aerodrome of Departure (Given as an ICAO Location Indicator)
- ADES Aerodrome of Destination (Given as an ICAO Location Indicator)
- AIP Aeronautical Information Publication
- ATC Air Traffic Control
- ATS Air Traffic Service
- CFMU Central Flow Management Unit
- DCT Direct (used to specify direct routing between points)
- ERS Extracted Route Sequence
- ETO Estimated Time Over
- GAT General Air Traffic
- 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)
- OAT Operational Air Traffic (typically military)
- PRP Published Route Points
- SI Metric measurement system
- SID Standard Instrument Departure
- STAR Standard Arrival Route
- VFR Visual Flight Rules