Index: src/fsuipc.py
===================================================================
--- src/fsuipc.py	(revision 7)
+++ src/fsuipc.py	(revision 8)
@@ -341,6 +341,12 @@
     via FSUIPC."""
     # The basic data that should be queried all the time once we are connected
-    normalData = [ (0x3d00, -256) ]
-
+    normalData = [ (0x0240, "H"),
+                   (0x023e, "H"),
+                   (0x023b, "b"),
+                   (0x023c, "b"),
+                   (0x023a, "b"),
+                   (0x3d00, -256),
+                   (0x3c00, -256) ]
+    
     def __init__(self, connectionListener, aircraft):
         """Construct the simulator.
@@ -407,5 +413,13 @@
         aircraft-specific values.
         """
-        self._setAircraftName(data[0])
+        timestamp = calendar.timegm(time.struct_time([data[0],
+                                                      1, 1, 0, 0, 0, -1, 1, 0]))
+        timestamp += data[1] * 24 * 3600
+        timestamp += data[2] * 3600
+        timestamp += data[3] * 60
+        timestamp += data[4]        
+
+        createdNewModel = self._setAircraftName(timestamp, data[5], data[6])
+        
         if self._monitoringRequested and not self._monitoring:
             self._monitoring = True
@@ -416,23 +430,36 @@
             self._stopNormal()
             self._startDefaultNormal()
-        elif self._monitoring and self._aircraftModel is not None:
-            aircraftState = self._aircraftModel.getAircraftState(self._aircraft, data)
+        elif self._monitoring and self._aircraftModel is not None and \
+             not createdNewModel:
+            aircraftState = self._aircraftModel.getAircraftState(self._aircraft, 
+                                                                 timestamp, data)
             self._aircraft.handleState(aircraftState)
 
-    def _setAircraftName(self, name):
+    def _setAircraftName(self, timestamp, name, airPath):
         """Set the name of the aicraft and if it is different from the
         previous, create a new model for it.
         
-        If so, also notifty the aircraft about the change."""
-        if name==self._aircraftName:
-            return
-
-        self._aircraftName = name
-        if self._aircraftModel is None or \
-           not self._aircraftModel.doesHandle(name):            
-            self._setAircraftModel(AircraftModel.create(self._aircraft, name))
-        
-        self._aircraft.modelChanged(self._aircraftName, 
-                                    self._aircraftModel.name)
+        If so, also notifty the aircraft about the change.
+
+        Return if a new model was created."""
+        aircraftName = (name, airPath)
+        if aircraftName==self._aircraftName:
+            return False
+
+        self._aircraftName = aircraftName
+        needNew = self._aircraftModel is None
+        needNew = needNew or\
+            not self._aircraftModel.doesHandle(self._aircraft, aircraftName)
+        if not needNew:
+            specialModel = AircraftModel.findSpecial(self._aircraft, aircraftName)
+            needNew = specialModel is not None and \
+                specialModel is not self._aircraftModel.__class__
+
+        if needNew:
+            self._setAircraftModel(AircraftModel.create(self._aircraft, aircraftName))
+        
+        self._aircraft.modelChanged(timestamp, name, self._aircraftModel.name)        
+
+        return needNew
 
     def _setAircraftModel(self, model):
@@ -444,5 +471,5 @@
         
         if self._monitoring:
-            self._handler.clearPeriodic(self._normalRequestID)            
+            self._stopNormal()
             self._startMonitoring()
             
@@ -465,10 +492,5 @@
     Aircraft models handle the data arriving from FSUIPC and turn it into an
     object describing the aircraft's state."""
