aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python/usrp_mpm/sys_utils
diff options
context:
space:
mode:
Diffstat (limited to 'mpm/python/usrp_mpm/sys_utils')
-rw-r--r--mpm/python/usrp_mpm/sys_utils/CMakeLists.txt1
-rw-r--r--mpm/python/usrp_mpm/sys_utils/ectool.py45
-rw-r--r--mpm/python/usrp_mpm/sys_utils/gpio.py10
-rw-r--r--mpm/python/usrp_mpm/sys_utils/sysfs_gpio.py31
-rw-r--r--mpm/python/usrp_mpm/sys_utils/uio.py6
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