Categories
Tools

FS2EFB data export toolbar

Get latest version

Base functionality copied from Blanik tablet script. Shortly, it’s a toolbar which sends aircraft data to the mobile app. This app then shares data with navigation app, like XCSoar or SkyDemon. Android app supports GPS spoofing, which can be used common nav apps like Google Maps (developer mode should be enabled on the smartphone).

Limitations of current version:
– toolbar can’t be closed while data export is active
– while minimised, toolbar icon disappears only when placed in top left corner of the screen
– iOS app does not work correctly when data export frequency is lower than 5Hz
– some apps require to set data export frequency as 1Hz (these use XPlane data exchange protocol)
-both apps in beta stage and may behave unexpectedly – crash, freeze, stay at background and consume power. You may delete the app while it not used. Report issues if you will find any.

To configure NMEA data export toolbar you have to install the app on your mobile device (separate apps for Android and iOS).

1. Install FS2EFB app:

Android
Follow this link https://play.google.com/apps/testing/com.touchingcloud.msfs2nmea or scan QR code which is on the navigation tablet screen in MSFS. Install the app, blue app icon with glider image will appear on the desktop.
iOS
Follow this link to join testing group https://testflight.apple.com/join/YgDUXEmr
Install TestFlight app from App Store (this is kind of “app store for beta apps”). Open TestFlight, click on the  FS2EFB tab, select INSTALL. Blue app icon with glider image will appear on the desktop.

2. Ensure that your mobile device is connected to the same router as PC/Xbox (either WiFi or LAN), and data exchange between clients is not blocked by firewall (usually don’t if you haven’t set your network as Public).

Send mobile device IP to the server

1. Launch Android/iOS app. Once loaded, it will try yo sync your local IP with server. If you see Sync Success in the log, everything went well. If not, fix connection issues and press SYNC IP.

Configure MSFS nav tablet

1. Time to  configure MSFS part. Open NMEA data export toolbar

2. Press the SYNC IP button

3. If it went well, you will see your local IP and correct port in the field. If not, try to fix connection issues, or type IP by hands using keyboard. Then press START button

4.Starting send to x.x.x.x will appear in log if everything okay, START button became red.5. Back to the FS2EFB app. Incoming data should be indicated in the log as RX lines. If not – something wrong with your network, try to change ports and start from beginning, or change router settings to prevent data exchange block by firewall.

 

 

Screenshot
CONFIGURE NAV APP
XCSoar (Android/iOS)

1.In the app, select TCP Client mode, TCP port 8880. press START button, Web Server OK and TCP Server OK should appear in log. If not, some of the ports are busy – change 5555 to 5556 for example, or 8880 to 8881. Press SYNC IP again, then START.

2. Open XCSoar and select FLY.3. Tap twice the screen, choose CONFIG4. Then DEVICES5. First, disable built in sensors. If you will not do it, your device GPS and barometer sensors data will conflict with simulator data. Select first line and tap DISABLE

