1#/usr/bin/env python3.4
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16"""
17This test script exercises power test scenarios for different scan modes.
18This test script was designed with this setup in mind:
19Shield box one: Android Device and Monsoon tool box
20"""
21
22import json
23import os
24import sys
25
26from acts.test_decorators import test_tracker_info
27from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
28from acts.test_utils.bt.bt_constants import ble_scan_settings_modes
29from acts.test_utils.bt.bt_test_utils import bluetooth_enabled_check
30from acts.test_utils.bt.bt_test_utils import disable_bluetooth
31from acts.test_utils.bt.bt_test_utils import generate_ble_scan_objects
32from acts.test_utils.bt.PowerBaseTest import PowerBaseTest
33
34
35class BleScanPowerTest(PowerBaseTest):
36    # Repetitions for scan and idle
37    REPETITIONS_40 = 5
38    REPETITIONS_360 = 40
39
40    # Power measurement start time in seconds
41    SCAN_START_TIME = 60
42    # BLE scanning time in seconds
43    SCAN_TIME_60 = 60
44    SCAN_TIME_5 = 5
45    # BLE no scanning time in seconds
46    IDLE_TIME_30 = 30
47    IDLE_TIME_5 = 5
48
49    PMC_BASE_CMD = ("am broadcast -a com.android.pmc.BLESCAN --es ScanMode ")
50    # Log file name
51    LOG_FILE = "BLEPOWER.log"
52
53    def setup_class(self):
54        super(BleScanPowerTest, self).setup_class()
55        # Get power test device serial number
56        power_test_device_serial = self.user_params["PowerTestDevice"]
57        # If there are multiple devices in the shield box turn off
58        # all of them except the one for the power testing
59        if len(self.android_devices) > 1:
60            for ad in self.android_devices:
61                if ad.serial != power_test_device_serial[0]:
62                    self.ad.log.info("Disable BT for %s != %s", ad.serial,
63                                     power_test_device_serial[0])
64                    disable_bluetooth(ad.droid)
65
66    def _measure_power_for_scan_n_log_data(self, scan_mode, scan_time,
67                                           idle_time, repetitions, test_case):
68        """utility function for power test with BLE scan.
69
70        Steps:
71        1. Prepare adb shell command
72        2. Send the adb shell command to PMC
73        3. PMC start first alarm to start scan
74        4. After first alarm triggered it start the second alarm to stop scan
75        5. Repeat the scan/idle cycle for the number of repetitions
76        6. Save the power usage data into log file
77
78        Args:
79            scan_mode: Scan mode
80            scan_time: Time duration for scanning
81            idle_time: Time duration for idle after scanning
82            repetitions:  The number of cycles of scanning/idle
83
84        Returns:
85            True if the average current is within the allowed tolerance;
86            False otherwise.
87        """
88
89        if not self.disable_location_scanning():
90            return False
91
92        first_part_msg = "%s%s --es StartTime %d --es ScanTime %d" % (
93            self.PMC_BASE_CMD, scan_mode, self.SCAN_START_TIME, scan_time)
94        msg = "%s --es NoScanTime %d --es Repetitions %d" % (first_part_msg,
95                                                             idle_time,
96                                                             repetitions)
97
98        self.ad.log.info("Send broadcast message: %s", msg)
99        self.ad.adb.shell(msg)
100
101        # Check if PMC is ready
102        if not self.check_pmc_status(self.LOG_FILE, "READY",
103                                     "PMC is not ready"):
104            return
105
106        # Start the power measurement
107        sample_time = (scan_time + idle_time) * repetitions
108        result = self.mon.measure_power(self.POWER_SAMPLING_RATE, sample_time,
109                               self.current_test_name, self.SCAN_START_TIME)
110
111        self.ad.log.info("Monsoon start_time: {}".format(result.timestamps[0]))
112
113        start_times = []
114        end_times = []
115        json_data = self.check_pmc_timestamps(self.LOG_FILE)
116        for timestamp in json_data:
117            start_times.append(timestamp["StartTime"])
118            end_times.append(timestamp["EndTime"])
119
120        self.ad.log.info("Number of test cycles: {}".format(len(start_times)))
121
122        (current_avg, stdev) = self.save_logs_for_power_test(
123            result, start_times, end_times, False)
124
125        # perform watermark comparison numbers
126        self.log.info("==> CURRENT AVG from PMC Monsoon app: %s" % current_avg)
127        self.log.info(
128            "==> WATERMARK from config file: %s" % self.user_params[test_case])
129        return self.check_test_pass(current_avg, self.user_params[test_case])
130
131    @BluetoothBaseTest.bt_test_wrap
132    @test_tracker_info(uuid='1e8c793f-897d-4160-8ebf-fd1addcd9c71')
133    def test_power_for_scan_w_low_latency(self):
134        """Test power usage when scan with low latency.
135
136        Tests power usage when the device scans with low latency mode
137        for 60 seconds and then idle for 30 seconds, repeat for 60 minutes
138        where there are no advertisements.
139
140        Steps:
141        1. Prepare adb shell command
142        2. Send the adb shell command to PMC
143        3. PMC start first alarm to start scan
144        4. After first alarm triggered it start the second alarm to stop scan
145        5. Repeat the cycle for 60 minutes
146        6. Save the power usage data into log file
147
148        Expected Result:
149        power consumption results
150
151        TAGS: LE, Scanning, Power
152        Priority: 3
153        """
154        current_test_case = func_name = sys._getframe().f_code.co_name
155        return self._measure_power_for_scan_n_log_data(
156            ble_scan_settings_modes['low_latency'], self.SCAN_TIME_60,
157            self.IDLE_TIME_30, self.REPETITIONS_40, current_test_case)
158
159    @BluetoothBaseTest.bt_test_wrap
160    @test_tracker_info(uuid='83e37081-9f00-4b5f-ba1c-92136047fa83')
161    def test_power_for_scan_w_balanced(self):
162        """Test power usage when scan with balanced mode.
163
164        Tests power usage when the device scans with balanced mode
165        for 60 seconds and then idle for 30 seconds, repeat for 60 minutes
166        where there are no advertisements.
167
168        Steps:
169        1. Prepare adb shell command
170        2. Send the adb shell command to PMC
171        3. PMC start first alarm to start scan
172        4. After first alarm triggered it start the second alarm to stop scan
173        5. Repeat the cycle for 60 minutes
174        6. Save the power usage data into log file
175
176        Expected Result:
177        power consumption results
178
179        TAGS: LE, Scanning, Power
180        Priority: 3
181        """
182        current_test_case = func_name = sys._getframe().f_code.co_name
183        return self._measure_power_for_scan_n_log_data(
184            ble_scan_settings_modes['balanced'], self.SCAN_TIME_60,
185            self.IDLE_TIME_30, self.REPETITIONS_40, current_test_case)
186
187    @BluetoothBaseTest.bt_test_wrap
188    @test_tracker_info(uuid='cbf16414-3468-4f60-8a62-2a88556d7a87')
189    def test_power_for_scan_w_low_power(self):
190        """Test power usage when scan with low power.
191
192        Tests power usage when the device scans with low power mode
193        for 60 seconds and then idle for 30 seconds, repeat for 60 minutes
194        where there are no advertisements.
195
196        Steps:
197        1. Prepare adb shell command
198        2. Send the adb shell command to PMC
199        3. PMC start first alarm to start scan
200        4. After first alarm triggered it start the second alarm to stop scan
201        5. Repeat the cycle for 60 minutes
202        6. Save the power usage data into log file
203
204        Expected Result:
205        power consumption results
206
207        TAGS: LE, Scanning, Power
208        Priority: 3
209        """
210        current_test_case = func_name = sys._getframe().f_code.co_name
211        return self._measure_power_for_scan_n_log_data(
212            ble_scan_settings_modes['low_power'], self.SCAN_TIME_60,
213            self.IDLE_TIME_30, self.REPETITIONS_40, current_test_case)
214
215    @BluetoothBaseTest.bt_test_wrap
216    @test_tracker_info(uuid='0b1eaedb-4385-48ba-a175-7db79360aed8')
217    def test_power_for_intervaled_scans_w_balanced(self):
218        """Test power usage when intervaled scans with balanced mode
219
220        Tests power usage when the device perform multiple intervaled scans with
221        balanced mode for 5 seconds each where there are no advertisements.
222
223        Steps:
224        1. Prepare adb shell command
225        2. Send the adb shell command to PMC
226        3. PMC start first alarm to start scan
227        4. After first alarm triggered it starts the second alarm to stop scan
228        5. After second alarm triggered it starts the third alarm to start scan
229        6. Repeat the alarms until 360 scans are done
230        7. Save the power usage data into log file
231
232        Expected Result:
233        power consumption results
234
235        TAGS: LE, Scanning, Power
236        Priority: 3
237        """
238        current_test_case = func_name = sys._getframe().f_code.co_name
239        return self._measure_power_for_scan_n_log_data(
240            ble_scan_settings_modes['balanced'], self.SCAN_TIME_5,
241            self.IDLE_TIME_5, self.REPETITIONS_360, current_test_case)
242
243    @BluetoothBaseTest.bt_test_wrap
244    @test_tracker_info(uuid='90e6b341-9b11-4740-8ec1-dc605db93ec9')
245    def test_power_for_intervaled_scans_w_low_latency(self):
246        """Test power usage when intervaled scans with low latency mode
247
248        Tests power usage when the device perform multiple intervaled scans with
249        low latency mode for 5 seconds each where there are no advertisements.
250
251        Steps:
252        1. Prepare adb shell command
253        2. Send the adb shell command to PMC
254        3. PMC start first alarm to start scan
255        4. After first alarm triggered it starts the second alarm to stop scan
256        5. After second alarm triggered it starts the third alarm to start scan
257        6. Repeat the alarms until 360 scans are done
258        7. Save the power usage data into log file
259
260        Expected Result:
261        power consumption results
262
263        TAGS: LE, Scanning, Power
264        Priority: 3
265        """
266        current_test_case = func_name = sys._getframe().f_code.co_name
267        return self._measure_power_for_scan_n_log_data(
268            ble_scan_settings_modes['low_latency'], self.SCAN_TIME_5,
269            self.IDLE_TIME_5, self.REPETITIONS_360, current_test_case)
270
271    @BluetoothBaseTest.bt_test_wrap
272    @test_tracker_info(uuid='cbf16414-3468-4f60-8a62-2a88556d7a87')
273    def test_power_for_intervaled_scans_w_low_power(self):
274        """Test power usage when intervaled scans with low power mode
275
276        Tests power usage when the device perform multiple intervaled scans with
277        low power mode for 5 seconds each where there are no advertisements.
278
279        Steps:
280        1. Prepare adb shell command
281        2. Send the adb shell command to PMC
282        3. PMC start first alarm to start scan
283        4. After first alarm triggered it starts the second alarm to stop scan
284        5. After second alarm triggered it starts the third alarm to start scan
285        6. Repeat the alarms until 360 scans are done
286        7. Save the power usage data into log file
287
288        Expected Result:
289        power consumption results
290
291        TAGS: LE, Scanning, Power
292        Priority: 3
293        """
294        current_test_case = func_name = sys._getframe().f_code.co_name
295        return self._measure_power_for_scan_n_log_data(
296            ble_scan_settings_modes['low_power'], self.SCAN_TIME_5,
297            self.IDLE_TIME_5, self.REPETITIONS_360, current_test_case)
298