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 RegisterMachine(state_machine.StateMachine): 13 """ 14 RegisterMachine handles the state transitions involved in bringing the 15 modem to the REGISTERED state. 16 17 """ 18 def __init__(self, modem, operator_code="", return_cb=None, raise_cb=None): 19 super(RegisterMachine, self).__init__(modem) 20 self._networks = None 21 self._operator_code = operator_code 22 self._return_cb = return_cb 23 self._raise_cb = raise_cb 24 25 26 def Cancel(self): 27 """ Overriden from superclass. """ 28 logging.info('RegisterMachine: Canceling register.') 29 super(RegisterMachine, self).Cancel() 30 state = self._modem.Get(mm1_constants.I_MODEM, 'State') 31 reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED 32 if state == mm1_constants.MM_MODEM_STATE_SEARCHING: 33 logging.info('RegisterMachine: Setting state to ENABLED.') 34 self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_ENABLED, 35 reason) 36 self._modem.SetRegistrationState( 37 mm1_constants.MM_MODEM_3GPP_REGISTRATION_STATE_IDLE) 38 self._modem.register_step = None 39 if self._raise_cb: 40 self._raise_cb( 41 pm_errors.MMCoreError(pm_errors.MMCoreError.CANCELLED, 42 'Cancelled')) 43 44 45 def _HandleEnabledState(self): 46 logging.info('RegisterMachine: Modem is ENABLED.') 47 logging.info('RegisterMachine: Setting registration state ' 48 'to SEARCHING.') 49 self._modem.SetRegistrationState( 50 mm1_constants.MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING) 51 logging.info('RegisterMachine: Setting state to SEARCHING.') 52 reason = mm1_constants.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED 53 self._modem.ChangeState(mm1_constants.MM_MODEM_STATE_SEARCHING, reason) 54 logging.info('RegisterMachine: Starting network scan.') 55 try: 56 self._networks = self._modem.SyncScan() 57 except pm_errors.MMError as e: 58 self._modem.register_step = None 59 logging.error('An error occurred during network scan: ' + str(e)) 60 self._modem.ChangeState( 61 mm1_constants.MM_MODEM_STATE_ENABLED, 62 mm1_constants.MODEM_STATE_CHANGE_REASON_UNKNOWN) 63 self._modem.SetRegistrationState( 64 mm1_constants.MM_MODEM_3GPP_REGISTRATION_STATE_IDLE) 65 if self._raise_cb: 66 self._raise_cb(e) 67 return False 68 logging.info('RegisterMachine: Found networks: ' + str(self._networks)) 69 return True 70 71 72 def _HandleSearchingState(self): 73 logging.info('RegisterMachine: Modem is SEARCHING.') 74 if not self._networks: 75 logging.info('RegisterMachine: Scan returned no networks.') 76 logging.info('RegisterMachine: Setting state to ENABLED.') 77 self._modem.ChangeState( 78 mm1_constants.MM_MODEM_STATE_ENABLED, 79 mm1_constants.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN) 80 # TODO(armansito): Figure out the correct registration 81 # state to transition to when no network is present. 82 logging.info('RegisterMachine: Setting registration state ' 83 'to IDLE.') 84 self._modem.SetRegistrationState( 85 mm1_constants.MM_MODEM_3GPP_REGISTRATION_STATE_IDLE) 86 self._modem.register_step = None 87 if self._raise_cb: 88 self._raise_cb(pm_errors.MMMobileEquipmentError( 89 pm_errors.MMMobileEquipmentError.NO_NETWORK, 90 'No networks were found to register.')) 91 return False 92 93 # Pick the last network in the list. Roaming networks will come before 94 # the home network which makes the last item in the list the home 95 # network. 96 if self._operator_code: 97 if not self._operator_code in self._modem.scanned_networks: 98 if self._raise_cb: 99 self._raise_cb(pm_errors.MMCoreError( 100 pm_errors.MMCoreError.FAILED, 101 "Unknown network: " + self._operator_code)) 102 return False 103 network = self._modem.scanned_networks[self._operator_code] 104 else: 105 network = self._networks[-1] 106 logging.info( 107 'RegisterMachine: Registering to network: ' + str(network)) 108 self._modem.SetRegistered( 109 network['operator-code'], 110 network['operator-long']) 111 112 # The previous call should have set the state to REGISTERED. 113 self._modem.register_step = None 114 115 if self._return_cb: 116 self._return_cb() 117 return False 118 119 120 def _GetModemStateFunctionMap(self): 121 return { 122 mm1_constants.MM_MODEM_STATE_ENABLED: 123 RegisterMachine._HandleEnabledState, 124 mm1_constants.MM_MODEM_STATE_SEARCHING: 125 RegisterMachine._HandleSearchingState 126 } 127 128 129 def _ShouldStartStateMachine(self): 130 if self._modem.register_step and self._modem.register_step != self: 131 # There is already an ongoing register operation. 132 message = 'Register operation already in progress.' 133 logging.info(message) 134 error = pm_errors.MMCoreError(pm_errors.MMCoreError.IN_PROGRESS, 135 message) 136 if self._raise_cb: 137 self._raise_cb(error) 138 else: 139 raise error 140 elif self._modem.register_step is None: 141 # There is no register operation going on, canceled or otherwise. 142 state = self._modem.Get(mm1_constants.I_MODEM, 'State') 143 if state != mm1_constants.MM_MODEM_STATE_ENABLED: 144 message = 'Cannot initiate register while in state %d, ' \ 145 'state needs to be ENABLED.' % state 146 error = pm_errors.MMCoreError(pm_errors.MMCoreError.WRONG_STATE, 147 message) 148 if self._raise_cb: 149 self._raise_cb(error) 150 else: 151 raise error 152 153 logging.info('Starting Register.') 154 self._modem.register_step = self 155 return True 156