aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python/usrp_mpm/periph_manager/e31x.py
diff options
context:
space:
mode:
Diffstat (limited to 'mpm/python/usrp_mpm/periph_manager/e31x.py')
-rw-r--r--mpm/python/usrp_mpm/periph_manager/e31x.py744
1 files changed, 744 insertions, 0 deletions
diff --git a/mpm/python/usrp_mpm/periph_manager/e31x.py b/mpm/python/usrp_mpm/periph_manager/e31x.py
new file mode 100644
index 000000000..722f8d7a9
--- /dev/null
+++ b/mpm/python/usrp_mpm/periph_manager/e31x.py
@@ -0,0 +1,744 @@
+#
+# Copyright 2018-2019 Ettus Research, a National Instruments Company
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+"""
+E310 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 E31x_db
+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_sysfs_sensors_value
+from usrp_mpm.sys_utils.udev import get_spidev_nodes
+from usrp_mpm.xports import XportMgrLiberio
+from usrp_mpm.periph_manager.e31x_periphs import MboardRegsControl
+from usrp_mpm.sys_utils.udev import get_eeprom_paths
+from usrp_mpm import e31x_legacy_eeprom
+
+E310_DEFAULT_CLOCK_SOURCE = 'internal'
+E310_DEFAULT_TIME_SOURCE = 'internal'
+E310_DEFAULT_ENABLE_FPGPIO = True
+E310_FPGA_COMPAT = (1,0)
+E310_DBOARD_SLOT_IDX = 0
+
+###############################################################################
+# Transport managers
+###############################################################################
+
+class E310XportMgrLiberio(XportMgrLiberio):
+ " E310-specific Liberio configuration "
+ max_chan = 4
+ xbar_dev = "/dev/crossbar0"
+ xbar_port = 0
+
+###############################################################################
+# Main Class
+###############################################################################
+class e31x(ZynqComponents, PeriphManagerBase):
+ """
+ Holds E310 specific attributes and methods
+ """
+ #########################################################################
+ # Overridables
+ #
+ # See PeriphManagerBase for documentation on these fields
+ #########################################################################
+ description = "E300-Series Device"
+ # 0x77d2 and 0x77d3
+ pids = {0x77D2: 'e310_sg1', #sg1
+ 0x77D3: 'e310_sg3'} #sg3
+ mboard_eeprom_addr = "e0004000.i2c"
+ mboard_eeprom_offset = 0
+ mboard_eeprom_max_len = 64
+ # We have two nvem paths on the E310.
+ # This one ensures that we get the right path for the MB.
+ mboard_eeprom_path_index = 1
+ mboard_info = {"type": "e3xx"}
+ mboard_sensor_callback_map = {
+ 'ref_locked': 'get_ref_lock_sensor',
+ 'temp_fpga' : 'get_fpga_temp_sensor',
+ 'temp_mb' : 'get_mb_temp_sensor',
+ }
+ dboard_eeprom_addr = "e0004000.i2c"
+
+ # Actual DB EEPROM bytes are just 28. Reading just a couple more.
+ # Refer e300_eeprom_manager.hpp
+ dboard_eeprom_max_len = 32
+
+ max_num_dboards = 1
+
+ # We're on a Zynq target, so the following two come from the Zynq standard
+ # device tree overlay (tree/arch/arm/boot/dts/zynq-7000.dtsi)
+ dboard_spimaster_addrs = ["e0006000.spi"]
+ # E310-specific settings
+ # Label for the mboard UIO
+ mboard_regs_label = "mboard-regs"
+ # Override the list of updateable components
+ updateable_components = {
+ 'fpga': {
+ 'callback': "update_fpga",
+ 'path': '/lib/firmware/{}.bin',
+ 'reset': True,
+ },
+ 'dts': {
+ 'callback': "update_dts",
+ 'path': '/lib/firmware/{}.dts',
+ 'output': '/lib/firmware/{}.dtbo',
+ 'reset': False,
+ },
+ }
+ # This class removes the overlay in tear_down() resulting
+ # in stale references to methods in the RPC server. Setting
+ # this to True ensures that the RPC server clears all registered
+ # methods on unclaim() and registers them on the following claim().
+ clear_rpc_method_registry_on_unclaim = True
+
+ @classmethod
+ def generate_device_info(cls, eeprom_md, mboard_info, dboard_infos):
+ """
+ Generate dictionary describing the device.
+ """
+ # Add the default PeriphManagerBase information first
+ device_info = super().generate_device_info(
+ eeprom_md, mboard_info, dboard_infos)
+ # Then add E31x-specific information
+ mb_pid = eeprom_md.get('pid')
+ device_info['product'] = cls.pids.get(mb_pid, 'unknown')
+ return device_info
+
+ @staticmethod
+ def list_required_dt_overlays(device_info):
+ """
+ Lists device tree overlays that need to be applied before this class can
+ be used. List of strings.
+ Are applied in order.
+
+ eeprom_md -- Dictionary of info read out from the mboard EEPROM
+ device_args -- Arbitrary dictionary of info, typically user-defined
+ """
+ return [device_info['product']]
+
+
+ @staticmethod
+ def get_idle_dt_overlay(device_info):
+ """
+ Overlay to be applied to enter low power idle state.
+ """
+ # e.g. e310_sg3_idle
+ idle_overlay = device_info['product'] + '_idle'
+ return idle_overlay
+
+ ###########################################################################
+ # Ctor and device initialization tasks
+ ###########################################################################
+ def __init__(self, args):
+ """
+ Does partial initialization which loads low power idle image
+ """
+ super(e31x, self).__init__()
+ # Start clean by removing MPM-owned overlays.
+ active_overlays = self.list_active_overlays()
+ mpm_overlays = self.list_owned_overlays()
+ for overlay in active_overlays:
+ if overlay in mpm_overlays:
+ dtoverlay.rm_overlay(overlay)
+ # Apply idle overlay on boot to save power until
+ # an application tries to use the device.
+ self.args_cached = args
+ self.apply_idle_overlay()
+ self._device_initialized = False
+
+ def _init_normal(self):
+ """
+ Does full initialization
+ """
+ if self._device_initialized:
+ return
+ if self.is_idle():
+ self.remove_idle_overlay()
+ self.overlay_apply()
+ self.init_dboards(self.args_cached)
+ if not self._device_initialized:
+ # Don't try and figure out what's going on. Just give up.
+ return
+ # Initialize _do_not_reload with value from _default_args (mpm.conf)
+ self._do_not_reload = str2bool(self._default_args.get("no_reload_fpga", "False"))
+ self._tear_down = False
+ self._clock_source = None
+ self._time_source = None
+ self._available_endpoints = list(range(256))
+ self.dboard = self.dboards[E310_DBOARD_SLOT_IDX]
+ try:
+ self._init_peripherals(self.args_cached)
+ except Exception as ex:
+ self.log.error("Failed to initialize motherboard: %s", str(ex))
+ self._initialization_status = str(ex)
+ self._device_initialized = False
+
+ def _init_dboards(self, dboard_infos, override_dboard_pids, default_args):
+ """
+ Initialize all the daughterboards
+
+ dboard_infos -- List of dictionaries as returned from
+ PeriphManagerBase._get_dboard_eeprom_info()
+ override_dboard_pids -- List of dboard PIDs to force
+ default_args -- Default args
+ """
+ # Override the base class's implementation in order to avoid initializing our one "dboard"
+ # in the same way that, for example, N310's dboards are initialized. Specifically,
+ # - skip dboard EEPROM setup (we don't have one)
+ # - change the way we handle SPI devices
+ if override_dboard_pids:
+ self.log.warning("Overriding daughterboard PIDs with: {}"
+ .format(override_dboard_pids))
+ raise NotImplementedError("Can't override dboard pids")
+ # We have only one dboard
+ dboard_info = dboard_infos[0]
+ # Set up the SPI nodes
+ spi_nodes = []
+ for spi_addr in self.dboard_spimaster_addrs:
+ for spi_node in get_spidev_nodes(spi_addr):
+ bisect.insort(spi_nodes, spi_node)
+
+ self.log.trace("Found spidev nodes: {0}".format(spi_nodes))
+
+ if not spi_nodes:
+ self.log.warning("No SPI nodes for dboard %d.", E310_DBOARD_SLOT_IDX)
+ else:
+ dboard_info.update({
+ 'spi_nodes': spi_nodes,
+ 'default_args': default_args,
+ })
+
+ self.dboards.append(E31x_db(E310_DBOARD_SLOT_IDX, **dboard_info))
+ self.log.info("Found %d daughterboard(s).", len(self.dboards))
+
+ def _check_fpga_compat(self):
+ " Throw an exception if the compat numbers don't match up "
+ actual_compat = self.mboard_regs_control.get_compat_number()
+ self.log.debug("Actual FPGA compat number: {:d}.{:d}".format(
+ actual_compat[0], actual_compat[1]
+ ))
+ assert_compat_number(
+ E310_FPGA_COMPAT,
+ self.mboard_regs_control.get_compat_number(),
+ component="FPGA",
+ fail_on_old_minor=True,
+ log=self.log
+ )
+
+ def _init_ref_clock_and_time(self, default_args):
+ """
+ Initialize clock and time sources. After this function returns, the
+ reference signals going to the FPGA are valid.
+ """
+ if not self.dboards:
+ self.log.warning(
+ "No dboards found, skipping setting clock and time source "
+ "configuration."
+ )
+ self._clock_source = E310_DEFAULT_CLOCK_SOURCE
+ self._time_source = E310_DEFAULT_TIME_SOURCE
+ else:
+ self.set_clock_source(
+ default_args.get('clock_source', E310_DEFAULT_CLOCK_SOURCE)
+ )
+ self.set_time_source(
+ default_args.get('time_source', E310_DEFAULT_TIME_SOURCE)
+ )
+
+ def _init_peripherals(self, args):
+ """
+ Turn on all peripherals. This may throw an error on failure, so make
+ sure to catch it.
+
+ Peripherals are initialized in the order of least likely to fail, to most
+ likely.
+ """
+ # Sanity checks
+ assert self.mboard_info.get('product') in self.pids.values(), \
+ "Device product could not be determined!"
+ # Init Mboard Regs
+ self.mboard_regs_control = MboardRegsControl(
+ self.mboard_regs_label, self.log)
+ self.mboard_regs_control.get_git_hash()
+ self.mboard_regs_control.get_build_timestamp()
+ self._check_fpga_compat()
+ self._update_fpga_type()
+ self.crossbar_base_port = self.mboard_regs_control.get_xbar_baseport()
+ self.log.debug("crossbar base port: {}".format(self.crossbar_base_port))
+
+ # Init clocking
+ self._init_ref_clock_and_time(args)
+ # Init CHDR transports
+ self._xport_mgrs = {
+ 'liberio': E310XportMgrLiberio(self.log.getChild('liberio')),
+ }
+ # Init complete.
+ self.log.debug("mboard info: {}".format(self.mboard_info))
+
+ def _read_mboard_eeprom(self):
+ """
+ Read out mboard EEPROM.
+ Returns a tuple: (eeprom_dict, eeprom_rawdata), where the the former is
+ a de-serialized dictionary representation of the data, and the latter
+ is a binary string with the raw data.
+
+ If no EEPROM is defined, returns empty values.
+ """
+ if len(self.mboard_eeprom_addr):
+ (eeprom_head, eeprom_rawdata) = e31x_legacy_eeprom.read_eeprom(
+ True, # isMotherboard
+ get_eeprom_paths(self.mboard_eeprom_addr)[self.mboard_eeprom_path_index],
+ self.mboard_eeprom_offset,
+ e31x_legacy_eeprom.MboardEEPROM.eeprom_header_format,
+ e31x_legacy_eeprom.MboardEEPROM.eeprom_header_keys,
+ self.mboard_eeprom_max_len
+ )
+ self.log.trace("Found EEPROM metadata: `{}'"
+ .format(str(eeprom_head)))
+ self.log.trace("Read {} bytes of EEPROM data."
+ .format(len(eeprom_rawdata)))
+ return eeprom_head, eeprom_rawdata
+ # Nothing defined? Return defaults.
+ self.log.trace("No mboard EEPROM path defined. "
+ "Skipping mboard EEPROM readout.")
+ return {}, b''
+
+ def _get_dboard_eeprom_info(self):
+ """
+ Read back EEPROM info from the daughterboards
+ """
+ if self.dboard_eeprom_addr is None:
+ self.log.debug("No dboard EEPROM addresses given.")
+ return []
+ dboard_eeprom_addrs = self.dboard_eeprom_addr \
+ if isinstance(self.dboard_eeprom_addr, list) \
+ else [self.dboard_eeprom_addr]
+ dboard_eeprom_paths = []
+ self.log.trace("Identifying dboard EEPROM paths from addrs `{}'..."
+ .format(",".join(dboard_eeprom_addrs)))
+ for dboard_eeprom_addr in dboard_eeprom_addrs:
+ self.log.trace("Resolving %s...", dboard_eeprom_addr)
+ dboard_eeprom_paths += get_eeprom_paths(dboard_eeprom_addr)
+ self.log.trace("Found dboard EEPROM paths: {}"
+ .format(",".join(dboard_eeprom_paths)))
+ if len(dboard_eeprom_paths) > self.max_num_dboards:
+ self.log.warning("Found more EEPROM paths than daughterboards. "
+ "Ignoring some of them.")
+ dboard_eeprom_paths = dboard_eeprom_paths[:self.max_num_dboards]
+ dboard_info = []
+ for dboard_idx, dboard_eeprom_path in enumerate(dboard_eeprom_paths):
+ self.log.debug("Reading EEPROM info for dboard %d...", dboard_idx)
+ dboard_eeprom_md, dboard_eeprom_rawdata = e31x_legacy_eeprom.read_eeprom(
+ False, # is not motherboard.
+ dboard_eeprom_path,
+ self.dboard_eeprom_offset,
+ e31x_legacy_eeprom.DboardEEPROM.eeprom_header_format,
+ e31x_legacy_eeprom.DboardEEPROM.eeprom_header_keys,
+ self.dboard_eeprom_max_len
+ )
+ self.log.trace("Found dboard EEPROM metadata: `{}'"
+ .format(str(dboard_eeprom_md)))
+ self.log.trace("Read %d bytes of dboard EEPROM data.",
+ len(dboard_eeprom_rawdata))
+ db_pid = dboard_eeprom_md.get('pid')
+ if db_pid is None:
+ self.log.warning("No dboard PID found in dboard EEPROM!")
+ else:
+ self.log.debug("Found dboard PID in EEPROM: 0x{:04X}"
+ .format(db_pid))
+ dboard_info.append({
+ 'eeprom_md': dboard_eeprom_md,
+ 'eeprom_rawdata': dboard_eeprom_rawdata,
+ 'pid': db_pid,
+ })
+ return dboard_info
+
+ ###########################################################################
+ # Session init and deinit
+ ###########################################################################
+ def claim(self):
+ """
+ Fully initializes a device when the rpc_server claim()
+ gets called to revive the device from idle state to be used
+ by an UHD application
+ """
+ super(e31x, self).claim()
+ try:
+ self._init_normal()
+ except Exception as ex:
+ self.log.error("e31x claim() failed: %s", str(ex))
+
+ def init(self, args):
+ """
+ Calls init() on the parent class, and then programs the Ethernet
+ dispatchers accordingly.
+ """
+ if not self._device_initialized:
+ self.log.warning(
+ "Cannot run init(), device was never fully initialized!")
+ return False
+ if args.get("clock_source", "") != "":
+ self.set_clock_source(args.get("clock_source"))
+ if args.get("time_source", "") != "":
+ self.set_time_source(args.get("time_source"))
+ if "no_reload_fpga" in args:
+ self._do_not_reload = str2bool(args.get("no_reload_fpga")) or args.get("no_reload_fpga") == ""
+ result = super(e31x, self).init(args)
+ for xport_mgr in itervalues(self._xport_mgrs):
+ xport_mgr.init(args)
+ return result
+
+
+ def apply_idle_overlay(self):
+ """
+ Load all overlays required to go into idle power savings mode.
+ """
+ idle_overlay = self.get_idle_dt_overlay(self.device_info)
+ self.log.debug("Motherboard requests device tree overlay for Idle power savings mode: {}".format(
+ idle_overlay
+ ))
+ dtoverlay.apply_overlay_safe(idle_overlay)
+
+ def remove_idle_overlay(self):
+ """
+ Remove idle mode overlay.
+ """
+ idle_overlay = self.get_idle_dt_overlay(self.device_info)
+ self.log.trace("Removing Idle overlay: {}".format(
+ idle_overlay
+ ))
+ dtoverlay.rm_overlay(idle_overlay)
+
+ def list_owned_overlays(self):
+ """
+ Lists all overlays that can be possibly applied by MPM.
+ """
+ all_overlays = self.list_required_dt_overlays(self.device_info)
+ all_overlays.append(self.get_idle_dt_overlay(self.device_info))
+ return all_overlays
+
+ def deinit(self):
+ """
+ Clean up after a UHD session terminates.
+ """
+ if not self._device_initialized:
+ self.log.warning(
+ "Cannot run deinit(), device was never fully initialized!")
+ return
+ super(e31x, self).deinit()
+ for xport_mgr in itervalues(self._xport_mgrs):
+ xport_mgr.deinit()
+ self.log.trace("Resetting SID pool...")
+ self._available_endpoints = list(range(256))
+ if not self._do_not_reload:
+ self.tear_down()
+ # Reset back to value from _default_args (mpm.conf)
+ self._do_not_reload = str2bool(self._default_args.get("no_reload_fpga", "False"))
+
+ def tear_down(self):
+ """
+ Tear down all members that need to be specially handled before
+ deconstruction.
+ For E310, this means the overlay.
+ """
+ self.log.trace("Tearing down E310 device...")
+ self._tear_down = True
+ self.dboards = []
+ self.dboard = None
+ self.mboard_regs_control = None
+ self._device_initialized = False
+ active_overlays = self.list_active_overlays()
+ self.log.trace("E310 has active device tree overlays: {}".format(
+ active_overlays
+ ))
+ for overlay in active_overlays:
+ dtoverlay.rm_overlay(overlay)
+ self.apply_idle_overlay()
+
+ def is_idle(self):
+ """
+ Determine if the device is in the idle state.
+ """
+ active_overlays = self.list_active_overlays()
+ idle_overlay = self.get_idle_dt_overlay(self.device_info)
+ is_idle = idle_overlay in active_overlays
+ if is_idle:
+ self.log.trace("Found idle overlay: %s", idle_overlay)
+ return is_idle
+
+ ###########################################################################
+ # Transport API
+ ###########################################################################
+ def request_xport(
+ self,
+ dst_address,
+ suggested_src_address,
+ xport_type
+ ):
+ """
+ See PeriphManagerBase.request_xport() for docs.
+ """
+ # Try suggested address first, then just pick the first available one:
+ src_address = suggested_src_address
+ if src_address not in self._available_endpoints:
+ if not self._available_endpoints:
+ raise RuntimeError(
+ "Depleted pool of SID endpoints for this device!")
+ else:
+ src_address = self._available_endpoints[0]
+ sid = SID(src_address << 16 | dst_address)
+ # Note: This SID may change its source address!
+ self.log.trace(
+ "request_xport(dst=0x%04X, suggested_src_address=0x%04X, xport_type=%s): " \
+ "operating on temporary SID: %s",
+ dst_address, suggested_src_address, str(xport_type), str(sid))
+ assert self.mboard_info['rpc_connection'] in ('local')
+ if self.mboard_info['rpc_connection'] == 'local':
+ return self._xport_mgrs['liberio'].request_xport(
+ sid,
+ xport_type,
+ )
+
+ def commit_xport(self, xport_info):
+ """
+ See PeriphManagerBase.commit_xport() for docs.
+
+ Reminder: All connections are incoming, i.e. "send" or "TX" means
+ remote device to local device, and "receive" or "RX" means this local
+ device to remote device. "Remote device" can be, for example, a UHD
+ session.
+ """
+ ## Go, go, go
+ assert self.mboard_info['rpc_connection'] in ('local')
+ sid = SID(xport_info['send_sid'])
+ self._available_endpoints.remove(sid.src_ep)
+ self.log.debug("Committing transport for SID %s, xport info: %s",
+ str(sid), str(xport_info))
+ if self.mboard_info['rpc_connection'] == 'local':
+ return self._xport_mgrs['liberio'].commit_xport(sid, xport_info)
+
+ ###########################################################################
+ # Device info
+ ###########################################################################
+ def get_device_info_dyn(self):
+ """
+ Append the device info with current IP addresses.
+ """
+ if not self._device_initialized:
+ return {}
+ device_info = {}
+ device_info.update({
+ 'fpga_version': "{}.{}".format(
+ *self.mboard_regs_control.get_compat_number()),
+ 'fpga_version_hash': "{:x}.{}".format(
+ *self.mboard_regs_control.get_git_hash()),
+ 'fpga': self.updateable_components.get('fpga', {}).get('type', ""),
+ })
+ return device_info
+
+ ###########################################################################
+ # Clock/Time API
+ ###########################################################################
+ def get_clock_sources(self):
+ " Lists all available clock sources. "
+ self.log.trace("Listing available clock sources...")
+ return ('internal',)
+
+ def get_clock_source(self):
+ " Returns the currently selected clock source "
+ return self._clock_source
+
+ def set_clock_source(self, *args):
+ """
+ Switch reference clock.
+
+ Throws if clock_source is not a valid value.
+ """
+ clock_source = args[0]
+ assert clock_source in self.get_clock_sources()
+ self.log.debug("Setting clock source to `{}'".format(clock_source))
+ if clock_source == self.get_clock_source():
+ self.log.trace("Nothing to do -- clock source already set.")
+ return
+ self._clock_source = clock_source
+ self.mboard_regs_control.set_clock_source(clock_source)
+
+ def get_time_sources(self):
+ " Returns list of valid time sources "
+ return ['internal', 'external', 'gpsdo']
+
+ def get_time_source(self):
+ " Return the currently selected time source "
+ return self._time_source
+
+ def set_time_source(self, time_source):
+ " Set a time source "
+ assert time_source in self.get_time_sources()
+ if time_source == self.get_time_source():
+ self.log.trace("Nothing to do -- time source already set.")
+ return
+ self._time_source = time_source
+ self.mboard_regs_control.set_time_source(time_source)
+
+ ###########################################################################
+ # Hardware peripheral controls
+ ###########################################################################
+
+ def set_fp_gpio_master(self, value):
+ """set driver for front panel GPIO
+ Arguments:
+ value {unsigned} -- value is a single bit bit mask of 12 pins GPIO
+ """
+ self.mboard_regs_control.set_fp_gpio_master(value)
+
+ def get_fp_gpio_master(self):
+ """get "who" is driving front panel gpio
+ The return value is a bit mask of 8 pins GPIO.
+ 0: means the pin is driven by PL
+ 1: means the pin is driven by PS
+ """
+ return self.mboard_regs_control.get_fp_gpio_master()
+
+ def set_fp_gpio_radio_src(self, value):
+ """set driver for front panel GPIO
+ Arguments:
+ value {unsigned} -- value is 2-bit bit mask of 8 pins GPIO
+ 00: means the pin is driven by radio 0
+ 01: means the pin is driven by radio 1
+ """
+ self.mboard_regs_control.set_fp_gpio_radio_src(value)
+
+ def get_fp_gpio_radio_src(self):
+ """get which radio is driving front panel gpio
+ The return value is 2-bit bit mask of 8 pins GPIO.
+ 00: means the pin is driven by radio 0
+ 01: means the pin is driven by radio 1
+ """
+ return self.mboard_regs_control.get_fp_gpio_radio_src()
+
+ def set_channel_mode(self, channel_mode):
+ "Set channel mode in FPGA and select which tx channel to use"
+ self.mboard_regs_control.set_channel_mode(channel_mode)
+
+ ###########################################################################
+ # Sensors
+ ###########################################################################
+ def get_ref_lock_sensor(self):
+ """
+ #TODO: Where is ref lock signal coming from?
+ """
+ self.log.trace("Querying ref lock status.")
+ lock_status = bool(self.mboard_regs_control.get_refclk_lock())
+ return {
+ 'name': 'ref_locked',
+ 'type': 'BOOLEAN',
+ 'unit': 'locked' if lock_status else 'unlocked',
+ 'value': str(lock_status).lower(),
+ }
+
+ def get_mb_temp_sensor(self):
+ """
+ Get temperature sensor reading of the E310.
+ """
+ self.log.trace("Reading temperature.")
+ temp = '-1'
+ raw_val = {}
+ data_probes = ['temp1_input']
+ try:
+ for data_probe in data_probes:
+ raw_val[data_probe] = read_sysfs_sensors_value('jc-42.4-temp', data_probe, 'hwmon', 'name')[0]
+ temp = str(raw_val['temp1_input'] / 1000)
+ except ValueError:
+ self.log.warning("Error when converting temperature value")
+ except KeyError:
+ self.log.warning("Can't read temp on thermal_zone".format(sensor))
+ return {
+ 'name': 'temp_mb',
+ 'type': 'REALNUM',
+ 'unit': 'C',
+ 'value': temp
+ }
+
+ def get_fpga_temp_sensor(self):
+ """
+ Get temperature sensor reading of the E310.
+ """
+ self.log.trace("Reading temperature.")
+ temp = '-1'
+ raw_val = {}
+ data_probes = ['in_temp0_raw', 'in_temp0_scale', 'in_temp0_offset']
+ try:
+ for data_probe in data_probes:
+ raw_val[data_probe] = read_sysfs_sensors_value('xadc', data_probe, 'iio', 'name')[0]
+ temp = str((raw_val['in_temp0_raw'] + raw_val['in_temp0_offset']) * raw_val['in_temp0_scale'] / 1000)
+ except ValueError:
+ self.log.warning("Error when converting temperature value")
+ except KeyError:
+ self.log.warning("Can't read temp on thermal_zone".format(sensor))
+ return {
+ 'name': 'temp_fpga',
+ 'type': 'REALNUM',
+ 'unit': 'C',
+ 'value': temp
+ }
+
+ ###########################################################################
+ # EEPROMs
+ ###########################################################################
+ def get_mb_eeprom(self):
+ """
+ Return a dictionary with EEPROM contents.
+
+ All key/value pairs are string -> string.
+
+ We don't actually return the EEPROM contents, instead, we return the
+ mboard info again. This filters the EEPROM contents to what we think
+ the user wants to know/see.
+ """
+ return self.mboard_info
+
+ def set_mb_eeprom(self, eeprom_vals):
+ """
+ See PeriphManagerBase.set_mb_eeprom() for docs.
+ """
+ self.log.warn("Called set_mb_eeprom(), but not implemented!")
+ raise NotImplementedError
+
+ def get_db_eeprom(self, dboard_idx):
+ """
+ See PeriphManagerBase.get_db_eeprom() for docs.
+ """
+ if dboard_idx != E310_DBOARD_SLOT_IDX:
+ self.log.warn("Trying to access invalid dboard index {}. "
+ "Using the only dboard.".format(dboard_idx))
+ db_eeprom_data = copy.copy(self.dboard.device_info)
+ return db_eeprom_data
+
+ def set_db_eeprom(self, dboard_idx, eeprom_data):
+ self.log.warn("Called set_db_eeprom(), but not implemented!")
+ raise NotImplementedError
+
+ ###########################################################################
+ # Component updating
+ ###########################################################################
+ # Note: Component updating functions defined by ZynqComponents
+ @no_rpc
+ def _update_fpga_type(self):
+ """Update the fpga type stored in the updateable components"""
+ fpga_type = self.mboard_regs_control.get_fpga_type()
+ self.log.debug("Updating mboard FPGA type info to {}".format(fpga_type))
+ self.updateable_components['fpga']['type'] = fpga_type