source: src/mlx/fs.py@ 497:0ac65bf1abb7

xplane
Last change on this file since 497:0ac65bf1abb7 was 420:fc063b7b571e, checked in by István Váradi <ivaradi@…>, 12 years ago

Implemented the most important parts of X-Plane support

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