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 5import pprint 6 7# Setup wardmodem package root and other autotest paths. 8import common 9 10import state_machine 11 12 13class 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