You have built your cockpit. The buttons are in the right place, the encoders turn smoothly, and MobiFlight communicates properly with Microsoft Flight Simulator. But then you encounter a situation where a simple button mapping is no longer sufficient: you want to calculate a value, check a condition, or combine two variables before sending a command. This is the moment when Reverse Polish Notation — or RPN for short — becomes your best friend. RPN is the language that MobiFlight uses to evaluate expressions that you send to the simulator or read from the simulator. Did you encounter one of the above-mentioned cases? Then keep on reading!
Overview
This blog provides an introduction to RPN, explain how MobiFlight and Microsoft Flight Simulator use it, and provide you with plenty of information to start you up with RPN to take your home cockpit to the next level.
The article has the following topics:
- What is Reverse Polish Notation (RPN)
- How do MSFS and MobiFlight use RPN
- Reading and Writing values in RPN
- RPN Operations and examples
- My learned lessons
- Resources
What is Reverse Polish Notation
Reverse Polish Notation, or RPN, is a clever mathematical notation invented by Polish logician Jan Łukasiewicz in the 1920s. Normally, when we write a calculation, the operator (like +, -, x, : ) sits between the operands; we call this the infix notation. However, since certain operators take precedence over others, we need parentheses to ensure the calculations are executed correctly. Processing such precedence rules can be complex and resource-intensive.
Instead of writing calculations the traditional way, such as 3 + 4, RPN places the operator at the end: 3 4 +. At first glance, this postfix notation looks unusual, but it has a big advantage: there’s no need for parentheses or complicated operator precedence rules. Interpreters simply process RPN from left to right, push numbers to the stack, and when it finds an operator, it executes the calculation.
Examples:
- Conventional Infix-notation: 3 + 4
- RPN notation: 3 4 +
When interpreters process the calculation in RPN, they push the numbers 3 and 4 to the stack. Next, the interpreter encounters the + operator, so it pops the values from the stack and performs the calculation. If required, the interpreter pushes the result of the calculation to the stack again and make it serve as an operand in the next calculation. You will see this in the next example.
A bit more complex calculation, which, with Infix-notation, requires parentheses: - Conventional Infix-notation: (3 + 4) * 5
- RPN notation: 3 4 + 5 *
Again, the RPN interpreter pushes 3 and 4 to the stack and encounters the + operator. After popping 3 and 4 from the stack, the interpreter pushed the result of the calculation to the stack. Next, it pushes the 5 to the stack, and when the interpreter finds the operator, the calculation will be performed.
Because of the way how RPN works, it is easier for computers and calculators to process, making it popular in programming, engineering calculators, and flight simulation scripting systems.
How do Microsoft Flight Simulator and MobiFlight use RPN
MobiFlight extensively uses RPN to communicate with the sim, and in most cases, the required RPN is already available at your fingertips. When you are in MobiFlight, you find RPN as part of the Presets you configure in the Input Config Wizard.
In the examples in the previous paragraph, we explained the main concept of RPN based on simple calculations with a couple of numbers. However, instead of numbers, we can also use variables that come from the sim or that we have defined ourselves and want to push to the sim. For example, you can read the value of the Master Battery switch, but you can also turn the Master Battery switch on or off with RPN expressions, and perform all kinds of other actions of your plane, depending on what Microsoft Flight Simulator and/or your third-party planes expose.

The screenshot above shows how to use a position in a rotary switch (XPDR On) to turn on the transponder in my A2A Piper Comanche 250. The dropdown under ‘Select Preset’ contains the list of presets you can choose from.
In this case, I only had to select the preset that I needed, and the required code to turn on the transponder was already there. The red arrow points to the ‘Show Preset Code’ checkbox, which is unchecked by default. By checking it, the textbox underneath shows the RPN code.
In most cases, the out-of-the-box code works just fine, but in certain cases, you might want to adjust the RPN code or write a completely new piece of RPN code. For example, I designed and built a transponder that looked similar to the one in my A2A Piper Comanche 250. I designed the case in SolidWorks, printed it in my 3D printer, purchased an Arduino and all the other required components, did all the wiring and soldering, connected it to my computer, and made it work with MobiFlight.

