#!   /usr/bin/env   python
#    coding: utf8
##_________________________________________________________________________________________________
##                                                                                                |
##                                           |TDC PTS|                                            |
##                                                                                                |
##                                         CERN,BE/CO-HT                                          |
##________________________________________________________________________________________________|

##-------------------------------------------------------------------------------------------------
##                                                                                                |
##                            Write Calibration values to TDC EEPROM                              |
##                                                                                                |
##-------------------------------------------------------------------------------------------------
##                                                                                                |
## Description  Writing of the White Rabbit calibration value into the TDC EEPROM.                |
##                                                                                                |
##              The wrabbit_calib.py test is the one that calculates the calibration value and    |
##              stores it in a .txt file. The wrabbit_calib.py should have run prior to this test.|
##              The role of this test is to transfer this calibration value from the .txt file    |
##              stored in the pts computer file system into the TDC EEPROM.                       |
##                                                                                                |
##              The channels and DAC calibration of the TDC board (pts tests 00 to 03) should     |
##              have also run prior to this test.                                                 |
##              First in this test the TDC EEPROM is read and the existing calib file is retrieved|
##              using the sdbfs tools.                                                            |
##              From the existing calib file, the channels and DAC calibration values are         |
##              retrieved; the White Rabbit calibration value is added to them and finally a new  |
##              calib file is created with all the calibration values. This new file is writen in |
##              the TDC EEPROM, using the sdbfs tools.                                            |
##                                                                                                |
##                                                                                                |
## FW to load   .bin                                                                              |
## Authors      Evangelia Gousiou (Evangelia.Gousiou@cern.ch)                                     |
## Website      http://www.ohwr.org/projects/pts                                                  |
## Date         11/01/2013                                                                        |
##-------------------------------------------------------------------------------------------------

##-------------------------------------------------------------------------------------------------
##                               GNU LESSER GENERAL PUBLIC LICENSE                                |
##                              ------------------------------------                              |
## This source file is free software; you can redistribute it and/or modify it under the terms of |
## the GNU Lesser General Public License as published by the Free Software Foundation; either     |
## version 2.1 of the License, or (at your option) any later version.                             |
## This source is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;       |
## without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.      |
## See the GNU Lesser General Public License for more details.                                    |
## You should have received a copy of the GNU Lesser General Public License along with this       |
## source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html                     |
##-------------------------------------------------------------------------------------------------


# Import system modules
import sys
import time
import datetime
import os
import numpy as np

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

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

# Import specific modules
import fmc_tdc#_sdb


# Converts two's complement hex to signed
def hex2signed(value):
    if(value & 0x80000000):
        return -((~value & 0xFFFFFFFF) + 1)
    else:
        return value

