test31.py 14.9 KB
Newer Older
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
#!   /usr/bin/env   python
#    coding: utf8

# Copyright CERN, 2011
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Last modifications: 16/5/2012

# Import system modules
import sys
import time
import datetime
import os

# Add common modules and libraries location to path
sys.path.append('../../../')
sys.path.append('../../../gnurabbit/python/')
sys.path.append('../../../common/')
sys.path.append('../../fmceeprom/python/')

# Import common modules
from ptsexcept import *
from fmc_eeprom import *
import rr

# Import specific modules
from fmc_adc_spec import *
from fmc_adc import *


"""
test31: Fix EEPROM content:
         - wrong IPMI format
         - add 'name' file
         - add 'data/' dir
         - rename sdb files
         - change sdb layout

        Serial number and manufacturing date are taken from the wrong EEPROM.

Note: Requires test00.py to run first to load the firmware!
"""

45
def main (default_directory='.', offset="0x1000", filename="calibration.sdb"):
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

    # Constants declaration
    TEST_NB = 31
    EXPECTED_BITSTREAM_TYPE = 0x1
    MANUFACTURER = "CERN"
    PRODUCT_NAME = "FmcAdc100m14b4cha"
    PART_NUMBER = "EDA-02063-V5-0"
    NAME = 'adc_100m'
    SDBFS_DIR = "sdbfs/"
    SDBFS_DIR = os.path.join(default_directory, SDBFS_DIR)
    NAME_BIN_FILENAME = SDBFS_DIR + "name"
    IPMI_BIN_FILENAME = SDBFS_DIR + "IPMI-FRU"
    CALIBR_BIN_FILENAME = SDBFS_DIR + "calib"
    BAD_EEPROM_BIN_FILENAME = "bad_eeprom_content.out"
    BAD_EEPROM_BIN_FILENAME = os.path.join(default_directory, BAD_EEPROM_BIN_FILENAME)
    NEW_EEPROM_BIN_FILENAME = "new_eeprom_content.out"
    NEW_EEPROM_BIN_FILENAME = os.path.join(default_directory, NEW_EEPROM_BIN_FILENAME)
    EEPROM_SIZE = 8192 # in Bytes

