aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python/usrp_mpm/dboard_manager/magnesium_update_cpld.py
blob: e827062c2b3fa5c9e2efab379bbb12c79b3d7184 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env python3
#
# Copyright 2017 Ettus Research, a National Instruments Company
#
# SPDX-License-Identifier: GPL-3.0
#
"""
Update the CPLD image for the N310
"""
import os
import argparse
import subprocess
import pyudev
from usrp_mpm.mpmlog import get_logger


OPENOCD_DIR = "/usr/share/openocd/scripts"
REQUIRED_FILES = ["interface/sysfsgpio-ettus-magnesium-dba.cfg",
                  "interface/sysfsgpio-ettus-magnesium-dbb.cfg",
                  "cpld/altera-5m570z-cpld.cfg"]
OPENOCD_CMD = "init; svf -tap 5m570z.tap %s -progress -quiet;exit"


def check_openocd_files(logger=None):
    """
    Check if all file required by OpenOCD exist
    :param logger: logger object
    """
    for ocd_file in REQUIRED_FILES:
        if not os.path.exists(os.path.join(OPENOCD_DIR, ocd_file)):
            if logger is not None:
                logger.error("Missing file %s" % os.path.join(OPENOCD_DIR, ocd_file))
            return False
    return True


def check_fpga_state(which=0):
    """
    Check if the FPGA is operational
    :param which: the FPGA to check
    """
    logger = get_logger('update_cpld')
    try:
        context = pyudev.Context()
        fpga_mgrs = [dev for dev in context.list_devices(subsystem="fpga_manager")]
        if fpga_mgrs:
            state = fpga_mgrs[which].attributes.asstring('state')
            logger.trace("FPGA State: {}".format(state))
            return state == "operating"
    except OSError as ex:
        logger.error("Error while checking FPGA status: {}".format(ex))
        return False


def do_update_cpld(filename, daughterboards, force=False):
    """
    Carry out update process for the CPLD
    :param filename: path (on device) to the new CPLD image
    :param daughterboards: iterable containing dboard numbers to update
    :param force: bool, ignore issues during update process
    :return: True on success, False otherwise
    """
    logger = get_logger('update_cpld')
    logger.info("Programming CPLD of dboards {} with image {}".format(daughterboards, filename))

    if not daughterboards:
        logger.error("Invalid daughterboard selection.")
        return False

    if not os.path.exists(filename):
        logger.error("CPLD image file {} not found".format(filename))
        return False

    # If we don't want to force this, check that the FPGA is operational
    if not force and not check_fpga_state():
        logger.error("CPLD lines are routed through fabric, FPGA is not programmed, giving up")
        return False

    if check_openocd_files(logger=logger):
        logger.trace("Found required OpenOCD files.")
    else:
        # check_openocd_files logs errors
        return False

    for dboard in daughterboards:
        logger.info("Updating daughterboard slot {}...".format(dboard))
        cmd = ["openocd",
               "-f", (REQUIRED_FILES[int(dboard, 10)]).strip(),
               "-f", (REQUIRED_FILES[2]).strip(),
               "-c", OPENOCD_CMD % filename]
        logger.trace("Update CPLD CMD: {}".format(" ".join(cmd)))
        subprocess.call(cmd)

    logger.trace("Done programming CPLD...")
    return True


def main():
    """
    Go, go, go!
    """
    # We need to make a logger if we're running stand-alone
    from usrp_mpm.mpmlog import get_main_logger
    log = get_main_logger()

    # Do some setup
    def parse_args():
        """Parse the command-line arguments"""
        parser = argparse.ArgumentParser(description='Update the CPLD image on NI Magnesium')
        parser.add_argument("--file", help="Filename of CPLD image",
                            default="/lib/firmware/ni/cpld-magnesium-revc.svf")
        parser.add_argument("--dboards", help="Slot name to program", default="0,1")
        parser.add_argument("--force", help="Ignore issues and move on",
                            default=False, action="store_true")
        return parser.parse_args()

    args = parse_args()
    dboards = args.dboards.split(",")
    if any([x not in ('0', '1') for x in dboards]):
        log.error("Unsupported dboards requested: {}".format(dboards))
        return False
    else:
        return do_update_cpld(args.file, dboards, args.force)

if __name__ == "__main__":
    exit(not main())