def main (default_directory='.'):

    # Constants declaration
    MANUFACTURER            = "CERN"
    PRODUCT_NAME            = "FmcTdc1ns5cha"
    PART_NUMBER             = "EDA-02290-V3-0"
    NAME                    = 'tdc_1ns_5cha'
    SERIAL_FILENAME         = "../../../../serial.txt"
    SERIAL_FILENAME         = os.path.join(default_directory, SERIAL_FILENAME)
    WRABBIT_CALIB_FILENAME = "wrabbit_calib_data.txt"
    WRABBIT_CALIB_FILENAME = os.path.join(default_directory, WRABBIT_CALIB_FILENAME)
    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"
    EXISTING_CALIB_BIN_FILENAME = SDBFS_DIR + "existing_calib"
    ALL_CALIB_BIN_FILENAME = SDBFS_DIR + "calib"
    EEPROM_BIN_FILENAME     = "eeprom_content.out"
    EEPROM_BIN_FILENAME     = os.path.join(default_directory, EEPROM_BIN_FILENAME)
    NEW_EEPROM_BIN_FILENAME = "eeprom_content.in"
    NEW_EEPROM_BIN_FILENAME = os.path.join(default_directory, NEW_EEPROM_BIN_FILENAME)
    EEPROM_SIZE             = 8192 # in Bytes
    EEPROM_ADDR             = 0x50

    start_test_time = time.time()

    # Constants declaration
    FMC_TDC_ADDR            = '1a39:0004/1a39:0004@000B:0000'
    FMC_TDC_BITSTREAM_PATH  = '../firmwares/tdc.bin'
    FPGA_LOADER_PATH        = '../../../../pts/gnurabbit/user/fpga_loader'

    # SPEC object declaration
    spec = rr.Gennum()

    # Bind SPEC object to FMC TDC card
    print "\n-------------------------------------------------------------------"
    print "----------------------------- FMC TDC -----------------------------"
    print "------ TDC mezz EEPROM writing with White Rabbit Calibration ------\n"

    print ("Retrieval of the existing calibration values already inside the\n"
           "TDC EEPROM, addition of the White Rabbit calibration value\n"
           "and rewriting of the TDC EEPROM with all the calibration values.\n")

    print "\n_______________________________Info______________________________\n"
    print "FMC TDC address to parse: %s"%(FMC_TDC_ADDR)
    for name, value in spec.parse_addr(FMC_TDC_ADDR).iteritems():
        print "%s:0x%04X"%(name, value)
    spec.bind(FMC_TDC_ADDR)

    # Load FMC TDC firmware
    print "\n_______________________TDC Initialisations________________________\n"
    print "Loading FMC TDC firmware...",
    firmware_loader = os.path.join(default_directory, FPGA_LOADER_PATH)
    bitstream = os.path.join(default_directory, FMC_TDC_BITSTREAM_PATH)
    os.system(firmware_loader + ' ' + bitstream)
    time.sleep(1)
    print "Firmware loaded!"

    # TDC object declaration
    tdc = fmc_tdc.CFMCTDC(spec)

    # Check bitsteam type
    bitstream_type = tdc.read_bitstream_type()
    if(bitstream_type == 0xFFFFFFFF):
        msg = ("FATAL ERROR: No access to TDC core")
        print (msg)
        raise PtsError (msg)

    if(bitstream_type != 0x2):
        msg = ("FATAL ERROR: Wrong bitstream type loaded 0x%08X") %bitstream_type
        print (msg)
        raise PtsError (msg)
    else:
        print('Access to TDC core OK')

    #==================================================
    # Get the calibration data that is already written in the EEPROM
    print "\n\n_________________Reading existing EEPROM content__________________\n"
    try:
        periph_addr = tdc.mezz_i2c_scan()
    except:
        msg = ("ERROR: EEPROM IC5: No peripheral detected")
        os.close(spec.fd)
        print (msg)
        raise PtsError (msg)

    # Check that the EEPROM is detected on the I2C bus
    if(0 == len(periph_addr)):
        msg = ("ERROR: EEPROM IC5: No peripheral detected on system management I2C bus")
        os.close(spec.fd)
        print (msg)
        raise PtsError (msg)
    else:
        if(1 != len(periph_addr)):
            msg = ("ERROR: EEPROM IC5: Signal integrity problem detected on system management I2C bus, %d devices detected instead of 1"%(len(periph_addr)))
            os.close(spec.fd)
            print (msg)
            raise PtsError (msg)
        else:
            if(EEPROM_ADDR != periph_addr[0]):
                msg = ("ERROR: EEPROM IC5: Wrong device mounted on system management I2C bus, address is:0x%.2X expected:0x%.2X"%(periph_addr[0],EEPROM_ADDR))
                os.close(spec.fd)
                print (msg)
                raise PtsError (msg)


    # Read entire EEPROM
    eeprom_data_read = tdc.mezz_i2c_eeprom_read(0, EEPROM_SIZE)

    # Write EEPROM content to log
    print("Content read from the eeprom (length=0x%X (%d)):"%(len(eeprom_data_read), len(eeprom_data_read)))
    for i in range(len(eeprom_data_read)/16):
        print("0x%04X"%(i*16)),
        for j in range(16):
            print("%02X"%eeprom_data_read[(i*16)+j]),
        print("")
    print("")

    # Write EEPROM content to binary file
    print("Writing eeprom content to binary file: %s"%(EEPROM_BIN_FILENAME))
    f_eeprom = open(EEPROM_BIN_FILENAME, "wb")
    for byte in eeprom_data_read:
        f_eeprom.write(chr(byte))
    f_eeprom.close()

    # Get calibration data from this binary file
    cmd = 'sdb-read -e 0x200 ' + EEPROM_BIN_FILENAME + ' calib > ' + EXISTING_CALIB_BIN_FILENAME
    print("Exctracting calibration binary file, cmd: %s"%(cmd))
    os.system(cmd)
    existing_calib_data = []
    f_existing_calib_data = open(EXISTING_CALIB_BIN_FILENAME, "rb")
    try:
        byte = f_existing_calib_data.read(1)
        while byte != "":
            existing_calib_data.append(ord(byte))
            byte = f_existing_calib_data.read(1)
    finally:
        f_eeprom.close()

    # Re-arrange calibration data into 32-bit numbers (from bytes)
    existing_calib_data = existing_calib_data[0:28]
    existing_calib_words = []
    for i in range(0,28-3,4):
        existing_calib_words.append((existing_calib_data[i+3] << 24)+(existing_calib_data[i+2] << 16)+(existing_calib_data[i+1] << 8) + (existing_calib_data[i]))

    existing_ch_calibration = []
    existing_dac_value      = existing_calib_words[4]
    existing_temperature    = existing_calib_words[5]
    existing_wrabbit_calib  = existing_calib_words[6]
    for i in range(4):
        existing_ch_calibration.append(float((hex2signed(existing_calib_words[i])))/100)
    print ("\nCh1-Ch2 calibration value: 0x%08X | %.2f ps")%(existing_calib_words[0], existing_ch_calibration[0])
    print ("Ch1-Ch3 calibration value: 0x%08X | %.2f ps")  %(existing_calib_words[1], existing_ch_calibration[1])
    print ("Ch1-Ch4 calibration value: 0x%08X | %.2f ps")  %(existing_calib_words[2], existing_ch_calibration[2])
    print ("Ch1-Ch5 calibration value: 0x%08X | %.2f ps")  %(existing_calib_words[3], existing_ch_calibration[3])
    print ("DAC calibration value    : 0x%8X")             %existing_dac_value
    print ("Calibration temperature  : 0x%08X | %d oC")    %(existing_temperature, existing_temperature) 
    print ("White Rabbit calibration : 0x%08X | %.2f ps")  %(existing_wrabbit_calib, existing_wrabbit_calib/100)

    if existing_wrabbit_calib == 0:
        print ("\nNo White Rabbit calibration already in the EEPROM") 
    #==================================================
    # Read calibration data from the wrabbit_calib.txt file
    # The file must be written by the test performing the White Rabbit calibration
    print "\n\n_________ White Rabbit calibration value from .txt file ________\n"
    try:
        f_wrabbit_calib = open(WRABBIT_CALIB_FILENAME, 'r+')
    except:
        msg = ("ERROR: Text file wrabbit_calib.txt: Not found")
        os.close(spec.fd)
        print (msg)
        raise PtsError (msg)

    calib_data_wrabbit = []
    for line in iter(f_wrabbit_calib):
        calib_data_wrabbit.append(0xFF & int(line, 16))
        calib_data_wrabbit.append(0xFF & (int(line, 16) >> 8))
        calib_data_wrabbit.append(0xFF & (int(line, 16) >> 16))
        calib_data_wrabbit.append(0xFF & (int(line, 16) >> 24))
    f_wrabbit_calib.close()


    #==================================================
    # Write the DAC, Channels, temperature and White Rabbit calibration data to binary file
    # This file will be fed to gensdbfs
    f_bin_all_calib = open(ALL_CALIB_BIN_FILENAME, 'wb')

    calib_data_no_wrabbit = existing_calib_data[0:24] # add the first 6 32-bit words
    for byte in calib_data_no_wrabbit:
        f_bin_all_calib.write(chr(byte))

    for byte in calib_data_wrabbit:                   # add the White Rabbit calib 32-bit word
        f_bin_all_calib.write(chr(byte))
    f_bin_all_calib.close()

    # Read the binary file that was just written
    all_calib_data = []
    f_bin_all_calib = open(ALL_CALIB_BIN_FILENAME, "rb")
    byte = f_bin_all_calib.read(1)
    while byte != "":
        all_calib_data.append(ord(byte))
        byte = f_bin_all_calib.read(1)

    # Re-arrange calibration data into 32-bit numbers (from bytes)
    new_calib_words = []
    for i in range(0,len(all_calib_data)-3,4):
        new_calib_words.append((all_calib_data[i+3] << 24)+(all_calib_data[i+2] << 16)+(all_calib_data[i+1] << 8) + (all_calib_data[i]))

    new_ch_calibration = []
    for i in range(4):
        new_ch_calibration.append(float((hex2signed(new_calib_words[i])))/100)
    new_dac_value      = new_calib_words[4]
    new_temperature    = new_calib_words[5]
    new_wrabbit_calib  = new_calib_words[6]

    if new_calib_words[0:6] != existing_calib_words[0:6]:
        print ("ERROR with binary files")


    print ("White Rabbit Calibration value: 0x%08X.")%(new_wrabbit_calib)

    if existing_wrabbit_calib != 0:
        print ("White Rabbit calibration value already in the EEPROM: 0x%08X,") %(existing_wrabbit_calib)
        print ("will be replaced by: 0x%08X.")%(new_wrabbit_calib) 


    print "\n\n___________ New calibration to be written in EEPROM_____________\n"
    print ("Ch1-Ch2 calibration value: 0x%08X | %.2f ps")  %(new_calib_words[0], new_ch_calibration[0])
    print ("Ch1-Ch3 calibration value: 0x%08X | %.2f ps")  %(new_calib_words[1], new_ch_calibration[1])
    print ("Ch1-Ch4 calibration value: 0x%08X | %.2f ps")  %(new_calib_words[2], new_ch_calibration[2])
    print ("Ch1-Ch5 calibration value: 0x%08X | %.2f ps")  %(new_calib_words[3], new_ch_calibration[3])
    print ("DAC calibration value    : 0x%8X")             %new_dac_value
    print ("Calibration temperature  : 0x%08X | %d oC")    %(new_temperature, new_temperature) 
    print ("White Rabbit calibration : 0x%08X | %.2f ps")  %(new_wrabbit_calib, new_wrabbit_calib/100)


    #==================================================
    # Get serial number from existing ipmi data
    print "\n\n_____________________Rest of EEPROM data________________________\n"
    serial_offset = 0x22
    serial_length = 19
    serial = ""
    for i in range(serial_length):
        serial += chr(eeprom_data_read[i+serial_offset])
    print("Serial number already in the EEPROM: %s"%serial)
    if serial == '':
        raise PtsCritical("Invalid serial number read in EEPROM!")

    #==================================================
    # 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))


    #==================================================
    # Check if a manufacturing date is present in the EEPROM.
    # If not, put the current date (it means it's the first time the test is run).
    # If a date is present, keep it.

    # EEPROM clear code used to test the test!
    #eeprom_data = [0x0] * EEPROM_SIZE
    #fmc.sys_i2c_eeprom_write(eeprom_data)


    # Read entire EEPROM
    #print "Read EEPROM content."
    eeprom_data_read = tdc.mezz_i2c_eeprom_read(0, EEPROM_SIZE)

    # Write EEPROM data to binary file
    #print "Write EEPROM content to file (binary)."
    f_eeprom = open(EEPROM_BIN_FILENAME, "wb")
    for byte in eeprom_data_read:
        f_eeprom.write(chr(byte))
    f_eeprom.close()

    # Get manufacturing date from EEPROM data, if exists
    eeprom_data = open(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 eeprom: %s"%(str(mfg_date)))
    print(" -> 0x%06X = %d minutes (since 0:00 1/1/96)\n"%(mfg_date_min, mfg_date_min))

    first_prod_date = datetime.datetime(2013, 3, 4)
    diff_date = first_prod_date - ref_date
    first_prod_date_min = int(diff_date.total_seconds()//60)

    # No manufacturing date present in EEPROM, put the current date
    if(mfg_date_min == 0 | mfg_date_min == 0xffffff):
        print("No manufacturing date found in the EEPROM => taking current date: %s\n" % str(current_date))
        mfg_date_min = current_date_min
    elif(mfg_date_min > current_date_min):
        print("Date found in the EEPROM is in the future => taking current date: %s\n" % str(current_date))
        mfg_date_min = current_date_min
    elif(mfg_date_min < first_prod_date_min):
        print("Date found in the EEPROM is older than the first production => taking current date: %s\n" % str(current_date))
        mfg_date_min = current_date_min
    else:
        print("Valid manufacturing date found in EEPROM: %s (will be preserved)\n" % str(mfg_date))

    #==================================================
    # 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 stuff..\n")
    ipmi_open_file(IPMI_BIN_FILENAME)
    ipmi_set(bia, dcload, dcout, oem)
    ipmi_write()
    ipmi_close_file()

    #==================================================
    # Read impi content from binary file
    f_ipmi = open(IPMI_BIN_FILENAME, "rb")
    ipmi_data = []
    byte = f_ipmi.read(1) # reads one byte
    while byte:
        ipmi_data.append(ord(byte))
        byte = f_ipmi.read(1) # reads one byte
    f_ipmi.close()

    #print "Raw IPMI data:"
    #for add, data in enumerate(ipmi_data):
    #    print "0x%02X(%3d): 0x%02X" % (add, add, data)

    #==================================================
    # Write 'name' file
    print("\nWriting %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()

    #==================================================
    # Create an empty 'data' folder
    data_dir = SDBFS_DIR + "data"
    if(not(os.path.exists(data_dir))):
        cmd = "mkdir " + data_dir
        print("Create empty data folder, cmd: %s\n"%(cmd))
        os.system(cmd)
    else:
        print("\nThe %s folder already exists.\n"%(data_dir))


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

    #==================================================
    # Erase EEPROM content
    print "\n______________________Writing EEPROM content______________________\n"
    print "Erasing EEPROM content..",
    eeprom_data = [0x0] * EEPROM_SIZE
    tdc.mezz_i2c_eeprom_write_page(eeprom_data)

    #==================================================
    # Read eeprom content from binary file
    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()

    #==================================================
    # Write content to EEPROM via I2C
    print "Writing new EEPROM content..\n"
    if eeprom_data != []:
        tdc.mezz_i2c_eeprom_write_page(eeprom_data)

    #==================================================
    # Get calibration data already written in the EEPROM
    # Read entire EEPROM
    print("Reading all eeprom content..")
    eeprom_data_read = tdc.mezz_i2c_eeprom_read(0, EEPROM_SIZE)

    # Dump EEPROM content to log
    print("Content read from the eeprom (length=0x%X (%d)):"%(len(eeprom_data_read), len(eeprom_data_read)))
    for i in range(len(eeprom_data_read)/16):
        print("0x%04X"%(i*16)),
        for j in range(16):
            print("%02X"%eeprom_data_read[(i*16)+j]),
        print("")
    print("")

    #==================================================
    # Read back EEPROM content via I2C
    print "Reading data back for validation..\n"
    eeprom_data_read = tdc.mezz_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"


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

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

    print "\n-----------------------------------------------------------------\n\n\n"
    end_test_time = time.time()
    print "\nTest elapsed time: %.2f seconds\n" % (end_test_time-start_test_time)


if __name__ == '__main__' :
    main()
