From aa0cc703fe9287e4de54c4c5c1a52c5fce9c4402 Mon Sep 17 00:00:00 2001
From: Martin Braun <martin.braun@ettus.com>
Date: Mon, 7 May 2018 17:27:39 -0700
Subject: mpm: Refactor periph manager init; split EEPROM read from rest

The readout of EEPROMs is moved to their own functions. This will allow
us to read out EEPROM values before starting the initialization.
---
 mpm/python/usrp_mpm/periph_manager/base.py | 239 ++++++++++++++++-------------
 1 file changed, 135 insertions(+), 104 deletions(-)

diff --git a/mpm/python/usrp_mpm/periph_manager/base.py b/mpm/python/usrp_mpm/periph_manager/base.py
index 3ded0d3c2..e3bf89c33 100644
--- a/mpm/python/usrp_mpm/periph_manager/base.py
+++ b/mpm/python/usrp_mpm/periph_manager/base.py
@@ -158,7 +158,12 @@ class PeriphManagerBase(object):
         # should always be a dictionary (or dictionary-like object).
         self._init_args = {}
         try:
-            self._init_mboard_with_eeprom()
+            self._eeprom_head, self._eeprom_rawdata = \
+                self._read_mboard_eeprom()
+            self.mboard_info = self._get_mboard_info(self._eeprom_head)
+            self.log.info("Device serial number: {}"
+                          .format(self.mboard_info.get('serial', 'n/a')))
+            dboard_infos = self._get_dboard_eeprom_info()
             self._default_args = self._update_default_args(args)
             self.log.debug("Using default args: {}".format(self._default_args))
             self._init_mboard_overlays(self._eeprom_head, self._default_args)
@@ -169,7 +174,11 @@ class PeriphManagerBase(object):
                 ]
             else:
                 override_db_pids = []
-            self._init_dboards(override_db_pids, self._default_args)
+            self._init_dboards(
+                dboard_infos,
+                override_db_pids,
+                self._default_args
+            )
             self._device_initialized = True
             self._initialization_status = "No errors."
         except Exception as ex:
@@ -177,15 +186,19 @@ class PeriphManagerBase(object):
             self._device_initialized = False
             self._initialization_status = str(ex)
 
-    def _init_mboard_with_eeprom(self):
+    def _read_mboard_eeprom(self):
         """
-        Starts the device initialization. Typically requires reading from an
-        EEPROM.
+        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):
             self.log.trace("Reading EEPROM from address `{}'..."
                            .format(self.mboard_eeprom_addr))
-            (self._eeprom_head, self._eeprom_rawdata) = eeprom.read_eeprom(
+            (eeprom_head, eeprom_rawdata) = eeprom.read_eeprom(
                 get_eeprom_paths(self.mboard_eeprom_addr)[0],
                 self.mboard_eeprom_offset,
                 eeprom.MboardEEPROM.eeprom_header_format,
@@ -194,54 +207,109 @@ class PeriphManagerBase(object):
                 self.mboard_eeprom_max_len,
             )
             self.log.trace("Found EEPROM metadata: `{}'"
-                           .format(str(self._eeprom_head)))
+                           .format(str(eeprom_head)))
             self.log.trace("Read {} bytes of EEPROM data."
-                           .format(len(self._eeprom_rawdata)))
-            for key in ('pid', 'serial', 'rev', 'eeprom_version'):
-                # In C++, we can only handle dicts if all the values are of the
-                # same type. So we must convert them all to strings here:
-                try:
-                    self.mboard_info[key] = str(
-                        self._eeprom_head.get(key, ''),
-                        'ascii'
-                    )
-                except TypeError:
-                    self.mboard_info[key] = str(self._eeprom_head.get(key, ''))
-            if 'pid' in self._eeprom_head:
-                if self._eeprom_head['pid'] not in self.pids.keys():
-                    self.log.error(
-                        "Found invalid PID in EEPROM: 0x{:04X}. " \
-                        "Valid PIDs are: {}".format(
-                            self._eeprom_head['pid'],
-                            ", ".join(["0x{:04X}".format(x)
-                                       for x in self.pids.keys()]),
-                        )
-                    )
-                    raise RuntimeError("Invalid PID found in EEPROM.")
-                self.mboard_info['product'] = \
-                    self.pids[self._eeprom_head['pid']]
-            if 'rev' in self._eeprom_head:
-                try:
-                    rev_numeric = int(self._eeprom_head.get('rev'))
-                except (ValueError, TypeError):
-                    raise RuntimeError(
-                        "Invalid revision info read from EEPROM!"
+                           .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_mboard_info(self, eeprom_head):
+        """
+        Creates the mboard info dictionary from the EEPROM data.
+        """
+        mboard_info = self.mboard_info
+        if not eeprom_head:
+            self.log.debug("No EEPROM info: Can't generate mboard_info")
+            return mboard_info
+        for key in ('pid', 'serial', 'rev', 'eeprom_version'):
+            # In C++, we can only handle dicts if all the values are of the
+            # same type. So we must convert them all to strings here:
+            try:
+                mboard_info[key] = str(eeprom_head.get(key, ''), 'ascii')
+            except TypeError:
+                mboard_info[key] = str(eeprom_head.get(key, ''))
+        if 'pid' in eeprom_head:
+            if eeprom_head['pid'] not in self.pids.keys():
+                self.log.error(
+                    "Found invalid PID in EEPROM: 0x{:04X}. " \
+                    "Valid PIDs are: {}".format(
+                        eeprom_head['pid'],
+                        ", ".join(["0x{:04X}".format(x)
+                                   for x in self.pids.keys()]),
                     )
-                if self.mboard_max_rev is not None \
-                        and rev_numeric > self.mboard_max_rev:
-                    raise RuntimeError(
-                        "Device has revision `{}', but max supported " \
-                        "revision is `{}'".format(
-                            rev_numeric, self.mboard_max_rev
-                        ))
-            else:
-                raise RuntimeError("No revision found in EEPROM.")
+                )
+                raise RuntimeError("Invalid PID found in EEPROM.")
+            mboard_info['product'] = self.pids[eeprom_head['pid']]
+        if 'rev' in eeprom_head:
+            try:
+                rev_numeric = int(eeprom_head.get('rev'))
+            except (ValueError, TypeError):
+                raise RuntimeError(
+                    "Invalid revision info read from EEPROM!"
+                )
+            if self.mboard_max_rev is not None \
+                    and rev_numeric > self.mboard_max_rev:
+                raise RuntimeError(
+                    "Device has revision `{}', but max supported " \
+                    "revision is `{}'".format(
+                        rev_numeric, self.mboard_max_rev
+                    ))
         else:
-            self.log.trace("No EEPROM address to read from.")
-            self._eeprom_head = {}
-            self._eeprom_rawdata = ''
-        self.log.info("Device serial number: {}"
-                      .format(self.mboard_info.get('serial', 'n/a')))
+            raise RuntimeError("No revision found in EEPROM.")
+        return mboard_info
+
+    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 = eeprom.read_eeprom(
+                dboard_eeprom_path,
+                self.dboard_eeprom_offset,
+                eeprom.DboardEEPROM.eeprom_header_format,
+                eeprom.DboardEEPROM.eeprom_header_keys,
+                self.dboard_eeprom_magic,
+                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
 
     def _update_default_args(self, default_args):
         """
