#!   /usr/bin/env   python

# Author:
# Wojciech M. Zabolotny <wzab@ise.pw.edu.pl>
# Institute of Electronic Systems, Warsaw University of Technology
# Based on:
# 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 sys import __stdout__

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

import numpy
from pylab import *

#import scipy.io.numpyio as nio

from spec import *
from ad9516 import *
from dac import *
from ptsexcept import *



import calibr_box
import find_usb_tty
import calibration_box_connections

from spec_identification import *

"""
test01:
    DAC tests
"""

AUTOMATION = True

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

DEBUG = False


card=None
default_directory='.'
suite=None

delay = 0;




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")

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


carrier=spec( FIRMWARE_PATH, specid, True );


sys_pll = ad9516(carrier);
dacinst = dac(carrier);
#Number of samples
n_samples = 16384

gen_figs = False


# kind of signal to noise ratio error counter
# errors_snr = [ 0 for i in range(14) ]
# bit power ratio error counter
errors_bpr = [ 0 for i in range(14) ];


MAXATTEMPTS = 2;
RETRYDELAY = 5;

#        warnings.simplefilter('ignore')
# Function below measures spectra of signal in channel 0
def measure_spectrum(bit_amp,urange,f, logname):
    # Number of averaged spectra
    n_repeat=30
    dacinst.set_en(1);
    dacinst.set_ampl_bit(bit_amp)
    dacinst.set_shape(dacinst.SHAPE_SQUARE);
    dacinst.set_frequency(f);
    time.sleep(2.0)
    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")
    

#   
  
#     print bit_amp
    with open("/tmp/data.bin","rb") as fin:
        x=fin.read(512) # Discard header
        d=numpy.fromfile(file=fin,dtype=numpy.int16).reshape(n_samples*n_repeat,4)
        for i in range(0,n_repeat):
            #print i
            y=range(n_samples*i,n_samples*(i+1))
            dd=scipy.signal.detrend(d[y,0])
            #dd=scipy.signal.detrend(dd)
            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 ):
    plot(w_bkgr)
    title("background: bit value=%d frequency=%g" % (i, fm))
    grid()
    savefig("spectrum_bg_u%i_f_%g.png" % (i, fm))
    show()
    clf()
    plot(w_sig_bk)
    title("s+b: bit value=%d frequency=%g" % (i, fm))
    grid()
    savefig("spectrum_with_bg_u%i_f_%g.png" % (i, fm))
    show()
    clf()
    plot(w_sig)
    title("s+b-b: bit value=%d frequency=%g" % (i,  fm))
    grid()
    savefig("spectrum_with_rmvd_bg_u%d_f_%g.png" % (i, fm))
    show()
    clf()


def verify_power_ratio( b, s_pow, m_pow ):
    if s_pow/m_pow < 0:    
        # raise PtsError("DAC: bit nr %d does not generate output signal, P/Pt=%g", (b, s_pow/m_pow))
        # print "DAC: bit nr %d does not generate output signal, P/Pt=%g" % (b, s_pow/m_pow)
        print "DAC: bit nr %d measurement failed P/Pt=%g" % (b, s_pow/m_pow);
        return False;
    else:
        return True;

def verify_bit_power_ratio( b, s_pow, old_s_pow ):
    
    global errors_bpr
    
    r_pow = s_pow / old_s_pow
    
    if (r_pow < 2) or (r_pow > 8):
        
        if errors_bpr[b] < MAXATTEMPTS:
            
            errors_bpr[b] += 1;
            
            print >> __stdout__, "Bit test failed, but will be retried in %d seconds. Make sure that test probe is connected correctly" % (RETRYDELAY)
            print "Bit test failed, but will be retried."

            time.sleep(RETRYDELAY);
            print >> __stdout__, "Retrying"
            
            return False;

        else:
            # raise PtsError("DAC: incorrect increase of power when switching from bit nr %d to bit nr %d : %g (expected between 2 and 8). Took %d attmempts." % (b-1, b,  r_pow, MAXATTEMPTS))
            print "DAC: incorrect increase of power when switching from bit nr %d to bit nr %d : %g (expected between 2 and 8)" % (b-1, b,  r_pow)
            print >> __stdout__,  "DAC: incorrect increase of power when switching from bit nr %d to bit nr %d : %g (expected between 2 and 8)" % (b-1, b,  r_pow)

            return True;
        

    else:
        return True;

