blob: f54cc8bb744044929fe43c82b5a975a34316d690 [file] [log] [blame]
# 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 pm_errors
import state_machine
from autotest_lib.client.cros.cellular import mm1_constants
class DisableMachine(state_machine.StateMachine):
"""
DisableMachine handles the state transitions involved in bringing the modem
to the DISABLED state.
"""
def __init__(self, modem, return_cb, raise_cb):
super(DisableMachine, self).__init__(modem)
self.return_cb = return_cb
self.raise_cb = raise_cb
def _HandleConnectedState(self):
logging.info('DisableMachine: Modem is CONNECTED.')
assert self._modem.connect_step is None
# TODO(armansito): Pass a different raise_cb here to handle
# disconnect failure
logging.info('DisableMachine: Starting Disconnect.')
self._modem.Disconnect(mm1_constants.ROOT_PATH, DisableMachine.Step,
DisableMachine.Step, self)
return True
def _HandleConnectingState(self):
logging.info('DisableMachine: Modem is CONNECTING.')
assert self._modem.connect_step
logging.info('DisableMachine: Canceling connect.')
self._modem.connect_step.Cancel()
return True
def _HandleDisconnectingState(self):
logging.info('DisableMachine: Modem is DISCONNECTING.')
assert self._modem.disconnect_step
logging.info('DisableMachine: Waiting for disconnect.')
# wait until disconnect ends
return True
def _HandleRegisteredState(self):
logging.info('DisableMachine: Modem is REGISTERED.')
assert not self._modem.IsPendingRegister()
assert not self._modem.IsPendingEnable()
assert not self._modem.IsPendingConnect()
assert not self._modem.IsPendingDisconnect()
self._modem.UnregisterWithNetwork()
logging.info('DisableMachine: Setting state to DISABLING.')
reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED
self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLING, reason)
return True
def _HandleSearchingState(self):
logging.info('DisableMachine: Modem is SEARCHING.')
assert self._modem.register_step
assert not self._modem.IsPendingEnable()
assert not self._modem.IsPendingConnect()
logging.info('DisableMachine: Canceling register.')
self._modem.register_step.Cancel()
return True
def _HandleEnabledState(self):
logging.info('DisableMachine: Modem is ENABLED.')
assert not self._modem.IsPendingRegister()
assert not self._modem.IsPendingEnable()
assert not self._modem.IsPendingConnect()
logging.info('DisableMachine: Setting state to DISABLING.')
reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED
self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLING, reason)
return True
def _HandleDisablingState(self):
logging.info('DisableMachine: Modem is DISABLING.')
assert not self._modem.IsPendingRegister()
assert not self._modem.IsPendingEnable()
assert not self._modem.IsPendingConnect()
assert not self._modem.IsPendingDisconnect()
logging.info('DisableMachine: Setting state to DISABLED.')
reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED
self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLED, reason)
self._modem.disable_step = None
if self.return_cb:
self.return_cb()
return False
def _GetModemStateFunctionMap(self):
return {
mm1_constants.MM_MODEM_STATE_CONNECTED:
DisableMachine._HandleConnectedState,
mm1_constants.MM_MODEM_STATE_CONNECTING:
DisableMachine._HandleConnectingState,
mm1_constants.MM_MODEM_STATE_DISCONNECTING:
DisableMachine._HandleDisconnectingState,
mm1_constants.MM_MODEM_STATE_REGISTERED:
DisableMachine._HandleRegisteredState,
mm1_constants.MM_MODEM_STATE_SEARCHING:
DisableMachine._HandleSearchingState,
mm1_constants.MM_MODEM_STATE_ENABLED:
DisableMachine._HandleEnabledState,
mm1_constants.MM_MODEM_STATE_DISABLING:
DisableMachine._HandleDisablingState
}
def _ShouldStartStateMachine(self):
if self._modem.disable_step and self._modem.disable_step != self:
# There is already a disable operation in progress.
message = 'Modem disable already in progress.'
logging.info(message)
raise pm_errors.MMCoreError(pm_errors.MMCoreError.IN_PROGRESS,
message)
elif self._modem.disable_step is None:
# There is no disable operation going in, cancelled or otherwise.
state = self._modem.Get(mm1_constants.I_MODEM, 'State')
if state == mm1_constants.MM_MODEM_STATE_DISABLED:
# The reason we're not raising an error here is that
# shill will make multiple successive calls to disable
# but WON'T check for raised errors, which causes
# problems. Treat this particular case as success.
logging.info('Already in a disabled state. Ignoring.')
if self.return_cb:
self.return_cb()
return False
invalid_states = [
mm1_constants.MM_MODEM_STATE_FAILED,
mm1_constants.MM_MODEM_STATE_UNKNOWN,
mm1_constants.MM_MODEM_STATE_INITIALIZING,
mm1_constants.MM_MODEM_STATE_LOCKED
]
if state in invalid_states:
raise pm_errors.MMCoreError(
pm_errors.MMCoreError.WRONG_STATE,
('Modem disable cannot be initiated while in state'
' %u.') % state)
if self._modem.connect_step:
logging.info('There is an ongoing Connect, canceling it.')
self._modem.connect_step.Cancel()
if self._modem.register_step:
logging.info('There is an ongoing Register, canceling it.')
self._modem.register_step.Cancel()
if self._modem.enable_step:
# This needs to be done here, because the case where an enable
# cycle has been initiated but it hasn't triggered any state
# transitions yet would not be detected in a state handler.
logging.info('There is an ongoing Enable, canceling it.')
logging.info('This should bring the modem to a disabled state.'
' DisableMachine will not start.')
self._modem.enable_step.Cancel()
assert self._modem.Get(mm1_constants.I_MODEM, 'State') == \
mm1_constants.MM_MODEM_STATE_DISABLED
if self._modem.Get(mm1_constants.I_MODEM, 'State') == \
mm1_constants.MM_MODEM_STATE_DISABLED:
if self.return_cb:
self.return_cb()
return False
logging.info('Starting Disable.')
self._modem.disable_step = self
return True