65 66
    BAD_SDB_DIR_OFFSET = offset
    BAD_CALIBR_BIN_FILENAME = filename
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 127 128 129 130 131 132 133 134 135 136

    start_test_time = time.time()
    print "================================================================================"
    print "Test%02d start\n" % TEST_NB

    # SPEC object declaration
    print "Loading hardware access library and opening device.\n"
    spec = rr.Gennum()

    # Carrier object declaration (SPEC board specific part)
    try:
        carrier = CFmcAdc100mSpec(spec, EXPECTED_BITSTREAM_TYPE)
    except FmcAdc100mSpecOperationError as e:
        raise PtsCritical("Carrier init failed, test stopped: %s" % e)

    # Mezzanine object declaration (FmcAdc100m14b4cha board specific part)
    try:
        fmc = CFmcAdc100m(spec)
    except FmcAdc100mOperationError as e:
        raise PtsCritical("Mezzanine init failed, test stopped: %s" % e)


    ###########################################################################
    # Real test stuff here
    try:

        #==================================================
        # Get data from bad eeprom
        #==================================================
        print("\n==================================================")
        print("Get bad image from mezzanine EEPROM.\n")

        # Calculate number of minutes since 0:00 1/1/96
        current_date = datetime.datetime.now()
        ref_date = datetime.datetime(1996, 1, 1)
        diff_date = current_date - ref_date
        current_date_min = int(diff_date.total_seconds()//60)
        print("Current date/time: %s"%(str(current_date)))
        print(" -> 0x%06X = %d minutes (since 0:00 1/1/96)\n" % (current_date_min, current_date_min))

        # Read entire bad EEPROM
        eeprom_data_read = fmc.sys_i2c_eeprom_read(0, EEPROM_SIZE)

        # Write EEPROM data to binary file
        print("Dumping bad EEPROM content (length=0x%x, %d):"%(len(eeprom_data_read), len(eeprom_data_read)))
        f_eeprom = open(BAD_EEPROM_BIN_FILENAME, "wb")
        for i,byte in enumerate(eeprom_data_read):
            f_eeprom.write(chr(byte))
            if not(i%16):
                print("")
            print("%02x"%(byte)),
        print("\n")
        f_eeprom.close()

        # Get calibration date from bad ipmi data
        eeprom_data = open(BAD_EEPROM_BIN_FILENAME, "rb").read()
        mfg_date_min = ipmi_get_mfg_date(eeprom_data)
        ref_date = datetime.datetime(1996, 1, 1)
        mfg_date = ref_date + datetime.timedelta(minutes=mfg_date_min)
        print("Mfg date read from bad EEPROM image: %s"%(str(mfg_date)))
        print(" -> 0x%06X = %d minutes (since 0:00 1/1/96)\n"%(mfg_date_min, mfg_date_min))

        # Get serial number from bad ipmi data
        serial_offset = 0x26
        serial_length = 19
        serial = ""
        for i in range(serial_length):
            serial += chr(eeprom_data_read[i+serial_offset])
        print("Serial number read from bad EEPROM image: %s"%serial)
137 138 139 140 141
        if serial == '':
            raise PtsCritical("Invalid serial number read in EEPROM!")

        BAK_CALIBR_BIN_FILENAME = "calibr_bak/calibr_" + serial + ".bin"
        BAK_CALIBR_BIN_FILENAME = os.path.join(default_directory, BAK_CALIBR_BIN_FILENAME)
142 143

        # Check that the manufacturing date is valid
144
        first_prod_date = datetime.datetime(2013, 2, 20)
145 146 147
        diff_date = first_prod_date - ref_date
        first_prod_date_min = int(diff_date.total_seconds()//60)
        if(mfg_date_min == 0 | mfg_date_min == 0xffffff):
148
            raise PtsCritical("No manufacturing date found in the EEPROM!")
149
        elif(mfg_date_min > current_date_min):
150
            raise PtsCritical("Date found in the EEPROM is in the future!")
151
        elif(mfg_date_min < first_prod_date_min):
152
            raise PtsCritical("Date found in the EEPROM is older than the first production!")
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
        else:
            print("Valid manufacturing date found in EEPROM: %s (will be preserved)\n" % str(mfg_date))


        #==================================================
        # Build the new ipmi file
        #==================================================
        print("\n==================================================")

        # Create Board Info Area
        # FRU field is used to store the date of generation of the eeprom content
        # This could be used later to determine if the content has to be udated (bug fix, ...)
        print("EEPROM content generation date: %s\n" % str(current_date))

        print("IPMI: Board Info Area")
        print(" - Mfg. Date/Time     : 0x%06X" % mfg_date_min)
        print(" - Board Manufacturer : %s" % MANUFACTURER)
        print(" - Board Product Name : %s" % PRODUCT_NAME)
        print(" - Board Serial Number: %s" % serial)
        print(" - Board Part Number  : %s" % PART_NUMBER)
        print(" - FRU File ID        : %s" % str(current_date))
        print("")
        fru = "%s" % str(current_date)
        bia = BoardInfoArea(mfg_date_min, MANUFACTURER, PRODUCT_NAME, serial, PART_NUMBER, fru)

        # Multirecords Area
        print("IPMI: Multi-record area")

        # output number, vnom, vmin, vmax, ripple, imin, imax
        vnom=2.5; vmin=2.375; vmax=2.625; ripple=0.0; imin=0; imax=4000
        print(" - DC Load (VADJ): vnom=%2.3fV, vmin=%2.3fV, vmax=%2.3fV, ripple=%2.3fV, imin=%dmA, imax=%dmA"%(vnom, vmin, vmax, ripple, imin, imax))
        dcload0 = DCLoadRecord(0, vnom, vmin, vmax, ripple, imin, imax) # VADJ

        vnom=3.3; vmin=3.135; vmax=3.465; ripple=0.0; imin=0; imax=3000
        print(" - DC Load (P3V3): vnom=%2.3fV, vmin=%2.3fV, vmax=%2.3fV, ripple=%2.3fV, imin=%dmA, imax=%dmA"%(vnom, vmin, vmax, ripple, imin, imax))
        dcload1 = DCLoadRecord(1, vnom, vmin, vmax, ripple, imin, imax) # P3V3

        vnom=12.0; vmin=11.4; vmax=12.6; ripple=0.0; imin=0; imax=1000
        print(" - DC Load (P12V): vnom=%2.3fV, vmin=%2.3fV, vmax=%2.3fV, ripple=%2.3fV, imin=%dmA, imax=%dmA"%(vnom, vmin, vmax, ripple, imin, imax))
        dcload2 = DCLoadRecord(2, vnom, vmin, vmax, ripple, imin, imax) # P12V

        dcload = [ dcload0, dcload1, dcload2 ]

        # output number, vnom, vmin, vmax, ripple, imin, imax
        vnom=0.0; vmin=0.0; vmax=0.0; ripple=0.0; imin=0; imax=0
        print(" - DC Out (VIO_B_M2C): vnom=%2.3fV, vmin=%2.3fV, vmax=%2.3fV, ripple=%2.3fV, imin=%dmA, imax=%dmA"%(vnom, vmin, vmax, ripple, imin, imax))
        dcout0 = DCOutputRecord(3, vnom, vmin, vmax, ripple, imin, imax) # VIO_B_M2C

        print(" - DC Out (VREF_A_M2C): vnom=%2.3fV, vmin=%2.3fV, vmax=%2.3fV, ripple=%2.3fV, imin=%dmA, imax=%dmA"%(vnom, vmin, vmax, ripple, imin, imax))
        dcout1 = DCOutputRecord(4, vnom, vmin, vmax, ripple, imin, imax) # VREF_A_M2C

        print(" - DC Out (VREF_B_M2C): vnom=%2.3fV, vmin=%2.3fV, vmax=%2.3fV, ripple=%2.3fV, imin=%dmA, imax=%dmA"%(vnom, vmin, vmax, ripple, imin, imax))
        dcout2 = DCOutputRecord(5, vnom, vmin, vmax, ripple, imin, imax) # VREF_B_M2C

        dcout = [ dcout0, dcout1, dcout2 ]

        # module size  : 0=single width, 1=double width
        # P1 size      : 0=LPC, 1=HPC
        # P2 size      : 0=LPC, 1=HPC, 3=not fitted
        # clock dir    : 0=M2C, 1=C2M
        # nb sig P1 A  : number
        # nb sig P1 B  : number
        # nb sig P2 A  : number
        # nb sig P2 B  : number
        # nb GBT P1    : number
        # nb GBT P2    : number
        # max TCK freq : frequency in MHz
        size=0; p1_size=0; p2_size=3; clk_dir=0; sig_p1_a=68; sig_p1_b=0; sig_p2_a=0; sig_p2_b=0; gbt_p1=0; gbt_p2=0; tck=0
        print(" - OEM: Module Size=%d, P1 Connector Size=%d, P2 Connector Size=%d, Clock Direction=%d, \
P1 Bank A nb signal=%d, P1 Bank B nb signal=%d, P2 Bank A nb signal=%d, P2 Bank B nb signal=%d, P1 GBT nb=%d, P2 GBT nb=%d, TCK max freq=%d\n"%(size, p1_size, p2_size, clk_dir, sig_p1_a, sig_p1_b, sig_p2_a, sig_p2_b, gbt_p1, gbt_p2, tck))
        oem = OEMRecord(size, p1_size, p2_size, clk_dir, sig_p1_a, sig_p1_b, sig_p2_a, sig_p2_b, gbt_p1, gbt_p2, tck)

        # Write ipmi content to a binary file
        print("Generate binary file with IPMI crap.\n -> Filename: %s"%IPMI_BIN_FILENAME)
        ipmi_open_file(IPMI_BIN_FILENAME)
        ipmi_set(bia, dcload, dcout, oem)
        ipmi_write()
        ipmi_close_file()

        #==================================================
        # Write 'name' file
        #==================================================
        print("\n==================================================")
        print("Writing %s with: %s"%(NAME_BIN_FILENAME, NAME))
        f_name = open(NAME_BIN_FILENAME, "wb")
        for char in NAME:
            f_name.write(char)
        f_name.close()

        #==================================================
        # Extract calibration data from bad eeprom image
        #==================================================
        print("\n==================================================")
246
        cmd = 'sdb-read -e ' + BAD_SDB_DIR_OFFSET + ' ' + BAD_EEPROM_BIN_FILENAME + ' ' + BAD_CALIBR_BIN_FILENAME + ' > ' + CALIBR_BIN_FILENAME
247 248
        print("Exctract calibration binary file from bad EEPROM image, cmd: %s"%(cmd))
        os.system(cmd)
249 250
        cmd = "cp " + CALIBR_BIN_FILENAME + " " + BAK_CALIBR_BIN_FILENAME
        print("Copy calibration binary, cmd: %s"%(cmd))
251
        os.system(cmd)
252 253 254 255 256 257 258 259 260

        #==================================================
        # Check that valid calibration data were extracted
        #==================================================
        print("\n==================================================")
        print("Check calibration data")
        calib_data = open(CALIBR_BIN_FILENAME, "rb").read()
        if calib_data == '':
            raise PtsCritical("Invalid calibration data read in EEPROM!")
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

        #==================================================
        # Generate eeprom image with gensdbfs
        #==================================================
        print("\n==================================================")
        cmd = "gensdbfs " + SDBFS_DIR + " " + NEW_EEPROM_BIN_FILENAME
        print("Generate new EEPROM image, cmd: %s\n"%(cmd))
        os.system(cmd)

        #==================================================
        # Read eeprom content from binary file
        #==================================================
        print("\n==================================================")
        f_bin_eeprom = open(NEW_EEPROM_BIN_FILENAME, "rb")
        eeprom_data = []
        byte = f_bin_eeprom.read(1) # reads one byte
        while byte:
            eeprom_data.append(ord(byte))
            byte = f_bin_eeprom.read(1) # reads one byte
        f_bin_eeprom.close()

        # Dump EEPROM content to log
        print("Dumping new EEPROM content (length=0x%x, %d):"%(len(eeprom_data), len(eeprom_data)))
        for i,byte in enumerate(eeprom_data):
            if not(i%16):
                print("")
            print("%02x"%(byte)),
        print("\n")

        #==================================================
        # Erase EEPROM content
        #==================================================
        print("\n==================================================")
        print "Erase EEPROM content."
295
        fmc.sys_i2c_eeprom_write([0x0] * EEPROM_SIZE)
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343

        #==================================================
        # Write content to EEPROM via I2C
        #==================================================
        print("\n==================================================")
        print "Write EEPROM content."
        if eeprom_data != []:
            fmc.sys_i2c_eeprom_write(eeprom_data)

        #==================================================
        # Read back EEPROM content via I2C
        #==================================================
        print("\n==================================================")
        eeprom_data_read = fmc.sys_i2c_eeprom_read(0, len(eeprom_data))
        mismatch = 0
        for i in range(len(eeprom_data)):
            wr_data = eeprom_data[i]
            rd_data = eeprom_data_read[i]
            if wr_data == rd_data:
                check = "OK"
            else:
                check = "FAILED"
                mismatch += 1
                print "0x%02X 0x%02X => %s" % (wr_data, rd_data, check)
            #print "0x%02X 0x%02X => %s" % (wr_data, rd_data, check)
        print "EEPROM content comparison => ",
        if(mismatch == 0):
            print "OK"
        else:
            print "FAILED"

    except FmcAdc100mOperationError as e:
        raise PtsError("Test failed: %s" % e)

    ###########################################################################

    print ""
    print "==> End of test%02d" % TEST_NB
    print "================================================================================"
    end_test_time = time.time()
    print "Test%02d elapsed time: %.2f seconds\n" % (TEST_NB, end_test_time-start_test_time)

    # Check if an error occured during EEPROM verification
    if(mismatch != 0):
        raise PtsError("EEPROM comparison failed: %d mismatch found. Check log for details." % mismatch)


if __name__ == '__main__' :
344 345 346 347 348 349 350 351 352 353 354 355
    arg_nb = len(sys.argv[1:])
    if arg_nb == 2:
        offset = sys.argv[1]
        filename = sys.argv[2]
    elif arg_nb > 2:
        print("Too many arguments.")
        sys.exit()
    else:
        offset = "0x1000"
        filename = "calibration.sdb"

    main('.', offset, filename)