#!   /usr/bin/env   python

# Copyright Creotech SA, 2016
# Author: Marek Guminski <marek.guminski@creotech.pl>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org


import spec
import fmcmasterfip as fmc
import utilities as util
import ptsexcept
import time
import sys
import subprocess

WRITE_EEPROM    = True


def erase_eeprom( dut ):
    for i in xrange( 0x300 ):
        dut.sys_i2c_eeprom_write( i, [0xff] )
        time.sleep(0.01)


def sys_i2c_eeprom_write_wrapper(dut,test_addr, test_pattern):
    if WRITE_EEPROM:
        dut.sys_i2c_eeprom_write( test_addr, test_pattern )
    else:
        util.info_msg("EEPROM should be written")
        util.info_msg("Skipping write in order to save EEPROM")
        
def main (card=None, default_directory='.',suite=None, serial=None):
    
    testname= "Test05: EEPROM communication"
    util.header_msg( testname, [ "EEPROM communication" ] )
    
    if(serial == None):
        raise ptsexcept.PtsError("Serial number was not specified. Cannot create EEPROM content")
    
    abspath         = util.find_prj_topdir(util.TOPDIRNAME);
    output_file     = util.test05_output_file
    fru_gen_path    = abspath+util.test05_fru_gen_path
    gensdbfs_path   = abspath+util.test05_gensdbfs_path
    sdbfs_path      = abspath+util.test05_sdbfs_path

    util.section_msg("Hardware initialization")
    test_results = {}
    carrier = spec.spec( abspath );
    # FPGA bitstream and FMC presence are verified during initialization
    # any error there causes critical error and test termination
    dut = fmc.fmcmasterfip(carrier, abspath, util.FIRMWARE_PATH)
    
    ###############################################################################
    
    test_pattern        = [0xaa, 0x55, 0xff, 0xaa]
    test_pattern_not    = [0x55, 0xaa, 0x00, 0xff]
    
    # should be unused
    test_addr           = 0x6B0
    
    # some delays are required between operations
    # otherwise no ACK error may happen
    delval = 0.01
    
    util.section_msg("Testing communication with EEPROM")
    
    # in case of communication errors
    # exceptions are thrown
    # in order to prevent test termination with no verbose reason 
    # exceptions are caught 
    try:
        # backup current eeprom content (in case selected address is actually used)
        eeprom_bck = dut.sys_i2c_eeprom_read(test_addr, len(test_pattern) )
        time.sleep(delval)
        
        # overwrite some data bytes
        sys_i2c_eeprom_write_wrapper( dut, test_addr, test_pattern )
        time.sleep(delval)
        
        # verify eeprom content
        test_pattern_read = dut.sys_i2c_eeprom_read(test_addr, len(test_pattern) )
        time.sleep(delval)
        
        # write other pattern
        sys_i2c_eeprom_write_wrapper(dut, test_addr, test_pattern_not )
        time.sleep(delval)
        
        # verify content
        test_pattern_not_read = dut.sys_i2c_eeprom_read(test_addr, len(test_pattern) )
        
        test_results['EEPROM communication'] = 1
    
    except:
        util.err_msg( "Error during eeprom communication", sys.exc_info() )
        test_results['EEPROM communication'] = 0
        
    
    # verify content
    # assume success
    test_results['EEPROM content'] = 1
    
    # any error changes result to failure
    for i in xrange( len( test_pattern) ):
        
        if test_pattern[i] != test_pattern_read[i]:
            util.err_msg("Written to EEPROM: 0x%.2x. Read from EEPROM: 0x%.2x" % ( test_pattern[i], test_pattern_read[i] ) )
            test_results['EEPROM content'] = 0
        else:
            util.info_msg("Written to EEPROM: 0x%.2x. Read from EEPROM: 0x%.2x" % ( test_pattern[i], test_pattern_read[i] ) )
            
        if test_pattern_not[i] != test_pattern_not_read[i]:
            util.err_msg("Written to EEPROM: 0x%.2x. Read from EEPROM: 0x%.2x" % ( test_pattern_not[i], test_pattern_not_read[i] ) )
            test_results['EEPROM content'] = 0
        else:
            util.info_msg("Written to EEPROM: 0x%.2x. Read from EEPROM: 0x%.2x" % ( test_pattern_not[i], test_pattern_not_read[i] ) )
            
            
   
    # restore backed up eeprom content
    sys_i2c_eeprom_write_wrapper( dut, test_addr, eeprom_bck )
    
    
    
    speed = dut.fipcore.read_regname('speed')
    
    # create FRU information
    util.section_msg("Creating IPMI-FRU information")
    subprocess.call(
                    [fru_gen_path,
                    # vendor
                    "-v", "CERN",
                    # name
                    "-n", "fmc-masterfip",
                    # serial
                    "-s", serial,
                    # part
                    "-p", "EDA-03098-V3-%d" % speed,
                    # output
                    "-o", sdbfs_path+"/IPMI-FRU" ]
                    )
    
    # create file in sdbfs
    # containing speed version
    
    with open(sdbfs_path+"speed","w") as f:
        f.write(str(speed))
    f.close()
        
    # generate binary file containing 
    # sdbfs with specified files
    # contant of sdbfs is configured in sdbfs directory
#     Use "./gensdbfs [<options>] <inputdir> <output>"
    subprocess.call( [ gensdbfs_path, sdbfs_path, output_file ])
    
    
    # write generated file to EEPROM
    util.info_msg("Writing EEPROM")
    cnt = 0
    with open(output_file, "rb") as f:
        byte = f.read(1)
        while byte != "":
            sys_i2c_eeprom_write_wrapper(dut, cnt, [ ord(byte) ] )
            time.sleep(0.01)
            cnt += 1
            byte = f.read(1)
        
    f.close()
    util.info_msg("Writing done")
    
    # summarize results
    errors = util.summarise_test_results( "Test05: EEPROM", test_results)
    
    sys.stdout.flush()
    return 0
  

if __name__ == '__main__' :
    main()