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