#!   /usr/bin/env   python

import sys
import time
import os
import time
from sys import __stdout__

import warnings
with warnings.catch_warnings():
    warnings.simplefilter("ignore", category=DeprecationWarning)
    import scipy
    import scipy.signal

import numpy
from pylab import *
from spec import *
from ad9516 import *
from dac import *
from ptsexcept import *
import copy


from spec_identification import *

"""
test08
    Beam clock output
        Generate known signal on beam clock coutput
        Sample with FMC-ADC
        Check if signal of expected frequency was captured (with the spectrum)

"""

AUTOMATION = True
DEBUG = False
gen_figs = False

FIRMWARE_PATH = '/../gateware/syn/spec_top.bin'
WORK_PATH='/python/'
LOG_PATH = 'log_fmcdac600m12b1chadds/tmp'

card=None
default_directory='.'
suite=None

BEAM_FREQ = 15.6250e6
ADC_CHANNEL = 1

#Number of samples
N_SAMPLES = 16384


# Function below measures spectra of signal in channel 0
def measure_spectrum(urange,f, logname, adcid):
    # Number of averaged spectra
    n_repeat=30

    curr = os.getcwd()

    if DEBUG:
        os.system(curr+WORK_PATH+"acq.sh "+str(N_SAMPLES*n_repeat)+" "+urange + " " + str( adcid ) +"")
    else:
        os.system(curr+WORK_PATH+"acq.sh "+str(N_SAMPLES*n_repeat)+" "+urange + " " + str( adcid ) +" 2>>" + logname + " 1>/dev/null")
    
    with open("/tmp/data.bin","rb") as fin:
        # Discard header
        x=fin.read(512) 
        # read samples from file
        # all the channels are triggered simultaneously
        d=numpy.fromfile(file=fin,dtype=numpy.int16).reshape(N_SAMPLES*n_repeat,4)
        # for each subset of data
        for i in range(0,n_repeat):
            # get the vector indexes
            y=range(N_SAMPLES*i,N_SAMPLES*(i+1))

            # get raw data
            raw = d[y,ADC_CHANNEL]
            
            # detrend raw data
            dd=scipy.signal.detrend(raw)
            
            # calculate fft
            wt=abs(scipy.fft(dd))
            
            #Range correction
            if int(urange)==10:
                wt *= 10
            
            if i==0:
                w=wt*wt
            else:
                w+=wt*wt

    return w/n_repeat

def print_figs( w_bkgr, w_sig_bk, w_sig, pos ):
    figure(1)
    semilogy(w_bkgr)
    ylim(bottom=1e5)  # adjust the top leaving bottom unchanged
    title("Background spectra. Expected position of signal: %d" % (pos))
    grid()
    savefig("spectrum_bg.png")

    figure(2)
    semilogy(w_sig_bk)
    ylim(bottom=1e5)  # adjust the top leaving bottom unchanged
    title("Signal and noise spectra. Expected position of signal: %d" % (pos))
    grid()
    savefig("spectrum_sig_bg.png")

    figure(3)
    semilogy(w_sig)
    ylim(bottom=1e5)  # adjust the top leaving bottom unchanged
    title("Signal spectra. Expected position of signal: %d" % (pos))
    grid()
    savefig("spectrum_sig.png")

    show()
    clf()





def test_proc( logname, adcid, pll ):
    
    #Select the voltage range appropriately
    urange = "10"
    fm = BEAM_FREQ
    FREQ_DIFF_THD =5
    THD_POW_RATIO = 1000
    print "\n\nTesting the BEAM CLK\n"

    print "The clock is measured with the ADC. Signal frequency and power is verified.\n"

    print "Disabling BEAM CLK output in IC26"
    pll.write_reg(0xf4, 2)
    pll.update_config()
    time.sleep(1)
    
    print "Measuring the noise"
    w_bkgr=measure_spectrum(urange,fm, logname, adcid)

    print "Enabling the BEAM_CLK output in IC26"
    pll.test_config()
    time.sleep(1)

    print "Measuring the signal (with noise)"
    w_sig_bk=measure_spectrum(urange,fm, logname, adcid)
    
    print "Removing the noise from the measurement"
    w_sig=w_sig_bk-w_bkgr
        
    #Expected position of the signal
    n_pos=int((N_SAMPLES*fm)/100e6+1.5)

    print "Expected position: %d" % n_pos
    
    # Find two biggest bins
    sorted_samples = copy.copy(w_sig)
    sorted_samples.sort()
    second_biggest = sorted_samples[-2]

    # Find positions of the biggest bins
    found_pos=numpy.where(w_sig >= second_biggest)
    found_pos=found_pos[0]
    print "Found maximums: " + str(found_pos)

    if gen_figs:
        print_figs( w_bkgr, w_sig_bk, w_sig, n_pos );
    
    print "Maximum accepted distance is: %d bins" % FREQ_DIFF_THD
    for p in found_pos:
        if abs(p-n_pos) < FREQ_DIFF_THD:
            print "The maximum of %d fulfilled the criteria" % p
            break
    else:
        print "Non of the selected maximums fulfilled the criteria"
        raise PtsException("Didn't find a signal of frequency generated by BEAM CLK output")

    print "\nChecking the power"
    #Mean power (with noise!)
    m_pow=sum(w_sig)/N_SAMPLES
    #Power of the signal per bin
    s_pow=sum(w_sig[(n_pos-2):(n_pos+3)])/5

    # print "Power of the signal: %f. Mean power: %f." % (s_pow/1e9, m_pow/1e9 )
    pow_ratio = s_pow/m_pow
    print "Ratio power of signal and mean power is: %f. Expected it to be bigger than %f" % (pow_ratio, THD_POW_RATIO)

    if pow_ratio < THD_POW_RATIO:
        raise PtsException("Ratio of power of BEAM CLK signal to the noise was too low.")

    
def main (card=None, logname=None, default_directory='.',suite=None, configure_fpga=True):
    
    if logname == None :
        logname = '../log_fmcdac600m12b1chadds/tmp'

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

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

    carrier=spec( FIRMWARE_PATH, specid, configure_fpga );

    sys_pll = IC9(carrier);

    print "Configuring the DAC to generate reference frequency for IC26"
    dacinst = dac(carrier);

    print "Configuring the IC26 to lock on REF input and generate %f Mhz" % (BEAM_FREQ/1e6)
    pll = IC26(carrier);
    pll.test_config()
    time.sleep(2)

    print "Checking if the PLL locked"
    pll.check_lock()
    
  
  
    res=test_proc(logname, adcid, pll)
    
    return 0

if __name__ == '__main__' :
    
    WORK_PATH='/./'
    import argparse

    parser = argparse.ArgumentParser(description='Start test08')
    parser.add_argument('-p', action='store_true')
    args = vars(parser.parse_args())

    if args['p']:
        main(configure_fpga=False)
    else:
        main()

