blob: 47c54cfaedae4543aacbd1c489f1189ee628fee5 [file] [log] [blame]
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Compass test which requires operator place the DUT heading north and south.
"""
import math
import factory_common # pylint: disable=unused-import
from cros.factory.device import device_utils
from cros.factory.test.i18n import _
from cros.factory.test import test_case
from cros.factory.utils.arg_utils import Arg
from cros.factory.utils import sync_utils
from cros.factory.utils import type_utils
_TEST_ITEMS = [(_('north'), (0, 1)), (_('south'), (0, -1))]
_FLASH_STATUS_TIME = 1
class CompassTest(test_case.TestCase):
ARGS = [
Arg('tolerance', int, 'The tolerance in degree.',
default=5),
Arg('location', type_utils.Enum(['base', 'lid']),
'Where the compass is located.',
default='base')
]
def setUp(self):
self.dut = device_utils.CreateDUTInterface()
self.controller = self.dut.magnetometer.GetController(
location=self.args.location)
def runTest(self):
for direction_label, direction in _TEST_ITEMS:
self.ui.SetView('main')
self.ui.SetInstruction(_(
'Put the DUT towards {direction}', direction=direction_label))
sync_utils.PollForCondition(
poll_method=type_utils.BindFunction(self._CheckDirection, direction),
timeout_secs=1000,
poll_interval_secs=0.1)
self.ui.SetView('success')
self.Sleep(_FLASH_STATUS_TIME)
def _CalculateDirection(self, x, y):
"""Calculate the absolute direction of the compass in degree.
Args:
x: X-axis component of the direction. X-axis points towards east.
y: Y-axis component of the direction. Y-axis points towards north.
Returns:
Directed angle relative to north (0, 1), in degree, clockwise.
For example:
North = 0
East = 90
South = 180 = -180
West = -90
"""
rad = math.atan2(x, y)
return rad / math.pi * 180
def _CalculateAngle(self, x1, y1, x2, y2):
"""Calculate the angle between two vectors (x1, y1) and (x2, y2)."""
rad = math.acos(
(x1 * x2 + y1 * y2) / math.hypot(x1, y1) / math.hypot(x2, y2))
return rad / math.pi * 180
def _CheckDirection(self, expected_direction):
values = self.controller.GetData(capture_count=1)
x, y = values['in_magn_x'], values['in_magn_y']
if x == 0 and y == 0:
# atan2(0, 0) returns 0, we need to avoid this case.
self.FailTask('Sensor outputs (0, 0), possibly not working.')
degree = self._CalculateDirection(x, y)
self._UpdateUI(degree=degree, **values)
return (
self._CalculateAngle(x, y, *expected_direction) < self.args.tolerance)
def _UpdateUI(self, degree, in_magn_x, in_magn_y, in_magn_z):
self.ui.SetHTML('%.2f' % degree, id='degree')
self.ui.SetHTML(in_magn_x, id='in-magn-x')
self.ui.SetHTML(in_magn_y, id='in-magn-y')
self.ui.SetHTML(in_magn_z, id='in-magn-z')
self.ui.RunJS('document.getElementById("compass").style.transform = '
'"rotate(%ddeg)";' % degree)