-    monitoringData = [("year", 0x0240, "H"),
-                      ("dayOfYear", 0x023e, "H"),
-                      ("zuluHour", 0x023b, "b"),
-                      ("zuluMinute", 0x023c, "b"),
-                      ("seconds", 0x023a, "b"),
-                      ("paused", 0x0264, "H"),
+    monitoringData = [("paused", 0x0264, "H"),
                       ("frozen", 0x3364, "H"),
                       ("replay", 0x0628, "d"),
@@ -484,4 +506,5 @@
                       ("groundSpeed", 0x02b4, "d"),
                       ("vs", 0x02c8, "d"),
+                      ("radioAltitude", 0x31e4, "d"),
                       ("altitude", 0x0570, "l"),
                       ("gLoad", 0x11ba, "H"),
@@ -491,4 +514,5 @@
                       ("lights", 0x0d0c, "H"),
                       ("pitot", 0x029c, "b"),
+                      ("parking", 0x0bc8, "H"),
                       ("noseGear", 0x0bec, "d"),
                       ("spoilersArmed", 0x0bcc, "d"),
@@ -496,21 +520,6 @@
                       ("altimeter", 0x0330, "H"),
                       ("nav1", 0x0350, "H"),
-                      ("nav2", 0x0352, "H")]
-
-    genericModels = { const.AIRCRAFT.B736 : B737Model,
-                      const.AIRCRAFT_B737 : B737Model,
-                      const.AIRCRAFT_B738 : B737Model,
-                      const.AIRCRAFT_B733 : B737Model,
-                      const.AIRCRAFT_B734 : B737Model,
-                      const.AIRCRAFT_B735 : B737Model,
-                      const.AIRCRAFT_DH8D : DH8DModel,
-                      const.AIRCRAFT_B762 : B767Model,
-                      const.AIRCRAFT_B763 : B767Model,
-                      const.AIRCRAFT_CRJ2 : B767Model,
-                      const.AIRCRAFT_F79  : F70Model,
-                      const.AIRCRAFT_DC3  : DC3Model,
-                      const.AIRCRAFT_T134 : T134Model,
-                      const.AIRCRAFT_T154 : T154Model,
-                      const.AIRCRAFT_YK40 : YK40Model }
+                      ("nav2", 0x0352, "H"),
+                      ("squawk", 0x0354, "H")]
 
     specialModels = []
@@ -522,27 +531,38 @@
 
     @staticmethod
+    def findSpecial(aircraft, aircraftName):
+        for specialModel in AircraftModel.specialModels:
+            if specialModel.doesHandle(aircraft, aircraftName):
+                return specialModel
+        return None
+
+    @staticmethod
     def create(aircraft, aircraftName):
         """Create the model for the given aircraft name, and notify the
         aircraft about it."""
-        for specialModel in AircraftModel.specialModels:
-            if specialModel.doesHandle(aircraft, aircraftName):
-                return specialModel(aircraft, aircraftName)
-        
-        if aircraft.type in AircraftModel.genericModels:
-            return AircraftModel.genericModels[aircraft.type]()
+        specialModel = AircraftModel.findSpecial(aircraft, aircraftName)
+        if specialModel is not None:
+            return specialModel()
+        if aircraft.type in _genericModels:
+            return _genericModels[aircraft.type]()
         else:
             return GenericModel()
+
+    @staticmethod
+    def convertBCD(data, length):
+        """Convert a data item encoded as BCD into a string of the given number
+        of digits."""
+        bcd = ""
+        for i in range(0, length):
+            digit = chr(ord('0') + (data&0x0f))
+            data >>= 4
+            bcd = digit + bcd
+        return bcd
 
     @staticmethod
     def convertFrequency(data):
         """Convert the given frequency data to a string."""
-        frequency = ""
-        for i in range(0, 4):
-            digit = chr(ord('0') + (data&0x0f))
-            data >>= 4
-            frequency = digit + frequency
-            if i==1:
-                frequency = "." + frequency
-        return "1" + frequency            
+        bcd = AircraftModel.convertBCD(data, 4)
+        return "1" + bcd[0:2] + "." + bcd[2:4]
 
     def __init__(self, flapsNotches):
@@ -557,5 +577,5 @@
         return "FSUIPC/Generic"
     
