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 | 
