aboutsummaryrefslogtreecommitdiffstats
path: root/mpm
diff options
context:
space:
mode:
authorSugandha Gupta <sugandha.gupta@ettus.com>2018-06-26 15:38:02 -0700
committerBrent Stapleton <bstapleton@g.hmc.edu>2018-07-18 15:37:27 -0700
commit1e4649ce296e1af376e1864576ab207b1b30fc41 (patch)
tree9cf648316ad2707fd7fb50a4b9739adcd4b83003 /mpm
parent7d28d9140e2c57db36b37d60d9ce4bff86357bac (diff)
downloaduhd-1e4649ce296e1af376e1864576ab207b1b30fc41.tar.gz
uhd-1e4649ce296e1af376e1864576ab207b1b30fc41.tar.bz2
uhd-1e4649ce296e1af376e1864576ab207b1b30fc41.zip
e320: mpm: Add dboard and mboard sensors
Adding the following sensors: - Catalina temperature, RSSI, and LO Lock sensors - GPS lock, time, TPV, and SKY sensors Co-authored-by: Brent Stapleton <brent.stapleton@ettus.com>
Diffstat (limited to 'mpm')
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/neon.py70
-rw-r--r--mpm/python/usrp_mpm/periph_manager/e320.py77
-rw-r--r--mpm/python/usrp_mpm/periph_manager/e320_periphs.py31
3 files changed, 148 insertions, 30 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/neon.py b/mpm/python/usrp_mpm/dboard_manager/neon.py
index e3797c7d3..5ab014330 100644
--- a/mpm/python/usrp_mpm/dboard_manager/neon.py
+++ b/mpm/python/usrp_mpm/dboard_manager/neon.py
@@ -17,6 +17,7 @@ from usrp_mpm.dboard_manager import DboardManagerBase
from usrp_mpm.mpmlog import get_logger
from usrp_mpm.sys_utils.udev import get_eeprom_paths
from usrp_mpm.sys_utils.uio import UIO
+from usrp_mpm.periph_manager.e320_periphs import MboardRegsControl
###############################################################################
@@ -34,6 +35,8 @@ class Neon(DboardManagerBase):
pids = [0xe320]
rx_sensor_callback_map = {
'ad9361_temperature': 'get_catalina_temp_sensor',
+ 'rssi' : 'get_rssi_sensor',
+ 'lo_lock' : 'get_lo_lock_sensor',
}
tx_sensor_callback_map = {
'ad9361_temperature': 'get_catalina_temp_sensor',
@@ -258,24 +261,65 @@ class Neon(DboardManagerBase):
##########################################################################
# Sensors
##########################################################################
- # TODO add sensors
def get_ad9361_lo_lock(self, which):
"""
Return LO lock status (Boolean!) of AD9361. 'which' must be
either 'tx' or 'rx'
"""
- # return self.catalina.
+ self.mboard_regs_label = "mboard-regs"
+ self.mboard_regs_control = MboardRegsControl(
+ self.mboard_regs_label, self.log)
+ if which == "tx":
+ locked = self. mboard_regs_control.get_ad9361_tx_lo_lock()
+ elif which == "rx":
+ locked = self. mboard_regs_control.get_ad9361_rx_lo_lock()
+ else:
+ locked = False
+ return locked
- # uhd::sensor_value_t e300_impl::_get_fe_pll_lock(const bool is_tx)
- # {
- # const uint32_t st =
- # _global_regs->peek32(global_regs::RB32_CORE_PLL);
- # const bool locked = is_tx ? ((st & 0x1) > 0) : ((st & 0x2) > 0);
- # return sensor_value_t("LO", locked, "locked", "unlocked");
- # }
- #return self.mykonos.get_lo_locked(which.upper())
- #FIXME: Implement on RevB
- time.sleep(5)
- return True
+ def get_lo_lock_sensor(self, which):
+ """
+ Get sensor dict with LO lock status
+ """
+ self.log.trace("Reading LO Lock.")
+ lo_locked = self.get_ad9361_lo_lock(which)
+ return {
+ 'name': 'ad9361_lock',
+ 'type': 'BOOLEAN',
+ 'unit': 'locked' if lo_locked else 'unlocked',
+ 'value': str(lo_locked).lower(),
+ }
+ def get_catalina_temp_sensor(self, _):
+ """
+ Get temperature sensor reading of Catalina.
+ """
+ # Note: the unused argument is channel
+ self.log.trace("Reading Catalina temperature.")
+ return {
+ 'name': 'ad9361_temperature',
+ 'type': 'REALNUM',
+ 'unit': 'C',
+ 'value': str(self.catalina.get_temperature())
+ }
+
+ def get_rssi_val(self, which):
+ """
+ Return the current RSSI of `which` chain in Catalina
+ """
+ return self.catalina.get_rssi(which)
+
+ def get_rssi_sensor(self, which=None):
+ """
+ Return a sensor dictionary containing the current RSSI of `which` chain in Catalina
+ """
+ if which is None:
+ # Default to RX1 chain
+ which = "RX1"
+ return {
+ 'name': 'rssi',
+ 'type': 'REALNUM',
+ 'unit': 'dB',
+ 'value': str(self.get_rssi_val(which)),
+ }
diff --git a/mpm/python/usrp_mpm/periph_manager/e320.py b/mpm/python/usrp_mpm/periph_manager/e320.py
index ac50909ff..848b320b0 100644
--- a/mpm/python/usrp_mpm/periph_manager/e320.py
+++ b/mpm/python/usrp_mpm/periph_manager/e320.py
@@ -10,15 +10,18 @@ E320 implementation module
from __future__ import print_function
import bisect
import copy
+import re
import threading
from six import iteritems, itervalues
from usrp_mpm.components import ZynqComponents
from usrp_mpm.dboard_manager import Neon
+from usrp_mpm.gpsd_iface import GPSDIfaceExtension
from usrp_mpm.mpmtypes import SID
from usrp_mpm.mpmutils import assert_compat_number, str2bool
from usrp_mpm.periph_manager import PeriphManagerBase
from usrp_mpm.rpc_server import no_rpc
from usrp_mpm.sys_utils import dtoverlay
+from usrp_mpm.sys_utils.sysfs_thermal import read_thermal_sensor_value
from usrp_mpm.sys_utils.udev import get_spidev_nodes
from usrp_mpm.xports import XportMgrUDP, XportMgrLiberio
from usrp_mpm.periph_manager.e320_periphs import MboardRegsControl
@@ -77,7 +80,9 @@ class e320(ZynqComponents, PeriphManagerBase):
}
mboard_max_rev = 2 # RevB
mboard_sensor_callback_map = {
- # FIXME add sensors
+ 'gps_locked': 'get_gps_lock_sensor',
+ 'temp': 'get_temp_sensor',
+ 'fan': 'get_fan_sensor',
}
max_num_dboards = 1
crossbar_base_port = 2 # It's 2 because 0,1 are SFP,DMA
@@ -129,6 +134,7 @@ class e320(ZynqComponents, PeriphManagerBase):
self._clock_source = None
self._time_source = None
self._available_endpoints = list(range(256))
+ self._gpsd = None
self.dboard = self.dboards[E320_DBOARD_SLOT_IDX]
try:
self._init_peripherals(args)
@@ -264,6 +270,8 @@ class e320(ZynqComponents, PeriphManagerBase):
)
# Init clocking
self._init_ref_clock_and_time(args)
+ # Init GPSd iface and GPS sensors
+ self._init_gps_sensors()
# Init CHDR transports
self._xport_mgrs = {
'udp': E320XportMgrUDP(self.log.getChild('UDP')),
@@ -280,6 +288,22 @@ class e320(ZynqComponents, PeriphManagerBase):
# Init complete.
self.log.debug("mboard info: {}".format(self.mboard_info))
+ def _init_gps_sensors(self):
+ "Init and register the GPSd Iface and related sensor functions"
+ self.log.trace("Initializing GPSd interface")
+ self._gpsd = GPSDIfaceExtension()
+ new_methods = self._gpsd.extend(self)
+ for method_name in new_methods:
+ try:
+ # Extract the sensor name from the getter
+ sensor_name = re.search(r"get_.*_sensor", method_name).string
+ # Register it with the MB sensor framework
+ self.mboard_sensor_callback_map[sensor_name] = method_name
+ self.log.trace("Adding %s sensor function", sensor_name)
+ except AttributeError:
+ # re.search will return None is if can't find the sensor name
+ self.log.warning("Error while registering sensor function: %s", method_name)
+
###########################################################################
# Session init and deinit
###########################################################################
@@ -571,27 +595,46 @@ class e320(ZynqComponents, PeriphManagerBase):
"""
Get temperature sensor reading of the E320.
"""
- # TODO: This is Catalina's temperature. Do we want to return a different temp?
- return self.catalina.get_temperature()
+ self.log.trace("Reading FPGA temperature.")
+ return_val = '-1'
+ try:
+ raw_val = read_thermal_sensor_value('fpga-thermal-zone', 'temp')
+ return_val = str(raw_val / 1000)
+ except ValueError:
+ self.log.warning("Error when converting temperature value")
+ except KeyError:
+ self.log.warning("Can't read temp on fpga-thermal-zone")
+ return {
+ 'name': 'temperature',
+ 'type': 'REALNUM',
+ 'unit': 'C',
+ 'value': return_val
+ }
def get_gps_lock_sensor(self):
"""
Get lock status of GPS as a sensor dict
"""
- self.log.trace("Reading status GPS lock pin from port expander")
- raise NotImplementedError("GPS lock not implemented")
- # FIXME put it in a register
- # TODO: implement get_gps_lock, splits up functionality
- #gps_locked = bool(self._gpios.get("GPS-LOCKOK"))
- #return {
- # 'name': 'gps_lock',
- # 'type': 'BOOLEAN',
- # 'unit': 'locked' if gps_locked else 'unlocked',
- # 'value': str(gps_locked).lower(),
- #}
-
- # TODO: Add other GPS sensors (time, TPV, SKY, etc.)
- # TODO: Add all physical sensors we can
+ gps_locked = self.mboard_regs_control.get_gps_locked_val()
+ return {
+ 'name': 'gps_lock',
+ 'type': 'BOOLEAN',
+ 'unit': 'locked' if gps_locked else 'unlocked',
+ 'value': str(gps_locked).lower(),
+ }
+
+ def get_fan_sensor(self):
+ """
+ Return a sensor dictionary containing the RPM of the fan
+ """
+ raise NotImplementedError("Fan sensor not implemented")
+ # TODO implement
+ # return {
+ # 'name': 'rssi',
+ # 'type': 'REALNUM',
+ # 'unit': 'rpm',
+ # 'value': XX,
+ # }
###########################################################################
# EEPROMs
diff --git a/mpm/python/usrp_mpm/periph_manager/e320_periphs.py b/mpm/python/usrp_mpm/periph_manager/e320_periphs.py
index d98c5a0e5..ee092e248 100644
--- a/mpm/python/usrp_mpm/periph_manager/e320_periphs.py
+++ b/mpm/python/usrp_mpm/periph_manager/e320_periphs.py
@@ -94,6 +94,10 @@ class MboardRegsControl(object):
MB_DBOARD_CTRL_MIMO = 0
MB_DBOARD_CTRL_TX_CHAN_SEL = 1
+ # Bitfield locations for the MB_DBOARD_STATUS register.
+ MB_DBOARD_STATUS_RX_LOCK = 6
+ MB_DBOARD_STATUS_TX_LOCK = 7
+
def __init__(self, label, log):
self.log = log
self.regs = UIO(
@@ -381,3 +385,30 @@ class MboardRegsControl(object):
self.log.trace("Writing MB_DBOARD_CTRL to 0x{:08X}".format(reg_val))
self.poke32(self.MB_DBOARD_CTRL, reg_val)
+ def get_ad9361_tx_lo_lock(self):
+ """
+ Check the status of TX LO lock from CTRL_OUT pins from Catalina
+ """
+ mask = 0b1 << self.MB_DBOARD_STATUS_TX_LOCK
+ with self.regs.open():
+ reg_val = self.peek32(self.MB_DBOARD_STATUS)
+ locked = (reg_val & mask) > 0
+ if not locked:
+ self.log.warning("TX RF PLL reporting unlocked. ")
+ else:
+ self.log.trace("TX RF PLL locked")
+ return locked
+
+ def get_ad9361_rx_lo_lock(self):
+ """
+ Check the status of RX LO lock from CTRL_OUT pins from Catalina
+ """
+ mask = 0b1 << self.MB_DBOARD_STATUS_RX_LOCK
+ with self.regs.open():
+ reg_val = self.peek32(self.MB_DBOARD_STATUS)
+ locked = (reg_val & mask) > 0
+ if not locked:
+ self.log.warning("RX RF PLL reporting unlocked. ")
+ else:
+ self.log.trace("RX RF PLL locked")
+ return locked