-    def doesHandle(self, aircraftName):
+    def doesHandle(self, aircraft, aircraftName):
         """Determine if the model handles the given aircraft name.
         
@@ -568,5 +588,5 @@
         dest.append((offset, type))
         if attrName is not None:
-            setattr(self, attrName, len(dest))
+            setattr(self, attrName, len(dest)-1)
 
     def _addDataWithIndexMembers(self, dest, prefix, data):
@@ -586,17 +606,11 @@
     def addMonitoringData(self, data):
         """Add the model-specific monitoring data to the given array."""
-        self.addDataWithIndexMembers(data, "_monidx_",
-                                     AircraftModel.monitoringData)
+        self._addDataWithIndexMembers(data, "_monidx_",
+                                      AircraftModel.monitoringData)
     
-    def getAircraftState(self, aircraft, data):
+    def getAircraftState(self, aircraft, timestamp, data):
         """Get an aircraft state object for the given monitoring data."""
         state = fs.AircraftState()
         
-        timestamp = calendar.timegm(time.struct_time([data[self._monidx_year],
-                                                      1, 1, 0, 0, 0, -1, 1, 0]))
-        timestamp += data[self._monidx_dayOfYear] * 24 * 3600
-        timestamp += data[self._monidx_zuluHour] * 3600
-        timestamp += data[self._monidx_zuluMinute] * 60
-        timestamp += data[self._monidx_seconds]        
         state.timestamp = timestamp
         
@@ -622,4 +636,5 @@
         state.vs = data[self._monidx_vs]*60.0/const.FEETTOMETRES/256.0
 
+        state.radioAltitude = data[self._monidx_radioAltitude]/const.FEETTOMETRES/65536.0
         state.altitude = data[self._monidx_altitude]/const.FEETTOMETRES/65536.0/65536.0
 
@@ -655,4 +670,6 @@
         state.pitotHeatOn = data[self._monidx_pitot]!=0
 
+        state.parking = data[self._monidx_parking]!=0
+
         state.gearsDown = data[self._monidx_noseGear]==16383
 
@@ -669,4 +686,5 @@
         state.nav1 = AircraftModel.convertFrequency(data[self._monidx_nav1])
         state.nav2 = AircraftModel.convertFrequency(data[self._monidx_nav2])
+        state.squawk = AircraftModel.convertBCD(data[self._monidx_squawk], 4)
         
         return state
@@ -699,4 +717,10 @@
         self._isN1 = isN1
 
+    def doesHandle(self, aircraft, aircraftName):
+        """Determine if the model handles the given aircraft name.
+        
+        This implementation returns True."""
+        return True
+
     def addMonitoringData(self, data):
         """Add the model-specific monitoring data to the given array."""
@@ -716,5 +740,5 @@
                 self._addOffsetWithIndexMember(data, 0x088c + i * 0x98, "d")  # throttle lever
         
-    def getAircraftState(self, aircraft, data):
+    def getAircraftState(self, aircraft, timestamp, data):
         """Get the aircraft state.
 
