diff options
author | Denys Fedoryshchenko <denys.f@collabora.com> | 2023-03-27 17:43:56 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-27 17:43:56 +0300 |
commit | fad9423ae3c64bfd48c207de34a1177000d45fa8 (patch) | |
tree | 029968890d65f01d2de102c754575cdcec189fd8 | |
parent | f6c0dbf63842d5751000c5527808aca38354db55 (diff) | |
parent | e0204ebca1486eb7e174ccca15bfed6d3ad64e36 (diff) | |
download | cros-ec-tests-main.tar.gz |
Merge pull request #1 from penvirus/for-clean-upmain
For clean up
-rw-r--r-- | cros/helpers/ec_cmd.py | 143 | ||||
-rw-r--r-- | cros/helpers/kernel.py | 13 | ||||
-rw-r--r-- | cros/helpers/mcu.py | 220 | ||||
-rw-r--r--[-rwxr-xr-x] | cros/helpers/sysfs.py | 41 | ||||
-rw-r--r--[-rwxr-xr-x] | cros/runners/lava_runner.py | 101 | ||||
-rw-r--r-- | cros/tests/__init__.py | 7 | ||||
-rw-r--r--[-rwxr-xr-x] | cros/tests/cros_ec_accel.py | 75 | ||||
-rw-r--r--[-rwxr-xr-x] | cros/tests/cros_ec_extcon.py | 36 | ||||
-rw-r--r-- | cros/tests/cros_ec_gyro.py | 9 | ||||
-rw-r--r-- | cros/tests/cros_ec_mcu.py | 69 | ||||
-rw-r--r-- | cros/tests/cros_ec_power.py | 3 | ||||
-rw-r--r-- | cros/tests/cros_ec_pwm.py | 62 | ||||
-rw-r--r--[-rwxr-xr-x] | cros/tests/cros_ec_rtc.py | 54 | ||||
-rw-r--r-- | docs/source/testhelpers.rst | 4 | ||||
-rw-r--r-- | setup.py | 2 |
15 files changed, 377 insertions, 462 deletions
diff --git a/cros/helpers/ec_cmd.py b/cros/helpers/ec_cmd.py new file mode 100644 index 0000000..dbcb565 --- /dev/null +++ b/cros/helpers/ec_cmd.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from ctypes import addressof +from ctypes import c_ubyte, c_uint8, c_uint32, c_uint64 +from ctypes import memmove +from ctypes import sizeof +from ctypes import Structure +import fcntl + + +EC_HOST_PARAM_SIZE = 0xFC +EC_DEV_IOCXCMD = 0xC014EC00 # _IOWR(EC_DEV_IOC, 0, struct cros_ec_command) + +# EC commands +EC_CMD_PROTO_VERSION = 0x0000 +EC_CMD_HELLO = 0x0001 +EC_CMD_GET_VERSION = 0x0002 +EC_CMD_GET_FEATURES = 0x000D +EC_CMD_REBOOT = 0x00D1 + +ECFEATURES_CACHE = -1 +# EC features +EC_FEATURE_LIMITED = 0 +EC_FEATURE_FLASH = 1 +EC_FEATURE_PWM_FAN = 2 +EC_FEATURE_PWM_KEYB = 3 +EC_FEATURE_LIGHTBAR = 4 +EC_FEATURE_LED = 5 +EC_FEATURE_MOTION_SENSE = 6 +EC_FEATURE_KEYB = 7 +EC_FEATURE_PSTORE = 8 +EC_FEATURE_PORT80 = 9 +EC_FEATURE_THERMAL = 10 +EC_FEATURE_BKLIGHT_SWITCH = 11 +EC_FEATURE_WIFI_SWITCH = 12 +EC_FEATURE_HOST_EVENTS = 13 +EC_FEATURE_GPIO = 14 +EC_FEATURE_I2C = 15 +EC_FEATURE_CHARGER = 16 +EC_FEATURE_BATTERY = 17 +EC_FEATURE_SMART_BATTERY = 18 +EC_FEATURE_HANG_DETECT = 19 +EC_FEATURE_PMU = 20 +EC_FEATURE_SUB_MCU = 21 +EC_FEATURE_USB_PD = 22 +EC_FEATURE_USB_MUX = 23 +EC_FEATURE_MOTION_SENSE_FIFO = 24 +EC_FEATURE_VSTORE = 25 +EC_FEATURE_USBC_SS_MUX_VIRTUAL = 26 +EC_FEATURE_RTC = 27 +EC_FEATURE_FINGERPRINT = 28 +EC_FEATURE_TOUCHPAD = 29 +EC_FEATURE_RWSIG = 30 +EC_FEATURE_DEVICE_EVENT = 31 +EC_FEATURE_UNIFIED_WAKE_MASKS = 32 +EC_FEATURE_HOST_EVENT64 = 33 +EC_FEATURE_EXEC_IN_RAM = 34 +EC_FEATURE_CEC = 35 +EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS = 36 +EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37 +EC_FEATURE_SCP = 39 +EC_FEATURE_ISH = 40 + +# enum ec_current_image +EC_IMAGE_UNKNOWN = 0 +EC_IMAGE_RO = 1 +EC_IMAGE_RW = 2 + + +class cros_ec_command(Structure): + _fields_ = [ + ("version", c_uint32), + ("command", c_uint32), + ("outsize", c_uint32), + ("insize", c_uint32), + ("result", c_uint32), + ("data", c_uint8 * EC_HOST_PARAM_SIZE), + ] + + +class ec_params_hello(Structure): + _fields_ = [("in_data", c_uint32)] + + +class ec_response_hello(Structure): + _fields_ = [("out_data", c_uint32)] + + +class ec_response_get_version(Structure): + _fields_ = [ + ("version_string_ro", c_ubyte * 32), + ("version_string_rw", c_ubyte * 32), + ("reserved", c_ubyte * 32), + ("current_image", c_uint32), + ] + + +class ec_response_get_features(Structure): + _fields_ = [("in_data", c_uint64)] + + +def EC_FEATURE_MASK_0(event_code): + return 1 << (event_code % 32) + + +def EC_FEATURE_MASK_1(event_code): + return 1 << (event_code - 32) + + +def is_feature_supported(feature): + """ Returns true if the Embedded Controller supports the specified + 'feature'. + """ + global ECFEATURES_CACHE + + if ECFEATURES_CACHE == -1: + param, response = None, ec_response_get_features() + + cmd = send_ec_command("/dev/cros_ec", EC_CMD_GET_FEATURES, param, response) + if cmd.result == 0: + ECFEATURES_CACHE = response.in_data + else: + return False + + return bool(ECFEATURES_CACHE & EC_FEATURE_MASK_0(feature)) + + +def send_ec_command(dev, command, param=None, resp=None): + cmd = cros_ec_command() + cmd.version = 0 + cmd.command = command + cmd.outsize = 0 if param is None else sizeof(param) + cmd.insize = 0 if resp is None else sizeof(resp) + + if cmd.outsize != 0: + memmove(addressof(cmd.data), addressof(param), cmd.outsize) + with open(dev) as fh: + fcntl.ioctl(fh, EC_DEV_IOCXCMD, cmd) + if cmd.insize != 0: + memmove(addressof(resp), addressof(cmd.data), cmd.insize) + + return cmd diff --git a/cros/helpers/kernel.py b/cros/helpers/kernel.py index db0c69f..c3a29e2 100644 --- a/cros/helpers/kernel.py +++ b/cros/helpers/kernel.py @@ -14,9 +14,8 @@ def current_kernel_version(): """ Returns the current kernel version as an integer you can compare. """ - fd = open("/proc/version", "r") - current = fd.read().split()[2].split("-")[0].split(".") - fd.close() + with open("/proc/version") as fh: + current = fh.read().split()[2].split("-")[0].split(".") return version_to_int(int(current[0]), int(current[1]), int(current[2])) @@ -24,15 +23,11 @@ def kernel_lower_than(version, major, minor): """ Returns true if the given version is lower than the running kernel version. """ - if version_to_int(version, major, minor) > current_kernel_version(): - return True - return False + return current_kernel_version() < version_to_int(version, major, minor) def kernel_greater_than(version, major, minor): """ Returns true if the given version is greater than the running kernel version. """ - if version_to_int(version, major, minor) < current_kernel_version(): - return True - return False + return current_kernel_version() > version_to_int(version, major, minor) diff --git a/cros/helpers/mcu.py b/cros/helpers/mcu.py deleted file mode 100644 index 36d125b..0000000 --- a/cros/helpers/mcu.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import fcntl -import os -from cros.helpers.sysfs import * -from ctypes import * - -EC_CMD_PROTO_VERSION = 0x0000 -EC_CMD_HELLO = 0x0001 -EC_CMD_GET_VERSION = 0x0002 -EC_CMD_GET_FEATURES = 0x000D -EC_CMD_REBOOT = 0x00D1 - -EC_HOST_PARAM_SIZE = 0xFC - -EC_DEV_IOCXCMD = 0xC014EC00 # _IOWR(EC_DEV_IOC, 0, struct cros_ec_command) - -ECFEATURES = -1 -# Supported features -EC_FEATURE_LIMITED = 0 -EC_FEATURE_FLASH = 1 -EC_FEATURE_PWM_FAN = 2 -EC_FEATURE_PWM_KEYB = 3 -EC_FEATURE_LIGHTBAR = 4 -EC_FEATURE_LED = 5 -EC_FEATURE_MOTION_SENSE = 6 -EC_FEATURE_KEYB = 7 -EC_FEATURE_PSTORE = 8 -EC_FEATURE_PORT80 = 9 -EC_FEATURE_THERMAL = 10 -EC_FEATURE_BKLIGHT_SWITCH = 11 -EC_FEATURE_WIFI_SWITCH = 12 -EC_FEATURE_HOST_EVENTS = 13 -EC_FEATURE_GPIO = 14 -EC_FEATURE_I2C = 15 -EC_FEATURE_CHARGER = 16 -EC_FEATURE_BATTERY = 17 -EC_FEATURE_SMART_BATTERY = 18 -EC_FEATURE_HANG_DETECT = 19 -EC_FEATURE_PMU = 20 -EC_FEATURE_SUB_MCU = 21 -EC_FEATURE_USB_PD = 22 -EC_FEATURE_USB_MUX = 23 -EC_FEATURE_MOTION_SENSE_FIFO = 24 -EC_FEATURE_VSTORE = 25 -EC_FEATURE_USBC_SS_MUX_VIRTUAL = 26 -EC_FEATURE_RTC = 27 -EC_FEATURE_FINGERPRINT = 28 -EC_FEATURE_TOUCHPAD = 29 -EC_FEATURE_RWSIG = 30 -EC_FEATURE_DEVICE_EVENT = 31 -EC_FEATURE_UNIFIED_WAKE_MASKS = 32 -EC_FEATURE_HOST_EVENT64 = 33 -EC_FEATURE_EXEC_IN_RAM = 34 -EC_FEATURE_CEC = 35 -EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS = 36 -EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37 -EC_FEATURE_SCP = 39 -EC_FEATURE_ISH = 40 - -EC_IMAGE_UNKNOWN = 0 -EC_IMAGE_RO = 1 -EC_IMAGE_RW = 2 - -class cros_ec_command(Structure): - _fields_ = [ - ("version", c_uint), - ("command", c_uint), - ("outsize", c_uint), - ("insize", c_uint), - ("result", c_uint), - ("data", c_ubyte * EC_HOST_PARAM_SIZE), - ] - - -class ec_params_hello(Structure): - _fields_ = [("in_data", c_uint)] - - -class ec_response_hello(Structure): - _fields_ = [("out_data", c_uint)] - -class ec_response_get_version(Structure): - _fields_ = [ - ("version_string_ro", c_ubyte * 32), - ("version_string_rw", c_ubyte * 32), - ("reserved", c_ubyte * 32), - ("current_image", c_uint), - ] - -class ec_params_get_features(Structure): - _fields_ = [("in_data", c_ulong)] - - -class ec_response_get_features(Structure): - _fields_ = [("out_data", c_ulong)] - - -def EC_FEATURE_MASK_0(event_code): - return 1 << (event_code % 32) - - -def EC_FEATURE_MASK_1(event_code): - return 1 << (event_code - 32) - - -def is_feature_supported(feature): - """ Returns true if the Embedded Controller supports the specified - 'feature'. - """ - global ECFEATURES - - if ECFEATURES == -1: - fd = open("/dev/cros_ec", "r") - - param = ec_params_get_features() - response = ec_response_get_features() - - cmd = cros_ec_command() - cmd.version = 0 - cmd.command = EC_CMD_GET_FEATURES - cmd.insize = sizeof(param) - cmd.outsize = sizeof(response) - - memmove(addressof(cmd.data), addressof(param), cmd.outsize) - fcntl.ioctl(fd, EC_DEV_IOCXCMD, cmd) - memmove(addressof(response), addressof(cmd.data), cmd.outsize) - - fd.close() - - if cmd.result == 0: - ECFEATURES = response.out_data - else: - return False - - return (ECFEATURES & EC_FEATURE_MASK_0(feature)) > 0 - - -def check_mcu_abi(s, name): - """ Checks that the MCU character device exists in /dev and then verifies - the standard MCU ABI in /sys/class/chromeos. - """ - if not os.path.exists(os.path.join("/dev", name)): - s.skipTest(f"MCU {name} not supported") - files = ["flashinfo", "reboot", "version"] - sysfs_check_attributes_exists( - s, "/sys/class/chromeos/", name, files, False - ) - - -def mcu_hello(s, name): - """ Checks basic comunication with MCU. """ - devpath = os.path.join("/dev", name) - if not os.path.exists(devpath): - s.skipTest(f"MCU {name} not present") - fd = open(devpath, "r") - param = ec_params_hello() - param.in_data = 0xA0B0C0D0 # magic number that the EC expects on HELLO - - response = ec_response_hello() - - cmd = cros_ec_command() - cmd.version = 0 - cmd.command = EC_CMD_HELLO - cmd.insize = sizeof(param) - cmd.outsize = sizeof(response) - - memmove(addressof(cmd.data), addressof(param), cmd.insize) - fcntl.ioctl(fd, EC_DEV_IOCXCMD, cmd) - memmove(addressof(response), addressof(cmd.data), cmd.outsize) - - fd.close() - - s.assertEqual(cmd.result, 0, msg="Error sending EC HELLO") - # magic number that the EC answers on HELLO - s.assertEqual(response.out_data, 0xA1B2C3D4, - msg=f"Wrong EC HELLO magic number ({response.out_data})") - -def mcu_get_version(name): - devpath = os.path.join("/dev", name) - if os.path.exists(devpath): - fd = open(devpath, "r") - - response = ec_response_get_version() - - cmd = cros_ec_command() - cmd.version = 0 - cmd.command = EC_CMD_GET_VERSION - cmd.insize = sizeof(response) - cmd.outsize = 0 - - fcntl.ioctl(fd, EC_DEV_IOCXCMD, cmd) - memmove(addressof(response), addressof(cmd.data), cmd.insize) - - fd.close() - if cmd.result == 0: - return response - -def mcu_reboot(name): - fd = open(os.path.join("/dev", name), "r") - cmd = cros_ec_command() - cmd.version = 0 - cmd.command = EC_CMD_REBOOT - cmd.insize = 0 - cmd.outsize = 0 - try: - fcntl.ioctl(fd, EC_DEV_IOCXCMD, cmd) - except IOError: - pass - fd.close() - -def check_mcu_reboot_rw(s, name): - if not os.path.exists(os.path.join("/dev", name)): - s.skipTest("cros_fp not present") - mcu_reboot(name) - response = mcu_get_version(name) - s.assertEqual(response.current_image, EC_IMAGE_RW, - msg="Current EC image is not RW") - diff --git a/cros/helpers/sysfs.py b/cros/helpers/sysfs.py index 83dc38b..131584a 100755..100644 --- a/cros/helpers/sysfs.py +++ b/cros/helpers/sysfs.py @@ -4,36 +4,27 @@ import os -def read_file(name): - """ Returns the content of the file named 'name'.""" - fd = open(name, "r") - contents = fd.read() - fd.close() - return contents - - def sysfs_check_attributes_exists(s, path, name, files, check_devtype): """ Checks that all attributes listed in 'files' for a given 'path' exists. Note that the 'name' parameter is used to define a pattern to match before checking a device path. """ match = 0 - try: - for devname in os.listdir(path): - if check_devtype: - fd = open(os.path.join(path, devname, 'name'), "r") - devtype = fd.read() - fd.close() - if not devtype.startswith(name): - continue - else: - if not devname.startswith(name): - continue - match += 1 - for filename in files: - p = os.path.join(path, devname, filename) - s.assertTrue(os.path.exists(p), msg=f"{p} not found") - except IOError as e: - s.skipTest(f"{e}") + for devname in os.listdir(path): + if check_devtype: + p = os.path.join(path, devname, "name") + if not os.path.exists(p): + s.skipTest(f"{p} not found") + with open(p) as fh: + devtype = fh.read() + if not devtype.startswith(name): + continue + else: + if not devname.startswith(name): + continue + match += 1 + for filename in files: + p = os.path.join(path, devname, filename) + s.assertTrue(os.path.exists(p), msg=f"{p} not found") if match == 0: s.skipTest(f"No {name} found") diff --git a/cros/runners/lava_runner.py b/cros/runners/lava_runner.py index 554a79e..baedb83 100755..100644 --- a/cros/runners/lava_runner.py +++ b/cros/runners/lava_runner.py @@ -1,107 +1,50 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -import sys +import functools import unittest -import traceback -from cros.tests.cros_ec_accel import * -from cros.tests.cros_ec_gyro import * -from cros.tests.cros_ec_mcu import * -from cros.tests.cros_ec_pwm import * -from cros.tests.cros_ec_rtc import * -from cros.tests.cros_ec_power import * -from cros.tests.cros_ec_extcon import * +class LavaTestResult(unittest.TextTestResult): + def writeLavaSignal(self, test, result): + test_case_id = test.id().rsplit(".")[-1] -class LavaTextTestResult(unittest.TestResult): - def __init__(self, runner, verbosity=0): - super().__init__() - self.trace_on = verbosity > 0 - self.debug_on = verbosity > 1 - self.runner = runner + # LAVA signal must be start-of-line. Print a newline if verbosity >= 1. + if self.showAll or self.dots: + self.stream.writeln() + + self.stream.writeln( + f"<LAVA_SIGNAL_TESTCASE TEST_CASE_ID={test_case_id} RESULT={result}>" + ) + self.stream.flush() def addSuccess(self, test): super().addSuccess(test) - testcase = test.id().rsplit(".")[-1] - self.runner.writeUpdate( - f"<LAVA_SIGNAL_TESTCASE TEST_CASE_ID={testcase} RESULT=pass>\n") + self.writeLavaSignal(test, "pass") def addError(self, test, err): super().addError(test, err) - testcase = test.id().rsplit(".")[-1] - if self.trace_on: - exc_type, exc_value, exc_tb = err - msg = str(exc_value).split(' : ') - if len(msg) > 1: - msg = ''.join(msg[1:]) - else: - msg = msg[0] - self.runner.writeUpdate(f"{testcase} ERROR: {msg}\n") - if self.debug_on: - exc_type, exc_value, exc_tb = err - traceback.print_tb(exc_tb, file=self.runner.stream) - self.runner.writeUpdate( - f"<LAVA_SIGNAL_TESTCASE TEST_CASE_ID={testcase} RESULT=unknown>\n") + self.writeLavaSignal(test, "unknown") def addFailure(self, test, err): super().addFailure(test, err) - testcase = test.id().rsplit(".")[-1] - if self.trace_on: - exc_type, exc_value, exc_tb = err - msg = str(exc_value).split(' : ') - if len(msg) > 1: - msg = ''.join(msg[1:]) - else: - msg = msg[0] - self.runner.writeUpdate(f"{testcase} FAIL: {msg}\n") - if self.debug_on: - exc_type, exc_value, exc_tb = err - traceback.print_tb(exc_tb, file=self.runner.stream) - self.runner.writeUpdate( - f"<LAVA_SIGNAL_TESTCASE TEST_CASE_ID={testcase} RESULT=fail>\n") + self.writeLavaSignal(test, "fail") def addSkip(self, test, reason): super().addSkip(test, reason) - testcase = test.id().rsplit(".")[-1] - if self.trace_on: - self.runner.writeUpdate(f"{testcase} SKIP: {reason}\n") - self.runner.writeUpdate( - f"<LAVA_SIGNAL_TESTCASE TEST_CASE_ID={testcase} RESULT=skip>\n") - - -class LavaTestRunner: - def __init__(self, stream=sys.stderr, verbosity=0): - self.stream = stream - self.verbosity = verbosity + self.writeLavaSignal(test, "skip") - def writeUpdate(self, message): - self.stream.write(message) - def run(self, test): - result = LavaTextTestResult(self, self.verbosity) - test(result) - result.testsRun - return result +class LavaTestRunner(unittest.TextTestRunner): + __init__ = functools.partialmethod( + unittest.TextTestRunner.__init__, + resultclass=LavaTestResult) if __name__ == "__main__": - verbosity = 0 - # Parse additional "verbosity" parameter and strip it from sys.argv - # so that unittest can do the rest of the command line parsing - if '--verbosity' in sys.argv: - i = sys.argv.index('--verbosity') - try: - verbosity = int(sys.argv[i+1]) - sys.argv.pop(i+1) - except IndexError: - pass - except ValueError: - sys.argv.pop(i+1) - finally: - sys.argv.pop(i) unittest.main( - testRunner=LavaTestRunner(verbosity=verbosity), + module="cros.tests", + testRunner=LavaTestRunner, # these make sure that some options that are not applicable # remain hidden from the help menu. failfast=False, diff --git a/cros/tests/__init__.py b/cros/tests/__init__.py index e69de29..36f6890 100644 --- a/cros/tests/__init__.py +++ b/cros/tests/__init__.py @@ -0,0 +1,7 @@ +from .cros_ec_accel import * +from .cros_ec_extcon import * +from .cros_ec_gyro import * +from .cros_ec_mcu import * +from .cros_ec_power import * +from .cros_ec_pwm import * +from .cros_ec_rtc import * diff --git a/cros/tests/cros_ec_accel.py b/cros/tests/cros_ec_accel.py index bf3aaf0..308b42f 100755..100644 --- a/cros/tests/cros_ec_accel.py +++ b/cros/tests/cros_ec_accel.py @@ -1,12 +1,17 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from cros.helpers.kernel import * -from cros.helpers.mcu import * -from cros.helpers.sysfs import * +import glob import math -import unittest import os +import unittest + +from cros.helpers.ec_cmd import EC_FEATURE_MOTION_SENSE_FIFO +from cros.helpers.ec_cmd import is_feature_supported +from cros.helpers.kernel import kernel_greater_than +from cros.helpers.kernel import kernel_lower_than +from cros.helpers.sysfs import sysfs_check_attributes_exists + class TestCrosECAccel(unittest.TestCase): def test_cros_ec_accel_iio_abi(self): @@ -29,7 +34,7 @@ class TestCrosECAccel(unittest.TestCase): "sampling_frequency", "sampling_frequency_available", "scale", - "scan_elements/", + "scan_elements", "trigger", ] if (kernel_greater_than(5, 6, 0) and @@ -51,32 +56,40 @@ class TestCrosECAccel(unittest.TestCase): """ ACCEL_1G_IN_MS2 = 9.8185 ACCEL_MAG_VALID_OFFSET = 0.25 + exp = ACCEL_1G_IN_MS2 + err = exp * ACCEL_MAG_VALID_OFFSET + match = 0 - try: - basepath = "/sys/bus/iio/devices" - for devname in os.listdir(basepath): - dev_basepath = os.path.join(basepath, devname) - fd = open(os.path.join(dev_basepath, "name"), "r") - devtype = fd.read() - if devtype.startswith("cros-ec-accel"): - accel_scale = float(read_file(os.path.join(dev_basepath, "scale"))) - exp = ACCEL_1G_IN_MS2 - err = exp * ACCEL_MAG_VALID_OFFSET - mag = 0 - for axis in ["in_accel_x_raw", - "in_accel_y_raw", - "in_accel_z_raw"]: - axis_path = os.path.join(dev_basepath, axis) - value = int(read_file(axis_path)) - value *= accel_scale - mag += value * value - mag = math.sqrt(mag) - self.assertTrue(abs(mag - exp) <= err, - msg=("Incorrect accelerometer data " - f"in {dev_basepath} ({abs(mag - exp)})")) - match += 1 - fd.close() - except IOError as e: - self.skipTest(f"{e}") + for dev in glob.glob("/sys/bus/iio/devices/*"): + p = os.path.join(dev, "name") + if not os.path.exists(p): + self.skipTest(f"{p} not found") + with open(p) as fh: + devtype = fh.read() + if not devtype.startswith("cros-ec-accel"): + continue + + p = os.path.join(dev, "scale") + if not os.path.exists(p): + self.skipTest(f"{p} not found") + with open(p) as fh: + accel_scale = float(fh.read()) + + mag = 0 + for axis in ["in_accel_x_raw", "in_accel_y_raw", "in_accel_z_raw"]: + axis_path = os.path.join(dev, axis) + if not os.path.exists(axis_path): + self.skipTest(f"{axis_path} not found") + + with open(axis_path) as fh: + value = int(fh.read()) + value *= accel_scale + mag += value * value + mag = math.sqrt(mag) + + self.assertTrue(abs(mag - exp) <= err, + msg=("Incorrect accelerometer data " + f"in {dev} ({abs(mag - exp)})")) + match += 1 if match == 0: self.skipTest("No accelerometer found") diff --git a/cros/tests/cros_ec_extcon.py b/cros/tests/cros_ec_extcon.py index 9d3e84c..c1bc966 100755..100644 --- a/cros/tests/cros_ec_extcon.py +++ b/cros/tests/cros_ec_extcon.py @@ -1,30 +1,30 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from cros.helpers.sysfs import * -import unittest +import glob import os +import unittest + class TestCrosECextcon(unittest.TestCase): def test_cros_ec_extcon_usbc_abi(self): """ Checks the cros-ec extcon ABI. """ match = 0 - try: - basepath = "/sys/class/extcon" - for devname in os.listdir(basepath): - dev_basepath = os.path.join(basepath, devname) - devtype = read_file(os.path.join(dev_basepath, "name")) - if ".spi:ec@0:extcon@" in devtype: - p = os.path.join(dev_basepath, "state") + for dev in glob.glob("/sys/class/extcon/*"): + with open(os.path.join(dev, "name")) as fh: + devtype = fh.read() + if ".spi:ec@0:extcon@" not in devtype: + continue + + p = os.path.join(dev, "state") + self.assertTrue(os.path.exists(p), msg=f"{p} not found") + + for cable in os.listdir(dev): + if cable.startswith("cable"): + p = os.path.join(dev, cable, "name") + self.assertTrue(os.path.exists(p), msg=f"{p} not found") + p = os.path.join(dev, cable, "state") self.assertTrue(os.path.exists(p), msg=f"{p} not found") - for cable in os.listdir(dev_basepath): - if cable.startswith("cable"): - p = os.path.join(dev_basepath, cable, "name") - self.assertTrue(os.path.exists(p), msg=f"{p} not found") - p = os.path.join(dev_basepath, cable, "state") - self.assertTrue(os.path.exists(p), msg=f"{p} not found") - match += 1 - except IOError as e: - self.skipTest(f"{e}") + match += 1 if match == 0: self.skipTest("No extcon device found") diff --git a/cros/tests/cros_ec_gyro.py b/cros/tests/cros_ec_gyro.py index 88a549c..28783a2 100644 --- a/cros/tests/cros_ec_gyro.py +++ b/cros/tests/cros_ec_gyro.py @@ -1,11 +1,14 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from cros.helpers.kernel import * -from cros.helpers.mcu import * -from cros.helpers.sysfs import * import unittest +from cros.helpers.ec_cmd import EC_FEATURE_MOTION_SENSE_FIFO +from cros.helpers.ec_cmd import is_feature_supported +from cros.helpers.kernel import kernel_greater_than +from cros.helpers.kernel import kernel_lower_than +from cros.helpers.sysfs import sysfs_check_attributes_exists + class TestCrosECGyro(unittest.TestCase): def test_cros_ec_gyro_iio_abi(self): diff --git a/cros/tests/cros_ec_mcu.py b/cros/tests/cros_ec_mcu.py index 1465286..1e6d29b 100644 --- a/cros/tests/cros_ec_mcu.py +++ b/cros/tests/cros_ec_mcu.py @@ -1,48 +1,95 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from cros.helpers.mcu import * -import fcntl +import os import unittest +from cros.helpers.ec_cmd import ec_params_hello, ec_response_hello +from cros.helpers.ec_cmd import send_ec_command +from cros.helpers import ec_cmd +from cros.helpers.sysfs import sysfs_check_attributes_exists + class TestCrosECMCU(unittest.TestCase): + def check_abi(self, name): + """ Checks that the MCU character device exists in /dev and then verifies + the standard MCU ABI in /sys/class/chromeos. + """ + dev = os.path.join("/dev", name) + if not os.path.exists(dev): + self.skipTest(f"MCU {name} not supported") + + files = ["flashinfo", "reboot", "version"] + sysfs_check_attributes_exists( + self, "/sys/class/chromeos/", name, files, False + ) + def test_cros_ec_abi(self): """ Checks the standard ABI for the main Embedded Controller. """ - check_mcu_abi(self, "cros_ec") + self.check_abi("cros_ec") def test_cros_fp_abi(self): """ Checks the standard ABI for the Fingerprint EC. """ - check_mcu_abi(self, "cros_fp") + self.check_abi("cros_fp") def test_cros_tp_abi(self): """ Checks the standard ABI for the Touchpad EC. """ - check_mcu_abi(self, "cros_tp") + self.check_abi("cros_tp") def test_cros_pd_abi(self): """ Checks the standard ABI for the Power Delivery EC. """ - check_mcu_abi(self, "cros_pd") + self.check_abi("cros_pd") def test_cros_ec_chardev(self): """ Checks the main Embedded controller character device. """ self.assertTrue(os.path.exists("/dev/cros_ec"), msg="/dev/cros_ec not found") + def check_hello(self, name): + """ Checks basic comunication with MCU. """ + dev = os.path.join("/dev", name) + if not os.path.exists(dev): + self.skipTest(f"MCU {name} not found") + + param, response = ec_params_hello(), ec_response_hello() + # magic number that the EC expects on HELLO + param.in_data = 0xA0B0C0D0 + + cmd = send_ec_command(dev, ec_cmd.EC_CMD_HELLO, param, response) + self.assertEqual(cmd.result, 0, msg="Error sending EC HELLO") + # magic number that the EC answers on HELLO + self.assertEqual(response.out_data, 0xA1B2C3D4, + msg=f"Wrong EC HELLO magic number ({response.out_data})") + def test_cros_ec_hello(self): """ Checks basic comunication with the main Embedded controller. """ - mcu_hello(self, "cros_ec") + self.check_hello("cros_ec") def test_cros_fp_hello(self): """ Checks basic comunication with the fingerprint controller. """ - mcu_hello(self, "cros_fp") + self.check_hello("cros_fp") def test_cros_tp_hello(self): """ Checks basic comunication with the touchpad controller. """ - mcu_hello(self, "cros_tp") + self.check_hello("cros_tp") def test_cros_pd_hello(self): """ Checks basic comunication with the power delivery controller. """ - mcu_hello(self, "cros_pd") + self.check_hello("cros_pd") + + def check_reboot_rw(self, name): + dev = os.path.join("/dev", name) + if not os.path.exists(dev): + self.skipTest(f"MCU {name} not found") + + cmd = send_ec_command(dev, ec_cmd.EC_CMD_REBOOT) + self.assertEqual(cmd.result, 0, msg="Failed to REBOOT") + + param, response = None, ec_response_get_version() + cmd = send_ec_command(dev, ec_cmd.EC_CMD_GET_VERSION, param, response) + self.assertEqual(cmd.result, 0, msg="Failed to GET_VERSION") + self.assertEqual(response.current_image, EC_IMAGE_RW, + msg="Current EC image is not RW") def test_cros_fp_reboot(self): """ Test reboot command on Fingerprint MCU. @@ -62,4 +109,4 @@ class TestCrosECMCU(unittest.TestCase): ("platform/chrome: cros_ec: Query EC protocol version if EC transitions between RO/RW). """ - check_mcu_reboot_rw(self, "cros_fp") + self.check_reboot_rw("cros_fp") diff --git a/cros/tests/cros_ec_power.py b/cros/tests/cros_ec_power.py index e72ce90..d0250a2 100644 --- a/cros/tests/cros_ec_power.py +++ b/cros/tests/cros_ec_power.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from cros.helpers.sysfs import * import unittest +from cros.helpers.sysfs import sysfs_check_attributes_exists + class TestCrosECPower(unittest.TestCase): def test_cros_ec_usbpd_charger_abi(self): diff --git a/cros/tests/cros_ec_pwm.py b/cros/tests/cros_ec_pwm.py index c8e6180..90723c7 100644 --- a/cros/tests/cros_ec_pwm.py +++ b/cros/tests/cros_ec_pwm.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from cros.helpers.sysfs import * +import re import unittest import os + class TestCrosECPWM(unittest.TestCase): def test_cros_ec_pwm_backlight(self): """ Check that the backlight is connected to a pwm of the EC and that @@ -13,42 +14,31 @@ class TestCrosECPWM(unittest.TestCase): """ if not os.path.exists("/sys/class/backlight/backlight/max_brightness"): self.skipTest("No backlight pwm found") - is_ec_pwm = False + if not os.path.exists("/sys/kernel/debug/pwm"): self.skipTest("/sys/kernel/debug/pwm not found") - fd = open("/sys/kernel/debug/pwm", "r") - line = fd.readline() - while line and not is_ec_pwm: - if line[0] != " " and ":ec-pwm" in line: - line = fd.readline() - while line: - if line[0] == "\n": - is_ec_pwm = False - break - if "backlight" in line: - is_ec_pwm = True - break - line = fd.readline() - line = fd.readline() - fd.close() - if not is_ec_pwm: + + with open("/sys/kernel/debug/pwm") as fh: + pwm = fh.read() + for s in pwm.split("\n\n"): + if re.match(r".*:ec-pwm.*backlight", s, re.DOTALL): + ec_pwm = s + break + else: self.skipTest("No EC backlight pwm found") - fd = open("/sys/class/backlight/backlight/max_brightness", "r") - brightness = int(int(fd.read()) / 2) - fd.close() - fd = open("/sys/class/backlight/backlight/brightness", "w") - fd.write(str(brightness)) - fd.close() - fd = open("/sys/kernel/debug/pwm", "r") - line = fd.readline() - while line: - if "backlight" in line: - start = line.find("duty") + 6 - self.assertNotEqual(start, 5, msg=f"error reading back PWM info: {line}") - end = start + line[start:].find(" ") - self.assertNotEqual(start, end, msg=f"error reading back PWM info: {line}") - duty = int(line[start:end]) - self.assertNotEqual(duty, 0, msg=f"error reading back PWM info: {line}") + + with open("/sys/class/backlight/backlight/max_brightness") as fh: + brightness = int(int(fh.read()) / 2) + with open("/sys/class/backlight/backlight/brightness", "w") as fh: + fh.write(str(brightness)) + for s in ec_pwm.split("\n"): + if "backlight" not in s: + continue + + m = re.search(r"duty: (\d+)", s) + if m: + duty = int(m.group(1)) + self.assertNotEqual(duty, 0, msg="duty should not be 0") break - line = fd.readline() - fd.close() + else: + self.fail("Failed to parse duty") diff --git a/cros/tests/cros_ec_rtc.py b/cros/tests/cros_ec_rtc.py index 471a04c..75cae50 100755..100644 --- a/cros/tests/cros_ec_rtc.py +++ b/cros/tests/cros_ec_rtc.py @@ -1,37 +1,39 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from cros.helpers.mcu import * -from cros.helpers.sysfs import * -import unittest +import glob import os +import unittest + +from cros.helpers.ec_cmd import EC_FEATURE_RTC +from cros.helpers.ec_cmd import is_feature_supported + class TestCrosECRTC(unittest.TestCase): def test_cros_ec_rtc_abi(self): """ Check the cros RTC ABI. """ if not is_feature_supported(EC_FEATURE_RTC): self.skipTest("EC_FEATURE_RTC not supported, skipping") + + files = [ + "date", + "hctosys", + "max_user_freq", + "since_epoch", + "time", + "wakealarm", + ] + match = 0 - try: - basepath = "/sys/class/rtc" - for devname in os.listdir(basepath): - dev_basepath = os.path.join(basepath, devname) - fd = open(os.path.join(dev_basepath, "name"), "r") - devtype = fd.read() - fd.close() - if devtype.startswith("cros-ec-rtc"): - files = [ - "date", - "hctosys", - "max_user_freq", - "since_epoch", - "time", - "wakealarm", - ] - match += 1 - for filename in files: - p = os.path.join(dev_basepath, filename) - self.assertTrue(os.path.exists(p), msg=f"{p} not found") - except IOError as e: - self.skipTest(f"{e}") - self.assertNotEqual(match, 0, msg="No RTC device found") + for dev in glob.glob("/sys/class/rtc/*"): + with open(os.path.join(dev, "name")) as fh: + devtype = fh.read() + if not devtype.startswith("cros-ec-rtc"): + continue + + match += 1 + for filename in files: + p = os.path.join(dev, filename) + self.assertTrue(os.path.exists(p), msg=f"{p} not found") + if match == 0: + self.skipTest("No RTC device found") diff --git a/docs/source/testhelpers.rst b/docs/source/testhelpers.rst index 380b1bd..2db0605 100644 --- a/docs/source/testhelpers.rst +++ b/docs/source/testhelpers.rst @@ -8,10 +8,10 @@ kernel .. automodule:: cros.helpers.kernel :members: -mcu +ec_cmd === -.. automodule:: cros.helpers.mcu +.. automodule:: cros.helpers.ec_cmd :members: sysfs @@ -3,7 +3,7 @@ import setuptools -with open("README.md", "r") as fh: +with open("README.md") as fh: long_description = fh.read() setuptools.setup( |