6. Then select 2nd device and tab EDIT7. On the device page, set values like on the example picture.
– If your FS2EFB app installed on different device than XCSoar, IP address should match local IP of the device with app installed (you can find it at the top of the black screen
– If you change TCP server port, set new value in TCP Port field.
Once finished, press OK

8. In the devices list, you can see such data comes from the device #2: GPS fix, Baro, Airspeed, Vario. Press CLOSE.9. Validate XCSoar values with simulator data – altitude, airspeed should match.10. Configure XCSoar for your needs – track indication, thermalling assist, download map for your area. You can find detailed manual on the official website https://www.xcsoar.org/

ForeFlight (iOS)

1.In the app, select UDP Server mode, IP 127.0.0.1 (if ForeFlight launched on same device, otherwise local IP of that device), UDP port 49002, ensure XGPS and XATT sentences are enabled. Press START button.

2. Open ForeFlight, tap MENU and select DEVICES

3. MSFS connection should be presented. Tap it to open connection settings.

If it missing, back to NMEA export app and restart the server. Check log for error messages.4. Enable connection, return to devices list

5. MSFS should appear as Connected now

6. Return to map, your simulation location should be received correctly. ForeFlight official tutorial

SkyDemon (Android/iOS)

1.In the app, select UDP Server mode, IP 127.0.0.1 (if SkyDemon launched on same device, otherwise local IP of that device), UDP port 49002, ensure XGPS and XATT sentences are enabled. Press START button.

2. Open SkyDemon, tap Settings gear icon and select Connectivity

3. Enable Flight Simulator option4. Tap Go Flying, select Use X-Plane (as we use X-Plane data sentence)

5. Return to map, your simulation location should be received correctly. SkyDemon official tutorial

Spoiler

1.In the app, select UDP Server mode, IP 127.0.0.1 (if Garmin Pilot launched on same device, otherwise local IP of that device), UDP port 49002, ensure XGPS and XATT sentences are enabled. Press START button.

2. Open Garmin Pilot, tap Settings gear icon

3. Enable Flight Simulation tab, enable Use Flight Simulator Data option4. Return to map, aircraft data should be updated

Garmin Pilot manual

LX North (Android/iOS)

1.In the app, select UDP Server mode, IP 127.0.0.1 (if LX North launched on same device, otherwise local IP of that device), UDP port 49002, ensure XGPS and XATT sentences are enabled. Press START button.

2. Open LX North, tap Library icon and check all MSFS options in the list

3. Return to map, your simulation location should be received correctly.

OzRunways (Android/iOS)

1.In the app, select UDP Server mode, IP 127.0.0.1 (if OzRunways launched on same device, otherwise local IP of that device), UDP port 49002, ensure XGPS and XATT sentences are enabled. Press START button.

2. Open OzRunways, tap Settings gear icon and select SimulatorMode tab. Enable Simulator Mode and Remember selection on startup options

3. Return to map, your simulation location should be received correctly. OzRunways manual

Sky-Map (iOS)

1.In the app, select UDP Server mode, IP 127.0.0.1 (if Sky-Map launched on same device, otherwise local IP of that device), UDP port 49002, ensure XGPS and XATT sentences are enabled. Press START button.

2. Open Sky-Map, tap Menu then Setup

3. Select Wireless Interface Setup option4. Enable connection to device option , select X-Plane device (as we use X-Plane data sentence)

5. Return to map, your simulation location should be received correctly.

Garmin Pilot (Android/iOS)

1.In the app, select UDP Server mode, IP 127.0.0.1 (if Garmin Pilot launched on same device, otherwise local IP of that device), UDP port 49002, ensure XGPS and XATT sentences are enabled. Press START button.

2. Open Garmin Pilot, tap Settings gear icon

3. Select Flight Simulation mode, enable option Use Flight Simulator Data
4. Return to the map, ensure that your location and aircraft data displayed correctly
Garmin Pilot official tutorial

Stratus Insight (iOS)

1.In the app, select UDP Server mode, IP 127.0.0.1 (if Stratus Insight launched on same device, otherwise local IP of that device), UDP port 49002, ensure XGPS and XATT sentences are enabled. Press START button.

2. Open Stratus Insight, tap Settings icon and enable Listen to UDP 49002

3. Return to map, your simulation location should be received correctly. Stratus Insight official tutorial

WingX (Android/iOS)

1.In the app, select UDP Server mode, IP 127.0.0.1 (if SkyDemon launched on same device, otherwise local IP of that device), UDP port 49002, ensure XGPS and XATT sentences are enabled. Press START button.

2. Open WingX, tap Settings gear icon and enable Use X-plane/MS option

5. Return to map, your simulation location should be received correctly. WingX official tutorial

 

 


FS2EFB – toolbar user manual

FS2EFB adds a small panel to the Microsoft Flight Simulator toolbar. It reads your aircraft’s position and flight data from the simulator and sends it wirelessly to your phone or tablet so your navigation app always knows where you are.

## Opening the Panel

Click the **FS2EFB** icon in the MSFS toolbar (the row of icons at the top of the screen). The panel will appear as a floating window you can move and resize. If you don’t see the icon, make sure the add-on is installed in your Community folder and that you have restarted the simulator after installing it.

## The Setup Screen

When you first open the panel — or whenever the service is not running — you see the setup screen. It has three main areas: connection mode, address entry, and the log.

### Choosing a Connection Mode

At the top of the panel are two buttons:

– **DIRECT CONNECTION** — The simulator talks directly to your phone or tablet over your local Wi-Fi network. This is the standard mode for most setups. Choose this if your phone and PC are on the same Wi-Fi.

– **RELAY SERVER** — The data travels through an internet relay server instead of going directly to your device. Use this if you cannot get a direct connection to work (for example, if your phone is on mobile data rather than the same Wi-Fi as your PC). Relay mode limits data to 1 update per second.

### Entering the Address (Direct Connection mode)

Below the mode buttons is a display showing the current address — for example `192.168.1.50:5544`. This is the IP address and port number of the Android or iOS bridge app on your phone or tablet.

To change it, use the on-screen number pad that appears below the display. Tap the digits, the dot (`.`), and the colon (`:`) to type the address. Use **Backspace** to delete the last character.

You do not usually need to type this manually. Instead, use the **SYNC IP WITH APP** button (see below).

> **Tip:** The correct address to enter is shown in the bridge app on your phone. It is displayed near the top of the app screen when the app is running.

### Getting the App (QR Codes)

Below the number pad are two QR codes — one for the iOS app and one for the Android app. Point your phone’s camera at the appropriate code to go directly to the download page if you have not installed the app yet.

### Buttons

**SYNC IP WITH APP**
Automatically reads the address from the bridge app and fills it in for you. Press this button after starting the bridge app on your phone — the panel will contact the app and update the address field. If it fails, check that both devices are on the same Wi-Fi network and that the app is running.

In Relay mode this button changes to **SHOW USER ID QR** — tap it to display a QR code that you scan with the bridge app to link the two together.

**START / STOP**
Press **START** to begin sending flight data to your phone. The button changes to **STOP** while the service is running. Press **STOP** to end the session.

– In Direct mode, the address must be filled in correctly before you can start.
– In Relay mode, you must have scanned a User ID (UID) QR code first.

### The Log

Below the buttons is a scrollable text area showing status messages — connection results, errors, and confirmations. Click anywhere on the log area to clear it.

Common messages you may see:

| Message | What it means |
|—|—|
| `Ready` | The panel is idle, waiting for you to press START |
| `Starting send to 192.168.1.x:5544` | The service has started successfully |
| `Stopped` | You pressed STOP or the session ended |
| `Error: Invalid Format. Use IP:PORT` | The address you entered is not valid |
| `Sync Success` | SYNC IP found the app and updated the address |
| `Sync Failed` | Could not reach the app — check Wi-Fi and that the app is running |
| `Waiting for simulator data…` | The panel is running but hasn’t received aircraft data yet — can happen briefly after loading a flight |

## While Flying

Once you press START and see `Starting send to…` in the log, data is flowing to your phone. You can minimise the panel or leave it open — it continues working in the background either way.

### Flight Plan Import

You can send a flight plan from your phone or tablet to the simulator. When the bridge app sends a flight plan, a popup appears in the FS2EFB panel asking you to confirm:

– **LOAD** — Loads the waypoints into the simulator’s GPS/flight plan system.
– **LOAD AND TELEPORT** — Loads the flight plan and also instantly moves your aircraft to the first waypoint. Useful when you want to start a flight at a distant location without flying there first.
– **CANCEL** — Dismisses the popup without doing anything.

The log will show progress as each waypoint is added. Some waypoints may be skipped if the simulator cannot find them by name — this is normal, especially for custom or GPS waypoints.

> **Note:** Flight plan loading uses the simulator’s internal GPS system. Results vary depending on your aircraft and MSFS version. If loading fails or produces unexpected results, try the CANCEL option and load the plan manually in the World Map instead.

### Weather Preset Import

When the bridge app sends a weather preset (a `.WPR` file), a popup appears asking you to confirm before applying it to the simulator. The preset replaces the current weather with the saved conditions (wind, visibility, cloud layers, etc.).

> **Note:** Weather preset import works only when the simulator weather system has already loaded. If you import a preset immediately after loading a flight, wait a few seconds and try again from the app.

### Teleport

The flight plan popup includes a **LOAD AND TELEPORT** option. When used, the simulator will move your aircraft to the coordinates of the first waypoint in the plan. The panel waits for the terrain to load before completing the teleport, so there may be a brief pause.

### Screen Sharing (if enabled in the app)

If you have enabled the Screen Share feature in the Android bridge app, your phone’s screen is displayed inside the FS2EFB panel as a live image. You can tap and drag on the image inside the simulator to control the phone remotely — for example, to tap buttons in your navigation app without reaching for the phone. Scroll up and down the panel to see the full screen image.

This feature is not available in Relay mode.

## Troubleshooting

**The panel shows “Sync Failed”**
Make sure the bridge app on your phone is running and that your phone and PC are connected to the same Wi-Fi network. Also check that no firewall is blocking port 5544 on your PC.

**The panel shows “Waiting for simulator data…” for a long time**
This can happen if you open the panel before selecting an aircraft or loading a flight. Once you are in the cockpit with the simulation running, data should appear within a few seconds.

**The flight plan loaded but is missing some waypoints**
The simulator could not find those waypoints by name. Custom or GPS-only waypoints without a recognised ICAO code are added by coordinates instead, which may not always succeed in all aircraft. Check the log for messages about which waypoints were skipped.

**Relay mode feels slow**
Relay mode is limited to 1 update per second by design. For smooth navigation, use Direct Connection mode whenever possible.

**The panel is blank or not responding**
Try closing and reopening the panel from the toolbar. If that does not help, reload the current flight (Dev Menu → Reload Current Page, or restart MSFS).

FS2EFB – Android and iOS apps user manual

The FS2EFB Android app is a bridge between Microsoft Flight Simulator running on your PC and a navigation app on your phone or tablet (such as SkyDemon, ForeFlight, XCSoar, or any other GPS-capable app). The simulator sends flight data to this app, which converts it into a format your navigation app understands and forwards it over your local network.

## First Launch

When you open the app you will see all settings on a single scrollable screen. The app remembers everything you set — you only need to configure it once.

At the very top of the screen are two small controls that affect the whole app:

## Language

A dropdown at the top left lets you change the display language. The app detects your phone’s system language automatically, but you can override it here. The entire interface updates immediately when you select a language.

## Presets

Next to the language selector is a **preset dropdown**. Presets are ready-made configurations for specific navigation apps. Selecting a preset automatically sets the correct connection type, port number, and data format for that app — you do not need to configure these manually.

**Available presets include:**

Aviation EFBs: ForeFlight, SkyDemon, Garmin Pilot, FlyQ EFB, WingX, LZ North, OzRunways, Stratus Insight, Sky-Map, Enroute Flight Navigation, Air Navigation Pro, EasyVFR, AvPlan EFB, AirMate, FltplnGO, iFly GPS

Gliding/soaring apps: XCSoar, LK8000

Marine/boating apps: Aqua Map, iNavX, iSailor, SeaNav, i-Boating

Three buttons sit beside the preset dropdown:

– **?** — Opens the documentation page for the currently selected preset in your browser. Useful if you are unsure how to configure the navigation app side.
– **↺** (reset arrow) — Restores all settings to their default values. Use this if you have made changes and want to start fresh.
– **✕** (close) — Closes the app after asking for confirmation. This also stops any running service.

> **Tip:** Always start by selecting the preset for your navigation app. It will configure most settings automatically. You can fine-tune anything afterward.

## Mobile Device Mode

**Label: “Mobile device configured as:”**

This section tells the app how your phone is connected to the network. Choose the option that matches your setup.

### WiFi Client (default)
Your phone is connected to your home or office Wi-Fi router, and your PC is on the same network. This is the most common setup.

After selecting this mode, a short connection test runs automatically. A popup walks you through the steps and confirms whether the phone can reach the simulator. If the test passes, it fills in the address for you.

### Hotspot
Your phone creates its own Wi-Fi hotspot and the PC connects to it. Use this if you do not have a Wi-Fi router, or if your router does not allow devices to talk to each other (common in hotels or office networks).

In this mode you connect your PC to your phone’s hotspot the same way you would connect to any Wi-Fi network. No IP address configuration is needed — the app handles it automatically.

### Remote
For connecting over the internet when your PC and phone are on different networks (for example, the PC is at home and you are using the phone on mobile data). This mode attempts to set up automatic port forwarding on your router. A step-by-step popup shows progress. Results depend on your router’s capabilities — not all routers support this.

### Relay Client
Uses a cloud relay server instead of a direct connection. Both the simulator and the phone connect to the same relay server over the internet, so they do not need to be on the same network. This is the simplest setup for remote use when the Remote mode does not work.

To use Relay mode:
1. Select **Relay Client**
2. Tap **GET USER ID** and scan the QR code shown in the FS2EFB toolbar panel inside the simulator
3. Your User ID (UID) appears below the button once scanned
4. Press START

> **Note:** Relay mode limits data updates to 1 per second. Traffic and screen sharing are not available in Relay mode.

## Navigation App (Transport Mode)

**Label: “Navigation app configured as:”**

This section configures how the app communicates with your navigation app. Most navigation apps have a preferred method — the preset for your app sets this automatically.

– **TCP Client** — The bridge app connects to a server that your navigation app is running. Use this if your navigation app listens for incoming connections.
– **TCP Server** — The bridge app waits for your navigation app to connect to it. The navigation app must be pointed at your phone’s IP address and the port number shown.
– **UDP Client** — The bridge app sends data packets to a specific address. You need to enter the IP address of the device running the navigation app.
– **UDP Server** — The bridge app listens for a discovery packet from the navigation app. Some apps (like SkyDemon and ForeFlight) use this method — they find the bridge app automatically on the network.

> **If your preset is correct, you do not need to change this manually.**

## Network Configuration

### FS Server IP and FS Port
The IP address and port number of your PC running MSFS. The bridge app connects to this address to receive flight data from the simulator.

– **FS Server IP** — Usually filled in automatically after a connection test or sync. If you need to enter it manually, find your PC’s local IP address (in Windows: open a Command Prompt and type `ipconfig`, look for “IPv4 Address”).
– **FS Port** — Default is `5544`. Change this only if you have changed the port in the MSFS toolbar panel.

These fields are hidden in Hotspot and Relay modes (the app handles addressing automatically).

### NMEA Server IP and Port
Where the bridge app sends navigation data. This is the address of the device running your navigation app.

– If the navigation app is on the **same phone** as the bridge app, leave this as `127.0.0.1`.
– If the navigation app is on a **different device** (a tablet, a second phone), enter that device’s IP address.
– **Port** — Set automatically by the preset. Change only if your navigation app requires a specific port number.

## Control Buttons

### SYNC IP
Sends your phone’s current IP address to the FS2EFB toolbar panel in the simulator. Press this after the app is running and before you press START in the simulator — it ensures the simulator knows where to send data. You only need to do this once per session, or whenever your phone’s IP address changes (usually when you reconnect to Wi-Fi).

Not available in Relay mode.

### GET USER ID
*Visible in Relay mode only.* Opens the camera to scan a QR code. Point it at the QR code shown in the FS2EFB toolbar panel inside the simulator (tap **SHOW USER ID QR** in the toolbar panel first). Once scanned, the User ID is stored and the START button becomes available.

### START / STOP
Starts or stops the bridge service. When the service is running, the button shows **STOP** and a notification appears in your phone’s status bar. The service continues running even if you switch to another app or lock the screen.

The START button is greyed out and cannot be pressed if:
– You are in Relay mode and have not scanned a User ID yet
– Required fields (such as FS Server IP) are empty

## Aircraft Data

This section controls what flight information is sent to your navigation app.

### Data Format Checkboxes

Each checkbox enables or disables a particular data format. Your navigation app only understands certain formats — the preset for your app enables the correct ones and hides or disables the rest.

| Format | What it contains | Typically used by |
|—|—|—|
| **GPGGA** | GPS position, altitude, fix quality | XCSoar, LK8000, most NMEA apps |
| **GPRMC** | Position, speed, track, date/time | XCSoar, LK8000, most NMEA apps |
| **LXWP0** | Airspeed, altitude, climb rate, wind | XCSoar, LK8000 (gliding/soaring) |
| **XGPS** | Position, altitude, track, ground speed | SkyDemon, ForeFlight, Garmin Pilot |
| **XATT** | Heading, pitch, roll | SkyDemon, ForeFlight, Garmin Pilot |
| **RPOS** | Combined position and attitude | AvPlan EFB, Air Navigation Pro |

> Checkboxes that appear half-transparent are disabled by the preset because they are not compatible with the selected navigation app.

### Data Frequency
A slider from **1 Hz to 10 Hz** that controls how many times per second flight data is sent. Higher values give smoother movement on the map but use slightly more battery. The default is 5 Hz, which is a good balance. In Relay mode this is automatically limited to 1 Hz.

## Traffic Data

This section enables nearby aircraft to appear on your navigation app’s map. Traffic data comes from the simulator’s AI and multiplayer aircraft — not from real-world ADS-B.

> **Note:** Traffic is not available in Relay mode.

### Traffic Format Checkboxes

Select the formats your navigation app supports. These are split into ground traffic (aircraft on the ground) and air traffic (airborne aircraft):

| Format | Compatible apps |
|—|—|
| **XTRAFFIC GND / AIR** | SkyDemon, ForeFlight, Garmin Pilot, AirMate |
| **GDL90 GND / AIR** | Stratus Insight, WingX, Sky-Map, OzRunways, EasyVFR |
| **PFLAA GND / AIR** | XCSoar, LK8000 |

### Traffic Range
Sets how far from your aircraft (in nautical miles) other aircraft are included. The default is 100 NM. Reducing this can improve performance if there are many AI aircraft nearby.

### Traffic Frequency
Sets how often the traffic list is updated (in seconds). The default is 4 seconds. Increasing this can help if you notice performance issues.

The Range and Frequency sliders only appear when at least one traffic format is enabled.

## Live Flight Data

Four boxes in the lower part of the screen show the current values received from the simulator in real time:

– **IAS** — Indicated airspeed in knots
– **TE** — Vertical speed (total energy) in knots
– **Heading** — Compass heading in degrees
– **Altitude** — Altitude above mean sea level in feet

These update continuously while the service is running. They show `—` when the service is stopped or when no data has been received yet.

## Activity Log

The scrollable text area at the bottom shows all status messages from the app. It updates in real time and scrolls automatically to the latest message.

Common messages:

| Message | What it means |
|—|—|
| `TCP Server OK: Port 49002` | Navigation app connection is ready |
| `TCP Connected: 192.168.x.x` | Navigation app has connected |
| `Relay connected.` | Relay server connection established |
| `Relay disconnected. Reconnecting in 5s…` | Relay connection dropped; will retry automatically |
| `Waiting for simulator data…` | App is running but no data from MSFS yet |
| `Service Stopped` | The service was stopped |
| `GPS Spoofing Enabled` | Mock location is now active |
| `Screen Cast Started` | Screen sharing is active |

The log is automatically trimmed when it gets too long. Messages older than a certain length are removed to keep the app running smoothly.

## Special Features of Android app

These three features are shown at the bottom of the main button row. They are advanced options that require extra permissions on your phone.

### GPS Spoof

When enabled, the app replaces your phone’s built-in GPS with the simulator aircraft’s position. Any app on your phone that uses GPS — including your navigation app — will see the simulator’s location as if you were actually flying there.

**To use this feature:**
1. Enable **Developer Options** on your Android phone (go to Settings → About Phone → tap Build Number 7 times)
2. In Developer Options, find **Mock Location App** and select FS2EFB
3. Grant location permission to the app when prompted
4. Tap **GPS Spoof** in the app to enable it

> **Limitation:** Mock location requires Developer Options to remain enabled. On some phones, enabling Developer Options may trigger a warning from banking or security apps. Mock location applies to the whole phone — all apps will see the simulator position, not your real location.

### Screen Share

When enabled, your phone’s screen is streamed live into the FS2EFB panel inside the simulator. You can then tap and drag on the image inside the simulator to control your phone remotely — for example, to interact with your navigation app without taking your hands off the simulator controls.

**To use this feature:**
1. Tap **Screen Share** and accept the privacy notice
2. Accept the screen capture permission when Android asks
3. The phone screen will appear inside the FS2EFB panel

> **Limitation:** Screen capture requires explicit permission each time the service starts. If you restart the app, you will be asked again. Screen Share is not available in Relay mode.

### Remote Touch

When enabled, taps and gestures you make on the phone’s screen image inside the simulator are sent back to the phone and executed as real touch actions. This works together with Screen Share — you see the phone screen in the simulator and can control it.

**To use this feature:**
1. Tap **Remote Touch** and accept the privacy notice
2. The app will open Android’s Accessibility Settings — find FS2EFB in the list and enable it
3. Return to the app

> **Limitation:** Android’s Accessibility Service requires manual activation in settings. Some Android phones (particularly those with strict security policies) may prevent this from working. Remote Touch is not available in Relay mode.

## Notification Bar

While the service is running, a persistent notification appears in your phone’s status bar. It shows the current port numbers and active mode, for example:

“`
FS2EFB
WEB 5544 | OUT 49002 | HOTSPOT (Spoofing ON)
“`

Tapping the notification brings you back to the app.

## Troubleshooting

**Navigation app shows no GPS position**
Check that the correct preset is selected. Make sure the service is running (START was pressed) and that the simulator has an aircraft loaded and flying. Confirm the navigation app is configured to receive GPS data on the correct port.

**”Waiting for simulator data…” stays in the log**
The app is connected and waiting, but the simulator is not sending anything. Make sure the FS2EFB toolbar panel in MSFS has been started (press START in the panel too).

**Traffic does not appear in the navigation app**
Not all navigation apps support traffic. Check that the correct traffic format is enabled for your app (use the preset). Also check that traffic is enabled in the simulator (AI aircraft must be present).

**Relay mode reconnects repeatedly**
This usually means the internet connection on either the phone or the PC is unstable. Check your internet connection. If using mobile data, try moving to an area with better signal.

**GPS Spoof button does nothing**
Make sure Developer Options are enabled and that FS2EFB is selected as the Mock Location App. Also confirm location permission is granted to the app in Android Settings → Apps → FS2EFB → Permissions.

**Screen Share stops working after a phone restart**
Screen capture permission must be granted again after each phone restart. This is an Android security requirement and cannot be bypassed.

**The app stops sending data after 30 minutes**
If the simulator is paused or closed and no data arrives for 30 minutes, the service stops automatically to save battery. Simply press START again when you resume flying.

FS2EFB — Technical Description

System Architecture Overview

FS2EFB is a three-component bridge that extracts real-time telemetry from Microsoft Flight Simulator (MSFS) and delivers it to Electronic Flight Bag (EFB) apps on smartphones and tablets. The data flow is unidirectional:

MSFS (PC)
  └─ In-Game Panel (JavaScript, Coherent GT engine)
       │
       └── HTTP GET requests ──► Smartphone Bridge App (Android or iOS)
                                    │
                                    ├── NMEA 0183 sentences ──► EFB App (TCP or UDP)
                                    ├── GDL90 binary packets ──► EFB App (UDP port 4000)
                                    └── X-Plane DATA* binary ──► EFB App (same transport)

The smartphone acts as a protocol translator: it receives flight data via HTTP, converts it into the formats that EFB apps expect (NMEA, GDL90, or X-Plane binary), and delivers it over the appropriate transport.


Part 1: MSFS In-Game Panel

How Aircraft Data Is Extracted

The panel runs as a Web Component inside MSFS’s Coherent GT browser engine. Coherent GT exposes a global API for reading simulation variables synchronously. Each call takes a variable name and a unit string. The panel reads approximately 20 SimVars every tick:

Position & Navigation: Latitude and longitude (degrees, 6 decimal places), GPS ground track (degrees), magnetic heading (degrees), magnetic variation (degrees).

Altitudes: GPS altitude (meters, geometric) and barometric/indicated altitude (meters).

Speeds: True airspeed, indicated airspeed, and GPS ground speed — all in meters per second.

Vertical rates: Total energy variometer, netto variometer, and vertical speed — all in m/s.

Attitude: Pitch and bank angles in degrees.

Environment: Ambient wind direction (degrees) and wind velocity (km/h).

Time: Local hour, minute, second (2 decimal places), day, month, year (mod 100) — assembled into UTC time (HHMMSS.ss) and date (DDMMYY) strings.

Update Loop and Timing

The main loop is driven by requestAnimationFrame, which fires at the Coherent GT refresh rate (typically 30-60 fps). Two independent delta-time accumulators control data dispatch:

  1. Ownship accumulator: Compared against 1 / frequency (default 5 Hz = 200ms interval). When exceeded, ownship telemetry is sent and the accumulator resets.
  2. Traffic accumulator: Compared against the configured traffic polling interval (default 4 seconds). When exceeded and the previous traffic batch is fully drained, a new traffic fetch is triggered.

This accumulator-based approach decouples the data send rate from the frame rate, providing consistent output regardless of MSFS rendering performance.

How Data Is Sent to the Smartphone

All communication from the panel to the bridge app uses asynchronous HTTP GET requests via XMLHttpRequest.

Ownship request format:

GET http://<ip>:<port>/?user=1&UTCtime=HHMMSS.ss&UTCdate=DDMMYY&TAS=...&IAS=...&GRspeed=...&TE=...&NETTO=...&GPStrack=...&MAGNhead=...&VS=...&lat=...&long=...&GPSalt=...&BAROalt=...&magVar=...&windDir=...&windSpd=...&pitch=...&bank=...&w=...&h=...

All values are SI units (meters, m/s, degrees). The w and h parameters convey the panel’s pixel dimensions for the screen-share feature. Request timeout is 1000ms; errors are silently ignored since the periodic nature of the loop provides automatic retry.

Traffic request format:

GET http://<ip>:<port>/?traffic=1&id=...&name=...&lat=...&long=...&alt=...&vspeed=...&airborne=...&heading=...&speed=...&callsign=...

String values are URI-encoded. Timeout is 1500ms.

IP Address Discovery and Synchronization

The panel needs to know the smartphone’s IP address and port. Two mechanisms exist:

  1. Local persistence: The MSFS SDK provides a key-value storage API. The IP:port string is saved on every keypress of the on-screen numpad and restored when the panel loads. A fallback DOM event listener handles cases where the storage API isn’t immediately available.
  2. Cloud sync: An HTTP GET to an external web server retrieves the IP:port. The smartphone can push its address to this same server via its own SYNC button. The panel validates the response (must contain both : and ., must not contain “Error”) before applying.

Traffic Data Collection and Queuing

Traffic collection is a two-phase process designed to avoid frame-rate drops:

Phase 1 — Bulk fetch: The panel calls an asynchronous Coherent API to request the full list of AI and multiplayer aircraft. This returns a promise. When it resolves, each aircraft is filtered by haversine distance against the configured range (default 250 NM). Qualifying aircraft are pushed onto a queue as structured objects.

Phase 2 — One-per-frame dispatch: Each frame, exactly one aircraft is shifted from the front of the queue and transmitted. Before sending, the panel computes ground speed from position history (a map keyed by aircraft ID storing previous lat/lon/timestamp). If previous data exists, speed is calculated as distance-over-time using haversine. The airborne flag is dynamically adjusted: below 1 m/s forces ground state, above 10 m/s forces airborne. The history map is capped at 500 entries with a 5-minute expiry.

Skip-frame mechanism: After every ownship send, traffic dispatch is suppressed for the current frame and the next frame. This prevents ownship and traffic data from competing for network bandwidth in the same frame.

Configuration Feedback Loop

The HTTP response from the bridge app carries a JSON object with the current configuration:

{
  "webPort": 5555,
  "tcpPort": 49002,
  "transportMode": "UDP_SERVER",
  "dataFrequency": 5,
  "trafficRange": 250,
  "trafficFrequency": 4,
  "nmea": {
    "GPGGA": true, "GPRMC": true, "LXWP0": true,
    "XGPS": true, "XATT": true,
    "XTRAFFIC_GND": false, "XTRAFFIC_AIR": false,
    "GDL90_GND": false, "GDL90_AIR": false,
    "PFLAA_GND": false, "PFLAA_AIR": false
  }
}

The panel applies the received frequency, range, and traffic-enable settings, keeping itself synchronized with the user’s choices on the smartphone. If the response is larger than ~100 bytes and passes magic-byte checks (JPEG: FF D8, PNG: 89 50), it is treated as a screen-share image frame instead.

Network Requirements and Difficulties

Same local network requirement: The MSFS PC and the smartphone must be on the same local network (WiFi). The panel sends HTTP requests directly to the smartphone’s IP address. If the devices are on different subnets or VLANs, communication will fail silently (the panel’s error handler is intentionally empty to avoid log flooding at 5+ Hz).

Firewall considerations: Windows Firewall may block inbound connections to the MSFS panel (if the EFB app needed to connect back), but since the panel is the initiator of HTTP requests, the typical issue is the smartphone’s firewall blocking incoming connections on port 5555. On Android, the app’s own firewall rules usually allow this. On iOS, the app uses Network.framework which handles local network permissions via the iOS local network privacy prompt.

Router AP isolation: Some consumer routers enable “AP isolation” or “client isolation” which prevents WiFi devices from communicating with each other. This silently breaks the bridge. The workaround is to use the smartphone’s mobile hotspot instead.

Hotspot mode: When the smartphone acts as a WiFi hotspot and the PC connects to it, the network topology is simpler (no router in between) and generally more reliable. The Android app provides a WiFi/Hotspot mode toggle that adjusts the displayed IP accordingly.

Port conflicts: Port 5555 is also used by Android Debug Bridge (ADB). If ADB over WiFi is enabled, the bridge app’s web server may fail to bind. The port is configurable to avoid conflicts.


Part 2: Smartphone Bridge Apps

Web Server (Receiving MSFS Data)

Both Android and iOS apps run a TCP server on the configurable web port (default 5555). When an HTTP GET request arrives:

  1. CORS preflight (OPTIONS) requests receive a 204 No Content with permissive CORS headers.
  2. The query string is parsed into key-value pairs.
  3. A traffic=1 parameter routes to traffic processing; otherwise it’s ownship data.
  4. The HTTP response is either JSON configuration (described above) or, if screen sharing is active on Android, a Base64-encoded JPEG image.

Every received request resets a 30-minute inactivity timer. If no data arrives for 30 minutes, the service auto-stops to conserve battery.

Output Transport Modes

Transport modes are named from the EFB app’s perspective, not the phone’s:

ModePhone’s RoleHow It Works
TCP ClientPhone hosts a TCP server on the output port.EFB connects as a TCP client. Multiple EFB connections are accepted and stored in a thread-safe list. Data is broadcast to all connected clients.
TCP ServerPhone connects out as a TCP client.The EFB hosts a TCP server. The phone lazily connects to the target IP:port when data needs to be sent. A 2-second cooldown prevents rapid reconnection attempts.
UDP ClientPhone binds a UDP socket on the output port.The EFB sends a discovery/registration UDP packet to the phone. The phone records the sender’s address and replies with data to that endpoint.
UDP ServerPhone creates an unbound UDP socket.The phone sends UDP datagrams to the configured target IP and output port. No handshake required — fire and forget.

GDL90 always uses a separate dedicated UDP socket on port 4000, regardless of the NMEA transport mode. This matches the behavior of real ADS-B receivers (like Stratux) that EFB apps expect.

Data Flow Summary

HTTP Request (port 5555)
  │
  ├── Parse query parameters
  │
  ├── Ownship data?
  │     ├── Generate enabled NMEA sentences ──► Send via selected transport
  │     ├── Generate X-Plane DATA* packets ──► Send via selected transport (if RPOS enabled)
  │     ├── Generate GDL90 ownship report ──► Send via dedicated UDP:4000
  │     ├── Generate GDL90 AHRS report ──► Send via dedicated UDP:4000
  │     └── Update GPS mock location (Android only, if enabled)
  │
  └── Traffic data?
        ├── Generate XTRAFFIC sentence ──► Send via selected transport
        ├── Generate PFLAA sentence ──► Send via selected transport
        └── Generate GDL90 traffic report ──► Send via dedicated UDP:4000

Part 3: Output Protocols in Detail

NMEA 0183 Sentences

All standard NMEA sentences follow the format: $<TALKER><SENTENCE>,<fields>*<XX>\r\n where <XX> is the XOR checksum of all bytes between $ and * (exclusive), formatted as two uppercase hex digits.

Coordinate encoding: Decimal degrees are converted to DDmm.mmmm format (degrees + minutes with 4 decimal places). Latitude uses 2-digit degrees (DDmm.mmmm), longitude uses 3-digit degrees (DDDmm.mmmm). Hemisphere is indicated by N/S or E/W suffix.

$GPGGA — GPS Fix Data

$GPGGA,<HHMMSS.ss>,<lat>,<N/S>,<lon>,<E/W>,1,08,0.9,<alt_m>,M,0.0,M,,*XX\r\n
  • Fix quality: hardcoded to 1 (GPS fix)
  • Satellites: hardcoded to 08
  • HDOP: hardcoded to 0.9
  • Altitude: GPS altitude in meters MSL
  • Geoid separation: hardcoded to 0.0

$GPRMC — Recommended Minimum

$GPRMC,<HHMMSS.ss>,A,<lat>,<N/S>,<lon>,<E/W>,<speed_kts>,<track>,<DDMMYY>,<magVar>,<E/W>,A*XX\r\n
  • Status: always “A” (active)
  • Speed: ground speed converted from m/s to knots (x 1.94384)
  • Mode indicator: always “A” (autonomous)

$LXWP0 — LXNAV Variometer

$LXWP0,Y,<ias_kmh>,<baro_alt_m>,<vario_ms>,,,,,,<heading>,<wind_dir>,<wind_spd>*XX\r\n
  • IAS converted from m/s to km/h (x 3.6)
  • Vario: total energy in m/s
  • Five empty fields between vario and heading

XGPS — ForeFlight/SkyDemon GPS (Proprietary)

XGPSFS,<lon>,<lat>,<alt_m>,<track>,<groundspeed_ms>\r\n
  • No $ prefix, no checksum — raw proprietary format
  • Note: longitude comes before latitude
  • Units: meters and m/s (no conversion)

XATT — ForeFlight/SkyDemon Attitude (Proprietary)

XATTFS,<heading>,<-pitch>,<-roll>,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0\r\n
  • No $ prefix, no checksum
  • Pitch and roll are sign-negated (MSFS convention to EFB convention)
  • Nine trailing zero-value placeholder fields

XTRAFFIC — Custom MSFS Traffic (Proprietary)

XTRAFFIC<name>,<id>,<lat>,<lon>,<alt>,<vspeed>,<airborne>,<heading>,<speed>,<callsign>\r\n
  • No $ prefix, no checksum
  • Aircraft name is embedded directly in the sentence identifier

$PFLAA — FLARM Traffic

$PFLAA,0,<relNorth>,<relEast>,<relVert>,2,<hexID>,<track>,,<speed>,<vspeed>,8*XX\r\n
  • Relative distances use flat-Earth approximation: ~111,320 m/degree latitude; longitude scaled by cos(ownship latitude)
  • Traffic ID is hashed to a 6-character uppercase hex string (lower 24 bits of hash)
  • Aircraft type: hardcoded to 8 (powered aircraft)

X-Plane Binary DATA* Packets

When the RPOS mode is enabled, three separate 41-byte binary packets are sent in the standard X-Plane UDP DATA format:

Each packet structure:

Bytes 0-4:   ASCII "DATA*" (0x44 0x41 0x54 0x41 0x2A)
Bytes 5-8:   Group index (32-bit little-endian integer)
Bytes 9-40:  Eight 32-bit little-endian IEEE 754 floats

Group 20 (Position): latitude (deg), longitude (deg), altitude MSL (feet), altitude AGL (feet). Four unused zeros.

Group 3 (Speeds): IAS (knots), EAS (= IAS), TAS (knots), ground speed (knots). All converted from m/s (x 1.94384).

Group 17 (Attitude): pitch (deg, negated), roll (deg, negated), true heading (deg), magnetic heading (deg). Four unused zeros.

Additionally, a proprietary compact 41-byte RPOS packet format exists that interleaves longitude bytes across non-contiguous positions for a specific EFB app compatibility. The longitude float32 is split: its MSB is placed at byte 0 (serving as a frame-sync byte), while the lower 3 bytes are placed at bytes 38-40.

GDL90 Binary Protocol

GDL90 is the FAA standard for ADS-B data exchange, used by hardware receivers like Stratux and ForeFlight Sentry. The bridge emulates this protocol over UDP port 4000.

Frame Structure

Every GDL90 message is wrapped in a frame:

[0x7E] [message payload with byte stuffing] [CRC-16 LSB] [CRC-16 MSB] [0x7E]
  • Flag byte: 0x7E marks frame boundaries
  • Byte stuffing: Within the frame (excluding flag bytes), 0x7E is escaped as 0x7D 0x5E, and 0x7D is escaped as 0x7D 0x5D
  • CRC-16: Polynomial 0x1021 (CRC-CCITT), initial value 0x0000. Computed over the unescaped message payload. Appended LSB-first, and the CRC bytes themselves are subject to byte stuffing.

Heartbeat (Message ID 0x00)

7-byte payload: [0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00]

  • Status byte 1: 0x81 = initialized + GPS valid
  • Sent every 1 second (required by the GDL90 specification)

Ownship Report (Message ID 0x0A) and Traffic Report (Message ID 0x14)

29 bytes total (1 byte message ID + 28 bytes payload). Both share the same structure:

Offset  Size  Field                    Encoding
──────  ────  ─────                    ────────
0       1     Message ID               0x0A (ownship) or 0x14 (traffic)
1       1     Alert/Address Type       Always 0x00
2-4     3     Participant Address      3-byte hash of ID string (ownship uses 0xAAAAAA)
5-7     3     Latitude                 24-bit signed: degrees / 180 * 2^23
8-10    3     Longitude                Same encoding as latitude
11-12   2     Altitude + Misc          Upper 12 bits: (alt_feet + 1000) / 25, clamped [0, 0xFFE]
                                       Lower 4 bits (misc nibble):
                                         bit 3 = airborne (1=yes, 0=ground)
                                         bit 0 = true track angle (always 1)
                                       → 0x09 for airborne, 0x01 for ground
13      1     NIC/NACp                 Fixed 0xB0
14-15   2     Horizontal Speed         12-bit unsigned scalar in knots, clamped [0, 4094]
              + Vertical Velocity      Byte 14: speed[11..4] (upper 8 bits)
                                       Byte 15 upper nibble: speed[3..0]
                                       Byte 15 lower nibble: vv[11..8]
16      1     Vertical Velocity cont.  vv[7..0] (lower 8 bits)
                                       12-bit two's complement, 64 fpm per LSB
                                       Clamped [-2048, 2047]
17      1     Track/Heading            0-360° mapped to 0-255 (heading * 256 / 360)
18      1     Emitter/Emergency        Upper nibble = category (1 = light aircraft)
                                       Lower nibble = emergency (0 = none) → 0x10
19-26   8     Callsign                 8 ASCII characters, space-padded

Unit conversions applied:

  • Altitude: meters to feet (x 3.28084)
  • Speed: m/s to knots (x 1.94384)
  • Vertical speed: m/s to ft/min (x 196.8504), then divided by 64 for the 64-fpm LSB

Note on speed encoding: The horizontal speed and vertical velocity share byte 15 — the upper nibble contains the 4 least significant bits of speed, while the lower nibble contains the 4 most significant bits of the 12-bit vertical velocity value. This packing is specified by the GDL90 standard.

AHRS/Attitude Report (Message ID 0x4C — ForeFlight Proprietary)

13-byte payload (1 byte message ID + 12 bytes data):

Offset  Size  Field      Encoding
──────  ────  ─────      ────────
0       1     Msg ID     0x4C
1-2     2     Pitch      Signed 16-bit big-endian, tenths of a degree
3-4     2     Roll       Signed 16-bit big-endian, tenths of a degree
5-6     2     Heading    Unsigned 16-bit big-endian, tenths of a degree
7-12    6     Reserved   All zeros

Part 4: Presets System

Both Android and iOS apps include a preset system that configures the bridge for specific EFB applications. Presets are stored in a bundled CSV file with 18 columns:

EFB name, TCP_CLIENT, TCP_SERVER, UDP_CLIENT, UDP_SERVER, tcpPort, GPGGA, GPRMC, LXWP0, XGPS, XATT, Rpos, XTRAFFICGnd, XTRAFFICAir, Gdl90Gnd, Gdl90Air, PflaaGnd, PflaaAir

Value semantics for each integer:

ValueMeaning
0Force OFF and lock the control (disabled, nearly invisible at 5% opacity)
1Leave the control enabled but don’t change its current state (user’s choice)
2Force ON — check the checkbox or select the transport mode

This three-state system allows presets to enforce required settings while leaving optional ones to the user.

Preset categories in the bundled data:

  • XGPS/XATT-based aviation EFBs (ForeFlight, SkyDemon, Garmin Pilot, FlyQ EFB, AirMate, FltplnGO): UDP Server, port 49002, XGPS + XATT enabled, XTRAFFIC for traffic
  • GDL90-based aviation EFBs (WingX, OzRunways, Stratus Insight, Sky-Map, EasyVFR, iFly GPS): UDP Server, port 49002, XGPS + XATT plus GDL90 traffic
  • Soaring/glider EFBs (XCSoar, LK8000): TCP Client or UDP Server, port 4353, standard NMEA (GPGGA + GPRMC + LXWP0) plus PFLAA traffic
  • Binary RPOS EFBs (Air Navigation Pro, AvPlan EFB): UDP Server, port 49002, only RPOS binary output
  • Marine EFBs (Aqua Map, iNavX, iSailor, SeaNav, i-Boating): Various TCP modes, custom ports, only GPGGA + GPRMC

Selecting “EFB Preset” (the first entry) restores all controls to their unlocked state.


Part 5: Android-Exclusive Features

GPS Spoofing (Mock Location Provider)

The Android app can inject simulated GPS coordinates into the system location service, making all apps on the device (including EFB apps that read GPS) believe the phone is at the simulated aircraft’s position.

How it works:

  1. Permission flow: The app checks for ACCESS_FINE_LOCATION runtime permission, then probes for mock location capability by attempting to add a test provider to the system’s Location Manager. This requires the app to be set as the “Mock Location App” in Android Developer Options.
  2. Prominent disclosure: Before enabling, a dialog explains that the app will replace the device’s real GPS with simulated flight data, with an explicit consent mechanism.
  3. Location injection: On each ownship HTTP request, if spoofing is enabled, the service creates a mock Location object with the simulated latitude, longitude, altitude, speed, bearing, and a synthetic accuracy value. This is pushed to the system’s Location Manager as a test provider update. All Android apps reading GPS will receive this simulated position.
  4. Service lifecycle: The foreground service declares LOCATION as a foreground service type when spoofing is active. On stop, the mock provider is removed, restoring real GPS.

Screen Sharing (MediaProjection)

The Android app can capture the device’s screen and transmit it back to the MSFS in-game panel, enabling VR users to see their EFB app without removing the headset.

How it works:

  1. Permission flow: A disclosure dialog explains screen capture. On acceptance, the system’s screen capture intent is launched via startActivityForResult.
  2. Capture pipeline: When granted, the result code and intent data are passed to the service. The service creates a MediaProjection, an ImageReader (for receiving frames), and a VirtualDisplay that renders the screen content into the ImageReader’s surface.
  3. Frame serving: Captured frames are stored as a volatile Bitmap reference behind a synchronized lock. When the MSFS panel sends an HTTP request with width/height parameters (indicating it wants a screen image), the latest bitmap is resized to fit the requested dimensions while maintaining aspect ratio, compressed as JPEG at quality 60, Base64-encoded, and returned as a data:image/jpeg;base64,... string in the HTTP response body.
  4. Throttling: Image frames are sent at most every 500ms (or 100ms during active drag gestures) to balance quality and bandwidth.
  5. Panel-side rendering: The MSFS panel detects image responses by checking magic bytes and displays them using a double-buffered foreground/background image pair for smooth transitions.

Remote Touch Simulation (Accessibility Service)

The Android app can simulate touch gestures on the device screen, dispatched remotely from the MSFS in-game panel. This enables VR users to interact with the EFB app without taking off the headset.

How it works:

  1. Touch event flow: The MSFS panel captures mouse clicks on the screen-share image and sends the coordinates as HTTP query parameters (percentage-based X/Y and gesture type). The bridge service broadcasts these as a namespaced intent.
  2. Accessibility Service: A separate Android Accessibility Service receives the broadcast intents and uses the Accessibility API’s gesture dispatch mechanism to simulate touches.
  3. Coordinate conversion: Incoming coordinates are percentages (0-100%) of the screen. The service queries real display metrics and converts to absolute pixel coordinates.
  4. Four gesture types:
    • “tap”: Creates a stroke path at the coordinates with a 50ms duration and dispatches immediately.
    • “down”: Begins a continued/drag gesture using the accessibility continued-stroke API with a 100ms segment and the “willContinue” flag.
    • “drag”: Continues the stroke at updated coordinates with another 100ms segment.
    • “up”: Ends the continued stroke with “willContinue” set to false.
  5. Safety timeout: A 2-second timer auto-releases orphaned drag gestures if no follow-up event arrives.
  6. Permission: Requires the user to manually enable the Accessibility Service in Android Settings. The app provides a direct link to the correct settings page.

Thread Safety (Android)

The Android service uses several mechanisms for thread safety across its web server thread, network I/O threads, and the main thread:

  • Volatile fields: All shared state (running flag, timestamps, transport mode, ownship coordinates, UDP peer address, bitmap reference, generation counter) is declared volatile for visibility guarantees.
  • CopyOnWriteArrayList: TCP client connections are stored in a thread-safe list that allows concurrent iteration and modification without explicit locking.
  • Synchronized locks: The screen capture bitmap is guarded by a dedicated lock object; old bitmaps are recycled within the lock.
  • Generation counter: An integer counter is incremented on every socket restart. Each background thread captures the current generation when it starts and exits silently if the generation changes, preventing stale threads from producing confusing error messages during reconfiguration.

Part 6: iOS-Specific Details

Background Execution

iOS aggressively suspends apps that are not actively producing audio or using location services. The bridge app plays a silent audio loop using AVAudioEngine: a 1-second buffer of zeros at 44,100 Hz, looped continuously on a player node. The audio session is configured with the .playback category, which prevents iOS from suspending the app when the screen locks.

Audio Variometer

The iOS app includes an audio variometer that produces climb/sink tones based on the aircraft’s vertical speed:

Three zones based on climb rate (m/s):

ZoneRangeAudio Behavior
Dead-0.5 to +0.5 m/sSilence
SinkBelow -0.5 m/sContinuous solid tone, pitch decreasing with sink rate. At -0.5 m/s: ~440 Hz; at -5.0 m/s: ~220 Hz
LiftAbove +0.5 m/sPulsed/beeping tone. Pitch and beep rate increase with climb rate. At +0.5 m/s: ~440 Hz, slow beeps (~0.37s interval); at +10 m/s: ~1067 Hz, rapid beeps (0.1s interval)

The implementation uses a 440 Hz sine wave buffer played through an AVAudioUnitVarispeed node. Changing the varispeed rate shifts both pitch and playback speed proportionally. Pulsing is achieved by a repeating timer that toggles the player volume between the master level and zero. To avoid audio jitter, the timer is only recreated if the interval changes by more than 0.05 seconds.

Networking

The iOS app uses Apple’s Network.framework (NWListener, NWConnection) exclusively — no third-party libraries. Network I/O runs on a private concurrent dispatch queue, while client list mutations are serialized on a dedicated serial queue to prevent race conditions.

Settings Persistence

All user settings use SwiftUI’s @AppStorage (backed by UserDefaults), providing automatic persistence without explicit save/load logic. The bridge manager is an ObservableObject whose published properties drive the SwiftUI view updates on the main thread.

FS2EFB data export toolbar v0.11 (FS20)

– weather import improved

– UI translated

Android & iOS app required: v1.26

FS2EFB data export toolbar v0.10 (FS20)

Weather preset and flight plan import issues fixed

FS2EFB data export toolbar v0.9 (FS20)

– Relay mode for Cloud Gaming support (some features does not work, like traffic export and screen share)
– issue fixed: LX NAV does not display imported flight plan

FS2EFB data export toolbar v0.8 (FS20)

* weather preset import
* language selector in Android/iOS apps

Android app version required: 1.23
iOS app version required: 1.23

FS2EFB data export toolbar v0.7 (FS20)

– flight plan import (supported formats: PLN, GPX, FLP)
– better screen share (Android)

Android app version required: 0.20 iOS app version required: 1.21

FS2EFB data export toolbar v0.6 (FS20)

  • navigation apps presets
  • better EFB support (artificial horizon, AI traffic)

Android app version required: 0.20 iOS app version required: 1.20

FS2EFB data export toolbar v0.5 (FS20)

traffic export, available sentences
* XTRAFF (X-Plane format, SkyDemon ForeFlight Garmin Pilot etc.)
* GDL90 (Stratus Insight)
* PFLAA (XCSoar, LK8000 – LXNAV data type)

Android app version required: 0.19
iOS app version required: 1.19

FS2EFB data export toolbar v0.4 (FS20)

* screen share of selected app or whole screen
* screen tap simulation (optional, require special accessibility permission)
* frequency slider moved from toolbat to the app
* minor UI changes
* default values set for SkyDemon/Foreflight compatibility

FS2EFB data export toolbar v0.2 (FS20)

– minimized GPS icon appears only when cursor is nearby (only works when placed in top left corner due to toolbar system limitations)
– QR images scalable
– frequency and IP stored in used data and restored on toolbar restart

FS2EFB data export toolbar v0.1 (FS20)

base functionality copied from Blanik tablet script. Shortly, it’s a toolbar which sends aircraft data to the mobile app. This app then shares data with navigation app, like XCSoar or SkyDemon. Android app supports GPS spoofing, which can be used common nav apps like Google Maps (developer mode should be enabled on the smartphone).

Have some questions?

Your email address will not be published.

Email and website fields are optional.

The maximum upload file size: 10 MB. You can upload: image. Drop files here