diff options
Diffstat (limited to 'mpm/python/usrp_mpm/sys_utils')
-rw-r--r-- | mpm/python/usrp_mpm/sys_utils/CMakeLists.txt | 1 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/sys_utils/ectool.py | 45 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/sys_utils/gpio.py | 10 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/sys_utils/sysfs_gpio.py | 31 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/sys_utils/uio.py | 6 |
5 files changed, 81 insertions, 12 deletions
diff --git a/mpm/python/usrp_mpm/sys_utils/CMakeLists.txt b/mpm/python/usrp_mpm/sys_utils/CMakeLists.txt index 71a06faf8..f3f3f40d4 100644 --- a/mpm/python/usrp_mpm/sys_utils/CMakeLists.txt +++ b/mpm/python/usrp_mpm/sys_utils/CMakeLists.txt @@ -15,6 +15,7 @@ set(USRP_MPM_SYSUTILS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/udev.py ${CMAKE_CURRENT_SOURCE_DIR}/uio.py ${CMAKE_CURRENT_SOURCE_DIR}/watchdog.py + ${CMAKE_CURRENT_SOURCE_DIR}/ectool.py ) list(APPEND USRP_MPM_FILES ${USRP_MPM_SYSUTILS_FILES}) set(USRP_MPM_FILES ${USRP_MPM_FILES} PARENT_SCOPE) diff --git a/mpm/python/usrp_mpm/sys_utils/ectool.py b/mpm/python/usrp_mpm/sys_utils/ectool.py new file mode 100644 index 000000000..0525d604a --- /dev/null +++ b/mpm/python/usrp_mpm/sys_utils/ectool.py @@ -0,0 +1,45 @@ +# +# Copyright 2020 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +""" +Utilities for interfacing with ectool +""" + +import subprocess + +def run_cmd(cmd): + """Run ectool utility's command named cmd.""" + cmd_str = ' '.join(['ectool', cmd]) + try: + output = subprocess.check_output( + cmd_str, + stderr=subprocess.STDOUT, + shell=True, + ) + except subprocess.CalledProcessError as ex: + raise RuntimeError("Failed to execute {} ectool command".format(cmd)) + return output.decode("utf-8") + +def get_num_fans(): + """ Run ectool utility's command pwmgetnumfans to get number of fans.""" + output = run_cmd('pwmgetnumfans') + num_fans = [int(s) for s in output.split() if s.isdigit()][0] + return num_fans + +def get_fan_rpm(): + """Run ectool utility's command pwmgetfanrpm to get fan rpm.""" + num_fans = get_num_fans() + if num_fans == 0: + raise RuntimeError("Number of fans is zero.") + output = run_cmd('pwmgetfanrpm') + fan_rpm_info = [int(s) for s in output.split() if s.isdigit()] + if len(fan_rpm_info) == 2 * num_fans: + return { + "fan{}".format(fan) : fan_rpm_info[fan * 2 + 1] + for fan in range (0, num_fans) + } + else: + raise RuntimeError("Error getting fan rpm using ectool, at least one fan" \ + " may be stalled. Command output: {}".format(output)) diff --git a/mpm/python/usrp_mpm/sys_utils/gpio.py b/mpm/python/usrp_mpm/sys_utils/gpio.py index b609479f1..e864149f3 100644 --- a/mpm/python/usrp_mpm/sys_utils/gpio.py +++ b/mpm/python/usrp_mpm/sys_utils/gpio.py @@ -30,6 +30,7 @@ class Gpio: INPUT = gpiod.LINE_REQ_DIR_IN OUTPUT = gpiod.LINE_REQ_DIR_OUT + FALLING_EDGE = gpiod.LINE_REQ_EV_FALLING_EDGE def __init__(self, name, direction=INPUT, default_val=None): self._direction = direction @@ -58,3 +59,12 @@ class Gpio: with request_gpio(self._line, self._direction) as gpio: gpio.set_value(int(value)) self._out_value = bool(value) + + def event_wait(self): + """ + Wait for an event to happen on this line + """ + with request_gpio(self._line, self._direction) as gpio: + while True: + if gpio.event_wait(sec=1): + return True diff --git a/mpm/python/usrp_mpm/sys_utils/sysfs_gpio.py b/mpm/python/usrp_mpm/sys_utils/sysfs_gpio.py index b542123bc..056c28fd0 100644 --- a/mpm/python/usrp_mpm/sys_utils/sysfs_gpio.py +++ b/mpm/python/usrp_mpm/sys_utils/sysfs_gpio.py @@ -145,6 +145,7 @@ class SysFSGPIO(object): self._use_mask = use_mask self._ddr = ddr self._init_value = init_value + self._out_value = 0 self.log.trace("Generating SysFSGPIO object for identifiers `{}'..." .format(identifiers)) self._gpio_dev, self._map_info = \ @@ -182,6 +183,8 @@ class SysFSGPIO(object): open(os.path.join(GPIO_SYSFS_BASE_DIR, 'export'), 'w').write('{}'.format(gpio_num)) ddr_str = 'out' if ddr_out else 'in' ddr_str = 'high' if ini_v else ddr_str + if ini_v and ddr_out: + self._out_value |= 1 << gpio_idx self.log.trace("On GPIO path `{}', setting DDR mode to {}.".format(gpio_path, ddr_str)) open(os.path.join(GPIO_SYSFS_BASE_DIR, gpio_path, 'direction'), 'w').write(ddr_str) @@ -196,12 +199,18 @@ class SysFSGPIO(object): value = 1 assert (1<<gpio_idx) & self._use_mask assert (1<<gpio_idx) & self._ddr + assert int(value) in [0, 1] + value = int(value) gpio_num = self._base_gpio + gpio_idx gpio_path = os.path.join(GPIO_SYSFS_BASE_DIR, 'gpio{}'.format(gpio_num)) value_path = os.path.join(gpio_path, GPIO_SYSFS_VALUEFILE) self.log.trace("Writing value `{}' to `{}'...".format(value, value_path)) assert os.path.exists(value_path) open(value_path, 'w').write('{}'.format(value)) + if value: + self._out_value |= 1 << gpio_idx + else: + self._out_value &= ~(1 << gpio_idx) def reset(self, gpio_idx): """ @@ -216,19 +225,23 @@ class SysFSGPIO(object): """ Read back a GPIO at given index. - Note: The GPIO must be in the valid range, and it's DDR value must be - low (for "in"). + Note: The GPIO must be in the valid range. If it's DDR value is + low (for "in") then the register value is read from a local variable. """ assert (1<<gpio_idx) & self._use_mask - assert (1<<gpio_idx) & (~self._ddr) - gpio_num = self._base_gpio + gpio_idx - gpio_path = os.path.join(GPIO_SYSFS_BASE_DIR, 'gpio{}'.format(gpio_num)) - value_path = os.path.join(gpio_path, GPIO_SYSFS_VALUEFILE) - assert os.path.exists(value_path) - read_value = int(open(value_path, 'r').read().strip()) - self.log.trace("Reading value {} from `{}'...".format(read_value, value_path)) + if (1<<gpio_idx) & (~self._ddr): + gpio_num = self._base_gpio + gpio_idx + gpio_path = os.path.join(GPIO_SYSFS_BASE_DIR, 'gpio{}'.format(gpio_num)) + value_path = os.path.join(gpio_path, GPIO_SYSFS_VALUEFILE) + assert os.path.exists(value_path) + read_value = int(open(value_path, 'r').read().strip()) + self.log.trace("Reading value {} from `{}'...".format(read_value, value_path)) + else: + read_value = 1 if self._out_value & (1 << gpio_idx) else 0 + self.log.trace("Reading value {} from local var".format(read_value)) return read_value + class GPIOBank: """ Usability / convenience wrapper for GPIO banks accessed by SysFSGPIO diff --git a/mpm/python/usrp_mpm/sys_utils/uio.py b/mpm/python/usrp_mpm/sys_utils/uio.py index 84e4b2b64..f660c39b3 100644 --- a/mpm/python/usrp_mpm/sys_utils/uio.py +++ b/mpm/python/usrp_mpm/sys_utils/uio.py @@ -144,15 +144,15 @@ class UIO(object): else: self.log.trace("Using UIO device by label `{0}'".format(label)) self._path, map_info = find_uio_device(label, self.log) + if self._path is None or map_info is None: + self.log.error("Could not find a UIO device for label {0}".format(label)) + raise RuntimeError("Could not find a UIO device for label {0}".format(label)) # TODO If we ever support multiple maps, check if this is correct... offset = offset or map_info['offset'] assert offset == 0 # ...and then remove this line length = length or map_info['size'] self.log.trace("UIO device is being opened read-{0}.".format( "only" if read_only else "write")) - if self._path is None: - self.log.error("Could not find a UIO device for label {0}".format(label)) - raise RuntimeError("Could not find a UIO device for label {0}".format(label)) self._read_only = read_only # Our UIO objects are managed in C++ land, which gives us more granular control over # opening and closing |