    #!   /usr/bin/env   python

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


import sys
import time
import os
import csr
import time

from fmcdds import *
from spec import *
from ad9516 import *
from ptsexcept import *

from utilFunctions import *

import calibr_box
import find_usb_tty
import calibration_box_connections

from spec_identification import *

"""
test01: 
    SPI communication with ad9516
    ad9516 reference clock (OSC1/OSC2 presence)
    ad9516 PLL locking on reference clock (OSC freq?)
    ad9516 PLL RESET line
    ad9516 clock lines to FPGA (CLK1OUT)
    ad9516 measure clock frequency
    OscDac control
    OscDac control range
    TODO: determine required control range
    TODO: find method to check SYNC line
    TODO: external clock input/output (trough UFL connector)???
    LATER: check DAC CLK
"""

AUTOMATION  = True

OSC_TUNNING_THD = 1e-6
FIRMWARE_PATH = '/../gateware/syn/spec_top.bin'
INPUT_TIMEOUT  = 30;

# make sure that this function is called after AD9516 init
def measure_clk1(carrier):
     
    # configure test
    samples=20;
    delay=0.1
    
    # set DAC value to zero
    carrier.writel(DDS_REG_OSCDAC, 0 );
    # send value
    carrier.writel(DDS_REG_OSCDAC, 0 | ( 1<<16) );
    # wait for it to take effect
    time.sleep(0.5)
    carrier.writel(DDS_REG_OSCDAC, 0 );
    time.sleep(0.5)
    
    #         take few measurements of received frequency
    min = 0
    for i in range(samples):
        min += carrier.readl(DDS_REG_CLK1);
        time.sleep(delay)
    #         average result
    min /= samples;
    
    # set DAC value to max
    carrier.writel(DDS_REG_OSCDAC, 0xffff );
    # send value
    carrier.writel(DDS_REG_OSCDAC, 0xffff | ( 1<<16) );
    # wait for it to take effect
    time.sleep(delay)
    carrier.writel(DDS_REG_OSCDAC, 0 );
    time.sleep(delay)
    
    # take few measurements of received frequency
    max = 0
    for i in range(samples):
        max += carrier.readl(DDS_REG_CLK1);
        time.sleep(delay)
    # average result
    max /= samples;
    
    # set medium value
    carrier.writel(DDS_REG_OSCDAC, 0x00ff );
    carrier.writel(DDS_REG_OSCDAC, 0x00ff | ( 1<<16) );
    time.sleep(delay)
    carrier.writel(DDS_REG_OSCDAC, 0x00ff );
    time.sleep(delay)
    
    # force float type
    min = float(min)/2.5
    max = float(max)/2.5
    
    
    # define control range
    # i am changing sampling clock frequency
    # so control direction is swapped
    control = (min-max)/((min+max)/2);
    
    
    
    print "Measuring 25 MHz oscillator clock (coarse)"
    print "Measured AD9516 frequency min:%d max:%d [MHz]" % ( min/1e6, max/1e6 )
#     print "Measured AD9516 frequency control range:%f" % control/1e6
    
    if(max > min):
        print "WARRNING! Voltage controlled oscillator polarity might be wrong"
    
    if(control < OSC_TUNNING_THD ):
        raise PtsError("Oscillator control range is too low")
    
    print "Main oscillator tests succeeded"
     
def ad9516_test_ld(carrier ):    
    # connect LD output to VCC
    device = ad9516(carrier);
    
    device.write_reg( 0x01A, 0x030 );
    device.write_reg( 0x232, 1);
    time.sleep(0.5)
    if( device.gpio_get(device.LD) == 0 ):
        raise PtsError("FPGA did not didn\'t read correct value of AD9516 LD pin. This might be caused by interrupted trace.")
  
    
    
    
#     redirector.InOut()
    print >> sys.__stdout__, "Please check if PLL LED on FmcDac600m12b1chaDDS is ON and type [y/n]."
