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 5 import logging 6 7 import pm_errors 8 import state_machine 9 10 from autotest_lib.client.cros.cellular import mm1_constants 11 12 class DisconnectMachine(state_machine.StateMachine): 13 """ 14 DisconnectMachine handles the state transitions involved in bringing the 15 modem to the DISCONNECTED state. 16 17 """ 18 def __init__(self, modem, bearer_path, return_cb, raise_cb, 19 return_cb_args=[]): 20 super(DisconnectMachine, self).__init__(modem) 21 self.bearer_path = bearer_path 22 self.return_cb = return_cb 23 self.raise_cb = raise_cb 24 self.return_cb_args = return_cb_args 25 26 27 def _HandleConnectedState(self): 28 logging.info('DisconnectMachine: Modem state is CONNECTED.') 29 logging.info('DisconnectMachine: Setting state to DISCONNECTING.') 30 reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED 31 self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_DISCONNECTING, 32 reason) 33 return True 34 35 36 def _HandleDisconnectingState(self): 37 logging.info('DisconnectMachine: Modem state is DISCONNECTING.') 38 assert not self._modem.IsPendingConnect() 39 assert not self._modem.IsPendingEnable() 40 assert not self._modem.IsPendingRegister() 41 42 dc_reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED 43 try: 44 if self.bearer_path == mm1_constants.ROOT_PATH: 45 for bearer in self._modem.active_bearers.keys(): 46 self._modem.DeactivateBearer(bearer) 47 else: 48 self._modem.DeactivateBearer(self.bearer_path) 49 except pm_errors.MMError as e: 50 logging.error('DisconnectMachine: Failed to disconnect: ' + str(e)) 51 dc_reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN 52 self.raise_cb(e) 53 finally: 54 # TODO(armansito): What should happen in a disconnect 55 # failure? Should we stay connected or become REGISTERED? 56 logging.info('DisconnectMachine: Setting state to REGISTERED.') 57 self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_REGISTERED, 58 dc_reason) 59 self._modem.disconnect_step = None 60 logging.info('DisconnectMachine: Calling return callback.') 61 self.return_cb(*self.return_cb_args) 62 return False 63 64 65 def _GetModemStateFunctionMap(self): 66 return { 67 mm1_constants.MM_MODEM_STATE_CONNECTED: 68 DisconnectMachine._HandleConnectedState, 69 mm1_constants.MM_MODEM_STATE_DISCONNECTING: 70 DisconnectMachine._HandleDisconnectingState 71 } 72 73 74 def _ShouldStartStateMachine(self): 75 if (self._modem.disconnect_step and 76 # There is already a disconnect operation in progress. 77 self._modem.disconnect_step != self): 78 message = 'There is already an ongoing disconnect operation.' 79 logging.error(message) 80 self.raise_cb( 81 pm_errors.MMCoreError(pm_errors.MMCoreError.IN_PROGRESS, 82 message)) 83 return False 84 elif self._modem.disconnect_step is None: 85 # There is no disconnect operation going on, canceled or otherwise. 86 state = self._modem.Get(mm1_constants.I_MODEM, 'State') 87 if state != mm1_constants.MM_MODEM_STATE_CONNECTED: 88 message = 'Modem cannot be disconnected when not connected.' 89 logging.error(message) 90 self.raise_cb( 91 pm_errors.MMCoreError(pm_errors.MMCoreError.WRONG_STATE, 92 message)) 93 return False 94 95 if self.bearer_path == mm1_constants.ROOT_PATH: 96 logging.info('All bearers will be disconnected.') 97 elif not (self.bearer_path in self._modem.bearers): 98 message = ('Bearer with path "%s" not found' % 99 self.bearer_path) 100 logging.error(message) 101 self.raise_cb( 102 pm_errors.MMCoreError(pm_errors.MMCoreError.NOT_FOUND, 103 message)) 104 return False 105 elif not (self.bearer_path in self._modem.active_bearers): 106 message = ('No active bearer with path ' + 107 self.bearer_path + 108 ' found, current active bearers are ' + 109 str(self._modem.active_bearers)) 110 logging.error(message) 111 self.raise_cb(pm_errors.MMCoreError( 112 pm_errors.MMCoreError.NOT_FOUND, message)) 113 return False 114 115 assert not self._modem.IsPendingConnect() 116 assert not self._modem.IsPendingEnable() 117 assert not self._modem.IsPendingRegister() 118 119 logging.info('Starting Disconnect.') 120 self._modem.disconnect_step = self 121 return True 122