1# Copyright (c) 2013 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 gobject
6import logging
7
8import pm_errors
9import state_machine
10
11from autotest_lib.client.cros.cellular import mm1_constants
12
13class CdmaActivateMachine(state_machine.StateMachine):
14    """
15    CdmaActivationMachine implements the asynchronous state updates for a fake
16    OTASP "automatic activation".
17
18    """
19    def __init__(self, modem, return_cb, raise_cb):
20        super(CdmaActivateMachine, self).__init__(modem)
21        self._return_cb = return_cb
22        self._raise_cb = raise_cb
23        self._step_delay = 1
24
25
26    def Cancel(self, message='Activation canceled.'):
27        """ Cancel the CdmaActivateMachine. """
28        logging.info('CdmaActivateMachine: Canceling activate.')
29        super(CdmaActivateMachine, self).Cancel()
30        state = self._modem.Get(mm1_constants.I_MODEM_CDMA, 'ActivationState')
31
32        # If activated, return success.
33        if state == mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED:
34            logging.info('CdmaActivateMachine: Already activated. '
35                         'Returning success.')
36            if self._return_cb:
37                self._return_cb()
38            return
39
40        self._modem.ChangeActivationState(
41            mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED,
42            pm_errors.MMCdmaActivationError.UNKNOWN)
43
44        self._modem.cdma_activate_step = None
45
46        if self._raise_cb:
47            self._raise_cb(
48                pm_errors.MMCoreError(pm_errors.MMCoreError.CANCELLED, message))
49
50
51    def _GetDefaultHandler(self):
52        return CdmaActivateMachine._HandleInvalidState
53
54
55    def _ScheduleNextStep(self):
56        def _DelayedStep():
57            self.Step()
58            return False
59        gobject.timeout_add(self._step_delay * 1000, _DelayedStep)
60
61    def _HandleInvalidState(self):
62        state = self._modem.Get(mm1_constants.I_MODEM, 'State')
63        message = 'Modem transitioned to invalid state: ' + \
64            mm1_constants.ModemStateToString(state)
65        logging.info('CdmaActivateMachine: ' + message)
66        self.Cancel(message)
67        return False
68
69
70    def _StepFunction(self):
71        state = self._modem.Get(mm1_constants.I_MODEM_CDMA, 'ActivationState')
72        if state == mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED:
73            return self._HandleNotActivated()
74        if state == mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING:
75            return self._HandleActivating()
76        message = 'Modem is in invalid activation state: ' + state
77        logging.error(message)
78        self.Cancel(message)
79        return False
80
81
82    def _HandleNotActivated(self):
83        logging.info('CdmaActivationMachine: Modem is NOT_ACTIVATED.')
84        logging.info('CdmaActivationMachine: Setting state to ACTIVATING')
85        self._modem.ChangeActivationState(
86            mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING,
87            pm_errors.MMCdmaActivationError.NONE)
88
89        # Make the modem reset after 5 seconds.
90        self._step_delay = 5
91        return True
92
93
94    def _HandleActivating(self):
95        logging.info('CdmaActivationMachine: Modem is ACTIVATING.')
96        logging.info('CdmaActivationMachine: Resetting modem.')
97        self._modem.ChangeActivationState(
98            mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED,
99            pm_errors.MMCdmaActivationError.NONE)
100        self._modem.Reset()
101        self._modem.cdma_activate_step = None
102        if self._return_cb:
103            self._return_cb()
104        return False
105
106
107    def _GetModemStateFunctionMap(self):
108        return {
109            mm1_constants.MM_MODEM_STATE_REGISTERED:
110                CdmaActivateMachine._StepFunction
111        }
112
113
114    def _ShouldStartStateMachine(self):
115        if self._modem.cdma_activate_step and \
116            self._modem.cdma_activate_step != self:
117            # There is already an activate operation in progress.
118            logging.error('There is already an ongoing activate operation.')
119            raise pm_errors.MMCoreError(pm_errors.MMCoreError.IN_PROGRESS,
120                                        "Activation already in progress.")
121
122
123        if self._modem.cdma_activate_step is None:
124            # There is no activate operation going on, cancelled or otherwise.
125            state = self._modem.Get(mm1_constants.I_MODEM_CDMA,
126                                    'ActivationState')
127            if (state !=
128                mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED):
129                message = "Modem is not in state 'NOT_ACTIVATED'."
130                logging.error(message)
131                raise pm_errors.MMCoreError(pm_errors.MMCoreError.WRONG_STATE,
132                                            message)
133
134            state = self._modem.Get(mm1_constants.I_MODEM, 'State')
135            if state != mm1_constants.MM_MODEM_STATE_REGISTERED:
136                message = 'Modem cannot be activated if not in the ' \
137                          'REGISTERED state.'
138                logging.error(message)
139                raise pm_errors.MMCoreError(pm_errors.MMCoreError.WRONG_STATE,
140                                            message)
141
142            self._modem.cdma_activate_step = self
143        return True
144