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

import sys
import rr
import time
import os
from numpy import *
from pylab import *

from ptsexcept import *

import gn4124
import spec_fmc_adc
import fmc_adc
from PAGE.Agilent33250A import *
from PAGE.SineWaveform import *


"""
test11: Test acquisition chain

Note: If not used with Chipscope, requires test00.py to run first to load the gateware!
"""

GN4124_CSR = 0x0

USB_DEVICE = "/dev/ttyUSB0"
RS232_BAUD = 57600
NB_CHANNELS = 4

AWG_SET_SLEEP = 0.3
SSR_SET_SLEEP = 0.05

ACQ_TIMEOUT = 10

MAX_GATEWARE_RELOAD = 10

PRE_TRIG_SAMPLES = 1000
POST_TRIG_SAMPLES = 1000
NB_SHOTS = 1

DMA_LENGTH = 4096 # DMA length in bytes


def load_gateware(default_directory):
    print('Load gateware to FPGA')
    path_fpga_loader = '../../../gnurabbit/user/fpga_loader';
    path_gateware = '../gatewares/spec_fmcadc100m14b4cha.bin';

    gateware_loader = os.path.join(default_directory, path_fpga_loader)
    bitstream = os.path.join(default_directory, path_gateware)
    print gateware_loader + ' ' + bitstream
    os.system( gateware_loader + ' ' + bitstream )

    time.sleep(2);


def open_all_channels(fmc):
    for i in range(1,NB_CHANNELS+1):
        fmc.set_input_range(i, 'OPEN')
        time.sleep(SSR_SET_SLEEP)


def fmc_adc_init(spec, fmc):
    print('Initialise FMC board.')
    fmc.__init__(spec)
    # Reset offset DACs
    fmc.dc_offset_reset()
    # Make sure all switches are OFF
    open_all_channels(fmc)
    # Set trigger
    # hw trig, rising edge, external, sw disable, no delay
    fmc.set_trig_config(1, 0, 1, 1, 0, 0, 0)
    # Set acquisition
    fmc.set_pre_trig_samples(PRE_TRIG_SAMPLES)
    fmc.set_post_trig_samples(POST_TRIG_SAMPLES)
    fmc.set_shots(NB_SHOTS)
    # Print configuration
    fmc.print_adc_core_config()


def set_awg_freq(gen, sine, freq):
    sine.frequency = freq
    gen.play(sine)
    print('Sine frequency:%3.3fMHz')%(sine.frequency/1E6)
    time.sleep(AWG_SET_SLEEP)


def acquisition(gnum, pages, fmc, channel_nb, channel_data):
    # Start acquisition
    fmc.stop_acq()
    #print('Acquisition FSM state : %s') % fmc.get_acq_fsm_state()
    fmc.start_acq()

    # Wait end of acquisition
    timeout = 0
    while('IDLE' != fmc.get_acq_fsm_state()):
        #print fmc.get_acq_fsm_state()
        time.sleep(.1)
        timeout += 1
        if(ACQ_TIMEOUT < timeout):
            print('Acquisition timeout. Check that the AWG is switched ON and properly connected.')
            return 1
            #raise PtsError('Acquisition timeout. Check that the AWG is switched ON and properly connected.')

    # Retrieve data trough DMA
    page1_data_before_dma = gnum.get_memory_page(1)
    gnum.add_dma_item(0x100, pages[1], DMA_LENGTH, 0, 0)
    gnum.start_dma()
    gnum.wait_irq()
    page1_data = gnum.get_memory_page(1)
    page_zeros = [0] * len(page1_data)
    if((page1_data_before_dma == page1_data) or (page_zeros == page1_data)):
        print('Previous page:')
        print page1_data_before_dma[0:20]
        print('Current page:')
        print page1_data[0:20]
        print('### Acquisition or DMA error. ###')
        #raise PtsWarning('Acquisition or DMA error.')
        return 1
    for i in range(len(page1_data)):
        channel_data.append(page1_data[i] & 0xFFFF)
        channel_data.append(page1_data[i]>>16)

    channel_data = channel_data[channel_nb-1::4]
    return 0

