diff options
author | Sugandha Gupta <sugandha.gupta@ettus.com> | 2018-06-26 15:38:02 -0700 |
---|---|---|
committer | Brent Stapleton <bstapleton@g.hmc.edu> | 2018-07-18 15:37:27 -0700 |
commit | 1e4649ce296e1af376e1864576ab207b1b30fc41 (patch) | |
tree | 9cf648316ad2707fd7fb50a4b9739adcd4b83003 /mpm | |
parent | 7d28d9140e2c57db36b37d60d9ce4bff86357bac (diff) | |
download | uhd-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.py | 70 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e320.py | 77 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e320_periphs.py | 31 |
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 |