#     redirector.InOut()
    tmp = yesnoquestion( "Please check if PLL LED on FmcDac600m12b1chaDDS is ON and type [y/n].", INPUT_TIMEOUT )
        
    if ( tmp == 0 ):
        raise PtsError("User verification of PLL LED on FmcDac600m12b1chaDDS failed. LED didn\'t turn on.")
    if ( tmp == 1 ):
        print "User verification of PLL LED on FmcDac600m12b1chaDDS succeeded"
    else:
        raise PtsError("User didn\'t verify FMC's PLL LED")
    
    # connect LD output to GND
    device.write_reg( 0x01A, 0x020 );
    device.write_reg( 0x232, 1);
    time.sleep(0.5)
    if( device.gpio_get(device.LD) != 0 ):
        raise PtsError("FPGA did not correct value of AD9516 LD pin. This might be caused by interrupted trace.")
    
#     redirector.InOut()
    print >> sys.__stdout__, "Please check if PLL LED on FmcDac600m12b1chaDDS is OFF and type [y/n]."
#     redirector.InOut()
    tmp = yesnoquestion( "Please check if PLL LED on FmcDac600m12b1chaDDS is OFF and type [y/n].", INPUT_TIMEOUT )
    
    if ( tmp == 0 ):
        raise PtsError("User verification of PLL LED on FmcDac600m12b1chaDDS failed. LED didn\'t turn off.")
    if ( tmp == 1 ):
        print "User verification of PLL LED on FmcDac600m12b1chaDDS succeeded"
    else:
        raise PtsError("User didn\'t verify FMC's PLL LED")
        
    print "FMC's PLL LED tests succeeded"
    

def ad9516_test_reset(carrier):
    # FPGA PLL must be locked if this method didnt fail
    dev=ad9516(carrier);
    
    # reset configuration to default
    dev.gpio_set( dev.RESET_N, 0 )
    
    if( (carrier.readl( DDS_REG_FPGACTRL ) & DDS_FPGACTRL_MAINPLL() ) != 0 ):
        raise PtsError("AD9516 didn\'t reset after receive reset signal. This line might be corrupted.") 
    
    print "AD9516 reset line tests succeeded"


def main (card=None, default_directory='.',suite=None):

    if AUTOMATION:
        BOX_USB_VENDOR_ID = 0x10c4 # Cygnal Integrated Products, Inc.
        BOX_USB_DEVICE_ID = 0xea60 # CP210x Composite Device

        print("Looking for calibration box")

        box_tty = find_usb_tty.CttyUSB().find_usb_tty(BOX_USB_VENDOR_ID, BOX_USB_DEVICE_ID)

        if len( box_tty ) < 1:
            raise PtsCritical( "Can't find calibration box. Make sure that it is connected, and that CP210x driver was correctly mounted");
        
        # print("Calibration Box device: %s" % box_tty[0])
        box = calibr_box.CCalibr_box(box_tty[0])
    
        box.select_trigger_loopback(0)
        box.select_output(calibration_box_connections.connections['ref_clk'])
        
    else:
        box = 0;

    specid = spec_identification()[0];
    if specid < 0 :
        raise PtsCritical("Bus number of FmcDac600m12b1chadds was not found")

    carrier=spec( FIRMWARE_PATH, specid, True );
       
    # verifies 
    #    SPI communication with the device
    #    PLL connection to FPGA
    
    ad9516_dev=ad9516(carrier);
    
    # verifies 
    #     presence of reference oscillator
    ad9516_dev.check_refclk();
    
    # verifies
    #    coarse measurement of oscillator frequency
    #    and tuning range
    #    tuning requires DAC's so these are also tested
    measure_clk1(carrier);
    # verifies LD line 
    ad9516_test_ld(carrier );
    # verifies reset line
    ad9516_test_reset(carrier);
    
    
    return 0
        
if __name__ == '__main__' :
    main()