Besides the rotary switch to set the transponder’s mode. and the green rotary encoder, the device has 4 rotary switches for the 4 digits of the transponder. Each rotary switch has 8 positions for the values 0 to 7. In MobiFlight, I needed to write RPN code for each position of each rotary switch to get the current transponder code from the sim and adapt it based on the selected value of the rotary switches.
So for my transponder to work correctly, I needed a combination of read and write operations, and calculations to correctly set the transponder code in the sim. In the rest of this article, we’ll have a better look at what such code looks like, but before we continue with more complex RPN, let’s have a look at some basic RPN operations.
Reading and Writing values in RPN
In MobiFlight, you can read and write RPN expressions for input and output purposes. For example, you can read a value from the sim to display it, or write a value to make something happen in the sim. Let’s first have a look at how to read values from the sim.
Reading values from the sim
In MobiFlight, you can read variables from the simulator, also called SimVars, to understand the status of switches and all sorts of other stuff that’s happening in the sim. Here you have a couple of examples:
- Status of the Autopilot Master switch: (A:AUTOPILOT MASTER, Bool)
- Status of the Battery switch: (L:Battery1Switch, Bool)
- Current transponder code: (A:TRANSPONDER CODE:1,number)
So, when reading a value from the sim, the format is as follows:
- [opening parenthesis][variable prefix]:[name of the variable], [variable type][closing parenthesis]
Note 1: When reading a variable, it is not mandatory to provide the variable type
Note 2: RPN is not case-sensitive, so (>L:SQ1, Number) is the same as (>l:sq1, number). Still, for readability purposes, it is recommended to use a consistent writing style.
Writing values to the sim
Likewise, you can use RPN instructions to write values to variables. The main difference with reading variables, is that you need to use the ‘>’ sign to indicate you want to write a value. See the examples below:
- Turn on Master Battery switch: 1 (>L:Battery1Switch)
- Turn off Master Battery switch: 0 (>L:Battery1Switch)
- Set the transponder code to 1200: 1200 (>L:SQ, number) (L:SQ, BCO16) (>K:XPNDR_SET)
When writing a simple value, like the first two expressions, the format is as follows:
- [value to be written] [opening parenthesis][greater than sign][variable prefix]:[name of the variable],[variable data type][closing parenthesis]
We’ll have a look at RPN expressions for setting the transponder code in the Examples section.
Supported types
Until now, we have only seen examples for A: Vars and L: Vars. However, there is support for other types as well. Check the list below for several other supported variable types.
| Variable Prefix | System Name | Description |
| A | Simulation Variable | Gets a specified SimVar from a simulation object. |
| B | Input Events | Gets the value of the specified input event (see Input Event Definitions for more information). |
| C | Callback Variables | This variable prefix is only used when dealing with GPS Variables. |
| E | Environment Variable | This is an environment variable. See the section on Environment Variables. |
| F | Function Library | This denotes a built in function from the function library. See the Function Library section below for more details. |
| G | Gauge Variables | Gets a variable that can be used to transfer unitless data between gauges. |
| I | Instrument Variable | Used for instrument variables, where the variable scope is the instrument itself, meaning it will be available to all components in the instrument hierarchy. |
| K | Key Event ID | This is a specific variable for a key Event ID for user input.(>K:TOGGLE_ICS) Note that some key events require one or more values to be sent, so please see the section Model Behaviors Inputs for more information on this. |
| L | Local Variable | Retrieves and/or creates a user-defined local variable. |
The content in this table is taken from the Variable Types section in the SDK Documentation page. This is also where you find the complete list of supported types.
RPN Operations and examples
Besides reading and writing values from/to the sim, we can also perform other operations. The kind of supported operations includes:
- Expression Operators – For example: +, -, /, *, %
- Comparison Operators – For example: ==, !=, >, <. >=, <=, ?
- Bit Operators – For example: &, |, ^, ~, >>, <<
- Logical Operators – For example: !, &&, ||
- Numerical Operators – For example: abs, int, flr, ceil, near, rng, min, max, dec
- Special Operators – For example: div, if{…}, else{…}, quit, case, rand
- String operators – For example: lc (lower case), uc (upper case), scat (concatenate), slen (length of a string), ssub (extract substring)
- Stack Operators – For example: c (clear stack), d (duplicate top value from stack), p (pop top value from stack), r (reverse top and second value from stack)
For their exact meaning and the way they work, check the Expression Operators section in the SDK Documentation page.
Examples
Now, we have seen what’s there with respect to RPN in Flight Simulator, let’s have a look at a couple of examples.
Example 1 – Set transponder code to 1200
We have already seen the expression earlier in the article, but let’s decipher it here:
- 1200 (>L:SQ, number) (L:SQ, BCO16) (>K:XPNDR_SET)
This expression consists of 4 parts, which are:
- 1200 – This is the code we want to send to the transponder
- (>L:SQ, number) – Here, we store the 1200 value in a variable L:SQ (watch the ‘>’ sign to write the value)
- (L:SQ, BCO16) – Here, we convert the variable to BCO16-format (Binary Coded Object), because the transponder code requires this
- (>K:XPNDR_SET) – Finally, we send the (converted) L:SQ variable as a parameter of K:XPNDR_SET event), thereby setting the transponder code
As you see, the whole expression is processed from left to right, which, with a little understanding of RPN, makes it easy to understand what’s happening. In case we want to use a button to assign the code 1200 to the transponder, we can use the above RPN expression for it.
Example 2 – Change the transponder code from 1200 to 2200
In this example, we assume the values of the rotary switches correspond with the transponder code set to 1200; in other words, the first digit is 1, the second digit is 2, and the third and fourth digits are 0.
When we want to change the transponder code from 1200 to 2200, we change the value from the first digit from 1 to 2. So, we need to configure the RPN instruction of the second position of the first digit. The instruction must read the current transponder code, set the first position to 2, leave positions 2, 3, and 4 as is, and send the new transponder code to the sim. We achieve this with the following RPN instruction:
- (A:TRANSPONDER CODE:1, Number)
- (A:TRANSPONDER CODE:1, Number) 1000 / int 1000 * –
- 2 1000 * + (>L:SQ0, number) (L:SQ0, BCO16) (>K:XPNDR_SET)
Let’s decipher the full instruction again to see what is happening.
In line 1, we see the code (which we have seen before) which reads the transponder code from the simulator, so 1200.
Next, in line 2, a lot is happening, so let’s decipher it in small steps:
- (A:TRANSPONDER CODE:1, Number) 1000 / – Here, the transponder code and 1000 are the operands and / is the operator. Since the transponder code is 1200, this leads to the calculation 1200 / 1000, which is 1.2.
- int 1000 * – Next, we make a whole number of the result of that calculation (which is 1) and multiply it by 1000, which results in 1000
- – – We now have two operands, which are the transponder code from line 1 (1200) and the result of the calculation in line 2 (1000). With the -, we decrease 1200 by 1000, which leads to 200. This value is an operand for the next calculation
In line 3, we multiply 2 by 1000 (2000) and add the value from the calculation in line 2 (200), resulting in 2200. We store the value in variable L:SQ0, convert it to BCO16 and then send it to the sim as the new transponder code.
Example 3 – Change the transponder code 2200 to 2300
In this example, we assume the values of the rotary switches correspond with the transponder code set to 2200; in other words, the first and second digits are 2, and the third and fourth digits are 0.
When we want to change the transponder code from 2200 to 2300, we keep the first digit as-is, change the value from the second digit from 2 to 3, and the third and fourth digits remain the same. So, we need to configure the RPN instruction of the third position of the second digit. The instruction will calculate the first digit of the current transponder code (2000), set the second position to 300, leave positions 3 and 4 as is, and send the new transponder code to the sim. To keep things a little bit easier, we store each digit in a variable, and in the end, we add up all variables. We achieve this with the following RPN instruction:
- (A:TRANSPONDER CODE:1, Number) 1000 / 10 % int 1000 * (>L:SQ1, Number)
- 300 (>L:SQ2, Number)
- (A:TRANSPONDER CODE:1, Number) 10 / 10 % int 10 * (>L:SQ3, Number)
- (A:TRANSPONDER CODE:1, Number) 10 % int (>L:SQ4, Number)
- (L:SQ1) (L:SQ2) + (>L:SQT1, Number)
- (L:SQ3) (L:SQ4) + (>L:SQT2, Number)
- (L:SQT1) (L:SQT2) + (>L:SQ, Number)
- (L:SQ, BCO16) (>K:XPNDR_SET)
At a high level, in the first 4 lines, we calculate all 4 digits are astore them in separate variables. Before we decipher the RPN, let’s first have a look at a couple of functions that we need a couple of times in the expressions.
Using the % or mod(ulus) function
With % or mod(ulus), the remainder of a division is taken. We’ll have a look at a couple of examples:
- 10 / 4 = 2.5, so the remainder is 5. In RPN, this would look like: 10 4 %
- 8 / 3 = 2.6, so the remainder is 6. In RPN, this would look like: 8 3 %
In the RPN expression in line 3, we have the following calculation:
- 220 10 %. With infix calculation, this is 220 / 10 = 22. Since there is no remainder, the remainder is 0. In other words, 220 10 % = 0
With the background information about the % function, we are now better able to understand the RPN expressions.
Limitations of the + function
In lines 5 to 7, we add the variables together until we have a variable containing the new transponder code, which we’ll send to the sim.
Unfortunately, the + function only accepts two parameters. In other words, we can only’t simply add all the variables in a single expression and store them in a variable. If you add more than two operands to the calculation, the leftmost operands will be skipped.
Examples:
- 1 2 + – Results in 3. This is a valid expression
- 1 2 3 + – More than 2 operands, the leftmost operand (1) will be skipped, so the result is 5
- 1 2 3 4 + – More than 2 operands, the leftmost operands (1 and 2) will be skipped, so the result is 7
So, if we take our four variables and try to add them together, the expression would look like this.
- (L:SQ1) (L:SQ2) (L:SQ3) (L:SQ4) + (>L:SQ, Number)
However, as said, the + operator does not accept more than 2 operands, so the 2 leftmost operands (2000 and 300) will be skipped, and the result of the calculation uses the two rightmost operands.
Calculating the 4 digits of the transponder code
Now, let’s decipher the whole calculation per line.
In line 1, we calculate the first digit:
- (A:TRANSPONDER CODE:1, Number) 1000 / – Here, the transponder code and 1000 are the operands and / is the operator. Since the transponder code is 2200, this leads to the calculation 2200 / 1000, which is 2.2.
- int 1000 * – Next, we make a whole number of the result of that calculation (which is 2) and multiply it by 1000, which results in 2000
- (>L:SQ1, Number) – Here, we store the value of the calculation (2000) in the variable, which represents the value of the first digit
In line 2, we set the second digit. For that, we simply take the value 300 and store it in the L:SQ2 variable.
In line 3, we calculate the third digit and store it in a variable.
- (A:TRANSPONDER CODE:1, Number) 10 / – We retrieve the transponder code and divide by 10, which is 220. This value is the first operand for the next calculation
- 10 % int – 10 is the second operand in the next calculation, and % (or mod) is the operator. In the explanation of the % or mod(ulus) function and the examples, we have already seen that 220 10 % = 0, so that’s the result of the calculation and the operand for the next calculation. Since the operand is not a number with a remainder, in this case, the operator int can be ignored.
- 10 * (>L:SQ3, Number) – 10 is the second operand in the calculation, and * is the operator. So, the calculation is 0 * 10, which is 0, and we store that value in variable L:SQ3
By the way: You might ask why the 0 * 10 is added to the whole expression for this digit. The main reason is that I prefer consistency in my RPN expressions over efficiency. Most of the RPN expressions that I use for my transponder are pretty much the same, with only small changes depending on the digit and its position. This makes the RPN expressions easy to maintain, and I don’t have to decipher each expression in case of any issues.
In line 4, we calculate the fourth digit and store it in a variable.
- (A:TRANSPONDER CODE:1, Number) 10 % – Here we take the mod(ulus) from the transponder code (2200) and 10, which results in 0
- int (>L:SQ4, Number) – The result from the previous line (0) is given to the int function, but since 0 is already a whole number, this has no impact. Next, 0 is stored in variable L:SQ4
Adding up the digits and send them to the transponder
We now have populated 4 variables; each variable contains the value of one of the digits.
- L:SQ1 = 2000
- L:SQ2 = 300
- L:SQ3 = 0
- L:SQ4 = 0
In the following lines, we add the variables together until we end up with a variable containing the new transponder code, which we’ll send to the sim. Since adding more than two operands is not supported by the + operator, we need to do the calculations in pairs, as we’ll see in the next lines.
First, in line 5, we add the variables with the first two digits to the first subtotal
- (L:SQ1) (L:SQ2) + (>L:SQT1, Number) – We take the values from the first two digits (2000 and 300), add them together, and store the new value in variable L:SQT1
Secondly, in the next line, line 6, we add the variables of the third and fourth digits to the second subtotal
- (L:SQ3) (L:SQ4) + (>L:SQT2, Number) – We take the values from the third and fourth digits (0 and 0), add them together, and store the results in variable L:SQT2
Next, in line 7, we add the two variables that hold the subtotals to a variable that will contain the full transponder code.
- (L:SQT1) (L:SQT2) + (>L:SQ, Number) – We take the values from the two subtotal variables (2300 and 00), and store the result in variable L:SQ
In line 8, the final step, we convert the L:SQ variable to BCO16 and then assign the transponder code with the new value
- (L:SQ, BCO16) (>K:XPNDR_SET) – Convert L:SQ to BCO16 and store the value as the new transponder code in the sim
With this, we had a detailed look at how RPN is used to read, change, and set the transponder code. In this case, we took the transponder code and did all the calculations with numbers. It might have reduced the amount of needed code by using string parsing. But to learn a bit about how to use RPN, it might not have made much difference.
My learned lessons
Along the way of using RPN, I picked up a couple of learnings. You might benefit from this as well.
- Use the > sign to declare variables and assign them a value
Example:
100 (>L:SQ1, number) ; Assigns the value 100 to the variable SQ1 - Syntax to use a variable for performing calculations, etc.
Example:
(L:SQ1) (L:SQ2) + (>L:SQ) - RPN is not case-sensitive
Example:
(>L:SQ1, Number) works just as well as (>l:sq1, number)
Still, for readability purposes, it is recommended to use a consistent writing style - Summarising allows only two operands
Examples:
Valid: 100 200 + (>L:SQ1); Result is 300
Invalid: 100 200 300 + (>L:SQ1); Result is 500, the first operand is ignored
In case you need to summarise more than 2 values, you need to use subtotals.
Example:
1000 200 + (>L:SQT1)
30 4 + (>L:SQT2)
(L:SQT1) (L:SQT2) + (L:SQ) - Document your RPN expressions
You can use the ‘;’ (at the end of a line) to describe what’s happening in that line. This works in MobiFlight in the Customised Preset Code Text box
Examples:
(L:SQ, BCO16) (>K:XPNDR_SET) ; Set the transponder code
; Concatenate the transponder code
(L:SQ1) (L:SQ2) + (>L:SQT1, Number)
(L:SQ3) (L:SQ4) + (>L:SQT2, Number)
(L:SQT1) (L:SQT2) + (>L:SQ, Number)
Conclusion
It is understandable if you don’t immediately understand a piece of RPN instructions. When I was reviewing this blog post, I also had to reread some of the RPN expressions I added because it wasn’t immediately clear what happened in the code I was reviewing. That’s one of the reasons why I decided to write this blog; both for my own purposes as well as for others who want to learn more about RPN.
I hope the article makes sense and that it is helpful for your own home cockpit purposes.
Acknowledgements
When I got stuck with the RPN expressions for my transponder, I reached out to the MobiFlight team on Discord. They helped me in such a way that after that, I managed to construct the remaining RPN expressions myself. So, here is a big thank you to the amazing MobiFlight software and the team that runs it!
Resources
A good resource to start learning RPN is the article below:
MSFS 2924 SDK Documentation – Reverse Polish Notation
https://docs.flightsimulator.com/msfs2024/html/6_Programming_APIs/Reverse_Polish_Notation.htm
MobiFlight HubHop – RPN expressions contributed by the MobiFlight community
https://hubhop.mobiflight.com

