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 logging
6
7from autotest_lib.client.bin import test, utils
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.cros import network
10
11from autotest_lib.client.cros.cellular import cellular
12from autotest_lib.client.cros.cellular import cell_tools
13from autotest_lib.client.cros.cellular import environment
14from autotest_lib.client.cros.cellular import mm
15
16import time
17
18import flimflam
19
20
21_STILL_REGISTERED_ERROR = error.TestError('modem registered to base station')
22_NOT_REGISTERED_ERROR = error.TestError('modem not registered to base station')
23
24CELLULAR_TIMEOUT = 180
25
26
27class _WrongTech(Exception):
28    def __init__(self, technology):
29        self.technology = technology
30
31
32class cellular_Signal(test.test):
33    version = 1
34
35    def TimedPollForCondition(
36        self, label, condition, exception=None, timeout=10, sleep_interval=0.5):
37        """Poll until a condition becomes true and report timing stats
38
39        Arguments:
40          label: label for a performance statistics to be logged
41          condition: function taking no args and returning bool
42          exception: exception to throw if condition doesn't become true
43          timeout: maximum number of seconds to wait
44          sleep_interval: time to sleep between polls
45          desc: description of default TimeoutError used if 'exception' is None
46
47        Returns:
48          The true value that caused the poll loop to terminate.
49
50        Raises:
51          'exception' arg
52        """
53        start_time = time.time();
54        utils.poll_for_condition(condition,
55                                 timeout=timeout,
56                                 exception=exception,
57                                 sleep_interval=sleep_interval);
58        self.write_perf_keyval({label: time.time() - start_time })
59
60    def run_once(self, config, technologies, wait_for_disc, verify_set_power):
61
62        # This test only works if all the technologies are in the same
63        # family. Check that before doing anything else.
64        families = set(
65            cellular.TechnologyToFamily[tech] for tech in technologies)
66        if len(families) > 1:
67            raise error.TestError('Specify only one family not: %s' % families)
68
69        # choose a technology other than the one we plan to start with
70        technology = technologies[-1]
71        with environment.DefaultCellularTestContext(config) as c:
72            env = c.env
73            flim = flimflam.FlimFlam()
74            flim.SetDebugTags('manager+device+modem')
75            env.StartDefault(technology)
76            network.ResetAllModems(flim)
77            logging.info('Preparing for %s' % technology)
78            cell_tools.PrepareModemForTechnology('', technology)
79
80            # TODO(jglasgow) Need to figure out what isn't settling here.
81            # Going to wait 'til after ResetAllModems changes land.
82            time.sleep(10)
83
84            # Clear all errors before we start.
85            # Resetting the modem above may have caused some errors on the
86            # 8960 (eg. lost connection, etc).
87            env.emulator.ClearErrors()
88
89            service = env.CheckedConnectToCellular(timeout=CELLULAR_TIMEOUT)
90
91            # Step through all technologies, forcing a transition
92            failed_technologies = []
93            manager, modem_path = mm.PickOneModem('')
94            cell_modem = manager.GetModem(modem_path)
95            for tech in technologies:
96                tname = str(tech).replace('Technology:', '')
97                if verify_set_power:
98                    logging.info('Powering off basestation')
99                    env.emulator.SetPower(cellular.Power.OFF)
100                    self.TimedPollForCondition(
101                        'Power.OFF.%s.deregister_time' % tname,
102                        lambda: not cell_modem.ModemIsRegistered(),
103                        timeout=CELLULAR_TIMEOUT,
104                        exception=_STILL_REGISTERED_ERROR)
105
106                    logging.info('Powering on basestation')
107                    env.emulator.SetPower(cellular.Power.DEFAULT)
108                    self.TimedPollForCondition(
109                        'Power.DEFAULT.%s.register_time' % tname,
110                        lambda: cell_modem.ModemIsRegistered(),
111                        timeout=CELLULAR_TIMEOUT,
112                        exception=_NOT_REGISTERED_ERROR)
113
114                logging.info('Stopping basestation')
115                env.emulator.Stop()
116                if wait_for_disc:
117                    self.TimedPollForCondition(
118                        'Stop.%s.deregister_time' % tname,
119                        lambda: not cell_modem.ModemIsRegistered(),
120                        timeout=CELLULAR_TIMEOUT,
121                        exception=_STILL_REGISTERED_ERROR)
122
123                logging.info('Reconfiguring for %s' % tech)
124                env.emulator.SetTechnology(tech)
125                env.emulator.Start()
126
127                try:
128                    self.TimedPollForCondition(
129                        'Start.%s.register_time' % tname,
130                        lambda: cell_modem.ModemIsRegisteredUsing(tech),
131                        timeout=CELLULAR_TIMEOUT,
132                        exception=_WrongTech(tech))
133                except _WrongTech, wt:
134                    failed_technologies.append(
135                        (wt.technology, cell_modem.GetAccessTechnology()))
136
137                # TODO(jglasgow): verify flimflam properties (signals?)
138
139        if failed_technologies:
140            msg = ('Failed to register using %s' %
141                   ', '.join(str(x) for x in failed_technologies))
142            raise error.TestError(msg)
143