Home | History | Annotate | Download | only in pseudomodem
      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