def test_proc(fm, logname ):
    
    results = [ [0,0,0] for i in range(14) ]
    
    # Iterate over possible bit values
    b = 0
    # old_s_pow = 1
    while b <= 13:
        
        retry = False;

        print "Testing bit %d" % b
        print >> __stdout__, "Testing bit %d" % b
        
        i = 1 << b
            #Select the voltage range appropriately
        if i < 512:
            urange = "1"
        else:
            urange = "10"
        
        #Measure the spectrum of the background noise
        w_bkgr=measure_spectrum(0, urange,fm, logname)
        w_sig_bk=measure_spectrum(i, urange,fm, logname)
        w_sig=w_sig_bk-w_bkgr
        
        if gen_figs:
            print_figs( w_bkgr, w_sig_bk, w_sig );

        #Expected position of the signal
        n_pos=int((n_samples*fm)/100e6+1.5)
        #Mean power (with noise!)
        m_pow=sum(w_sig_bk)/n_samples
        #Power of the signal per bin
        s_pow=sum(w_sig[(n_pos-2):(n_pos+3)])/5
        
        #Check if the signal is visible
        retry = not verify_power_ratio( b, s_pow, m_pow );

        #If this is not bit number 0, check if power increased ba ca.4 (in fact between 2 and 8)
        #comparing to the signal generated by the previous bit
        if b > 0:
            # errror = not verify_bit_power_ratio( s_pow, old_s_pow );
            retry = not verify_bit_power_ratio( b, s_pow, results[b-1][1] );
        
        # choose next bit    
        if not retry :        
            # old_s_pow = s_pow
            results[b] = [ i, s_pow, m_pow ];
            # Go to the next bit
            b += 1;
        elif retry and b > 0:
            b -= 1;


    #Now check if the result is reasonable
    #Signal should be visible
    return results
    
def main (card=None, logname=None, default_directory='.',suite=None):
    #Test frequencies
    f=[10.512e6,12.121e6]
    #Enforce generation of graphic files
    
    global gen_figs
    global errors_bpr
    
    gen_figs = False
    
    print >> __stdout__, "Please connect test probe to resistor R15 or R16 and confirm with ENTER button"
    raw_input("")
    
   

    if logname == None :
#         os.system( default_directory + "log_fmcdac600m")
        logname = '../../../log_fmcdac600m12b1chadds/tmp'
    
    test_fail = False;
    failed = []
    
    for fm in f:
#         print "Frequency=%g" % fm
        print >> __stdout__, "Frequency=%g" % fm
        
        errors_bpr = [ 0 for i in range(14) ];
        res=test_proc(fm, logname)
        for i in range(0,len(res)):
            
            if errors_bpr[i] == MAXATTEMPTS :
                test_fail = True;
                failed.append(i);

            r=res[i]
            if i==0:
                print "bit=%d P=%g P/Pt=%g errors=%g" % (r[0], r[1], r[1]/r[2], errors_bpr[i])
            else:
                print "bit=%d P=%g P/Pt=%g ratio=%g errors=%g" % (r[0], r[1], r[1]/r[2], r[1]/res[i-1][1], errors_bpr[i])
    
    if test_fail == True:
        raise PtsError("Some bits %s tests have failed." % failed )
    else:
        print "DAC test succeeded"
    
    print >> __stdout__, "Test finished, you may remove test probe."
    return 0

if __name__ == '__main__' :
    main()
