Changeset 321:8f6b55fb98ed


Ignore:
Timestamp:
10/07/12 18:16:07 (12 years ago)
Author:
István Váradi <ivaradi@…>
Branch:
default
hg-Phase:
(<MercurialRepository 1 'hg:/home/ivaradi/mlx/hg' '/'>, 'public')
Message:

Added the forced logging of radio frequencies when entering certain stages of the flight

Location:
src/mlx
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • src/mlx/acft.py

    r317 r321  
    8383
    8484        self._checkers.append(checks.AltimeterLogger())
     85
     86        self._nav1Logger = checks.NAV1Logger()
     87        self._checkers.append(self._nav1Logger)
     88        self._nav2Logger = checks.NAV2Logger()
     89        self._checkers.append(self._nav2Logger)
     90
     91        self._adf1Logger = checks.ADF1Logger()
     92        self._checkers.append(self._adf1Logger)
     93        self._adf2Logger = checks.ADF2Logger()
     94        self._checkers.append(self._adf2Logger)
    8595       
    86         self._checkers.append(checks.NAV1Logger())
    87         self._checkers.append(checks.NAV2Logger())
    88         self._checkers.append(checks.ADF1Logger())
    89         self._checkers.append(checks.ADF2Logger())
    9096        self._checkers.append(checks.SquawkLogger())
    9197
     
    248254                                    (aircraftState.windDirection,
    249255                                     aircraftState.windSpeed))
     256                self._logRadios(aircraftState)
    250257                self._logV1R2()
     258            elif newStage==const.STAGE_DESCENT or newStage==const.STAGE_LANDING:
     259                self._logRadios(aircraftState)
    251260            elif newStage==const.STAGE_TAXIAFTERLAND:
    252261                flight = self._flight
     
    427436       
    428437
     438    def _logRadios(self, aircraftState):
     439        """Log the radios from the given aircraft state."""
     440        flight = self._flight
     441        logger = flight.logger
     442
     443        self._nav1Logger.forceLog(flight, logger, aircraftState)
     444        self._nav2Logger.forceLog(flight, logger, aircraftState)
     445
     446        self._adf1Logger.logState(flight, logger, aircraftState)
     447        self._adf2Logger.logState(flight, logger, aircraftState)
     448
    429449#---------------------------------------------------------------------------------------
    430450
  • src/mlx/checks.py

    r320 r321  
    270270        - _changed(self, oldState, state): returns a boolean indicating if the
    271271        value has changed or not
    272         - _getMessage(self, flight, state): return a strings containing the
    273         message to log with the new value
     272        - _getMessage(self, flight, state, forced): return a strings containing
     273        the message to log with the new value
    274274        """
    275275        self._logInitial = logInitial   
     
    288288       
    289289        if shouldLog:
    290             message = self._getMessage(flight, state)
    291             if message is not None:
    292                 logger.message(self._getLogTimestamp(state), message)
     290            self.logState(flight, logger, state)
     291
     292    def logState(self, flight, logger, state, forced = False):
     293        """Log the state."""
     294        message = self._getMessage(flight, state, forced)
     295        if message is not None:
     296            logger.message(self._getLogTimestamp(state), message)
    293297       
    294298#-------------------------------------------------------------------------------
     
    340344           
    341345        newValue = self._getValue(state)
    342         if self._oldValue!=newValue:
     346        if self._isDifferent(self._oldValue, newValue):
    343347            if self._firstChange is None:
    344348                self._firstChange = state.timestamp
     
    359363               self._lastChangeState is not None else state.timestamp
    360364
     365    def _isDifferent(self, oldValue, newValue):
     366        """Determine if the given values are different.
     367
     368        This default implementation checks for simple equality."""
     369        return oldValue!=newValue
     370
    361371#---------------------------------------------------------------------------------------
    362372
     
    370380        self._template = template
    371381
    372     def _getMessage(self, flight, state):
     382    def _getMessage(self, flight, state, forced):
    373383        """Get the message."""
    374384        value = self._getValue(state)       
     
    393403#---------------------------------------------------------------------------------------
    394404
     405class ForceableLoggerMixin(object):
     406    """A mixin for loggers that can be forced to log a certain state.
     407
     408    The last logged state is always maintained, and when checking for a change,
     409    that state is compared to the current one (which may actually be the same,
     410    if a forced logging was performed for that state).
     411
     412    Children should implement the following functions:
     413    - _hasChanged(oldState, state): the real check for a change
     414    - _logState(flight, logger, state, forced): the real logging function
     415    """
     416    def __init__(self):
     417        """Construct the mixin."""
     418        self._lastLoggedState = None
     419
     420    def forceLog(self, flight, logger, state):
     421        """Force logging the given state."""
     422        self.logState(flight, logger, state, forced = True)
     423
     424    def logState(self, flight, logger, state, forced = False):
     425        """Log the state.
     426
     427        It calls _logState to perform the real logging, and saves the given
     428        state as the last logged one."""
     429        self._logState(flight, logger, state, forced)
     430        self._lastLoggedState = state
     431   
     432    def _changed(self, oldState, state):
     433        """Check if the state has changed.
     434
     435        This function calls _hasChanged for the real check, and replaces
     436        oldState with the stored last logged state, if any."""
     437        if self._lastLoggedState is not None:
     438            oldState = self._lastLoggedState
     439        return self._hasChanged(oldState, state)
     440
     441#---------------------------------------------------------------------------------------
     442
    395443class AltimeterLogger(StateChangeLogger, SingleValueMixin,
    396444                      DelayedChangeMixin):
     
    404452                                DelayedChangeMixin._getLogTimestamp(self, state)
    405453
    406     def _getMessage(self, flight, state):
     454    def _getMessage(self, flight, state, forced):
    407455        """Get the message to log on a change."""
    408456        logState = self._lastChangeState if \
     
    413461#---------------------------------------------------------------------------------------
    414462
    415 class NAVLogger(StateChangeLogger, DelayedChangeMixin):
     463class NAVLogger(StateChangeLogger, DelayedChangeMixin, ForceableLoggerMixin):
    416464    """Logger for NAV radios.
    417465
    418466    It also logs the OBS frequency set."""
     467    @staticmethod
     468    def getMessage(logName, frequency, obs):
     469        """Get the message for the given NAV radio setting."""
     470        message = u"%s frequency: %s MHz" % (logName, frequency)
     471        if obs is not None: message += u" [%d\u00b0]" % (obs,)
     472        return message
     473   
    419474    def __init__(self, attrName, logName):
    420475        """Construct the NAV logger."""
    421476        StateChangeLogger.__init__(self, logInitial = True)
    422477        DelayedChangeMixin.__init__(self)
     478        ForceableLoggerMixin.__init__(self)
     479
     480        self.logState = lambda flight, logger, state, forced = False: \
     481            ForceableLoggerMixin.logState(self, flight, logger, state,
     482                                          forced = forced)
     483        self._getLogTimestamp = \
     484            lambda state: DelayedChangeMixin._getLogTimestamp(self, state)
     485        self._changed = lambda oldState, state: \
     486            ForceableLoggerMixin._changed(self, oldState, state)
     487        self._hasChanged = lambda oldState, state: \
     488            DelayedChangeMixin._changed(self, oldState, state)
     489        self._logState = lambda flight, logger, state, forced: \
     490             StateChangeLogger.logState(self, flight, logger, state,
     491                                        forced = forced)
    423492
    424493        self._attrName = attrName
    425494        self._logName = logName
    426        
     495
    427496    def _getValue(self, state):
    428497        """Get the value.
     
    432501        frequency = getattr(state, self._attrName)
    433502        obs = getattr(state, self._attrName + "_obs")
    434         return None if frequency is None or obs is None else (frequency, obs)
    435 
    436     def _getMessage(self, flight, state):
     503        manual = getattr(state, self._attrName + "_manual")
     504        return (frequency, obs, manual)
     505
     506    def _getMessage(self, flight, state, forced):
    437507        """Get the message."""
    438         value = self._getValue(state)
    439         return None if value is None else \
    440                (u"%s frequency: %s MHz [%d\u00b0]" % (self._logName, value[0], value[1]))
     508        (frequency, obs, manual) = self._getValue(state)
     509        return None if frequency is None or obs is None or \
     510               (not manual and not forced) else \
     511               self.getMessage(self._logName, frequency, obs)
     512
     513    def _isDifferent(self, oldValue, newValue):
     514        """Determine if the valie has changed between the given states."""
     515        (oldFrequency, oldOBS, _oldManual) = oldValue
     516        (newFrequency, newOBS, _newManual) = newValue
     517        return oldFrequency!=newFrequency or oldOBS!=newOBS
    441518
    442519#---------------------------------------------------------------------------------------
     
    458535#---------------------------------------------------------------------------------------
    459536
    460 class ADF1Logger(GenericStateChangeLogger):
     537class ADFLogger(GenericStateChangeLogger, ForceableLoggerMixin):
     538    """Base class for the ADF loggers."""
     539    def __init__(self, attr, logName):
     540        """Construct the ADF logger."""
     541        GenericStateChangeLogger.__init__(self, attr,
     542                                          "%s frequency: %%s kHz" % (logName,),
     543                                          minDelay = 3.0, maxDelay = 10.0)
     544        ForceableLoggerMixin.__init__(self)
     545
     546        self.logState = lambda flight, logger, state, forced = False: \
     547            ForceableLoggerMixin.logState(self, flight, logger, state,
     548                                          forced = forced)
     549        self._changed = lambda oldState, state: \
     550            ForceableLoggerMixin._changed(self, oldState, state)
     551        self._hasChanged = lambda oldState, state: \
     552            DelayedChangeMixin._changed(self, oldState, state)
     553        self._logState = lambda flight, logger, state, forced: \
     554             StateChangeLogger.logState(self, flight, logger, state, forced)
     555
     556#---------------------------------------------------------------------------------------
     557
     558class ADF1Logger(ADFLogger):
    461559    """Logger for the ADF1 radio setting."""
    462560    def __init__(self):
    463561        """Construct the logger."""
    464         super(ADF1Logger, self).__init__("adf1", "ADF1 frequency: %s kHz",
    465                                          minDelay = 3.0, maxDelay = 10.0)
    466 
    467 #---------------------------------------------------------------------------------------
    468 
    469 class ADF2Logger(GenericStateChangeLogger):
     562        super(ADF1Logger, self).__init__("adf1", "ADF1")
     563
     564#---------------------------------------------------------------------------------------
     565
     566class ADF2Logger(ADFLogger):
    470567    """Logger for the ADF2 radio setting."""
    471568    def __init__(self):
    472569        """Construct the logger."""
    473         super(ADF2Logger, self).__init__("adf2", "ADF2 frequency: %s kHz",
    474                                          minDelay = 3.0, maxDelay = 10.0)
     570        super(ADF2Logger, self).__init__("adf2", "ADF2")
    475571
    476572#---------------------------------------------------------------------------------------
     
    494590        self._template = template
    495591
    496     def _getMessage(self, flight, state):
     592    def _getMessage(self, flight, state, forced):
    497593        """Get the message from the given state."""
    498594        return self._template % ("ON" if self._getValue(state) else "OFF")
     
    539635        SingleValueMixin.__init__(self, "flapsSet")
    540636
    541     def _getMessage(self, flight, state):
     637    def _getMessage(self, flight, state, forced):
    542638        """Get the message to log on a change."""
    543639        speed = state.groundSpeed if state.groundSpeed<80.0 else state.ias
     
    555651        SingleValueMixin.__init__(self, "gearControlDown")
    556652
    557     def _getMessage(self, flight, state):
     653    def _getMessage(self, flight, state, forced):
    558654        """Get the message to log on a change."""
    559655        return "Gears SET to %s at %.0f %s, %.0f feet" % \
  • src/mlx/fs.py

    r320 r321  
    231231    - nav1_obs: the OBS setting of the NAV1 radio in degrees (int). Can be None, if
    232232    the value is unreliable or meaningless.
     233    - nav1_manual: a boolean indicating if the NAV1 radio is on manual control
    233234    - nav2: the frequency of the NAV1 radio in MHz (string). Can be None, if
    234235    the frequency is unreliable or meaningless.
    235236    - nav2_obs: the OBS setting of the NAV2 radio in degrees (int). Can be None, if
    236237    the value is unreliable or meaningless.
     238    - nav2_manual: a boolean indicating if the NAV2 radio is on manual control
    237239    - adf1: the frequency of the ADF1 radio in kHz (string). Can be None, if
    238240    the frequency is unreliable or meaningless.
  • src/mlx/fsuipc.py

    r320 r321  
    11791179                      ("nav1_obs", 0x0c4e, "H"),
    11801180                      ("nav2", 0x0352, "H"),
    1181                       ("nav2_obs", 0x035e, "H"),
     1181                      ("nav2_obs", 0x0c5e, "H"),
    11821182                      ("adf1_main", 0x034c, "H"),
    11831183                      ("adf1_ext", 0x0356, "H"),
     
    13651365        state.nav1 = AircraftModel.convertFrequency(data[self._monidx_nav1])
    13661366        state.nav1_obs = data[self._monidx_nav1_obs]
     1367        state.nav1_manual = True
    13671368        state.nav2 = AircraftModel.convertFrequency(data[self._monidx_nav2])
    13681369        state.nav2_obs = data[self._monidx_nav2_obs]
     1370        state.nav2_manual = True
    13691371        state.adf1 = \
    13701372            AircraftModel.convertADFFrequency(data[self._monidx_adf1_main],
     
    17511753                                                         data)
    17521754        state.landingLightsOn = None
    1753         state.nav2 = None
     1755        state.nav2_manual = aircraft.flight.stage!=const.STAGE_CRUISE
    17541756
    17551757        return state
  • src/mlx/pyuipc_sim.py

    r317 r321  
    283283
    284284        self.nav1 = 117.3
     285        self.nav1_obs = 128
    285286        self.nav2 = 109.5
     287        self.nav2_obs = 308
    286288        self.adf1 = 382.7
    287289        self.adf2 = 1540.6
     
    450452        elif offset==0x0bec:       # Nose gear
    451453            return int(self.noseGear * 16383.0)
     454        elif offset==0x0c4e:       # NAV1 OBS
     455            return self.nav1_obs
     456        elif offset==0x0c5e:       # NAV2 OBS
     457            return self.nav2_obs
    452458        elif offset==0x0d0c:       # Lights
    453459            lights = 0
     
    684690        elif offset==0x0bec:       # Nose gear
    685691            self.noseGear = value / 16383.0
     692        elif offset==0x0c4e:       # NAV1 OBS
     693            self.nav1_obs = value
     694        elif offset==0x0c5e:       # NAV2 OBS
     695            self.nav2_obs = value
    686696        elif offset==0x0d0c:       # Lights
    687697            self.navLightsOn = (value&0x01)!=0
     
    12091219                                       Values._writeFrequency,
    12101220                                       lambda word: Values._readFrequency(float(word)))
     1221        self._valueHandlers["nav1_obs"] = ([(0x0c4e, "H")],
     1222                                           lambda value: value,
     1223                                           lambda word: int(word))
    12111224        self._valueHandlers["nav2"] = ([(0x0352, "H")],
    12121225                                       Values._writeFrequency,
    12131226                                       lambda word: Values._readFrequency(float(word)))
     1227        self._valueHandlers["nav2_obs"] = ([(0x0c5e, "H")],
     1228                                           lambda value: value,
     1229                                           lambda word: int(word))
    12141230        self._valueHandlers["adf1"] = ([(0x034c, "H"), (0x0356, "H")],
    12151231                                       lambda values:
Note: See TracChangeset for help on using the changeset viewer.