source: src/mlx/fs.py@ 953:ad2ac5a19fc2

version_0.39_maint
Last change on this file since 953:ad2ac5a19fc2 was 909:5df186bc203c, checked in by István Váradi <ivaradi@…>, 6 years ago

Explicit support for X-Plane 11.

File size: 12.9 KB
Line 
1
2import const
3from sound import startSound
4
5import os
6
7import fsuipc
8import xplane
9
10import threading
11import time
12
13#-------------------------------------------------------------------------------
14
15## @package mlx.fs
16#
17# The main interface to the flight simulator.
18#
19# The \ref createSimulator function can be used to create an instance of
20# the class that can be used to access the simulator. It expects an instance of
21# the \ref ConnectionListener class, the member functions of which will be
22# called when something happens with the connection to the simulator.
23#
24# The simulator interface is most often used to retrieve the state of the
25# simulated aircraft. Instances of class \ref AircraftState are used for this
26# purpose.
27#
28# This module also contains some definitions for message sending and implements
29# the timing logic itself.
30
31#-------------------------------------------------------------------------------
32
33class ConnectionListener(object):
34 """Base class for listeners on connections to the flight simulator."""
35 def connected(self, fsType, descriptor):
36 """Called when a connection has been established to the flight
37 simulator of the given type."""
38 print "fs.ConnectionListener.connected, fsType:", fsType, ", descriptor:", descriptor
39
40 def connectionFailed(self):
41 """Called when the connection could not be established."""
42 print "fs.ConnectionListener.connectionFailed"
43
44 def disconnected(self):
45 """Called when a connection to the flight simulator has been broken."""
46 print "fs.ConnectionListener.disconnected"
47
48#-------------------------------------------------------------------------------
49
50class SimulatorException(Exception):
51 """Exception thrown by the simulator interface for communication failure."""
52
53#-------------------------------------------------------------------------------
54
55def createSimulator(type, connectionListener):
56 """Create a simulator instance for the given simulator type with the given
57 connection listener.
58
59 The returned object should provide the following members:
60 FIXME: add info
61 """
62 if type in [const.SIM_MSFS9, const.SIM_MSFSX]:
63 return fsuipc.Simulator(connectionListener, connectAttempts = 3)
64 elif type in [const.SIM_XPLANE9, const.SIM_XPLANE10, const.SIM_XPLANE11]:
65 return xplane.Simulator(connectionListener, connectAttempts = 3)
66 else:
67 "Only MS Flight Simulator 2004 and X or X-Plane 9, 10 and 11 are supported"
68
69#-------------------------------------------------------------------------------
70
71class MessageThread(threading.Thread):
72 """Thread to handle messages."""
73 def __init__(self, config, simulator):
74 """Initialize the message thread with the given configuration and
75 simulator."""
76 super(MessageThread, self).__init__()
77
78 self._config = config
79 self._simulator = simulator
80
81 self._requestCondition = threading.Condition()
82 self._messages = []
83 self._nextMessageTime = None
84 self._toQuit = False
85
86 self.daemon = True
87
88 def add(self, messageType, text, duration, disconnect):
89 """Add the given message to the requested messages."""
90 with self._requestCondition:
91 self._messages.append((messageType, text, duration,
92 disconnect))
93 self._requestCondition.notify()
94
95 def quit(self):
96 """Quit the thread."""
97 with self._requestCondition:
98 self._toQuit = True
99 self._requestCondition.notify()
100 self.join()
101
102 def run(self):
103 """Perform the thread's operation."""
104 while True:
105 (messageType, text, duration, disconnect) = (None, None, None, None)
106 with self._requestCondition:
107 now = time.time()
108 while not self._toQuit and \
109 ((self._nextMessageTime is not None and \
110 self._nextMessageTime>now) or \
111 not self._messages):
112 self._requestCondition.wait(1)
113 now = time.time()
114
115 if self._toQuit: return
116 if self._nextMessageTime is None or \
117 self._nextMessageTime<=now:
118 self._nextMessageTime = None
119
120 if self._messages:
121 (messageType, text,
122 duration, disconnect) = self._messages[0]
123 del self._messages[0]
124
125 if text is not None:
126 self._sendMessage(messageType, text, duration, disconnect)
127
128 def _sendMessage(self, messageType, text, duration, disconnect):
129 """Send the message and setup the next message time."""
130 messageLevel = self._config.getMessageTypeLevel(messageType)
131 if messageLevel==const.MESSAGELEVEL_SOUND or \
132 messageLevel==const.MESSAGELEVEL_BOTH:
133 startSound(const.SOUND_NOTIFY
134 if messageType==const.MESSAGETYPE_VISIBILITY
135 else const.SOUND_DING)
136 if (messageLevel==const.MESSAGELEVEL_FS or \
137 messageLevel==const.MESSAGELEVEL_BOTH):
138 if disconnect:
139 self._simulator.disconnect("[MLX] " + text,
140 duration = duration)
141 else:
142 self._simulator.sendMessage("[MLX] " + text,
143 duration = duration)
144 elif disconnect:
145 self._simulator.disconnect()
146 self._nextMessageTime = time.time() + duration
147
148#-------------------------------------------------------------------------------
149
150_messageThread = None
151
152#-------------------------------------------------------------------------------
153
154def setupMessageSending(config, simulator):
155 """Setup message sending with the given config and simulator."""
156 global _messageThread
157 if _messageThread is not None:
158 _messageThread.quit()
159 _messageThread = MessageThread(config, simulator)
160 _messageThread.start()
161
162#-------------------------------------------------------------------------------
163
164def sendMessage(messageType, text, duration = 3, disconnect = False):
165 """Send the given message of the given type into the simulator and/or play
166 a corresponding sound."""
167 global _messageThread
168 if _messageThread is not None:
169 _messageThread.add(messageType, text, duration, disconnect)
170
171#-------------------------------------------------------------------------------
172
173class AircraftState(object):
174 """Base class for the aircraft state produced by the aircraft model based
175 on readings from the simulator.
176
177 The following data members should be provided at least:
178 - timestamp: the simulator time of the measurement in seconds since the
179 epoch (float)
180 - latitude (in degrees, North is positive)
181 - longitude (in degrees, East is positive)
182 - paused: a boolean indicating if the flight simulator is paused for
183 whatever reason (it could be a pause mode, or a menu, a dialog, or a
184 replay, etc.)
185 - trickMode: a boolean indicating if some "trick" mode (e.g. "SLEW" in
186 MSFS) is activated
187 - overspeed: a boolean indicating if the aircraft is in overspeed
188 - stalled: a boolean indicating if the aircraft is stalled
189 - onTheGround: a boolean indicating if the aircraft is on the ground
190 - zfw: the zero-fuel weight in kilograms (float)
191 - grossWeight: the gross weight in kilograms (float)
192 - heading: the heading of the aircraft in degrees (float)
193 - pitch: the pitch of the aircraft in degrees. Positive means pitch down,
194 negative means pitch up (float)
195 - bank: the bank of the aircraft in degrees. Positive means bank left,
196 negative means bank right (float)
197 - ias: the indicated airspeed in knots (float)
198 - smoothedIAS: the smoothed IAS in knots (float)
199 - mach: the airspeed in mach (float)
200 - groundSpeed: the ground speed (float)
201 - vs: the vertical speed in feet/minutes (float)
202 - smoothedVS: the smoothed VS in feet/minutes (float)
203 - radioAltitude: the radio altitude of the aircraft in feet (float)
204 - altitude: the altitude of the aircraft in feet (float)
205 - gLoad: G-load (float)
206 - flapsSet: the selected degrees of the flaps (float)
207 - flaps: the actual degrees of the flaps (float)
208 - fuel[]: the fuel information. It is a list of tuples with items:
209 the fuel tank identifier and the amount of fuel in that tank in
210 kgs
211 - totalFuel: the total amount of fuel in kg
212 - n1[]: the N1 values of the turbine engines (array of floats
213 of as many items as the number of engines, present only for aircraft with
214 turbines, for other aircraft it is None). If the aircraft has turbines, but
215 the N1 values cannot be read reliably, the array contains Nones.
216 - rpm[]: the RPM values of the piston engines (array of floats
217 of as many items as the number of engines, present only for aircraft with
218 pistons, for other aircraft it is None)
219 - reverser[]: an array of booleans indicating if the thrust reversers are
220 activated on any of the engines. The number of items equals to the number
221 of engines with a reverser.
222 - navLightsOn: a boolean indicating if the navigation lights are on. If
223 the detection of the state of the landing lights is unreliable, and should
224 not be considered, this is set to None.
225 - antiCollisionLightsOn: a boolean indicating if the anti-collision lights are on
226 - strobeLightsOn: a boolean indicating if the strobe lights are on
227 - landingLightsOn: a boolean indicating if the landing lights are on. If
228 the detection of the state of the landing lights is unreliable, and should
229 not be considered, this is set to None.
230 - pitotHeatOn: a boolean indicating if the pitot heat is on. Maybe None, if
231 the pitot heat setting cannot be read
232 - parking: a boolean indicating if the parking brake is set
233 - gearControlDown: a boolean indicating if the gear control is set to down
234 - gearsDown: a boolean indicating if the gears are down
235 - spoilersArmed: a boolean indicating if the spoilers have been armed for
236 automatic deployment
237 - spoilersExtension: the percentage of how much the spoiler is extended
238 (float)
239 - altimeter: the altimeter setting in hPa (float)
240 - qnh: the QNH in hPa (float)
241 - altimeterReliable: a boolean indicating if the altimeter setting is
242 reliable
243 - ils: the frequency of the ILS radio in MHz (string). Can be None, if
244 the frequency is unreliable or meaningless.
245 - ols_obs: the OBS setting of the ILS radio in degrees (int). Can be None, if
246 the value is unreliable or meaningless.
247 - ils_manual: a boolean indicating if the ILS radio is on manual control
248 - nav1: the frequency of the NAV1 radio in MHz (string). Can be None, if
249 the frequency is unreliable or meaningless.
250 - nav1_obs: the OBS setting of the NAV1 radio in degrees (int). Can be None, if
251 the value is unreliable or meaningless.
252 - nav1_manual: a boolean indicating if the NAV1 radio is on manual control
253 - nav2: the frequency of the NAV1 radio in MHz (string). Can be None, if
254 the frequency is unreliable or meaningless.
255 - nav2_obs: the OBS setting of the NAV2 radio in degrees (int). Can be None, if
256 the value is unreliable or meaningless.
257 - nav2_manual: a boolean indicating if the NAV2 radio is on manual control
258 - adf1: the frequency of the ADF1 radio in kHz (string). Can be None, if
259 the frequency is unreliable or meaningless.
260 - adf2: the frequency of the ADF2 radio in kHz (string). Can be None, if
261 the frequency is unreliable or meaningless.
262 - squawk: the transponder code (string)
263 - windSpeed: the speed of the wind at the aircraft in knots (float)
264 - windDirection: the direction of the wind at the aircraft in degrees (float)
265 - visibility: the visibility in metres (float)
266 - cog: the centre of gravity
267 - xpdrC: a boolean indicating whether the transponder is in C mode, or
268 None, if the state cannot be read properly
269 - autoXPDR: a boolean indicating whether the transponder is turned on
270 automatically if the aircraft becomes airborne
271 - apMaster: a boolean indicating whether the autopilot is switched on, or
272 None, if the state cannot be read properly
273 - apHeadingHold: a boolean indicating whether the autopilot's heading hold
274 mode is switched on, or None, if the state cannot be read properly
275 - apHeading: the autopilot heading value in degrees (float),
276 or None, if the state cannot be read properly
277 - apAltitudeHold: a boolean indicating whether the autopilot's altitude hold
278 mode is switched on, or None, if the state cannot be read properly
279 - apAltitude: the autopilot altitude value in feet (float),
280 or None, if the state cannot be read properly
281 - elevatorTrim: a float value indicating the deflection of the elevator
282 trim in degrees
283 - antiIceOn: a boolean value indicating if some anti-ice system is turned
284 on. It may be None, if the state of the anti-ice system cannot be read
285 reliably
286 """
Note: See TracBrowser for help on using the repository browser.