source: src/mlx/flight.py@ 304:9bfef8224383

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

Cruise level changes are logged

File size: 11.9 KB
RevLine 
[8]1
[176]2from soundsched import SoundScheduler, ChecklistScheduler
[170]3
[8]4import const
[89]5import util
[8]6
7import threading
8
9#---------------------------------------------------------------------------------------
10
[298]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
[8]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."""
[29]25 def __init__(self, logger, gui):
[8]26 """Construct the flight."""
27 self._stage = None
28 self.logger = logger
[29]29 self._gui = gui
[11]30
[31]31 gui.resetFlightStatus()
32
[170]33 self._pilotHotkeyPressed = False
34 self._checklistHotkeyPressed = False
35
[9]36 self.flareTimeFromFS = False
[11]37
[8]38 self.aircraftType = None
39 self.aircraft = None
40 self.simulator = None
41
[89]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
[8]55 self._endCondition = threading.Condition()
56
[9]57 self._flareStart = None
58 self._flareStartFS = None
59
[170]60 self._tdRate = None
61
[176]62 self._soundScheduler = SoundScheduler(self)
63 self._checklistScheduler = ChecklistScheduler(self)
64
[8]65 @property
[134]66 def config(self):
67 """Get the configuration."""
68 return self._gui.config
69
70 @property
[8]71 def stage(self):
72 """Get the flight stage."""
73 return self._stage
74
[84]75 @property
[215]76 def loggedIn(self):
77 """Indicate if the user has logged in properly."""
78 return self._gui.loggedIn
79
80 @property
[184]81 def entranceExam(self):
82 """Get whether an entrance exam is being performed."""
83 return self._gui.entranceExam
84
85 @property
[134]86 def bookedFlight(self):
87 """Get the booked flight."""
88 return self._gui.bookedFlight
89
90 @property
[303]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
[262]106 def cargoWeight(self):
107 """Get the cargo weight for the flight."""
108 return self._gui.cargoWeight
109
110 @property
[303]111 def mailWeight(self):
112 """Get the mail weight for the flight."""
113 return self._gui.mailWeight
114
115 @property
[84]116 def zfw(self):
117 """Get the Zero-Fuel Weight of the flight."""
118 return self._gui.zfw
119
120 @property
[262]121 def filedCruiseAltitude(self):
122 """Get the filed cruise altitude."""
123 return self._gui.filedCruiseAltitude
124
125 @property
[84]126 def cruiseAltitude(self):
127 """Get the cruise altitude of the flight."""
128 return self._gui.cruiseAltitude
129
130 @property
[262]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
[84]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
[86]170 @property
[262]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
[86]191 def vref(self):
192 """Get the VRef speed of the flight."""
193 return self._gui.vref
194
[170]195 @property
196 def tdRate(self):
197 """Get the touchdown rate if known, None otherwise."""
198 return self._tdRate
199
[241]200 @property
[262]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
[241]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
[89]232 def handleState(self, oldState, currentState):
233 """Handle a new state information."""
234 self._updateFlownDistance(currentState)
235
[274]236 self.endFuel = currentState.totalFuel
[89]237 if self.startFuel is None:
238 self.startFuel = self.endFuel
[170]239
240 self._soundScheduler.schedule(currentState,
241 self._pilotHotkeyPressed)
242 self._pilotHotkeyPressed = False
[89]243
[176]244 if self._checklistHotkeyPressed:
245 self._checklistScheduler.hotkeyPressed()
246 self._checklistHotkeyPressed = False
247
[8]248 def setStage(self, timestamp, stage):
[9]249 """Set the flight stage.
250
251 Returns if the stage has really changed."""
[8]252 if stage!=self._stage:
253 self._stage = stage
[84]254 self._gui.setStage(stage)
[8]255 self.logger.stage(timestamp, stage)
[89]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:
[8]265 with self._endCondition:
266 self._endCondition.notify()
[9]267 return True
268 else:
269 return False
270
[30]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)
[31]279 self._gui.setRating(self.logger.getRating())
[30]280
281 def handleNoGo(self, faultID, timestamp, what, shortReason):
282 """Handle a No-Go fault."""
283 self.logger.noGo(faultID, timestamp, what)
[31]284 self._gui.setNoGo(shortReason)
[30]285
[9]286 def flareStarted(self, flareStart, flareStartFS):
287 """Called when the flare time has started."""
288 self._flareStart = flareStart
289 self._flareStartFS = flareStartFS
290
[170]291 def flareFinished(self, flareEnd, flareEndFS, tdRate):
[9]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 """
[170]298 self._tdRate = tdRate
[9]299 if self.flareTimeFromFS:
300 return (True, flareEndFS - self._flareStartFS)
301 else:
302 return (False, flareEnd - self._flareStart)
[8]303
304 def wait(self):
305 """Wait for the flight to end."""
306 with self._endCondition:
307 while self._stage!=const.STAGE_END:
[14]308 self._endCondition.wait(1)
[8]309
[134]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
[170]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
[241]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
[274]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
[304]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
[89]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
[8]388#---------------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.