• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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