#!   /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

DEL = 0.5

def test_sync_output( dut, box ):
    
    util.section_msg("Testing trigger in output mode")
    result = {}

#     enable output
    dut.fipcore.write_regname('ext_sync.oe', 1)
#     disable termination (should bring input to gnd via resistors)
    dut.fipcore.write_regname('ext_sync.term_en', 0)
#     disable test pull up
    dut.fipcore.write_regname('ext_sync.tst', 0)
#     set output value
    dut.fipcore.write_regname('ext_sync.output_value', 0)
#     set trigger to output direction
    dut.fipcore.write_regname('ext_sync.dir', 1)
    
    util.info_msg("Setting trigger to output")
    # connect trigger to channel 2 of ADC
    box.trigger_output_to_awg()
    
    util.info_msg("Connecting ADC to channel 1 of secondary transformer side ")
    # connect ADC to secondary transformer side (connected to trigger)
    dut.close_relay( 2 )
    
    # wait
    time.sleep(DEL)
    
    util.info_msg("")
    util.info_msg("Generating low output")
    result['Trigger output verified to go low'] = 1
    for i in xrange(10):
        adc_samples = dut.adc_single_sample()
        
        if adc_samples[1] < util.test09_thd:
            util.info_msg("Value read by ADC: CH1=%d, CH2=%d" %( adc_samples[0], adc_samples[1] ) )
        else:
            util.err_msg("Value read by ADC: CH1=%d, CH2=%d" %( adc_samples[0], adc_samples[1] ) )
            result['Trigger output verified to go low'] = 0

        time.sleep(0.1)
    
    util.info_msg("")
    util.info_msg("Generating high output")
    dut.fipcore.write_regname('ext_sync.output_value', 1)
    result['Trigger output verified to go high'] = 1
    time.sleep(DEL)
    
    for i in xrange(10):
        adc_samples = dut.adc_single_sample()
        
        if adc_samples[1] >= util.test09_thd:
            util.info_msg("Value read by ADC: CH1=%d, CH2=%d" %( adc_samples[0], adc_samples[1] ) )
            
        else:
            util.err_msg("Value read by ADC: CH1=%d, CH2=%d" %( adc_samples[0], adc_samples[1] ) )
            result['Trigger output verified to go high'] = 0
        time.sleep(0.1)
    
#     set output value
    dut.fipcore.write_regname('ext_sync.output_value', 0)
    
    util.info_msg("")
    util.info_msg("Generating low output again")
    result['Trigger output verified to go low for the second time'] = 1
    for i in xrange(10):
        adc_samples = dut.adc_single_sample()
        util.dbg_msg("Read ADC value: CH1=%d, CH2=%d low trigger output" %( adc_samples[0], adc_samples[1] ) )
        
        if adc_samples[1] < util.test09_thd:
            util.info_msg("Value read by ADC: CH1=%d, CH2=%d" %( adc_samples[0], adc_samples[1] ) )
        else:
            util.err_msg("Value read by ADC: CH1=%d, CH2=%d" %( adc_samples[0], adc_samples[1] ) )
            result['Trigger output verified to go low for the second time'] = 0
        time.sleep(0.1)
    
        
    return result
    
    

def test_sync_input( dut, box ):
    
    result = {}
    
    util.section_msg("Testing trigger in input mode")
    
    box.trigger_input_low()
    
    time.sleep(DEL)
    
    util.info_msg("Setting trigger to input")
    util.info_msg("Disabling Test pullup resistor")
#     set trigger to input direction
    dut.fipcore.write_regname('ext_sync.dir', 0)
#     enable output
    dut.fipcore.write_regname('ext_sync.oe', 1)
#     enable termination (should bring input to gnd via resistors)
    dut.fipcore.write_regname('ext_sync.term_en', 1)
