FPAL is built around a set of rules, expressed in a simple textual description language. For ease of maintenance, we organize the rules in one file per country as the rules correspond to the flight plan addressing rules published in ENR 1.11 of the country’s AIP (plus amendments).
All rules are evaluated and the addresses they return are added to the list of flight plan addresses. Duplicate AFTN addresses are eliminated automatically by the processor.
Let’s look at a simple rule to get you started. In the AIP of Germany, section ENR 1.11 you find – among many other rules – the following statement:
for VFR flights at night from and to Lahr (EDTL) and Karlsruhe/Baden-Baden (EDSB): LFSTZPZX, LFSTZTZX
For some reason, Strasbourg needs to be informed about VFR night activity at these German aerodromes close to the French border. You can see this is a non trivial statement that – in the given form – can only be understood by a human brain.
The FPAL rule implementing this statement looks as follows:
# VFR night at Karlsruhe/Baden and Lahr goes to Strasbourg rule 3a032d31-c034-475b-a178-6cd9632363e4 { ident "ED_NVFR_EDSB_EDTL"; applicability 2014-05-01T00:00:00Z; aftn LFSTZPZX LFSTZTZX; cond { gor { gdep and { vfrnight; airport EDTL EDSB; } gdest and { vfrnight; airport EDTL EDSB; } } } }
Comment lines are either marked by the pound sign (#) or a double slash (//). These are ignored by the parser.
Each rule starts with the rule keyword. After that, a universal unique identifier (UUID version 4) is required. The number has no meaning, it is just unique and identifies a rule. When writing a rule, you can obtain a UUID from your computer or just use a web site offering this service. The rule is contained inside a block. Blocks are always enclosed by curly brackets. For every opening curly bracket, there needs to be a closing curly bracket, otherwise the parse will give a syntax error.
Inside the rule, there are a couple of statements.
ident "ED_NVFR_EDSB_EDTL";
This contains a human identifiable name of the rule. You can choose any name but should try to be consistent. We decided to start every identifier by the country’s ICAO code and then a term for the type of rule (NVFR = night VFR in this case) and another specifier (in this case the affected airports). This usually corresponds how the AIP information is structured.
Statements must be terminated by a semicolon (;). Failure to do so will throw a parser error.
applicability 2014-05-01T00:00:00Z;
This gives a timeframe for which the rule is applicable. Times are given in ISO 8601 format. The above example only contains a start timestamp which means the rule is valid forever. When a rule changes or is only temporary (e.g. NOTAMed), you would specify a time frame such as for the month of May 2014:
applicability 2014-05-01T00:00:00Z...2014-05-31T23:59:59Z;
The next line gives the list of AFTN addresses that the flight plan should be sent to if the rule matches:
aftn LFSTZPZX LFSTZTZX;
These can be one or more addresses. It is also possible to use variables such as
aftn "<DEST>ZTZX";
for an address that is built by appending letters to the ICAO code of the destination aerodrome.
Next we find the condition segment, enclosed in the cond block. This gives the conditions on which a flight plan matches against the rule. Only if there is a match, the addresses given in aftn are returned.
cond { gor { gdep and { vfrnight; airport EDTL EDSB; } gdest and { vfrnight; airport EDTL EDSB; } } }
Individual conditions are combined with logical operators. Inside the cond block, we see one gor block. The process will run the flight plan as a whole through that block (global OR) and the rule matches (i.e. is applied) if one of the elements inside the “gor” evaluate to true. If we used “or” instead, the processor would run every waypoint of the flight plan through the rule and it would match if one of the waypoints matched one of the criteria inside the “or”. We could actually write this rule with “or” instead of “gor” but then it would have to be evaluated for each waypoint which takes more time. If you do not need to check waypoints, it is preferable to use a global “or” (or global “and” etc.).
Inside the or group, we find two blocks next to each other. The first one says “the waypoint you are currently checking is the departure aerodrome and it is a VFR night flight (i.e. flight rules VFR and it’s night at the time of departure) and it’s either EDTL or EDSB”. The second rule is the same but the waypoint has to be the destination aerodrome.
Inside an (g)or block, only one statement has to be true for the block to match but inside an (g)and block all statements have to match.
Airspaces are referred to by their ADR identifier. To help you write the rules, we provide an ADR database lookup service.
cond { or { and { vfr; airspace EBBU/fir MSL-F999; } } }
This rule triggers for all VFR overflights of the Brussels FIR. ADR airspace identifiers have the name, a slash and the type of airspace. In our case it’s a FIR with the name EBBU. The altitude specifier (mean sea level until end of airspace at flight level 999) is optional and if not given, the altitude data of the airspace is taken. In this case we overwrite the altitude range because typically a FIR ends somewhere around FL245 and then an UIR (upper airspace information region) is above it which means a rule referencing the FIR would not match in the UIR and we’d have to mention the UIR as well which is perfectly possible but requires more typing.
The Antwerp control zone with its lateral and vertical extent would be written as:
airspace EBAWCTR/ctr;
The TMA of Brussels would be identified as
airspace EBBRTMA/tma;
Sometimes you have to do some creative lookup to find the suitable airspace in ADR but a general knowledge of the naming scheme usually gets you there quickly.