You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
8.8 KiB
222 lines
8.8 KiB
# Copyright (c) 2012 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 logging
|
|
import subprocess
|
|
|
|
import pm_errors
|
|
import state_machine
|
|
|
|
from autotest_lib.client.cros.cellular import mm1_constants
|
|
|
|
class ConnectMachine(state_machine.StateMachine):
|
|
"""
|
|
ConnectMachine handles the state transitions involved in bringing the modem
|
|
to the CONNECTED state.
|
|
|
|
"""
|
|
def __init__(self, modem, properties, return_cb, raise_cb):
|
|
super(ConnectMachine, self).__init__(modem)
|
|
self.connect_props = properties
|
|
self.return_cb = return_cb
|
|
self.raise_cb = raise_cb
|
|
self.enable_initiated = False
|
|
self.register_initiated = False
|
|
|
|
|
|
def Cancel(self):
|
|
""" Overriden from superclass. """
|
|
logging.info('ConnectMachine: Canceling connect.')
|
|
super(ConnectMachine, self).Cancel()
|
|
state = self._modem.Get(mm1_constants.I_MODEM, 'State')
|
|
reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED
|
|
if state == mm1_constants.MM_MODEM_STATE_CONNECTING:
|
|
logging.info('ConnectMachine: Setting state to REGISTERED.')
|
|
self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_REGISTERED,
|
|
reason)
|
|
elif self.enable_initiated and self._modem.enable_step:
|
|
self._modem.enable_step.Cancel()
|
|
self._modem.connect_step = None
|
|
|
|
|
|
def _HandleDisabledState(self):
|
|
logging.info('ConnectMachine: Modem is DISABLED.')
|
|
assert not self._modem.IsPendingEnable()
|
|
if self.enable_initiated:
|
|
message = 'ConnectMachine: Failed to enable modem.'
|
|
logging.error(message)
|
|
self.Cancel()
|
|
self._modem.connect_step = None
|
|
self.raise_cb(pm_errors.MMCoreError(
|
|
pm_errors.MMCoreError.FAILED, message))
|
|
return False
|
|
else:
|
|
logging.info('ConnectMachine: Initiating Enable.')
|
|
self.enable_initiated = True
|
|
self._modem.Enable(True)
|
|
|
|
# state machine will spin until modem gets enabled,
|
|
# or if enable fails
|
|
return True
|
|
|
|
|
|
def _HandleEnablingState(self):
|
|
logging.info('ConnectMachine: Modem is ENABLING.')
|
|
assert self._modem.IsPendingEnable()
|
|
logging.info('ConnectMachine: Waiting for enable.')
|
|
return True
|
|
|
|
|
|
def _HandleEnabledState(self):
|
|
logging.info('ConnectMachine: Modem is ENABLED.')
|
|
|
|
# Check to see if a register is going on, if not,
|
|
# start register
|
|
if self.register_initiated:
|
|
message = 'ConnectMachine: Failed to register.'
|
|
logging.error(message)
|
|
self.Cancel()
|
|
self._modem.connect_step = None
|
|
self.raise_cb(pm_errors.MMCoreError(pm_errors.MMCoreError.FAILED,
|
|
message))
|
|
return False
|
|
else:
|
|
logging.info('ConnectMachine: Waiting for Register.')
|
|
if not self._modem.IsPendingRegister():
|
|
self._modem.RegisterWithNetwork(
|
|
"", self._return_cb, self._raise_cb)
|
|
self.register_initiated = True
|
|
return True
|
|
|
|
|
|
def _HandleSearchingState(self):
|
|
logging.info('ConnectMachine: Modem is SEARCHING.')
|
|
logging.info('ConnectMachine: Waiting for modem to register.')
|
|
assert self.register_initiated
|
|
assert self._modem.IsPendingRegister()
|
|
return True
|
|
|
|
|
|
def _HandleRegisteredState(self):
|
|
logging.info('ConnectMachine: Modem is REGISTERED.')
|
|
assert not self._modem.IsPendingDisconnect()
|
|
assert not self._modem.IsPendingEnable()
|
|
assert not self._modem.IsPendingDisable()
|
|
assert not self._modem.IsPendingRegister()
|
|
logging.info('ConnectMachine: Setting state to CONNECTING.')
|
|
reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED
|
|
self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_CONNECTING,
|
|
reason)
|
|
return True
|
|
|
|
|
|
def _GetBearerToActivate(self):
|
|
# Import modem here to avoid circular imports.
|
|
import modem
|
|
bearer = None
|
|
bearer_path = None
|
|
bearer_props = {}
|
|
for p, b in self._modem.bearers.iteritems():
|
|
# assemble bearer props
|
|
for key, val in self.connect_props.iteritems():
|
|
if key in modem.ALLOWED_BEARER_PROPERTIES:
|
|
bearer_props[key] = val
|
|
if (b.bearer_properties == bearer_props):
|
|
logging.info('ConnectMachine: Found matching bearer.')
|
|
bearer = b
|
|
bearer_path = p
|
|
break
|
|
if bearer is None:
|
|
assert bearer_path is None
|
|
logging.info(('ConnectMachine: No matching bearer found, '
|
|
'creating brearer with properties: ' +
|
|
str(self.connect_props)))
|
|
bearer_path = self._modem.CreateBearer(self.connect_props)
|
|
|
|
return bearer_path
|
|
|
|
|
|
def _HandleConnectingState(self):
|
|
logging.info('ConnectMachine: Modem is CONNECTING.')
|
|
assert not self._modem.IsPendingDisconnect()
|
|
assert not self._modem.IsPendingEnable()
|
|
assert not self._modem.IsPendingDisable()
|
|
assert not self._modem.IsPendingRegister()
|
|
try:
|
|
bearer_path = self._GetBearerToActivate()
|
|
self._modem.ActivateBearer(bearer_path)
|
|
logging.info('ConnectMachine: Setting state to CONNECTED.')
|
|
reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED
|
|
self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_CONNECTED,
|
|
reason)
|
|
self._modem.connect_step = None
|
|
logging.info(
|
|
'ConnectMachine: Returning bearer path: %s', bearer_path)
|
|
self.return_cb(bearer_path)
|
|
except (pm_errors.MMError, subprocess.CalledProcessError) as e:
|
|
logging.error('ConnectMachine: Failed to connect: ' + str(e))
|
|
self.raise_cb(e)
|
|
self._modem.ChangeState(
|
|
mm1_constants.MM_MODEM_STATE_REGISTERED,
|
|
mm1_constants.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN)
|
|
self._modem.connect_step = None
|
|
return False
|
|
|
|
|
|
def _GetModemStateFunctionMap(self):
|
|
return {
|
|
mm1_constants.MM_MODEM_STATE_DISABLED:
|
|
ConnectMachine._HandleDisabledState,
|
|
mm1_constants.MM_MODEM_STATE_ENABLING:
|
|
ConnectMachine._HandleEnablingState,
|
|
mm1_constants.MM_MODEM_STATE_ENABLED:
|
|
ConnectMachine._HandleEnabledState,
|
|
mm1_constants.MM_MODEM_STATE_SEARCHING:
|
|
ConnectMachine._HandleSearchingState,
|
|
mm1_constants.MM_MODEM_STATE_REGISTERED:
|
|
ConnectMachine._HandleRegisteredState,
|
|
mm1_constants.MM_MODEM_STATE_CONNECTING:
|
|
ConnectMachine._HandleConnectingState
|
|
}
|
|
|
|
|
|
def _ShouldStartStateMachine(self):
|
|
if self._modem.connect_step and self._modem.connect_step != self:
|
|
# There is already a connect operation in progress.
|
|
message = 'There is already an ongoing connect operation.'
|
|
logging.error(message)
|
|
self.raise_cb(pm_errors.MMCoreError(
|
|
pm_errors.MMCoreError.IN_PROGRESS, message))
|
|
return False
|
|
elif self._modem.connect_step is None:
|
|
# There is no connect operation going on, cancelled or otherwise.
|
|
if self._modem.IsPendingDisable():
|
|
message = 'Modem is currently being disabled. Ignoring ' \
|
|
'connect.'
|
|
logging.error(message)
|
|
self.raise_cb(
|
|
pm_errors.MMCoreError(pm_errors.MMCoreError.WRONG_STATE,
|
|
message))
|
|
return False
|
|
state = self._modem.Get(mm1_constants.I_MODEM, 'State')
|
|
if state == mm1_constants.MM_MODEM_STATE_CONNECTED:
|
|
message = 'Modem is already connected.'
|
|
logging.error(message)
|
|
self.raise_cb(
|
|
pm_errors.MMCoreError(pm_errors.MMCoreError.CONNECTED,
|
|
message))
|
|
return False
|
|
if state == mm1_constants.MM_MODEM_STATE_DISCONNECTING:
|
|
assert self._modem.IsPendingDisconnect()
|
|
message = 'Cannot connect while disconnecting.'
|
|
logging.error(message)
|
|
self.raise_cb(
|
|
pm_errors.MMCoreError(pm_errors.MMCoreError.WRONG_STATE,
|
|
message))
|
|
return False
|
|
|
|
logging.info('Starting Connect.')
|
|
self._modem.connect_step = self
|
|
return True
|