#     disable test pull up
    dut.fipcore.write_regname('ext_sync.tst', 0)
    
    time.sleep(DEL);
    
    if dut.fipcore.read_regname('ext_sync_raw_input') == 0 :
        util.info_msg("Value read from trigger input is 0")
        result['Read low value on trigger input with pulldown resistor enabled'] = 1
    else:
        util.err_msg("Value read from trigger input is 1")
        result['Read low value on trigger input with pulldown resistor enabled'] = 0
    
    util.info_msg("")
    util.info_msg("Enabling Test pullup resistor")
    dut.fipcore.write_regname('ext_sync.tst', 1)
    
    time.sleep(DEL);
    
    
    if dut.fipcore.read_regname('ext_sync_raw_input') == 1 : 
        result['Read low value on trigger input with pullup resistor enabled'] = 1
        util.info_msg("Value read from trigger input is 1")
        
    else :
        util.err_msg("Value read from trigger input is 0")
        result['Read low value on trigger input with pullup resistor enabled'] = 0
    
    util.info_msg("")
    util.info_msg("Disabling bidir buffer outputs")
    util.info_msg("Repeating pullup switching")
    util.info_msg("Since outputs are disabled both values should be the same")
    # disable output
    dut.fipcore.write_regname('ext_sync.oe', 0)
    
    # should read the same value on pullup and pulldown since buffer outputs are high-z
    dut.fipcore.write_regname('ext_sync.tst', 1)
    
    time.sleep(DEL);
    
    output_disabled_pullup = dut.fipcore.read_regname('ext_sync_raw_input')
    
    dut.fipcore.write_regname('ext_sync.tst', 0)
    
    time.sleep(DEL);
    
    output_disabled_pulldown = dut.fipcore.read_regname('ext_sync_raw_input')
    
    if output_disabled_pulldown == output_disabled_pullup :
        result['Trigger output enable'] = 1
        util.info_msg("Value read with and without pullup was the same")
    else :
        result['Trigger output enable'] = 0
        util.err_msg("Value read with and without pullup was different")
    
    util.info_msg("")
    util.info_msg("Connecting input to reference voltage in calibration box")
    util.info_msg("Setting low input voltage")
    box.trigger_input_low()
    
#     set trigger to input direction
    dut.fipcore.write_regname('ext_sync.dir', 0)
#     enable output
    dut.fipcore.write_regname('ext_sync.oe', 1)
#     disable termination 
    dut.fipcore.write_regname('ext_sync.term_en', 0)
#     disable test pull up
    dut.fipcore.write_regname('ext_sync.tst', 0)
#     input should be "floating"
    
    time.sleep(DEL)
    if dut.fipcore.read_regname('ext_sync_raw_input') == 0: 
        result['Trigger input read low'] = 1
        util.info_msg("Read low input value") 
    else :
        util.err_msg("Read high input value")
        result['Trigger input read low'] = 0
        
    util.info_msg("")
    util.info_msg("Setting high input voltage")
    box.trigger_input_high()
    
    time.sleep(DEL)
    if dut.fipcore.read_regname('ext_sync_raw_input') == 1 :
        result['Trigger input read high'] = 1 
        util.info_msg("Read high input value")
    else :
        util.err_msg("Read low input value")
        result['Trigger input read high'] = 0 
        
    
    box.trigger_input_low()
    
    return result
    
def main (card=None, default_directory='.',suite=None, serial=""):
    
    testname= "Test09: Trigger Input/Output"
    util.header_msg( testname, [ "Bidirectional Buffer communication",
                                    "Termination switching",
                                    "Test pullup resistor switching",
                                    "Reading trigger input",
                                    "Generating trigger output" ] )
    
    ###############################################################################
    ############################ initialization ###################################
    ###############################################################################
    box = util.calibration_box_init()
    
    util.section_msg("Hardware initialization")
    abspath = util.find_prj_topdir(util.TOPDIRNAME);
    carrier = spec.spec( abspath );
        
   
    # FPGA bitstream and FMC presence are verified during initialization
    dut = fmc.fmcmasterfip(carrier, abspath, util.FIRMWARE_PATH)
    
    test_results = {}
    
    ###############################################################################
    ############################ actual test ######################################
    ###############################################################################
    
    
    
    
    test_results = util.merge_dictionaries( test_results, test_sync_input( dut, box ) )
    
    test_results = util.merge_dictionaries( test_results, test_sync_output( dut, box ) )
    
       
    ###############################################################################
    ########################## result processing ##################################
    ###############################################################################
    
    errors = util.summarise_test_results( testname, test_results)
        
if __name__ == '__main__' :
    main()