aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrent Stapleton <brent.stapleton@ettus.com>2017-10-30 17:01:44 -0700
committerMartin Braun <martin.braun@ettus.com>2017-12-22 15:04:28 -0800
commite63a3e8b740e537750e25bc09a82b8b7b557d4d1 (patch)
treef28a213f199051a1cfea04723724535a1575eb7a
parent458655be730602ae3d0b2f4202f6aa334dd38f23 (diff)
downloaduhd-e63a3e8b740e537750e25bc09a82b8b7b557d4d1.tar.gz
uhd-e63a3e8b740e537750e25bc09a82b8b7b557d4d1.tar.bz2
uhd-e63a3e8b740e537750e25bc09a82b8b7b557d4d1.zip
fpga load: add update_component function to MPM
-update_component takes a byte array containing the data to be written, and a dictionary containing the metadata of the component to be updated -The metadata must contain 'id' and 'filename' -The metadata may contain an md5 hash ('md5')
-rw-r--r--mpm/python/usrp_mpm/periph_manager/base.py68
-rw-r--r--mpm/python/usrp_mpm/periph_manager/n310.py27
2 files changed, 95 insertions, 0 deletions
diff --git a/mpm/python/usrp_mpm/periph_manager/base.py b/mpm/python/usrp_mpm/periph_manager/base.py
index 8c50b060d..6c22e1c5c 100644
--- a/mpm/python/usrp_mpm/periph_manager/base.py
+++ b/mpm/python/usrp_mpm/periph_manager/base.py
@@ -20,6 +20,7 @@ Mboard implementation base class
from __future__ import print_function
import os
+from hashlib import md5
from builtins import str
from builtins import range
from builtins import object
@@ -122,6 +123,11 @@ class PeriphManagerBase(object):
# availability. If the list is empty, no CHDR traffic will be possible over
# the network. Example: ['eth1', 'eth2']
chdr_interfaces = []
+ # Dictionary containing valid IDs for the update_component function for a
+ # specific implementation. Each PeriphManagerBase-derived class should list
+ # information required to update the component, like a callback function
+ updateable_components = {}
+
@staticmethod
# Yes, this is overridable too: List the required device tree overlays
def list_required_dt_overlays(eeprom_md, device_args):
@@ -395,6 +401,68 @@ class PeriphManagerBase(object):
"""
return [dboard.device_info for dboard in self.dboards]
+ def update_component(self, file_metadata, data):
+ """
+ Updates the device component specified by comp_dict
+ :param file_metadata: Dictionary of strings containing metadata
+ :param data: Binary string with the file contents to be written
+ """
+ id_str = file_metadata['id']
+ filename = os.path.basename(file_metadata['filename'])
+ if id_str not in self.updateable_components:
+ self.log.error("{0} not an updateable component ({1})".format(
+ id_str, self.updateable_components.keys()
+ ))
+ raise NotImplementedError("Update component not implemented for {}".format(id_str))
+ self.log.trace("Updating component: {}".format(id_str))
+ if 'md5' in file_metadata:
+ given_hash = file_metadata['md5']
+ comp_hash = md5()
+ comp_hash.update(data)
+ comp_hash = comp_hash.hexdigest()
+ if comp_hash == given_hash:
+ self.log.trace("FPGA bitfile hash matched: {}".format(
+ comp_hash
+ ))
+ raise KeyError("Update component not implemented for {}".format(id_str))
+ self.log.trace("Updating component: {}".format(id_str))
+ if 'md5' in metadata:
+ given_hash = metadata['md5']
+ comp_hash = md5()
+ comp_hash.update(data)
+ comp_hash = comp_hash.hexdigest()
+ if comp_hash == given_hash:
+ self.log.trace("Component file hash matched: {}".format(
+ comp_hash
+ ))
+ else:
+ self.log.error("Component file hash mismatched:\n"
+ "Calculated {}\n"
+ "Given {}\n".format(
+ comp_hash, given_hash))
+ raise RuntimeError("Component file hash mismatch")
+ else:
+ self.log.error("FPGA bitfile hash mismatched:")
+ self.log.error("Calculated {}".format(comp_hash))
+ self.log.error("Given {}".format(given_hash))
+ raise RuntimeError("FPGA Bitfile hash mismatch")
+ else:
+ self.log.trace("Loading unverified {} image.".format(
+ id_str
+ ))
+ basepath = os.path.join(os.sep, "tmp", "uploads")
+ filepath = os.path.join(basepath, filename)
+ if not os.path.isdir(basepath):
+ self.log.trace("Creating directory {}".format(basepath))
+ os.makedirs(basepath)
+ self.log.trace("Writing data to {}".format(filepath))
+ with open(filepath, 'wb') as f:
+ f.write(data)
+ update_func = getattr(self, self.updateable_components[id_str]['callback'])
+ update_func(filepath, file_metadata)
+ return True
+
+
def load_fpga_image(self, target=None):
"""
load a new fpga image
diff --git a/mpm/python/usrp_mpm/periph_manager/n310.py b/mpm/python/usrp_mpm/periph_manager/n310.py
index 06d9a444c..50123699a 100644
--- a/mpm/python/usrp_mpm/periph_manager/n310.py
+++ b/mpm/python/usrp_mpm/periph_manager/n310.py
@@ -624,3 +624,30 @@ class n310(PeriphManagerBase):
safe_db_eeprom_user_data[blob_id] = blob.encode('ascii')
dboard.set_user_eeprom_data(safe_db_eeprom_user_data)
+ @no_rpc
+ def update_fpga(self, filepath, metadata):
+ """
+ Update the FPGA image in the filesystem and reload the overlay
+ :param filepath: path to new FPGA image
+ :param metadata: Dictionary of strings containing metadata
+ """
+ self.log.trace("Updating FPGA with image at {}"
+ .format(filepath))
+ _, file_extension = os.path.splitext(filepath)
+ # Cut off the period from the file extension
+ file_extension = file_extension[1:].lower()
+ if file_extension == "bit":
+ self.log.trace("Converting bit to bin file and writing to {}"
+ .format(self.binfile_path))
+ from usrp_mpm.fpga_bit_to_bin import fpga_bit_to_bin
+ fpga_bit_to_bin(filepath, self.binfile_path, flip=True)
+ elif file_extension == "bin":
+ self.log.trace("Copying bin file to {}"
+ .format(self.binfile_path))
+ shutil.copy(filepath, self.binfile_path)
+ else:
+ self.log.error("Invalid FPGA bitfile: {}"
+ .format(filepath))
+ raise RuntimeError("Invalid N310 FPGA bitfile")
+ # TODO: Implement reload procedure
+ return True