Standalone Python with UDP¶
In addition to plugins, X-Plane supports external communications via UDP. This allows any number of separate processes (potentially on separate computers) to get and set data remotely and execute some commands.
This is completely unrelated to XPPython3, but as you’re programming in python I figured I might as well introduce you to this method of interaction as well.
Intro to UDP¶
UDP simply sends one packet of data – like throwing a rock – it might make it to the receiver, it might not (as opposed to TCP, which is more like a pipe.) Packets are not guaranteed to arrive in order, nor are they even guaranteed to arrive. But they’re quick, with low overhead.
The size of the packet is limited by the protocol – about 65k bytes. The content of the packet can be anything, but the sender and receiver have to agree.
UDP and Python¶
UDP is pretty simple: you’ll create a UDP (i.e., DATAGRAM) socket, and then use that socket to send information to a remote port:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
msg = makeMsg()
sock.send_to(msg, (X_PLANE_IP, UDP_PORT))
Receiving information is similarly simple:
data, addr = sock.recvfrom(2048)
handleData(data)
The more difficult part is working this sent_to() and recvfrom() into a working program
so you don’t get confused while interleaving sends and receives. (You can put the receiver in a
python thread. See example in RREF - Get Datarefs.)
UDP and X-Plane¶
X-Plane understands a particular format, described in <XP>/Instructions/X-Plane SPECS from Austin/Exchanging Data with X-Plane.rtfd. However, that document is not accurate. I suppose because it’s just not been updated in a while, but it no longer matches with X-Plane 11.55+ does.
X-Plane’s interface is (usually) described using C language structures and expects a particular size and encoding of data. You’ll have to format (‘pack’) the python data into the proper structure before sending it to X-Plane, and unpack any received data in a similar manner.
The easiest way to pack and unpack is to use the python struct module. For example:
cmd = b'RREF'
freq = 1
index = 0
msg = struct.pack("<4sxii400s", cmd, freq, index, b'sim/aircraft/engines/acf_num_engines')
The initial string <4sxii400s describes how to pack the remaining arguments:
>little endian (i.e., least significant byte in the lowest memory position)
4sa 4-byte object, commonly string, e.g., ‘RREF’, expressed as a bytes: b’RREF’.
xa null byte, or 0x00. X-Plane is looking for a null-terminated 4-character string & this encodes the null value. (does not consume an argument). Yes, you could use
5s, without thexfor the same effect, but this method emphasizes the usable command is a 4-character value
ia 4-byte integer
ianother 4-byte integer (you could also combine these as
2i, which consumes two integer arguments)
400sa 400-byte object. Note that Python pads and zero-fills to fit 400 bytes.
Basically what you’ll do is “find” X-Plane – the host IP address and port (See Connecting with X-Plane, next), and then you’ll send one or more command packets to it & wait for data packets.
Connecting with X-Plane¶
X-Plane automatically broadcasts a “beacon” on the network, allowing other programs to find it. Ideally, you should listen for this beacon to tell your standalone program a) X-Plane is running; and, b) where it is located.
Multicast beacons are pretty standard, the only “custom” aspects are which port the multicast is on (49707 for X-Plane) and the data contents of the beacon itself.
See example code in find_xp() which will wait for X-Plane to startup and will then return information about the version of X-Plane found.
You can use it like:
beacon = find_xp()
port = beacon['port']
ip = beacon['ip']
By default, X-Plane is set for UDP networking. You do not have to enable anything under X-Plane Settings->Network. This includes External Visuals, External Apps, or UDP Ports.
Note your socket related to the beacon is different from the socket you use to send and receive information from X-Plane. One you’ve found X-Plane, you can close the beacon socket.
X-Plane UDP Summary¶
SEND
Cmd - Description
Structure
ACFN <index><path><livery>
ACPR <acfn><prel>
ALRT <line1><line2<line3><line4>
CMND <command>
DREF <value><dataref>
DSEL <index><index>…
USEL <index><index>…
FAIL <index>
RECO <index>
FLIR <frequency>
(Deprecated since 11.41)
ISE4 <cmd><ip><port><enable>
ISE6 <cmd><ip><port><enable>
LSND<index><freq><vol><path>
SSND<index><freq><vol><path>
NFAL <navaid_id>
NREC <navaid_id>
OBJN <index><path>
- OBJL <index><lat><lon><ele><psi><theta>
<phi><on_ground><smoke_size>
- PREL <type_start><index><apt_id>
<rwy_id><rwy_dir> <lat><lon><elev><psi><spd>
RADR <freq>
RESE
RPOS <freq>
RREF <freq><index><dataref>
SIMO<type><path>
SHUT
QUIT
SOUN<freq><vol><path>
- VEHX <plane><lat><log><elev>
<psi><theta><ph>
RECEIVE
Cmd
In response to
Structure
DATA*
DATA*<index><val1><val2>…<val8>
FLIR
(Deprecated since 11.41)
RADR5
RADR5<lon><lat><level><height>
RPOS4
RPOS4 <lon><lat><elev><agl><theta><psi> <phi><vx><vy><vz><P><Q><R>
RREF
RREF <index><value><index><value>…
Details
- ACFN - Load an Aircraft
- ACPR - Load and Init the Airplane at Location
- ALRT - Display Alert Message
- CMND - Execute Command
- DREF - Set Datarefs
- DSEL/USEL - Stream Data Output
- FAIL/RECO - Fail a System
- FLIR - Forward Looking Infrared Images
- ISE4/ISE6 - Set Network Parameters
- LSND/SSND - Loop a Sound
- NFAL/NREC - Fail/Recover NavAid
- OBJN/OBJL - Load and Place Object
- PREL - Init the Airplane at Location
- RADR - Weather Radar
- RESE - Reset Failures
- RPOS - Request Aircraft Position
- RREF - Get Datarefs
- SIMO - Load or Save a Situation or Movie
- SHUT/QUIT - Quit X-Plane
- SOUN - Play a Sound
- VEHX - Drive X-Planes Visuals
