1# Copyright (c) 2012 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 logging 6 7import pm_errors 8import state_machine 9 10from autotest_lib.client.cros.cellular import mm1_constants 11 12class DisableMachine(state_machine.StateMachine): 13 """ 14 DisableMachine handles the state transitions involved in bringing the modem 15 to the DISABLED state. 16 17 """ 18 def __init__(self, modem, return_cb, raise_cb): 19 super(DisableMachine, self).__init__(modem) 20 self.return_cb = return_cb 21 self.raise_cb = raise_cb 22 23 24 def _HandleConnectedState(self): 25 logging.info('DisableMachine: Modem is CONNECTED.') 26 assert self._modem.connect_step is None 27 # TODO(armansito): Pass a different raise_cb here to handle 28 # disconnect failure 29 logging.info('DisableMachine: Starting Disconnect.') 30 self._modem.Disconnect(mm1_constants.ROOT_PATH, DisableMachine.Step, 31 DisableMachine.Step, self) 32 return True 33 34 35 def _HandleConnectingState(self): 36 logging.info('DisableMachine: Modem is CONNECTING.') 37 assert self._modem.connect_step 38 logging.info('DisableMachine: Canceling connect.') 39 self._modem.connect_step.Cancel() 40 return True 41 42 43 def _HandleDisconnectingState(self): 44 logging.info('DisableMachine: Modem is DISCONNECTING.') 45 assert self._modem.disconnect_step 46 logging.info('DisableMachine: Waiting for disconnect.') 47 # wait until disconnect ends 48 return True 49 50 51 def _HandleRegisteredState(self): 52 logging.info('DisableMachine: Modem is REGISTERED.') 53 assert not self._modem.IsPendingRegister() 54 assert not self._modem.IsPendingEnable() 55 assert not self._modem.IsPendingConnect() 56 assert not self._modem.IsPendingDisconnect() 57 self._modem.UnregisterWithNetwork() 58 logging.info('DisableMachine: Setting state to DISABLING.') 59 reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED 60 self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLING, reason) 61 return True 62 63 64 def _HandleSearchingState(self): 65 logging.info('DisableMachine: Modem is SEARCHING.') 66 assert self._modem.register_step 67 assert not self._modem.IsPendingEnable() 68 assert not self._modem.IsPendingConnect() 69 logging.info('DisableMachine: Canceling register.') 70 self._modem.register_step.Cancel() 71 return True 72 73 74 def _HandleEnabledState(self): 75 logging.info('DisableMachine: Modem is ENABLED.') 76 assert not self._modem.IsPendingRegister() 77 assert not self._modem.IsPendingEnable() 78 assert not self._modem.IsPendingConnect() 79 logging.info('DisableMachine: Setting state to DISABLING.') 80 reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED 81 self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLING, reason) 82 return True 83 84 85 def _HandleDisablingState(self): 86 logging.info('DisableMachine: Modem is DISABLING.') 87 assert not self._modem.IsPendingRegister() 88 assert not self._modem.IsPendingEnable() 89 assert not self._modem.IsPendingConnect() 90 assert not self._modem.IsPendingDisconnect() 91 logging.info('DisableMachine: Setting state to DISABLED.') 92 reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED 93 self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_DISABLED, reason) 94 self._modem.disable_step = None 95 if self.return_cb: 96 self.return_cb() 97 return False 98 99 100 def _GetModemStateFunctionMap(self): 101 return { 102 mm1_constants.MM_MODEM_STATE_CONNECTED: 103 DisableMachine._HandleConnectedState, 104 mm1_constants.MM_MODEM_STATE_CONNECTING: 105 DisableMachine._HandleConnectingState, 106 mm1_constants.MM_MODEM_STATE_DISCONNECTING: 107 DisableMachine._HandleDisconnectingState, 108 mm1_constants.MM_MODEM_STATE_REGISTERED: 109 DisableMachine._HandleRegisteredState, 110 mm1_constants.MM_MODEM_STATE_SEARCHING: 111 DisableMachine._HandleSearchingState, 112 mm1_constants.MM_MODEM_STATE_ENABLED: 113 DisableMachine._HandleEnabledState, 114 mm1_constants.MM_MODEM_STATE_DISABLING: 115 DisableMachine._HandleDisablingState 116 } 117 118 119 def _ShouldStartStateMachine(self): 120 if self._modem.disable_step and self._modem.disable_step != self: 121 # There is already a disable operation in progress. 122 message = 'Modem disable already in progress.' 123 logging.info(message) 124 raise pm_errors.MMCoreError(pm_errors.MMCoreError.IN_PROGRESS, 125 message) 126 elif self._modem.disable_step is None: 127 # There is no disable operation going in, cancelled or otherwise. 128 state = self._modem.Get(mm1_constants.I_MODEM, 'State') 129 if state == mm1_constants.MM_MODEM_STATE_DISABLED: 130 # The reason we're not raising an error here is that 131 # shill will make multiple successive calls to disable 132 # but WON'T check for raised errors, which causes 133 # problems. Treat this particular case as success. 134 logging.info('Already in a disabled state. Ignoring.') 135 if self.return_cb: 136 self.return_cb() 137 return False 138 139 invalid_states = [ 140 mm1_constants.MM_MODEM_STATE_FAILED, 141 mm1_constants.MM_MODEM_STATE_UNKNOWN, 142 mm1_constants.MM_MODEM_STATE_INITIALIZING, 143 mm1_constants.MM_MODEM_STATE_LOCKED 144 ] 145 if state in invalid_states: 146 raise pm_errors.MMCoreError( 147 pm_errors.MMCoreError.WRONG_STATE, 148 ('Modem disable cannot be initiated while in state' 149 ' %u.') % state) 150 if self._modem.connect_step: 151 logging.info('There is an ongoing Connect, canceling it.') 152 self._modem.connect_step.Cancel() 153 if self._modem.register_step: 154 logging.info('There is an ongoing Register, canceling it.') 155 self._modem.register_step.Cancel() 156 if self._modem.enable_step: 157 # This needs to be done here, because the case where an enable 158 # cycle has been initiated but it hasn't triggered any state 159 # transitions yet would not be detected in a state handler. 160 logging.info('There is an ongoing Enable, canceling it.') 161 logging.info('This should bring the modem to a disabled state.' 162 ' DisableMachine will not start.') 163 self._modem.enable_step.Cancel() 164 assert self._modem.Get(mm1_constants.I_MODEM, 'State') == \ 165 mm1_constants.MM_MODEM_STATE_DISABLED 166 if self._modem.Get(mm1_constants.I_MODEM, 'State') == \ 167 mm1_constants.MM_MODEM_STATE_DISABLED: 168 if self.return_cb: 169 self.return_cb() 170 return False 171 172 logging.info('Starting Disable.') 173 self._modem.disable_step = self 174 return True 175