def show_result_graph(points, ch_diff):
    pt = array(points)
    freq = pt[:,0]
    a_min = pt[:,1] - pt[:,2]
    a_max = pt[:,1] + pt[:,2]
    semilogx(freq, ch_diff[0::4], 'b', label='Channel 1')
    semilogx(freq, ch_diff[1::4], 'g', label='Channel 2')
    semilogx(freq, ch_diff[2::4], 'r', label='Channel 3')
    semilogx(freq, ch_diff[3::4], 'c', label='Channel 4')
    semilogx(freq, a_min, 'r:', label='Lower limit')
    semilogx(freq, a_max, 'r:', label='Upper limit')
    legend()
    show()
    return 0


def main (default_directory='.'):

    """
    # Load gateware to FPGA
    path_fpga_loader = '../../../gnurabbit/user/fpga_loader';
    path_gateware = '../gatewares/spec_fmcadc100m14b4cha.bin';

    gateware_loader = os.path.join(default_directory, path_fpga_loader)
    bitstream = os.path.join(default_directory, path_gateware)
    print gateware_loader + ' ' + bitstream
    os.system( gateware_loader + ' ' + bitstream )

    time.sleep(2);
    """

    # Objects declaration
    spec = rr.Gennum() # bind to the SPEC board
    gnum = gn4124.CGN4124(spec, GN4124_CSR)
    spec_fmc = spec_fmc_adc.CSpecFmcAdc100Ms(spec)
    fmc = fmc_adc.CFmcAdc100Ms(spec)
    gen = Agilent33250A(device=USB_DEVICE, bauds=RS232_BAUD)
    sine = SineWaveform()

    # Enables DMA interrupts
    spec_fmc.enable_dma_done_irq()
    spec_fmc.enable_dma_error_irq()
    print('Set IRQ enable mask: %.4X'%spec_fmc.get_dma_eic_en_mask())

    # Initialise fmc adc
    fmc_adc_init(spec, fmc)

    # Set sine params
    sine.frequency = 1E6
    sine.amplitude = 0.25
    sine.dc = 0
    print('Sine frequency:%3.3fMHz amplitude:%2.3fVp offset:%2.3fV')%(sine.frequency/1E6, sine.amplitude, sine.dc)

    # Set AWG
    gen.connect()
    gen.play(sine)
    gen.output = True

    # Get physical addresses of the pages for DMA transfer
    pages = gnum.get_physical_addr()

    # Test acquisition chain
    retry_cnt = 0
    error = 0
    channel=1
    for i in range(1000):
        fmc.set_input_range(channel, '1V')
        time.sleep(SSR_SET_SLEEP)
        channel_data = []
        retry = acquisition(gnum, pages, fmc, channel, channel_data)
        if(retry != 0):
            retry_cnt += 1
            print('RETRY: %d')%(retry_cnt)
            if(MAX_GATEWARE_RELOAD < retry_cnt):
                print('Maximium of %d retry exceeded (channel:%d, freq:%2.3fMHz)')%(MAX_GATEWARE_RELOAD, i, points[j][0]/1E6)
                error += 1
                break
            #load_gateware(default_directory)
            #fmc_adc_init(spec, fmc)
            #time.sleep(2)
            break
        diff = max(channel_data)-min(channel_data)
        print('%d:CH%d amplitude:%d')%(i, channel, diff)
        fmc.set_input_range(channel, 'OPEN')

    # Make sure all switches are OFF
    open_all_channels(fmc)

    # Switch AWG OFF
    gen.output = False
    gen.close()

    # Check if an error occured during frequency response test
    if(error != 0):
        pass


if __name__ == '__main__' :
    main()
