Home | History | Annotate | Download | only in state_machines
      1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import pprint
      6 
      7 # Setup wardmodem package root and other autotest paths.
      8 import common
      9 
     10 import state_machine
     11 
     12 
     13 class RequestResponse(state_machine.StateMachine):
     14     """
     15     The trivial state machine that implements all request-response interaction.
     16 
     17     A lot of interaction with the modem is simple request-response.
     18     There is a |request_response| GlobalState component. If it is |ENABLED|,
     19     this machine sends the expected responses. If it is |DISABLED|, the machine
     20     always responds with the appropriate error.
     21 
     22     """
     23 
     24     def __init__(self, state, transceiver, modem_conf):
     25         """
     26         @param state: The GlobalState object shared by all state machines.
     27 
     28         @param transceiver: The ATTransceiver object to interact with.
     29 
     30         @param modem_conf: A ModemConfiguration object containing the
     31                 configuration data for the current modem.
     32 
     33         """
     34         super(RequestResponse, self).__init__(state, transceiver, modem_conf)
     35 
     36         self._load_request_response_map(modem_conf)
     37 
     38         # Start off enabled.
     39         self.enable_machine()
     40 
     41 
     42     def get_well_known_name(self):
     43         """ Returns the well known name for this machine. """
     44         return 'request_response'
     45 
     46 
     47     # ##########################################################################
     48     # API that could be used by other state machines.
     49     def enable_machine(self):
     50         """ Enable the machine so that it responds to queries. """
     51         self._state['request_response_enabled'] = 'TRUE'
     52 
     53 
     54     def disable_machine(self):
     55         """ Disable machine so that it will only respond with error. """
     56         self._state['request_response_enabled'] = 'FALSE'
     57 
     58 
     59     # ##########################################################################
     60     # State machine API functions.
     61     def act_on(self, atcom):
     62         """
     63         Reply to the AT command |atcom| by following the request_response map.
     64 
     65         This is the implementation of state-less responses given by the modem.
     66         There is only one macro level handle to turn off the whole state
     67         machine. No other state is referenced / maintained.
     68 
     69         @param atcom: The AT command in query.
     70 
     71         """
     72         response = self._responses.get(atcom, None)
     73         if not response:
     74             self._respond_error()
     75             return
     76 
     77         # If |response| is a tuple, it is of the form |(response_ok ,
     78         # response_error)|. Otherwise, it is of the form |response_ok|.
     79         #
     80         # |response_ok| is either a list of str, or str
     81         # Let's say |response_ok| is ['response1', 'response2'], then we must
     82         # respond with ['response1', 'response2', 'OK']
     83         # Let's say |response_ok| is 'send_this'. Then we must respond with
     84         # 'send_this' (Without the trailing 'OK')
     85         #
     86         # |response_error| is str.
     87         #
     88         # Having such a flexible specification for response allows a very
     89         # natural definition of responses (@see base.conf). But we must be
     90         # careful with type checking, which we do next.
     91         if type(response) is tuple:
     92             assert len(response) == 2
     93             response_ok = response[0]
     94             response_error = response[1]
     95         else:
     96             response_ok = response
     97             response_error = None
     98 
     99         assert type(response_ok) is list or type(response_ok) is str
    100         if type(response_ok) is list:
    101             for part in response_ok:
    102                 assert type(part) is str
    103 
    104         if response_error:
    105             assert type(response_error) is str
    106 
    107         # Now construct the actual response.
    108         if self._is_enabled():
    109             if type(response_ok) is str:
    110                 self._respond_with_text(response_ok)
    111             else:
    112                 for part in response_ok:
    113                     self._respond_with_text(part)
    114                 self._respond_ok()
    115         else:
    116             if response_error:
    117                 self._respond_with_text(response_error)
    118             else:
    119                 self._respond_error()
    120 
    121 
    122     # #########################################################################
    123     # Helper functions.
    124     def _is_enabled(self):
    125         return self._state['request_response_enabled'] == 'TRUE'
    126 
    127 
    128     def _load_request_response_map(self, modem_conf):
    129         self._responses = modem_conf.base_wm_request_response_map
    130         # Now update specific entries with those overriden by the plugin.
    131         for key, value in modem_conf.plugin_wm_request_response_map.items():
    132             self._responses[key] = value
    133         self._logger.info('Loaded request-response map.')
    134         self._logger.debug(pprint.pformat(self._responses))
    135