@@ -722,4 +746,5 @@
         the engine parameters."""
         state = super(GenericAircraftModel, self).getAircraftState(aircraft,
+                                                                   timestamp,
                                                                    data)
 
@@ -746,5 +771,5 @@
     def __init__(self):
         """Construct the model."""
-        super(GenericAircraftModel, self).
+        super(GenericModel, self). \
             __init__(flapsNotches = [0, 10, 20, 30],
                      fuelInfo = [0x0b74, 0x0b7c, 0xb94], 
@@ -762,5 +787,5 @@
     def __init__(self):
         """Construct the model."""
-        super(GenericAircraftModel, self).
+        super(B737Model, self). \
             __init__(flapsNotches = [0, 1, 2, 5, 10, 15, 25, 30, 40],
                      fuelInfo = [0x0b74, 0x0b7c, 0xb94], 
@@ -771,4 +796,45 @@
         """Get the name for this aircraft model."""
         return "FSUIPC/Generic Boeing 737"
+
+#------------------------------------------------------------------------------
+
+class PMDGBoeing737NGModel(B737Model):
+    """A model handler for the PMDG Boeing 737NG model."""
+    @staticmethod
+    def doesHandle(aircraft, (name, airPath)):
+        """Determine if this model handler handles the aircraft with the given
+        name."""
+        return aircraft.type in [const.AIRCRAFT_B736,
+                                 const.AIRCRAFT_B737,
+                                 const.AIRCRAFT_B738] and \
+            (name.find("PMDG")!=-1 or airPath.find("PMDG")!=-1) and \
+            (name.find("737")!=-1 or airPath.find("737")!=-1) and \
+            (name.find("600")!=-1 or airPath.find("600")!=-1 or \
+             name.find("700")!=-1 or airPath.find("700")!=-1 or \
+             name.find("800")!=-1 or airPath.find("800")!=-1 or \
+             name.find("900")!=-1 or airPath.find("900")!=-1)
+
+    @property
+    def name(self):
+        """Get the name for this aircraft model."""
+        return "FSUIPC/PMDG Boeing 737NG"
+
+    def addMonitoringData(self, data):
+        """Add the model-specific monitoring data to the given array."""
+        super(PMDGBoeing737NGModel, self).addMonitoringData(data)
+                
+        self._addOffsetWithIndexMember(data, 0x6202, "b", "_pmdgidx_switches")
+
+    def getAircraftState(self, aircraft, timestamp, data):
+        """Get the aircraft state.
+
+        Get it from the parent, and then check some PMDG-specific stuff."""
+        state = super(PMDGBoeing737NGModel, self).getAircraftState(aircraft,
+                                                                   timestamp,
+                                                                   data)
+        if data[self._pmdgidx_switches]&0x01==0x01:
+            state.altimeter = 1013.25
+
+        return state
 
 #------------------------------------------------------------------------------
@@ -778,5 +844,5 @@
     def __init__(self):
         """Construct the model."""
-        super(GenericAircraftModel, self).
+        super(B767Model, self). \
             __init__(flapsNotches = [0, 1, 5, 15, 20, 25, 30],
                      fuelInfo = [0x0b74, 0x0b7c, 0xb94], 
@@ -794,5 +860,5 @@
     def __init__(self):
         """Construct the model."""
-        super(GenericAircraftModel, self).
+        super(DH8DModel, self). \
             __init__(flapsNotches = [0, 5, 10, 15, 35],
                      fuelInfo = [0x0b74, 0x0b7c, 0xb94], 
@@ -810,5 +876,5 @@
     def __init__(self):
         """Construct the model."""
-        super(GenericAircraftModel, self).
+        super(CRJ2Model, self). \
             __init__(flapsNotches = [0, 8, 20, 30, 45],
                      fuelInfo = [0x0b74, 0x0b7c, 0xb94], 
@@ -826,5 +892,5 @@
     def __init__(self):
         """Construct the model."""
-        super(GenericAircraftModel, self).
+        super(F70Model, self). \
             __init__(flapsNotches = [0, 8, 15, 25, 42],
                      fuelInfo = [0x0b74, 0x0b7c, 0xb94], 
@@ -842,5 +908,5 @@
     def __init__(self):
         """Construct the model."""
-        super(GenericAircraftModel, self).
+        super(DC3Model, self). \
             __init__(flapsNotches = [0, 15, 30, 45],
                      fuelInfo = [0x0b7c, 0x0b84, 0x0b94, 0x0b9c], 
@@ -858,5 +924,5 @@
     def __init__(self):
         """Construct the model."""
-        super(GenericAircraftModel, self).
+        super(T134Model, self). \
             __init__(flapsNotches = [0, 10, 20, 30],
                      fuelInfo = [0x0b74, 
@@ -877,8 +943,8 @@
     def __init__(self):
         """Construct the model."""
-        super(GenericAircraftModel, self).
+        super(T154Model, self). \
             __init__(flapsNotches = [0, 15, 28, 45],
                      fuelInfo = [0x0b74, 0x0b7c, 0x0b94, 
-                                 0x1244, 0x0b84, 0x0b9c]
+                                 0x1244, 0x0b84, 0x0b9c],
                      numEngines = 3)
 
@@ -888,9 +954,9 @@
         return "FSUIPC/Generic Tupolev Tu-154"
 
-    def getAircraftState(self, aircraft, data):
+    def getAircraftState(self, aircraft, timestamp, data):
         """Get an aircraft state object for the given monitoring data.
 
         This removes the reverser value for the middle engine."""
-        state = super(T154Model, self).getAircraftState(aircraft, data)
+        state = super(T154Model, self).getAircraftState(aircraft, timestamp, data)
         del state.reverser[1]
         return state
@@ -902,7 +968,7 @@
     def __init__(self):
         """Construct the model."""
-        super(GenericAircraftModel, self).
+        super(YK40Model, self). \
             __init__(flapsNotches = [0, 20, 35],
-                     fuelInfo = [0x0b7c, 0x0b94]
+                     fuelInfo = [0x0b7c, 0x0b94],
                      numEngines = 2)
 
@@ -914,2 +980,24 @@
 #------------------------------------------------------------------------------
 
+_genericModels = { const.AIRCRAFT_B736 : B737Model,
+                   const.AIRCRAFT_B737 : B737Model,
+                   const.AIRCRAFT_B738 : B737Model,
+                   const.AIRCRAFT_B733 : B737Model,
+                   const.AIRCRAFT_B734 : B737Model,
+                   const.AIRCRAFT_B735 : B737Model,
+                   const.AIRCRAFT_DH8D : DH8DModel,
+                   const.AIRCRAFT_B762 : B767Model,
+                   const.AIRCRAFT_B763 : B767Model,
+                   const.AIRCRAFT_CRJ2 : B767Model,
+                   const.AIRCRAFT_F70  : F70Model,
+                   const.AIRCRAFT_DC3  : DC3Model,
+                   const.AIRCRAFT_T134 : T134Model,
+                   const.AIRCRAFT_T154 : T154Model,
+                   const.AIRCRAFT_YK40 : YK40Model }
+
+#------------------------------------------------------------------------------
+
+AircraftModel.registerSpecial(PMDGBoeing737NGModel)
+
+#------------------------------------------------------------------------------
+
