source: src/mlx/flight.py@ 308:ce19a15a3152

Last change on this file since 308:ce19a15a3152 was 304:9bfef8224383, checked in by István Váradi <ivaradi@…>, 12 years ago

Cruise level changes are logged

File size: 11.9 KB
Line 
1
2from soundsched import SoundScheduler, ChecklistScheduler
3
4import const
5import util
6
7import threading
8
9#---------------------------------------------------------------------------------------
10
11## @package mlx.flight
12#
13# The global flight state.
14#
15# This module defines a single class, \ref Flight, which represents the flight
16# in progress.
17
18#---------------------------------------------------------------------------------------
19
20class Flight(object):
21 """The object with the global flight state.
22
23 It is also the hub for the other main objects participating in the handling of
24 the flight."""
25 def __init__(self, logger, gui):
26 """Construct the flight."""
27 self._stage = None
28 self.logger = logger
29 self._gui = gui
30
31 gui.resetFlightStatus()
32
33 self._pilotHotkeyPressed = False
34 self._checklistHotkeyPressed = False
35
36 self.flareTimeFromFS = False
37
38 self.aircraftType = None
39 self.aircraft = None
40 self.simulator = None
41
42 self.blockTimeStart = None
43 self.flightTimeStart = None
44 self.flightTimeEnd = None
45 self.blockTimeEnd = None
46
47 self._lastDistanceTime = None
48 self._previousLatitude = None
49 self._previousLongitude = None
50 self.flownDistance = 0.0
51
52 self.startFuel = None
53 self.endFuel = None
54
55 self._endCondition = threading.Condition()
56
57 self._flareStart = None
58 self._flareStartFS = None
59
60 self._tdRate = None
61
62 self._soundScheduler = SoundScheduler(self)
63 self._checklistScheduler = ChecklistScheduler(self)
64
65 @property
66 def config(self):
67 """Get the configuration."""
68 return self._gui.config
69
70 @property
71 def stage(self):
72 """Get the flight stage."""
73 return self._stage
74
75 @property
76 def loggedIn(self):
77 """Indicate if the user has logged in properly."""
78 return self._gui.loggedIn
79
80 @property
81 def entranceExam(self):
82 """Get whether an entrance exam is being performed."""
83 return self._gui.entranceExam
84
85 @property
86 def bookedFlight(self):
87 """Get the booked flight."""
88 return self._gui.bookedFlight
89
90 @property
91 def numCrew(self):
92 """Get the number of crew members on the flight."""
93 return self._gui.numCrew
94
95 @property
96 def numPassengers(self):
97 """Get the number of passengers on the flight."""
98 return self._gui.numPassengers
99
100 @property
101 def bagWeight(self):
102 """Get the baggage weight for the flight."""
103 return self._gui.bagWeight
104
105 @property
106 def cargoWeight(self):
107 """Get the cargo weight for the flight."""
108 return self._gui.cargoWeight
109
110 @property
111 def mailWeight(self):
112 """Get the mail weight for the flight."""
113 return self._gui.mailWeight
114
115 @property
116 def zfw(self):
117 """Get the Zero-Fuel Weight of the flight."""
118 return self._gui.zfw
119
120 @property
121 def filedCruiseAltitude(self):
122 """Get the filed cruise altitude."""
123 return self._gui.filedCruiseAltitude
124
125 @property
126 def cruiseAltitude(self):
127 """Get the cruise altitude of the flight."""
128 return self._gui.cruiseAltitude
129
130 @property
131 def route(self):
132 """Get the route of the flight."""
133 return self._gui.route
134
135 @property
136 def departureMETAR(self):
137 """Get the departure METAR of the flight."""
138 return self._gui.departureMETAR
139
140 @property
141 def arrivalMETAR(self):
142 """Get the arrival METAR of the flight."""
143 return self._gui.arrivalMETAR
144
145 @property
146 def departureRunway(self):
147 """Get the departure runway."""
148 return self._gui.departureRunway
149
150 @property
151 def sid(self):
152 """Get the SID followed."""
153 return self._gui.sid
154
155 @property
156 def v1(self):
157 """Get the V1 speed of the flight."""
158 return self._gui.v1
159
160 @property
161 def vr(self):
162 """Get the Vr speed of the flight."""
163 return self._gui.vr
164
165 @property
166 def v2(self):
167 """Get the V2 speed of the flight."""
168 return self._gui.v2
169
170 @property
171 def star(self):
172 """Get the STAR planned."""
173 return self._gui.star
174
175 @property
176 def transition(self):
177 """Get the transition planned."""
178 return self._gui.transition
179
180 @property
181 def approachType(self):
182 """Get the approach type."""
183 return self._gui.approachType
184
185 @property
186 def arrivalRunway(self):
187 """Get the arrival runway."""
188 return self._gui.arrivalRunway
189
190 @property
191 def vref(self):
192 """Get the VRef speed of the flight."""
193 return self._gui.vref
194
195 @property
196 def tdRate(self):
197 """Get the touchdown rate if known, None otherwise."""
198 return self._tdRate
199
200 @property
201 def flightType(self):
202 """Get the type of the flight."""
203 return self._gui.flightType
204
205 @property
206 def online(self):
207 """Get whether the flight was an online flight."""
208 return self._gui.online
209
210 @property
211 def comments(self):
212 """Get the comments made by the pilot."""
213 return self._gui.comments
214
215 @property
216 def flightDefects(self):
217 """Get the flight defects reported by the pilot."""
218 return self._gui.flightDefects
219
220 @property
221 def delayCodes(self):
222 """Get the delay codes."""
223 return self._gui.delayCodes
224
225 @property
226 def speedInKnots(self):
227 """Determine if the speeds for the flight are to be expressed in
228 knots."""
229 return self.aircraft.speedInKnots if self.aircraft is not None \
230 else True
231
232 def handleState(self, oldState, currentState):
233 """Handle a new state information."""
234 self._updateFlownDistance(currentState)
235
236 self.endFuel = currentState.totalFuel
237 if self.startFuel is None:
238 self.startFuel = self.endFuel
239
240 self._soundScheduler.schedule(currentState,
241 self._pilotHotkeyPressed)
242 self._pilotHotkeyPressed = False
243
244 if self._checklistHotkeyPressed:
245 self._checklistScheduler.hotkeyPressed()
246 self._checklistHotkeyPressed = False
247
248 def setStage(self, timestamp, stage):
249 """Set the flight stage.
250
251 Returns if the stage has really changed."""
252 if stage!=self._stage:
253 self._stage = stage
254 self._gui.setStage(stage)
255 self.logger.stage(timestamp, stage)
256 if stage==const.STAGE_PUSHANDTAXI:
257 self.blockTimeStart = timestamp
258 elif stage==const.STAGE_TAKEOFF:
259 self.flightTimeStart = timestamp
260 elif stage==const.STAGE_TAXIAFTERLAND:
261 self.flightTimeEnd = timestamp
262 elif stage==const.STAGE_PARKING:
263 self.blockTimeEnd = timestamp
264 elif stage==const.STAGE_END:
265 with self._endCondition:
266 self._endCondition.notify()
267 return True
268 else:
269 return False
270
271 def handleFault(self, faultID, timestamp, what, score):
272 """Handle the given fault.
273
274 faultID as a unique ID for the given kind of fault. If another fault of
275 this ID has been reported earlier, it will be reported again only if
276 the score is greater than last time. This ID can be, e.g. the checker
277 the report comes from."""
278 self.logger.fault(faultID, timestamp, what, score)
279 self._gui.setRating(self.logger.getRating())
280
281 def handleNoGo(self, faultID, timestamp, what, shortReason):
282 """Handle a No-Go fault."""
283 self.logger.noGo(faultID, timestamp, what)
284 self._gui.setNoGo(shortReason)
285
286 def flareStarted(self, flareStart, flareStartFS):
287 """Called when the flare time has started."""
288 self._flareStart = flareStart
289 self._flareStartFS = flareStartFS
290
291 def flareFinished(self, flareEnd, flareEndFS, tdRate):
292 """Called when the flare time has ended.
293
294 Return a tuple of the following items:
295 - a boolean indicating if FS time is used
296 - the flare time
297 """
298 self._tdRate = tdRate
299 if self.flareTimeFromFS:
300 return (True, flareEndFS - self._flareStartFS)
301 else:
302 return (False, flareEnd - self._flareStart)
303
304 def wait(self):
305 """Wait for the flight to end."""
306 with self._endCondition:
307 while self._stage!=const.STAGE_END:
308 self._endCondition.wait(1)
309
310 def getFleet(self, callback, force = False):
311 """Get the fleet and call the given callback."""
312 self._gui.getFleetAsync(callback = callback, force = force)
313
314 def pilotHotkeyPressed(self):
315 """Called when the pilot hotkey is pressed."""
316 self._pilotHotkeyPressed = True
317
318 def checklistHotkeyPressed(self):
319 """Called when the checklist hotkey is pressed."""
320 self._checklistHotkeyPressed = True
321
322 def speedFromKnots(self, knots):
323 """Convert the given speed value expressed in knots into the flight's
324 speed unit."""
325 return knots if self.speedInKnots else knots * const.KNOTSTOKMPH
326
327 def speedToKnots(self, speed):
328 """Convert the given speed expressed in the flight's speed unit into
329 knots."""
330 return speed if self.speedInKnots else speed * const.KMPHTOKNOTS
331
332 def getEnglishSpeedUnit(self):
333 """Get the English name of the speed unit used by the flight."""
334 return "knots" if self.speedInKnots else "km/h"
335
336 def getI18NSpeedUnit(self):
337 """Get the speed unit suffix for i18n message identifiers."""
338 return "_knots" if self.speedInKnots else "_kmph"
339
340 def logFuel(self, aircraftState):
341 """Log the amount of fuel"""
342 fuelStr = ""
343 for (tank, amount) in aircraftState.fuel:
344 if fuelStr: fuelStr += " - "
345 fuelStr += "%s=%.0f kg" % (const.fuelTank2logString(tank), amount)
346
347 self.logger.message(aircraftState.timestamp, "Fuel: " + fuelStr)
348 self.logger.message(aircraftState.timestamp,
349 "Total fuel: %.0f kg" % (aircraftState.totalFuel,))
350
351 def cruiseLevelChanged(self):
352 """Called when the cruise level hass changed."""
353 if self._stage in [const.STAGE_CRUISE, const.STAGE_DESCENT,
354 const.STAGE_LANDING]:
355 message = "Cruise altitude modified to %d feet" % \
356 (self.cruiseAltitude,)
357 self.logger.message(self.aircraft.timestamp, message)
358
359 def _updateFlownDistance(self, currentState):
360 """Update the flown distance."""
361 if not currentState.onTheGround:
362 updateData = False
363 if self._lastDistanceTime is None or \
364 self._previousLatitude is None or \
365 self._previousLongitude is None:
366 updateData = True
367 elif currentState.timestamp >= (self._lastDistanceTime + 30.0):
368 updateData = True
369 self.flownDistance += self._getDistance(currentState)
370
371 if updateData:
372 self._previousLatitude = currentState.latitude
373 self._previousLongitude = currentState.longitude
374 self._lastDistanceTime = currentState.timestamp
375 else:
376 if self._lastDistanceTime is not None and \
377 self._previousLatitude is not None and \
378 self._previousLongitude is not None:
379 self.flownDistance += self._getDistance(currentState)
380
381 self._lastDistanceTime = None
382
383 def _getDistance(self, currentState):
384 """Get the distance between the previous and the current state."""
385 return util.getDistCourse(self._previousLatitude, self._previousLongitude,
386 currentState.latitude, currentState.longitude)[0]
387
388#---------------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.