blob: b3a4277fcbffe13255633aef3e623d325c9a46fe [file] [log] [blame]
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import pprint
# Setup wardmodem package root and other autotest paths.
import common
import state_machine
class RequestResponse(state_machine.StateMachine):
"""
The trivial state machine that implements all request-response interaction.
A lot of interaction with the modem is simple request-response.
There is a |request_response| GlobalState component. If it is |ENABLED|,
this machine sends the expected responses. If it is |DISABLED|, the machine
always responds with the appropriate error.
"""
def __init__(self, state, transceiver, modem_conf):
"""
@param state: The GlobalState object shared by all state machines.
@param transceiver: The ATTransceiver object to interact with.
@param modem_conf: A ModemConfiguration object containing the
configuration data for the current modem.
"""
super(RequestResponse, self).__init__(state, transceiver, modem_conf)
self._load_request_response_map(modem_conf)
# Start off enabled.
self.enable_machine()
def get_well_known_name(self):
""" Returns the well known name for this machine. """
return 'request_response'
# ##########################################################################
# API that could be used by other state machines.
def enable_machine(self):
""" Enable the machine so that it responds to queries. """
self._state['request_response_enabled'] = 'TRUE'
def disable_machine(self):
""" Disable machine so that it will only respond with error. """
self._state['request_response_enabled'] = 'FALSE'
# ##########################################################################
# State machine API functions.
def act_on(self, atcom):
"""
Reply to the AT command |atcom| by following the request_response map.
This is the implementation of state-less responses given by the modem.
There is only one macro level handle to turn off the whole state
machine. No other state is referenced / maintained.
@param atcom: The AT command in query.
"""
response = self._responses.get(atcom, None)
if not response:
self._respond_error()
return
# If |response| is a tuple, it is of the form |(response_ok ,
# response_error)|. Otherwise, it is of the form |response_ok|.
#
# |response_ok| is either a list of str, or str
# Let's say |response_ok| is ['response1', 'response2'], then we must
# respond with ['response1', 'response2', 'OK']
# Let's say |response_ok| is 'send_this'. Then we must respond with
# 'send_this' (Without the trailing 'OK')
#
# |response_error| is str.
#
# Having such a flexible specification for response allows a very
# natural definition of responses (@see base.conf). But we must be
# careful with type checking, which we do next.
if type(response) is tuple:
assert len(response) == 2
response_ok = response[0]
response_error = response[1]
else:
response_ok = response
response_error = None
assert type(response_ok) is list or type(response_ok) is str
if type(response_ok) is list:
for part in response_ok:
assert type(part) is str
if response_error:
assert type(response_error) is str
# Now construct the actual response.
if self._is_enabled():
if type(response_ok) is str:
self._respond_with_text(response_ok)
else:
for part in response_ok:
self._respond_with_text(part)
self._respond_ok()
else:
if response_error:
self._respond_with_text(response_error)
else:
self._respond_error()
# #########################################################################
# Helper functions.
def _is_enabled(self):
return self._state['request_response_enabled'] == 'TRUE'
def _load_request_response_map(self, modem_conf):
self._responses = modem_conf.base_wm_request_response_map
# Now update specific entries with those overriden by the plugin.
for key, value in modem_conf.plugin_wm_request_response_map.items():
self._responses[key] = value
self._logger.info('Loaded request-response map.')
self._logger.debug(pprint.pformat(self._responses))