@@ -278,64 +346,30 @@ class PeriphManagerBase(object):
         # TODO: Fine-tune this number, or wait for some smarter signal.
         sleep(1)
 
-    def _init_dboards(self, override_dboard_pids, default_args):
+    def _init_dboards(self, dboard_infos, override_dboard_pids, default_args):
         """
         Initialize all the daughterboards
+
+        dboard_infos -- List of dictionaries as returned from
+                       _get_dboard_eeprom_info()
+        override_dboard_pids -- List of dboard PIDs to force
+        default_args -- Default args
         """
-        # Go, go, go!
-        override_dboard_pids = override_dboard_pids or []
         if override_dboard_pids:
             self.log.warning("Overriding daughterboard PIDs with: {}"
-                             .format(override_dboard_pids))
-        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]
+                             .format(",".join(override_dboard_pids)))
+        assert len(dboard_infos) <= self.max_num_dboards
         if len(override_dboard_pids) and \
-                len(override_dboard_pids) < len(dboard_eeprom_paths):
+                len(override_dboard_pids) < len(dboard_infos):
             self.log.warning("--override-db-pids is going to skip dboards.")
-            dboard_eeprom_paths = \
-                    dboard_eeprom_paths[:len(override_dboard_pids)]
-        for dboard_idx, dboard_eeprom_path in enumerate(dboard_eeprom_paths):
+            dboard_infos = dboard_infos[:len(override_dboard_pids)]
+        for dboard_idx, dboard_info in enumerate(dboard_infos):
             self.log.debug("Initializing dboard %d...", dboard_idx)
-            dboard_eeprom_md, dboard_eeprom_rawdata = eeprom.read_eeprom(
-                dboard_eeprom_path,
-                self.dboard_eeprom_offset,
-                eeprom.DboardEEPROM.eeprom_header_format,
-                eeprom.DboardEEPROM.eeprom_header_keys,
-                self.dboard_eeprom_magic,
-                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))
-            if len(override_dboard_pids) > dboard_idx:
-                db_pid = override_dboard_pids[dboard_idx]
-                self.log.warning("Overriding dboard PID for dboard {} "
-                                 "with 0x{:04X}.".format(dboard_idx, db_pid))
-            else:
-                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))
+            db_pid = dboard_info.get('pid')
             db_class = get_dboard_class_from_pid(db_pid)
             if db_class is None:
                 self.log.warning("Could not identify daughterboard class "
-                                 "for PID {:04X}!".format(db_pid))
+                                 "for PID {:04X}! Skipping.".format(db_pid))
                 continue
             if len(self.dboard_spimaster_addrs) > dboard_idx:
                 spi_nodes = sorted(get_spidev_nodes(
@@ -344,16 +378,13 @@ class PeriphManagerBase(object):
             else:
                 spi_nodes = []
                 self.log.warning("No SPI nodes for dboard %d.", dboard_idx)
-            dboard_info = {
-                'eeprom_md': dboard_eeprom_md,
-                'eeprom_rawdata': dboard_eeprom_rawdata,
-                'pid': db_pid,
+            dboard_info.update({
                 'spi_nodes': spi_nodes,
                 'default_args': default_args,
-            }
+            })
             # This will actually instantiate the dboard class:
             self.dboards.append(db_class(dboard_idx, **dboard_info))
-        self.log.info("Found %d daughterboard(s).", len(self.dboards))
+        self.log.info("Initialized %d daughterboard(s).", len(self.dboards))
 
     ###########################################################################
     # Session (de-)initialization (at UHD startup)
-- 
cgit v1.2.3