source: src/mlx/fs.py@ 1073:a5a22d24f890

python3
Last change on this file since 1073:a5a22d24f890 was 1073:a5a22d24f890, checked in by István Váradi <ivaradi@…>, 16 months ago

New constant for X-Plane 12

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