source: src/mlx/fs.py@ 166:e4ba22b7a13b

Last change on this file since 166:e4ba22b7a13b was 152:f0701a18628a, checked in by István Váradi <ivaradi@…>, 12 years ago

Made the sending of the closing message more reliable

File size: 9.1 KB
RevLine 
[3]1# Module for generic flight-simulator interfaces
2
[4]3#-------------------------------------------------------------------------------
[3]4
[4]5import const
[133]6from sound import startSound
[3]7
[59]8import fsuipc
[133]9import threading
10import time
[59]11
[4]12#-------------------------------------------------------------------------------
[3]13
[4]14class ConnectionListener(object):
[3]15 """Base class for listeners on connections to the flight simulator."""
16 def connected(self, fsType, descriptor):
17 """Called when a connection has been established to the flight
18 simulator of the given type."""
19 print "fs.ConnectionListener.connected, fsType:", fsType, ", descriptor:", descriptor
20
[59]21 def connectionFailed(self):
22 """Called when the connection could not be established."""
23 print "fs.ConnectionListener.connectionFailed"
24
[3]25 def disconnected(self):
26 """Called when a connection to the flight simulator has been broken."""
27 print "fs.ConnectionListener.disconnected"
28
[4]29#-------------------------------------------------------------------------------
30
31class SimulatorException(Exception):
32 """Exception thrown by the simulator interface for communication failure."""
33
34#-------------------------------------------------------------------------------
35
[15]36def createSimulator(type, connectionListener):
[4]37 """Create a simulator instance for the given simulator type with the given
38 connection listener.
39
40 The returned object should provide the following members:
41 FIXME: add info
42 """
[15]43 assert type in [const.SIM_MSFS9, const.SIM_MSFSX], \
44 "Only MS Flight Simulator 2004 and X are supported"
[59]45 return fsuipc.Simulator(connectionListener, connectAttempts = 3)
[4]46
47#-------------------------------------------------------------------------------
48
[133]49class MessageThread(threading.Thread):
50 """Thread to handle messages."""
51 def __init__(self, config, simulator):
52 """Initialize the message thread with the given configuration and
53 simulator."""
54 super(MessageThread, self).__init__()
55
56 self._config = config
57 self._simulator = simulator
58
59 self._requestCondition = threading.Condition()
60 self._messages = []
61 self._nextMessageTime = None
62 self._toQuit = False
63
64 self.daemon = True
65
[152]66 def add(self, messageType, text, duration, disconnect):
[133]67 """Add the given message to the requested messages."""
68 with self._requestCondition:
[152]69 self._messages.append((messageType, text, duration,
70 disconnect))
[133]71 self._requestCondition.notify()
72
73 def quit(self):
74 """Quit the thread."""
75 with self._requestCondition:
76 self._toQuit = True
77 self._requestCondition.notifty()
78 self.join()
79
80 def run(self):
81 """Perform the thread's operation."""
82 while True:
[152]83 (messageType, text, duration, disconnect) = (None, None, None, None)
[133]84 with self._requestCondition:
85 now = time.time()
86 while not self._toQuit and \
87 ((self._nextMessageTime is not None and \
88 self._nextMessageTime>now) or \
89 not self._messages):
90 self._requestCondition.wait(1)
91 now = time.time()
92
93 if self._toQuit: return
94 if self._nextMessageTime is None or \
95 self._nextMessageTime<=now:
96 self._nextMessageTime = None
97
98 if self._messages:
[152]99 (messageType, text,
100 duration, disconnect) = self._messages[0]
[133]101 del self._messages[0]
102
103 if text is not None:
[152]104 self._sendMessage(messageType, text, duration, disconnect)
[133]105
[152]106 def _sendMessage(self, messageType, text, duration, disconnect):
[133]107 """Send the message and setup the next message time."""
108 messageLevel = self._config.getMessageTypeLevel(messageType)
109 if messageLevel==const.MESSAGELEVEL_SOUND or \
110 messageLevel==const.MESSAGELEVEL_BOTH:
111 startSound(const.SOUND_DING)
112 if (messageLevel==const.MESSAGELEVEL_FS or \
113 messageLevel==const.MESSAGELEVEL_BOTH):
[152]114 if disconnect:
115 self._simulator.disconnect("[MLX] " + text,
116 duration = duration)
117 else:
118 self._simulator.sendMessage("[MLX] " + text,
119 duration = duration)
120 elif disconnecte:
121 self._simulator.disconnect()
[133]122 self._nextMessageTime = time.time() + duration
123
124#-------------------------------------------------------------------------------
125
126_messageThread = None
127
128#-------------------------------------------------------------------------------
129
130def setupMessageSending(config, simulator):
131 """Setup message sending with the given config and simulator."""
132 global _messageThread
133 if _messageThread is not None:
134 _messageThread.quit()
135 _messageThread = MessageThread(config, simulator)
136 _messageThread.start()
137
138#-------------------------------------------------------------------------------
139
[152]140def sendMessage(messageType, text, duration = 3, disconnect = False):
[133]141 """Send the given message of the given type into the simulator and/or play
142 a corresponding sound."""
143 global _messageThread
144 if _messageThread is not None:
[152]145 _messageThread.add(messageType, text, duration, disconnect)
[133]146
147#-------------------------------------------------------------------------------
148
[4]149class AircraftState(object):
150 """Base class for the aircraft state produced by the aircraft model based
151 on readings from the simulator.
152
153 The following data members should be provided at least:
154 - timestamp: the simulator time of the measurement in seconds since the
155 epoch (float)
[89]156 - latitude (in degrees, North is positive)
157 - longitude (in degrees, East is positive)
[4]158 - paused: a boolean indicating if the flight simulator is paused for
159 whatever reason (it could be a pause mode, or a menu, a dialog, or a
160 replay, etc.)
161 - trickMode: a boolean indicating if some "trick" mode (e.g. "SLEW" in
162 MSFS) is activated
163 - overspeed: a boolean indicating if the aircraft is in overspeed
164 - stalled: a boolean indicating if the aircraft is stalled
[89]165 - onTheGround: a boolean indicating if the aircraft is on the ground
[9]166 - zfw: the zero-fuel weight in kilograms (float)
[4]167 - grossWeight: the gross weight in kilograms (float)
168 - heading: the heading of the aircraft in degrees (float)
169 - pitch: the pitch of the aircraft in degrees. Positive means pitch down,
170 negative means pitch up (float)
171 - bank: the bank of the aircraft in degrees. Positive means bank left,
172 negative means bank right (float)
173 - ias: the indicated airspeed in knots (float)
[9]174 - mach: the airspeed in mach (float)
[5]175 - groundSpeed: the ground speed (float)
[4]176 - vs: the vertical speed in feet/minutes (float)
[8]177 - radioAltitude: the radio altitude of the aircraft in feet (float)
[4]178 - altitude: the altitude of the aircraft in feet (float)
[5]179 - gLoad: G-load (float)
[4]180 - flapsSet: the selected degrees of the flaps (float)
181 - flaps: the actual degrees of the flaps (float)
[5]182 - fuelWeight[]: the fuel weights in the different tanks in kgs (array of
183 floats of as many items as the number fuel tanks)
[4]184 - n1[]: the N1 values of the turbine engines (array of floats
185 of as many items as the number of engines, present only for aircraft with
186 turbines)
187 - rpm[]: the RPM values of the piston engines (array of floats
188 of as many items as the number of engines, present only for aircraft with
189 pistons)
190 - reverser[]: an array of booleans indicating if the thrust reversers are
191 activated on any of the engines. The number of items equals to the number
[11]192 of engines with a reverser.
[4]193 - navLightsOn: a boolean indicating if the navigation lights are on
194 - antiCollisionLightsOn: a boolean indicating if the anti-collision lights are on
195 - strobeLightsOn: a boolean indicating if the strobe lights are on
[15]196 - landingLightsOn: a boolean indicating if the landing lights are on
[4]197 - pitotHeatOn: a boolean indicating if the pitot heat is on
[8]198 - parking: a boolean indicating if the parking brake is set
[4]199 - gearsDown: a boolean indicating if the gears are down
200 - spoilersArmed: a boolean indicating if the spoilers have been armed for
201 automatic deployment
202 - spoilersExtension: the percentage of how much the spoiler is extended
203 (float)
[5]204 - altimeter: the altimeter setting in hPa (float)
205 - nav1: the frequency of the NAV1 radio in MHz (string)
206 - nav2: the frequency of the NAV1 radio in MHz (string)
[15]207 - squawk: the transponder code (string)
[9]208 - windSpeed: the speed of the wind at the aircraft in knots (float)
209 - windDirection: the direction of the wind at the aircraft in degrees (float)
[134]210 - visibility: the visibility in metres (float)
[4]211
212 FIXME: needed when taxiing only:
[5]213 - payload weight
[4]214
[5]215 FIXME: needed rarely:
216 - latitude, longitude
217 - transporter
218 - visibility
[4]219 """
220
Note: See TracBrowser for help on using the repository browser.