#!   /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: 29/5/2012

# Import system modules
import sys
import time
import os

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

# Import common modules
from ptsexcept import *
import rr

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


"""
test04: Test Si570 programmable oscillator

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

def main (default_directory='.'):

    # Constants declaration
    TEST_NB = 4
    EXPECTED_BITSTREAM_TYPE = 0x1
    SI570_ADDR = 0x55
    SI570_XTAL_FREQ_MIN = 114.056
    SI570_XTAL_FREQ_MAX = 114.514
    SI570_FOUT = 100.000
    SI570_FOUT_TOL = 1.0


    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)
    # Used to check that the firmware is loaded.
    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)

    # Scan i2c bus
    periph_addr = fmc.i2c_scan()

    # Check that the EEPROM is detected on the I2C bus
    if(0 == len(periph_addr)):
        raise PtsError('No peripheral detected on I2C bus')
    if(1 != len(periph_addr)):
        raise PtsError('Signal integrity problem detected on I2C bus, %d devices detected instead of 1'%(len(periph_addr)))
    if(SI570_ADDR != periph_addr[0]):
        raise PtsError('Wrong device mounted on I2C bus, address is:0x%.2X expected:0x%.2X'%(periph_addr[0],SI570_ADDR))

    try:
        # Get Si570 configuration
        rfreq, n1, hs_div = fmc.get_si570_config()

        # Pritn Si570 configuration
        fmc.print_si570_config()
        print ""

        raw_cfg = fmc.get_si570_raw_config()
        print("Si570 registers\naddr: data")
        for i in raw_cfg:
            print("0x%02X: 0x%02X"% (i[0], i[1]))
        print("")

        # Check that HS_DIV is different from 0
        # If HS_DIV register value is "100" or "110" (not used) get_si570_config returns 0
        if (hs_div == 0):
            raise PtsError('Si570 invalid HS_DIV value')

        # Calculate min and max output frequency based on the min and max xtal frequency
        # See http://cp-siliconlabs.kb.net/article.aspx?article=311398&p=12972
        f_out_min = (SI570_XTAL_FREQ_MIN * rfreq) / (float(n1) * float(hs_div))
        f_out_max = (SI570_XTAL_FREQ_MAX * rfreq) / (float(n1) * float(hs_div))

        print "FOUT_MIN  : %3.3f" % f_out_min
        print "FOUT_MAX  : %3.3f" % f_out_max

        # Check that output frequency is within the limits
        error = 0
        f_out_limit_min = SI570_FOUT - SI570_FOUT_TOL
        f_out_limit_max = SI570_FOUT + SI570_FOUT_TOL
        print "FOUT_LIMIT_MIN  : %3.3f" % f_out_limit_min
        print "FOUT_LIMIT_MAX  : %3.3f" % f_out_limit_max
        print "%3.3f < %3.3f < %3.3f < %3.3f < %3.3f ? => " % (f_out_limit_min, f_out_min, SI570_FOUT, f_out_max, f_out_limit_max),
        if (f_out_limit_min < f_out_min) and (f_out_min < SI570_FOUT) and (SI570_FOUT < f_out_max) and (f_out_max < f_out_limit_max):
            print "OK"
            print "Si570 frequency output is within tolerance"
        else:
            print "FAILED"
            error += 1


    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)

    # Raise an exception if Si570 frequency is outside the tolerance
    if(error != 0):
        raise PtsError('Si570 frequency output is outside of the tolerance.')


if __name__ == '__main__' :
    main()
