Changeset 59:a3e0b8455dc8
- Timestamp:
- 04/07/12 08:48:34 (13 years ago)
- Branch:
- default
- Phase:
- public
- Location:
- src/mlx
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
src/mlx/flight.py
r31 r59 34 34 self.flareTimeFromFS = False 35 35 self.entranceExam = False 36 self.zfw = 5000036 self.zfw = None 37 37 38 38 self.options = Options() -
src/mlx/fs.py
r27 r59 4 4 5 5 import const 6 7 import fsuipc 6 8 7 9 #------------------------------------------------------------------------------- … … 13 15 simulator of the given type.""" 14 16 print "fs.ConnectionListener.connected, fsType:", fsType, ", descriptor:", descriptor 17 18 def connectionFailed(self): 19 """Called when the connection could not be established.""" 20 print "fs.ConnectionListener.connectionFailed" 15 21 16 22 def disconnected(self): … … 34 40 assert type in [const.SIM_MSFS9, const.SIM_MSFSX], \ 35 41 "Only MS Flight Simulator 2004 and X are supported" 36 import fsuipc 37 return fsuipc.Simulator(connectionListener) 42 return fsuipc.Simulator(connectionListener, connectAttempts = 3) 38 43 39 44 #------------------------------------------------------------------------------- -
src/mlx/fsuipc.py
r51 r59 59 59 return None 60 60 61 # The number of times a read is attempted 61 62 NUM_READATTEMPTS = 3 63 64 # The number of connection attempts 65 NUM_CONNECTATTEMPTS = 3 66 67 # The interval between successive connect attempts 68 CONNECT_INTERVAL = 0.25 62 69 63 70 @staticmethod … … 172 179 return cmp(self._nextFire, other._nextFire) 173 180 174 def __init__(self, connectionListener): 181 def __init__(self, connectionListener, 182 connectAttempts = -1, connectInterval = 0.2): 175 183 """Construct the handler with the given connection listener.""" 176 184 threading.Thread.__init__(self) 177 185 178 186 self._connectionListener = connectionListener 187 self._connectAttempts = connectAttempts 188 self._connectInterval = connectInterval 179 189 180 190 self._requestCondition = threading.Condition() 181 191 self._connectionRequested = False 182 self._connected = False 192 self._connected = False 183 193 184 194 self._requests = [] … … 266 276 """Disconnect from the flight simulator.""" 267 277 with self._requestCondition: 278 self._requests = [] 268 279 if self._connectionRequested: 269 self._connectionRequested = False 280 self._connectionRequested = False 270 281 self._requestCondition.notify() 282 283 def clearRequests(self): 284 """Clear the outstanding one-shot requests.""" 285 with self._requestCondition: 286 self._requests = [] 271 287 272 288 def run(self): … … 286 302 self._requestCondition.wait() 287 303 288 def _connect(self ):304 def _connect(self, autoReconnection = False): 289 305 """Try to connect to the flight simulator via FSUIPC 290 306 … … 292 308 not due to no longer requested. 293 309 """ 310 attempts = 0 294 311 while self._connectionRequested: 295 312 try: 313 attempts += 1 296 314 pyuipc.open(pyuipc.SIM_ANY) 297 315 description = "(FSUIPC version: 0x%04x, library version: 0x%04x, FS version: %d)" % \ 298 316 (pyuipc.fsuipc_version, pyuipc.lib_version, 299 317 pyuipc.fs_version) 300 Handler._callSafe(lambda: 301 self._connectionListener.connected(const.SIM_MSFS9, 302 description)) 318 if not autoReconnection: 319 Handler._callSafe(lambda: 320 self._connectionListener.connected(const.SIM_MSFS9, 321 description)) 303 322 self._connected = True 304 323 return True 305 324 except Exception, e: 306 325 print "fsuipc.Handler._connect: connection failed: " + str(e) 307 time.sleep(0.1) 326 if attempts<self.NUM_CONNECTATTEMPTS: 327 time.sleep(self.CONNECT_INTERVAL) 328 else: 329 self._connectionRequested = False 330 if autoReconnection: 331 Handler._callSafe(lambda: 332 self._connectionListener.disconnected()) 333 else: 334 Handler._callSafe(lambda: 335 self._connectionListener.connectionFailed()) 308 336 309 337 return False … … 337 365 if self._connected: 338 366 pyuipc.close() 339 Handler._callSafe(lambda: self._connectionListener.disconnected())340 367 self._connected = False 341 342 def _failRequests(self, request): 343 """Fail the outstanding, single-shot requuests.""" 344 request.fail() 345 with self._requestCondition: 346 for request in self._requests: 347 try: 348 self._requestCondition.release() 349 request.fail() 350 finally: 351 self._requestCondition.acquire() 352 self._requests = [] 353 368 354 369 def _processRequest(self, request, time): 355 370 """Process the given request. … … 377 392 378 393 if needReconnect: 394 with self._requestCondition: 395 self._requests.insert(0, request) 379 396 self._disconnect() 380 self._failRequests(request) 381 self._connect() 397 self._connect(autoReconnection = True) 382 398 finally: 383 399 self._requestCondition.acquire() … … 437 453 (0x0580, "d") ] # Heading 438 454 439 def __init__(self, connectionListener): 455 def __init__(self, connectionListener, connectAttempts = -1, 456 connectInterval = 0.2): 440 457 """Construct the simulator. 441 458 … … 460 477 self._aircraft = None 461 478 462 self._handler = Handler(connectionListener) 479 self._handler = Handler(connectionListener, 480 connectAttempts = connectAttempts, 481 connectInterval = connectInterval) 463 482 self._handler.start() 464 483 … … 484 503 self._aircraftModel = None 485 504 self._handler.connect() 486 self._startDefaultNormal() 505 if self._normalRequestID is None: 506 self._startDefaultNormal() 507 508 def reconnect(self): 509 """Initiate a reconnection to the simulator. 510 511 It does not reset already set up data, just calls connect() on the 512 handler.""" 513 self._handler.connect() 514 515 def requestZFW(self, callback): 516 """Send a request for the ZFW.""" 517 self._handler.requestRead([(0x3bfc, "d")], self._handleZFW, extra = callback) 487 518 488 519 def startMonitoring(self): … … 683 714 else: 684 715 self._addFlareRate(data[2]) 716 717 def _handleZFW(self, data, callback): 718 """Callback for a ZFW retrieval request.""" 719 zfw = data[0] * const.LBSTOKG / 256.0 720 callback(zfw) 685 721 686 722 #------------------------------------------------------------------------------ -
src/mlx/gui/flight.py
r58 r59 494 494 #----------------------------------------------------------------------------- 495 495 496 class PayloadPage(Page): 497 """Page to allow setting up the payload.""" 498 def __init__(self, wizard): 499 """Construct the page.""" 500 help = "The briefing contains the weights below.\n" \ 501 "Setup the cargo weight and check if the simulator\n" \ 502 "reports the expected Zero Fuel Weight." 503 super(PayloadPage, self).__init__(wizard, "Payload", help) 504 505 button = gtk.Button("_Query ZFW") 506 button.connect("clicked", self._zfwRequested) 507 self.setMainWidget(button) 508 509 def _zfwRequested(self, button): 510 """Called when the ZFW is requested from the simulator.""" 511 self._wizard.gui.simulator.requestZFW(self._handleZFW) 512 513 def _handleZFW(self, zfw): 514 """Called when the ZFW value is retrieved.""" 515 print "ZFW", zfw 516 517 #----------------------------------------------------------------------------- 518 496 519 class Wizard(gtk.VBox): 497 520 """The flight wizard.""" … … 509 532 self._pages.append(GateSelectionPage(self)) 510 533 self._pages.append(ConnectPage(self)) 534 self._pages.append(PayloadPage(self)) 511 535 512 536 maxWidth = 0 … … 523 547 self.set_size_request(maxWidth, maxHeight) 524 548 525 self._fleet = None 526 self._fleetCallback = None 527 self._updatePlaneCallback = None 528 529 self._loginResult = None 530 self._bookedFlight = None 531 self._departureGate = "-" 532 533 self._logger = Logger(output = gui) 534 self._flight = None 535 self._simulator = None 536 537 self.setCurrentPage(0) 549 self._initialize() 538 550 539 551 @property … … 567 579 self._pages[self._currentPage].grabDefault() 568 580 581 def connected(self, fsType, descriptor): 582 """Called when the connection could be made to the simulator.""" 583 self.nextPage() 584 585 def connectionFailed(self): 586 """Called when the connection could not be made to the simulator.""" 587 self._initialize() 588 589 def disconnected(self): 590 """Called when we have disconnected from the simulator.""" 591 self._initialize() 592 593 def _initialize(self): 594 """Initialize the wizard.""" 595 self._fleet = None 596 self._fleetCallback = None 597 self._updatePlaneCallback = None 598 599 self._loginResult = None 600 self._bookedFlight = None 601 self._departureGate = "-" 602 603 self.setCurrentPage(0) 604 569 605 def _getFleet(self, callback, force = False): 570 606 """Get the fleet, if needed. … … 634 670 def _connectSimulator(self): 635 671 """Connect to the simulator.""" 636 self._logger.reset() 637 self._flight = Flight(self.gui._logger, self.gui) 638 639 self._flight.aircraftType = self._bookedFlight.aircraftType 640 aircraft = self._flight.aircraft = Aircraft.create(self._flight) 641 self._flight.aircraft._checkers.append(self.gui) 642 643 self._flight.cruiseAltitude = -1 644 self._flight.zfw = -1 645 646 if self._simulator is None: 647 self._simulator = fs.createSimulator(const.SIM_MSFS9, self.gui) 648 649 self._flight.simulator = self._simulator 650 self._simulator.connect(aircraft) 651 #self._simulator.startMonitoring() 672 self.gui.connectSimulator(self._bookedFlight.aircraftType) 652 673 653 674 #----------------------------------------------------------------------------- -
src/mlx/gui/gui.py
r51 r59 43 43 self.config = config 44 44 self._connecting = False 45 self._reconnecting = False 45 46 self._connected = False 46 47 self._logger = logger.Logger(output = self) 47 48 self._flight = None 48 49 self._simulator = None 50 self._monitoring = False 49 51 50 52 self._stdioLock = threading.Lock() … … 127 129 else gdk.WATCH) 128 130 131 @property 132 def simulator(self): 133 """Get the simulator used by us.""" 134 return self._simulator 135 129 136 def run(self): 130 137 """Run the GUI.""" … … 140 147 if self._flight is not None: 141 148 simulator = self._flight.simulator 142 simulator.stopMonitoring() 143 simulator.disconnect() 149 if self._monitoring: 150 simulator.stopMonitoring() 151 self._monitoring = False 152 simulator.disconnect() 144 153 145 154 def connected(self, fsType, descriptor): … … 147 156 self._connected = True 148 157 self._logger.untimedMessage("Connected to the simulator %s" % (descriptor,)) 149 gobject.idle_add(self._statusbar.updateConnection, 150 self._connecting, self._connected) 158 gobject.idle_add(self._handleConnected, fsType, descriptor) 159 160 def _handleConnected(self, fsType, descriptor): 161 """Called when the connection to the simulator has succeeded.""" 162 self._statusbar.updateConnection(self._connecting, self._connected) 163 self.endBusy() 164 if not self._reconnecting: 165 self._wizard.connected(fsType, descriptor) 166 self._reconnecting = False 167 168 def connectionFailed(self): 169 """Called when the connection failed.""" 170 self._logger.untimedMessage("Connection to the simulator failed") 171 gobject.idle_add(self._connectionFailed) 172 173 def _connectionFailed(self): 174 """Called when the connection failed.""" 175 self.endBusy() 176 self._statusbar.updateConnection(self._connecting, self._connected) 177 178 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR, 179 message_format = 180 "Cannot connect to the simulator.", 181 parent = self._mainWindow) 182 dialog.format_secondary_markup("Rectify the situation, and press <b>Try again</b> " 183 "to try the connection again, " 184 "or <b>Cancel</b> to cancel the flight.") 185 186 dialog.add_button("_Cancel", 0) 187 dialog.add_button("_Try again", 1) 188 dialog.set_default_response(1) 189 190 result = dialog.run() 191 dialog.hide() 192 if result == 1: 193 self.beginBusy("Connecting to the simulator.") 194 self._simulator.reconnect() 195 else: 196 self._connecting = False 197 self._reconnecting = False 198 self._statusbar.updateConnection(self._connecting, self._connected) 199 self._wizard.connectionFailed() 151 200 152 201 def disconnected(self): … … 154 203 self._connected = False 155 204 self._logger.untimedMessage("Disconnected from the simulator") 156 gobject.idle_add(self._statusbar.updateConnection, 157 self._connecting, self._connected) 205 206 gobject.idle_add(self._disconnected) 207 208 def _disconnected(self): 209 """Called when we have disconnected from the simulator unexpectedly.""" 210 self._statusbar.updateConnection(self._connecting, self._connected) 211 212 dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR, 213 message_format = 214 "The connection to the simulator failed unexpectedly.", 215 parent = self._mainWindow) 216 dialog.format_secondary_markup("If the simulator has crashed, restart it " 217 "and restore your flight as much as possible " 218 "to the state it was in before the crash.\n" 219 "Then press <b>Reconnect</b> to reconnect.\n\n" 220 "If you want to cancel the flight, press <b>Cancel</b>.") 221 222 dialog.add_button("_Cancel", 0) 223 dialog.add_button("_Reconnect", 1) 224 dialog.set_default_response(1) 225 226 result = dialog.run() 227 dialog.hide() 228 if result == 1: 229 self.beginBusy("Connecting to the simulator.") 230 self._reconnecting = True 231 self._simulator.reconnect() 232 else: 233 self._connecting = False 234 self._reconnecting = False 235 self._statusbar.updateConnection(self._connecting, self._connected) 236 self._wizard.disconnected() 158 237 159 238 def write(self, msg): … … 285 364 self._stdioAfterNewLine = False 286 365 366 def connectSimulator(self, aircraftType): 367 """Connect to the simulator for the first time.""" 368 self._logger.reset() 369 370 self._flight = flight.Flight(self._logger, self) 371 self._flight.aircraftType = aircraftType 372 self._flight.aircraft = acft.Aircraft.create(self._flight) 373 self._flight.aircraft._checkers.append(self) 374 375 if self._simulator is None: 376 self._simulator = fs.createSimulator(const.SIM_MSFS9, self) 377 378 self._flight.simulator = self._simulator 379 380 self.beginBusy("Connecting to the simulator...") 381 self._statusbar.updateConnection(self._connecting, self._connected) 382 383 self._connecting = True 384 self._simulator.connect(self._flight.aircraft) 385 287 386 def _connectToggled(self, button): 288 387 """Callback for the connection button.""" 289 388 if self._connectButton.get_active(): 290 self._logger.reset()291 self._flight = flight.Flight(self._logger, self)292 293 389 acftListModel = self._acftList.get_model() 294 self._flight.aircraftType = \ 295 acftListModel[self._acftList.get_active()][1] 296 self._flight.aircraft = acft.Aircraft.create(self._flight) 297 self._flight.aircraft._checkers.append(self) 298 390 self.connectSimulator(acftListModel[self._acftList.get_active()][1]) 391 299 392 self._flight.cruiseAltitude = self._flSpinButton.get_value_as_int() * 100 300 393 301 394 self._flight.zfw = self._zfwSpinButton.get_value_as_int() 302 303 if self._simulator is None: 304 self._simulator = fs.createSimulator(const.SIM_MSFS9, self) 305 306 self._flight.simulator = self._simulator 307 308 self._connecting = True 309 self._simulator.connect(self._flight.aircraft) 395 310 396 self._simulator.startMonitoring() 397 self._monitoring = True 311 398 else: 312 399 self.resetFlightStatus() 313 400 self._connecting = False 401 self._connected = False 402 314 403 self._simulator.stopMonitoring() 404 self._monitoring = False 405 315 406 self._simulator.disconnect() 316 407 self._flight = None -
src/mlx/gui/statusbar.py
r49 r59 87 87 88 88 def _drawConnState(self, connStateArea, eventOrContext): 89 """Draw the connection state.""" 89 """Draw the connection state.""" 90 90 context = eventOrContext if pygobject else connStateArea.window.cairo_create() 91 91 -
src/mlx/pyuipc_sim.py
r57 r59 637 637 #------------------------------------------------------------------------------ 638 638 639 failOpen = False 640 641 opened = False 642 643 #------------------------------------------------------------------------------ 644 639 645 def open(request): 640 646 """Open the connection.""" 641 return True 647 global opened 648 if failOpen: 649 raise FSUIPCException(ERR_NOFS) 650 elif opened: 651 raise FSUIPCException(ERR_OPEN) 652 else: 653 time.sleep(0.5) 654 opened = True 655 return True 642 656 643 657 #------------------------------------------------------------------------------ … … 645 659 def prepare_data(pattern, forRead = True): 646 660 """Prepare the given pattern for reading and/or writing.""" 647 return pattern 648 661 if opened: 662 return pattern 663 else: 664 raise FSUIPCException(ERR_OPEN) 665 649 666 #------------------------------------------------------------------------------ 650 667 651 668 def read(data): 652 669 """Read the given data.""" 653 return [values.read(offset) for (offset, type) in data] 670 print "opened", opened 671 if opened: 672 return [values.read(offset) for (offset, type) in data] 673 else: 674 raise FSUIPCException(ERR_OPEN) 654 675 655 676 #------------------------------------------------------------------------------ … … 657 678 def write(data): 658 679 """Write the given data.""" 659 for (offset, type, value) in data: 660 values.write(offset, value) 680 if opened: 681 for (offset, type, value) in data: 682 values.write(offset, value) 683 else: 684 raise FSUIPCException(ERR_OPEN) 661 685 662 686 #------------------------------------------------------------------------------ … … 664 688 def close(): 665 689 """Close the connection.""" 666 pass 690 global opened 691 opened = False 667 692 668 693 #------------------------------------------------------------------------------ … … 673 698 CALL_WRITE=2 674 699 CALL_CLOSE=3 700 CALL_FAILOPEN=4 701 CALL_QUIT = 99 675 702 676 703 RESULT_RETURNED=1 … … 715 742 elif call==CALL_WRITE: 716 743 result = write(args[0]) 744 elif call==CALL_CLOSE: 745 global opened 746 opened = False 747 result = None 748 elif call==CALL_FAILOPEN: 749 global failOpen 750 failOpen = args[0] 751 result = None 717 752 else: 718 753 break … … 753 788 """Write the given data.""" 754 789 return self._call(CALL_WRITE, data) 790 791 def close(self): 792 """Close the connection currently opened in the simulator.""" 793 return self._call(CALL_CLOSE, None) 794 795 def failOpen(self, really): 796 """Enable/disable open failure in the simulator.""" 797 return self._call(CALL_FAILOPEN, really) 798 799 def quit(self): 800 """Quit from the simulator.""" 801 data = cPickle.dumps((CALL_QUIT, None)) 802 self._socket.send(struct.pack("I", len(data)) + data) 755 803 756 804 def _call(self, command, data): … … 1024 1072 if line=="EOF": 1025 1073 print 1026 return True1074 return self.do_quit("") 1027 1075 else: 1028 1076 return super(CLI, self).default(line) … … 1102 1150 return [key + "=" for key in self._valueHandlers if key.startswith(text)] 1103 1151 1152 def do_close(self, args): 1153 """Close an existing connection so that FS will fail.""" 1154 try: 1155 self._client.close() 1156 print "Connection closed" 1157 except Exception, e: 1158 print >> sys.stderr, "Failed to close the connection: " + str(e) 1159 1160 def do_failopen(self, args): 1161 """Enable/disable the failing of opens.""" 1162 try: 1163 value = self.str2bool(args) 1164 self._client.failOpen(value) 1165 print "Opening will%s fail" % ("" if value else " not",) 1166 except Exception, e: 1167 print >> sys.stderr, "Failed to set open failure: " + str(e) 1168 1169 def help_failopen(self, usage = False): 1170 """Help for the failopen close""" 1171 if usage: print "Usage:", 1172 print "failopen yes|no" 1173 1174 def complete_failopen(self, text, line, begidx, endidx): 1175 if text: 1176 if "yes".startswith(text): return ["yes"] 1177 elif "no".startswith(text): return ["no"] 1178 else: return [] 1179 else: 1180 return ["yes", "no"] 1181 1104 1182 def do_quit(self, args): 1105 1183 """Handle the quit command.""" 1184 self._client.quit() 1106 1185 return True 1107 1186
Note:
See TracChangeset
for help on using the changeset viewer.