source: src/mlx/fs.py@ 708:2e411a2d77a0

Last change on this file since 708:2e411a2d77a0 was 666:bb1cfa673969, checked in by István Váradi <ivaradi@…>, 9 years ago

The pitot heat cannot be detected in case of certain models, so a value of None is handled here too (re #274)

File size: 12.8 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]:
65 return xplane.Simulator(connectionListener, connectAttempts = 3)
66 else:
67 "Only MS Flight Simulator 2004 and X or X-Plane 9 and 10 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)
215 - rpm[]: the RPM values of the piston engines (array of floats
216 of as many items as the number of engines, present only for aircraft with
217 pistons, for other aircraft it is None)
218 - reverser[]: an array of booleans indicating if the thrust reversers are
219 activated on any of the engines. The number of items equals to the number
220 of engines with a reverser.
221 - navLightsOn: a boolean indicating if the navigation lights are on. If
222 the detection of the state of the landing lights is unreliable, and should
223 not be considered, this is set to None.
224 - antiCollisionLightsOn: a boolean indicating if the anti-collision lights are on
225 - strobeLightsOn: a boolean indicating if the strobe lights are on
226 - landingLightsOn: a boolean indicating if the landing lights are on. If
227 the detection of the state of the landing lights is unreliable, and should
228 not be considered, this is set to None.
229 - pitotHeatOn: a boolean indicating if the pitot heat is on. Maybe None, if
230 the pitot heat setting cannot be read
231 - parking: a boolean indicating if the parking brake is set
232 - gearControlDown: a boolean indicating if the gear control is set to down
233 - gearsDown: a boolean indicating if the gears are down
234 - spoilersArmed: a boolean indicating if the spoilers have been armed for
235 automatic deployment
236 - spoilersExtension: the percentage of how much the spoiler is extended
237 (float)
238 - altimeter: the altimeter setting in hPa (float)
239 - qnh: the QNH in hPa (float)
240 - altimeterReliable: a boolean indicating if the altimeter setting is
241 reliable
242 - ils: the frequency of the ILS radio in MHz (string). Can be None, if
243 the frequency is unreliable or meaningless.
244 - ols_obs: the OBS setting of the ILS radio in degrees (int). Can be None, if
245 the value is unreliable or meaningless.
246 - ils_manual: a boolean indicating if the ILS radio is on manual control
247 - nav1: the frequency of the NAV1 radio in MHz (string). Can be None, if
248 the frequency is unreliable or meaningless.
249 - nav1_obs: the OBS setting of the NAV1 radio in degrees (int). Can be None, if
250 the value is unreliable or meaningless.
251 - nav1_manual: a boolean indicating if the NAV1 radio is on manual control
252 - nav2: the frequency of the NAV1 radio in MHz (string). Can be None, if
253 the frequency is unreliable or meaningless.
254 - nav2_obs: the OBS setting of the NAV2 radio in degrees (int). Can be None, if
255 the value is unreliable or meaningless.
256 - nav2_manual: a boolean indicating if the NAV2 radio is on manual control
257 - adf1: the frequency of the ADF1 radio in kHz (string). Can be None, if
258 the frequency is unreliable or meaningless.
259 - adf2: the frequency of the ADF2 radio in kHz (string). Can be None, if
260 the frequency is unreliable or meaningless.
261 - squawk: the transponder code (string)
262 - windSpeed: the speed of the wind at the aircraft in knots (float)
263 - windDirection: the direction of the wind at the aircraft in degrees (float)
264 - visibility: the visibility in metres (float)
265 - cog: the centre of gravity
266 - xpdrC: a boolean indicating whether the transponder is in C mode, or
267 None, if the state cannot be read properly
268 - autoXPDR: a boolean indicating whether the transponder is turned on
269 automatically if the aircraft becomes airborne
270 - apMaster: a boolean indicating whether the autopilot is switched on, or
271 None, if the state cannot be read properly
272 - apHeadingHold: a boolean indicating whether the autopilot's heading hold
273 mode is switched on, or None, if the state cannot be read properly
274 - apHeading: the autopilot heading value in degrees (float),
275 or None, if the state cannot be read properly
276 - apAltitudeHold: a boolean indicating whether the autopilot's altitude hold
277 mode is switched on, or None, if the state cannot be read properly
278 - apAltitude: the autopilot altitude value in feet (float),
279 or None, if the state cannot be read properly
280 - elevatorTrim: a float value indicating the deflection of the elevator
281 trim in degrees
282 - antiIceOn: a boolean value indicating if some anti-ice system is turned
283 on. It may be None, if the state of the anti-ice system cannot be read
284 reliably
285 """
Note: See TracBrowser for help on using the repository browser.