#!   /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 system modules
import sys
import time
import os
import math

# Import common modules
import rr
from ptsexcept import *
import csr
import gn4124_nodma
import i2c
import onewire
import ds18b20
import eeprom_24aa64
from vic import *

# Import register maps
from dma_eic_regs import *
from fmc_tdc_eic_regs import *

# Import specific modules
#import rr
from sdb import *
from csr import *
from onewire import *
from gn4124 import *

# Add common modules location tp path
sys.path.append('../../../../')
sys.path.append('../../../../gnurabbit/python/')
sys.path.append('../../../../common/')


"""
FMC TDC class
"""

class CFMCTDC:


    #GNUM_CSR_ADDR_DUMMY = 0x00000
    # Carrier One Wire
    #CARR_ONEWIRE_ADDR   = 0x10000

    # Carrier CSR info
    CARRIER_CSR_ADDR    = 0x20000
    CSR_BSTM_TYPE       = 0x04

    # VIC
    VIC_ADDR            = 0x30000

    # Mezzanine One Wire
    MEZZ_ONEWIRE_ADDR   = 0x50000

    # TDC core configuration
    TDC_CORE_ADDR       = 0x51000

    # Mezzanine EIC
    MEZZ_EIC_ADDR       = 0x52000

    # Mezzanine I2C
    MEZZ_I2C_ADDR       = 0x53000
    MEZZ_EEPROM_ADDR    = 0x50

    # TDC memory for timestamps retrieval
    TDC_TSTAMPS_ADDR    = 0x54000

    # ACAM register addresses and expected register contents
    ACAM_READBACK_ADDR = [0x40, 0x44, 0x48, 0x4C, 0X50, 0x54, 0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C, 0x70, 0x78]
    ACAM_READBACK_REGS = [0xC1F0FC81, 0xC0000000, 0xC0000E02, 0xC0000000, 0xC200000F, 0xC02007D0, 0xC00000FC, 0xC0001FEA, 0x00000000, 0x00000000, 0x00000000, 0xC3000000, 0xC4000800, 0xC0000000]

    # DMA length in bytes
    DMA_LENGTH = 4096

    # Write pointer register
    WP_MASK = 0xFFF
    WP_OVERFLOW_MASK = 0xFFFFF000

    # Timestamp meta-data
    META_CHANNEL_MASK = 0x07
    META_SLOPE_MASK = 0x10
    META_FIFO_LF_MASK = 0xF00
    META_FIFO_EF_MASK = 0xF000
    META_SLOPE = ['falling', 'rising']


###############################################################################################


    def __init__(self, bus):
        # Objects delcaration
        self.bus = bus;
        self.gnum = gn4124_nodma.CGN4124_nodma(self.bus)

        # Set GNUM local bus frequency
        self.gnum.set_local_bus_freq(160)
        print "Gennum local bus clock %d MHz"%(self.gnum.get_local_bus_freq())
        time.sleep(2)

        # Reset FPGA
        print "Resetting FPGA"
        #self.gnum.rstout33_cycle()
        time.sleep(2)


        self.tdc_regs = csr.CCSR(self.bus, self.TDC_CORE_ADDR)
        self.tdc_tstamps = csr.CCSR(self.bus, self.TDC_TSTAMPS_ADDR)
        self.carrier_csr = csr.CCSR(self.bus, self.CARRIER_CSR_ADDR)
        self.vic = CVic(self.bus, self.VIC_ADDR)
        self.fmc_eic = CCSR(self.bus, self.MEZZ_EIC_ADDR, FMC_TDC_EIC_REGS)


	# One Wire carrier
	#self.carr_onewire = onewire.COpenCoresOneWire(self.bus, self.CARR_ONEWIRE_ADDR, 624, 124)
        #self.carr_ds18b20 = ds18b20.CDS18B20(self.carr_onewire, 0)

	# One Wire mezzanine
	self.mezz_onewire = onewire.COpenCoresOneWire(self.bus, self.MEZZ_ONEWIRE_ADDR, 624, 124)
        self.mezz_ds18b20 = ds18b20.CDS18B20(self.mezz_onewire, 0)

	# I2C mezzanine
        self.mezz_i2c = i2c.COpenCoresI2C(self.bus, self.MEZZ_I2C_ADDR, 249)
        self.mezz_eeprom_24aa64 = eeprom_24aa64.C24AA64(self.mezz_i2c, self.MEZZ_EEPROM_ADDR)


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

        # Configure VIC
        #self.vic.print_regs()
        self.vic.set_polarity(1)      # output active high
        self.vic.enable_emu_edge(750) # emulate edge sensitive output (pulse width = 750 * 1/sys_clk = 6us)
        self.vic.enable_int(0)        # enable interrupts from fmc0 eic
        #self.vic.enable_int(1)        # enable interrupts from dma eic
        self.vic.enable_module()
        self.fmc_eic_addr = self.vic.get_vector_addr(0)
        #self.dma_eic_addr = self.vic.get_vector_addr(1)


###############################################################################################

    # Read bitstream type
    def read_bitstream_type(self):
        return self.carrier_csr.rd_reg(0x04)

    # Returns mezzanine unique ID
    def mezz_get_unique_id(self):
        return self.mezz_ds18b20.read_serial_number()


    # Returns mezzanine temperature
    def mezz_get_temp(self):
        serial_number = self.mezz_ds18b20.read_serial_number()
        if(serial_number == -1):
            return -1
        else:
            return self.mezz_ds18b20.read_temp(serial_number)


    # Returns carrier unique ID
    def carr_get_unique_id(self):
        return self.carr_ds18b20.read_serial_number()


    # Returns carrier temperature
    def carr_get_temp(self):
        serial_number = self.carr_ds18b20.read_serial_number()
        if(serial_number == -1):
            return -1
        else:
            return self.carr_ds18b20.read_temp(serial_number)


    # scan FMC i2c bus
    def mezz_i2c_scan(self):
        print 'Scanning I2C bus...',
        return self.mezz_i2c.scan()

    # write to EEPROM on system i2c bus
    def mezz_i2c_eeprom_write(self, addr, data):
        return self.mezz_eeprom_24aa64.wr_data(addr, data)

    # read from  EEPROM on system i2c bus
    def mezz_i2c_eeprom_read(self, addr, size):
        return self.mezz_eeprom_24aa64.rd_data(addr, size)


    # write to EEPROM on system i2c bus
    def mezz_i2c_eeprom_write_page(self, data):
        byte_to_write = len(data)
        addr = 0
        while byte_to_write:
            if byte_to_write > 32:
                size = 32
            else:
                size = byte_to_write
            self.mezz_eeprom_24aa64.wr_page(addr,data[addr:(addr+size)])
            byte_to_write -= size
            addr += size
            time.sleep(0.005) # have to wait between writes otherwise the eeprom gives NACK on the i2c bus


    # read from EEPROM on system i2c bus
    def mezz_i2c_eeprom_read_chunk(self, addr, size):
        return self.mezz_eeprom_24aa64.rd_seq(addr, size)

    # Configures ACAM    
    def config_acam(self):
        print "Loading ACAM and TDC core registers"
        time.sleep(1)
        self.tdc_regs.wr_reg(0x00, 0x1F0FC81)
        self.tdc_regs.wr_reg(0x04, 0x0)
        self.tdc_regs.wr_reg(0x08, 0xE02)
        time.sleep(1)
        self.tdc_regs.wr_reg(0x0C, 0x0)
        self.tdc_regs.wr_reg(0x10, 0x200000F)
        self.tdc_regs.wr_reg(0x14, 0x2007D0)
        self.tdc_regs.wr_reg(0x18, 0x3)
        self.tdc_regs.wr_reg(0x1C, 0x1FEA)
        #self.tdc_regs.wr_reg(0x2C, 0xFF0000)
        self.tdc_regs.wr_reg(0x2C, 0x03000000)
        self.tdc_regs.wr_reg(0x30, 0x4000000)
        self.tdc_regs.wr_reg(0x38, 0x0)
        self.tdc_regs.wr_reg(0xFC, 0x4)
        time.sleep(1)

    def load_acam_config(self):
        print "Loading ACAM configuration"
        self.tdc_regs.wr_reg(0xFC, 0x4)
        time.sleep(1)

    def reset_acam(self):
        print "Reseting ACAM"
        self.tdc_regs.wr_reg(0xFC, 0x100)
        time.sleep(1)


   # Configures DAC and PLL
    def configure_mezz_dac(self, dac_word):
        print "\nConfiguring mezzanine DAC to '0x%4X'"%dac_word
        self.tdc_regs.wr_reg(0x98, dac_word) # default: xA8F5, max: xFFFF, min: x0000
        self.tdc_regs.wr_reg(0xFC, 0x800)
        dac_status_test = self.tdc_regs.rd_reg(0x98)-dac_word
        if dac_status_test == 0:
            print "DAC configured OK!"
        else:
            print "DAC configuration failed: config word '0x%4X'; read-back word '0x%4X'"%(dac_word, self.tdc_regs.rd_reg(0x98))


#    def readback_acam_config(self):
#        self.tdc_regs.wr_reg(0xFC, 0x8)
#        time.sleep(1)
#        acam_regs = []
#        for i in range(len(self.ACAM_READBACK_REGS)):
#            acam_regs.append (self.tdc_regs.rd_reg(i))
#            if (self.tdc_regs.rd_reg(i) == self.ACAM_READBACK_REGS[i]):
#                print "ACAM IC8: reg 0x%02X: 0x%08X OK"%(i, self.tdc_regs.rd_reg(i))
#            else:
#                print "ERROR! ACAM IC8: reg 0x%02X: received 0x%08X; expected 0x%08X"%(i, self.tdc_regs.rd_reg(i), self.ACAM_READBACK_REGS[i])
#        return acam_regs


    def readback_acam_config(self):
        self.tdc_regs.wr_reg(0xFC, 0x8)
        time.sleep(1)
        acam_regs = []
        for i in self.ACAM_READBACK_ADDR:
            acam_regs.append (self.tdc_regs.rd_reg(i))
            #print "ACAM IC8: reg 0x%02X: 0x%08X OK"%(i, self.tdc_regs.rd_reg(i))
        return acam_regs

    # Read ACAM status register
    def read_acam_status(self):
        self.tdc_regs.wr_reg(0xFC, 0x10)
        return self.tdc_regs.rd_reg(0x70)

    # Deactivate ACAM channel 1
    def deact_acam_ch1(self):
        self.tdc_regs.wr_reg(0x08, 0xE12)
        self.tdc_regs.wr_reg(0xFC, 0x4)

    # Reactivate ACAM channel 1
    def react_acam_ch1(self):
        self.tdc_regs.wr_reg(0x08, 0xE02)
        self.tdc_regs.wr_reg(0xFC, 0x4)

    # Read ACAM START01
    def read_acam_start01(self):
        self.tdc_regs.wr_reg(0xFC, 0x80)
        print "Start01 0x%8X"%(self.tdc_regs.rd_reg(0x68))

    def enable_channels(self):
        print "Enabling channels"
        self.tdc_regs.wr_bit(0x84, 7, 1)

    def disable_channels(self):
        print "Disabling channels"
        self.tdc_regs.wr_bit(0x84, 7, 0)

    def channel_term(self, channel, enable):
        self.tdc_regs.wr_bit(0x84, channel-1, enable)
        #print "0x%08X"%self.tdc_regs.rd_reg(0x84)

    def set_local_utc(self, utc):
        self.tdc_regs.wr_reg(0x80, utc)
        self.tdc_regs.wr_reg(0xFC, 0x200)

    def get_wrabbit_utc(self):
        print "White Rabbit UTC: 0x%.8X"%(self.tdc_regs.rd_reg(0xA4))
        return self.tdc_regs.rd_reg(0xA4)

    def get_local_utc(self):
        print "Local UTC: 0x%.8X"%(self.tdc_regs.rd_reg(0xA0))
        return self.tdc_regs.rd_reg(0xA0)

    def get_utc(self):
        print "UTC: 0x%.8X"%(self.tdc_regs.rd_reg(0xAC))
        return self.tdc_regs.rd_reg(0xAC)

    def start_acq(self):
        self.tdc_regs.wr_reg(0xFC, 0x1)

    def stop_acq(self):
        self.tdc_regs.wr_reg(0xFC, 0x2)
        print "Aquisition stopped"


    def tdc_core_test(self):
        for i in range(0,150,4):
            print "Iteration %d: reg[%.3X]: 0x%.8X" %(i/4, i, self.tdc_regs.rd_reg(i))
            time.sleep(0.5)
        return self.tdc_regs.rd_reg(0xFC)


    def set_irq_tstamp_thresh(self,tstamp_thresh):
        self.tdc_regs.wr_reg(0x90, tstamp_thresh) # irq tstaps threshold; only 9 LSbits are significant
        print "IRQ tstamps threshold set at: 0x%.8X"%(self.tdc_regs.rd_reg(0x90))

    def set_irq_time_thresh(self, time_thresh):
        self.tdc_regs.wr_reg(0x94, time_thresh) # irq time (msec) threshold
        print "IRQ time threshold set at   : 0x%.8X"%(self.tdc_regs.rd_reg(0x94))

    def get_pointer(self):
        return (self.WP_MASK & self.tdc_regs.rd_reg(0xA8))

    def get_pointer2(self):
        return (self.tdc_regs.rd_reg(0xA8))

    def get_overflow_counter(self):
        return ((self.WP_OVERFLOW_MASK & self.tdc_regs.rd_reg(0xA8)) >> 12)


    def deactivate_tstamps_ch1(self):
        self.tdc_regs.wr_reg(0x9C, 0x01)
        print "Deactivated timestamps from ch1"

    def read_deactivate_reg(self):
         print "Deactivate reg: 0x%.8X"%(self.tdc_regs.rd_reg(0x9C))

    def deactivate_tstamps_ch2(self):
        self.tdc_regs.wr_reg(0x9C, 0x2)
        print "Deactivated timestamps from ch2"

    def deactivate_tstamps_ch3(self):
        self.tdc_regs.wr_reg(0x9C, 0x4)
        print "Deactivated timestamps from ch3"

    def deactivate_tstamps_ch4(self):
        self.tdc_regs.wr_reg(0x9C, 0x8)
        print "Deactivated timestamps from ch4"

    def deactivate_tstamps_ch5(self):
        self.tdc_regs.wr_reg(0x9C, 0x10)
        print "Deactivated timestamps from ch5"

    # White Rabbit
    def wrabbit_status(self):
        return (self.tdc_regs.rd_reg(0xB0))

    def wrabbit_enable(self):
        self.tdc_regs.wr_reg(0xB4, 0x1)

    def wrabbit_disable(self):
        self.tdc_regs.wr_reg(0xB4, 0x00000000)

    def wrabbit_rd_ctrl_reg(self):
        print "White Rabbit control reg: 0x%.8X"%(self.tdc_regs.rd_reg(0xB4))

    #======================================================================
    # Vectored Interrupt Controller (VIC)

    # Get current interrupt vector address
    def vic_get_current_vector_addr(self):
        return self.vic.get_int_vector_addr()

    # Acknowledge current vector
    def vic_ack_current_vector(self):
        self.vic.int_ack()

    # Get raw interrupt status
    def vic_get_raw_status(self):
        return self.vic.get_raw_int_status()


    #======================================================================
    # FMC-ADC Enhanced Interrupt Controller (EIC)

    # Print FMC-ADC EIC register map
    def print_eic_regs(self):
        self.fmc_eic.print_reg_map()

    # Enable timestamps interrupt
    def enable_tstamps_irq(self):
        self.fmc_eic.set_field('IER', 'TSTAMPS', 1)

    # Disable timestamps interrupt
    def disable_tstamps_irq(self):
        self.fmc_eic.set_field('IDR', 'TSTAMPS', 1)

    # Clear timestamps interrupt
    def clear_tstamps_irq(self):
        self.fmc_eic.set_field('ISR', 'TSTAMPS', 1)

    # Get tstamps interrupt status
    def get_tstamps_status(self):
        return self.fmc_eic.get_field('ISR', 'TSTAMPS')

    # Enable time interrupt
    def enable_time_irq(self):
        self.fmc_eic.set_field('IER', 'TIME', 1)

    # Disable time interrupt
    def disable_time_irq(self):
        self.fmc_eic.set_field('IDR', 'TIME', 1)

    # Clear time interrupt
    def clear_time_irq(self):
        self.fmc_eic.set_field('ISR', 'TIME', 1)

    # Get time interrupt status
    def get_time_status(self):
        return self.fmc_eic.get_field('ISR', 'TIME')

    # Enable ACAMerr interrupt
    def enable_acam_err_irq(self):
        self.fmc_eic.set_field('IER', 'ACAM_ERR', 1)

    # Disable ACAMerr interrupt
    def disable_acam_err_irq(self):
        self.fmc_eic.set_field('IDR', 'ACAM_ERR', 1)

    # Clear ACAMerr interrupt
    def clear_acam_err_irq(self):
        self.fmc_eic.set_field('ISR', 'ACAM_ERR', 1)

    # Get ACAMerr interrupt status
    def get_acam_err_status(self):
        return self.fmc_eic.get_field('ISR', 'ACAM_ERR')

    # Get FMC-TDC EIC enable mask
    def get_eic_en_mask(self):
        return self.fmc_eic.get_reg('IMR')

    # Get FMC-TDC interrupt source
    def get_eic_src(self):
        return self.fmc_eic.get_reg('ISR')


    #======================================================================
    # DMA Enhanced Interrupt Controller (EIC)

    # Print DMA EIC register map
    def print_dma_eic_regs(self):
        self.dma_eic.print_reg_map()

    # Enable DMA done interrupt
    def enable_dma_done_irq(self):
        self.dma_eic.set_field('IER', 'DMA_END', 1)

    # Disable DMA done interrupt
    def disable_dma_done_irq(self):
        self.dma_eic.set_field('IDR', 'DMA_END', 1)

    # Clear DMA done interrupt
    def clear_dma_done_irq(self):
        self.dma_eic.set_field('ISR', 'DMA_END', 1)

    # Enable DMA error interrupt
    def enable_dma_error_irq(self):
        self.dma_eic.set_field('IER', 'DMA_ERR', 1)

    # Disable DMA error interrupt
    def disable_dma_error_irq(self):
        self.dma_eic.set_field('IDR', 'DMA_ERR', 1)

    # Clear DMA error interrupt
    def clear_dma_error_irq(self):
        self.dma_eic.set_field('ISR', 'DMA_ERR', 1)

    # Get DMA EIC enable mask
    def get_dma_eic_en_mask(self):
        return self.dma_eic.get_reg('IMR')

    # Get DMA EIC interrupt source
    def get_dma_eic_src(self):
        return self.dma_eic.get_reg('ISR')

    # Get DMA done interrupt status
    def get_dma_done_status(self):
        return self.dma_eic.get_field('ISR', 'DMA_END')

    # Get DMA error interrupt status
    def get_dma_error_status(self):
        return self.dma_eic.get_field('ISR', 'DMA_ERR')

    #======================================================================


    # Check for IRQs
    def check_irq(self, verbose=0):
        if verbose:
            print("\n----------Entered check irq------------")
            print("VIC enable mask: 0x%08X"%(self.vic.get_int_enable_mask()))
            print("TDC EIC enable mask: 0x%08X"%self.get_eic_en_mask())
            #print("DMA EIC enable mask: 0x%08X"%self.get_dma_eic_en_mask())
        self.gnum.wait_irq(0)

        # Check the interrupt
        irq_vect = self.vic_get_current_vector_addr()
        if verbose:
            print("VIC current vector : 0x%08X"%irq_vect)
            print("-----------Out of check irq------------\n")


    #======================================================================
    def get_timestamps(self, verbose=0):
        # Read the number of bytes to be read from the board
        dma_length_tmp = self.get_pointer()
        if dma_length_tmp == 0: # add overflow> 0 
            dma_length = 4096
        else:
            dma_length = dma_length_tmp
        carrier_addr = 0x0

        # Calculate the number of DMA item required to get the data
        items_required = int(math.ceil(dma_length/float(self.DMA_LENGTH)))
        if(128 < items_required):
            print('Required items: %d')%items_required
            raise Exception('Current gn4124 class only supports up to 128 items.')
        if(verbose):
            print('Required items: %d')%items_required

        # Configure DMA
        for num in range(items_required):
            if(items_required == num+1):
                next_item = 0
                item_length = (dma_length-(num*self.DMA_LENGTH))
            else:
                next_item = 1
                item_length = self.DMA_LENGTH
            if(0 == num):
                item_start_addr = carrier_addr
            else:
                item_start_addr = carrier_addr + (num*self.DMA_LENGTH)
            if(verbose):
                print("item nb:%d item_carrier_addr:0x%.8X item_host_addr:0x%.8X item_length:%d next_item:%d)")%(num,item_start_addr,self.dma_pages[num+1],item_length,next_item)
            self.gnum.add_dma_item(item_start_addr, self.dma_pages[num+1], item_length, 0, next_item)
        if(verbose):
            if(items_required > 1):
                items = self.gnum.get_memory_page(0)
                print('DMA items:')
                for i in range(items_required*8):
                    print('%.4X: %.8X')%(i*4,items[i])

        # Start DMA
        dma_finished = 0
        if(verbose):
            print "Start DMA"
        self.gnum.start_dma()
        """
        # Poll on DMA status
        print "Wait for DMA done"
        while('Done' == self.gnum.get_dma_status()):
            time.sleep(0.01)
        print "DMA done!"
        """
        # Wait for end of DMA interrupt
        if verbose:
            print("-----Before DMA IRQ_WAIT-----")
            print("VIC enable mask: 0x%08X"%(self.vic.get_int_enable_mask()))
            print("DMA EIC enable mask: 0x%08X"%self.get_dma_eic_en_mask())
        self.gnum.wait_irq(verbose)
        print("-----After DMA IRQ_WAIT-----")
        # Check if interrupt is DMA DONE
        if verbose:
            print('Check if interrupt is DMA_DONE')
        irq_src = self.get_dma_eic_src()
        irq_vect = self.vic_get_current_vector_addr()
        if verbose:
            print("DMA EIC irq source : %.8X"%irq_src)
            print("VIC current vector : 0x%08X"%irq_vect)
        if(irq_vect == self.dma_eic_addr):
            if(self.get_dma_done_status()):
                self.clear_dma_done_irq()
                self.vic_ack_current_vector()
                if verbose:
                    print("OK!!!DMA EIC irq source : %.8X"%self.get_dma_eic_src())
            else:
               print("Bad IRQ source : 0x%08X"%irq_src)
        else:
            print("Bad IRQ vector. expected:0x%08X got:0x%08X" %(self.dma_eic_addr, irq_vect))
        if verbose:
            print('DMA finished!')

        # Retrieve data from host memory
        data = []
        for i in range(items_required):
            data += self.gnum.get_memory_page(i+1)
        if(verbose):
            print('data length:%d')%(len(data)*4)
            #for i in range(len(data)):
            #    print data[i]

        # Format timestamps
        if(verbose):
            print "Timestamps retreived:"
        raw_timestamps = []
        timestamps = []
        for i in range(0,dma_length/4,4):
            # timestamp value
            timestamp = data[i+2] * 1E12 + data[i+1] * 8E3 + data[i] * 81.03
            # timestamp metadata
            channel = self.META_CHANNEL_MASK & data[i+3]
            slope = ((self.META_SLOPE_MASK & data[i+3]) >> 4)
            fifo_lf = ((self.META_FIFO_LF_MASK & data[i+3]) >> 8)
            fifo_ef = ((self.META_FIFO_EF_MASK & data[i+3]) >> 12)
            # putting everything together
            raw_timestamps.append((data[i+3]<<96)+(data[i+2]<<64)+(data[i+1]<<32)+data[i])
            timestamps.append([timestamp, channel, slope, fifo_lf, fifo_ef])
            #if(verbose):
            #    print "[%03d] sec:%20.3f channel:%d slope:%7s fifo_lf:%d fifo_ef:%d"%(i/4,timestamp, channel, self.META_SLOPE[slope], fifo_lf, fifo_ef)


        eurika = 0
        for i in range(0,dma_length/4,8):
            # for debug check if UTC second changes
            if (data[i+2] != data[i+6]):
                #print "Euriika! second changed in these timestamps"
                eurika = 1

        if(verbose):
            print "Number of timestamps = %d" % (len(timestamps))
            #for i in range(len(timestamps)):
            #    print timestamps[i]

        return timestamps, data

    #======================================================================
    def get_timestamps_nodma(self, verbose=0):
        # Read the number of bytes to be read from the board
        length_tmp = self.get_pointer()
        if length_tmp == 0: # add overflow> 0 
            length = 4096
        else:
            length = length_tmp

        # Retrieve data from host memory
        data = []
        for i in range(0,length,4):
            data.append(self.tdc_tstamps.rd_reg(i))
        if(verbose):
            print('data length:%d')%(len(data))
            for i in range(len(data)):
                print "0x%08X"%(data[i])

        # Format timestamps
        if(verbose):
            print "Timestamps retreived:"
        raw_timestamps = []
        timestamps = []
        for i in range(0,len(data),4):
            # timestamp value
            timestamp = data[i+2] * 1E12 + data[i+1] * 8E3 + (data[i]) * 81.03
            # timestamp metadata
            channel = self.META_CHANNEL_MASK & data[i+3]
            slope = ((self.META_SLOPE_MASK & data[i+3]) >> 4)
            fifo_lf = ((self.META_FIFO_LF_MASK & data[i+3]) >> 8)
            fifo_ef = ((self.META_FIFO_EF_MASK & data[i+3]) >> 12)
            # putting everything together
            raw_timestamps.append((data[i+3]<<96)+(data[i+2]<<64)+(data[i+1]<<32)+data[i])
            timestamps.append([timestamp, channel, slope, fifo_lf, fifo_ef])
            #if(verbose):
            #    print "[%03d] sec:%20.3f channel:%d slope:%7s fifo_lf:%d fifo_ef:%d"%(i/4,timestamp, channel, self.META_SLOPE[slope], fifo_lf, fifo_ef)

        if(verbose):
            print "Number of timestamps = %d" % (len(timestamps))
            print ("channel: %d")%channel
            #for i in range(len(timestamps)):
            #    print timestamps[i]

        return timestamps, data


    #======================================================================
    def get_timestamps_nodma_noutc(self, verbose=0):
        # Read the number of bytes to be read from the board
        length_tmp = self.get_pointer()
        if length_tmp == 0: # add overflow> 0 
            length = 4096
            if (verbose):
                print "Raw data bytes: 4096"
        else:
            length = length_tmp
            if (verbose):
                print "Raw data bytes: %d"%length_tmp

        # Retrieve data from host memory
        data = []
        for i in range(0,length,4):
            data.append(self.tdc_tstamps.rd_reg(i))

        #if (verbose):
        #    for i in range(len(data)):
        #        print "0x%08X"%(data[i])

        if (verbose):
            print ("-------------------------------------------")
            for i in range(len(data)):
                if (i-3)%4 == 0:
                    print "0x%08X"%(data[i])
                else:
                    print "0x%08X"%(data[i]),
            print ("-------------------------------------------\n")

        # Format timestamps
        raw_timestamps = []
        timestamps = []
        for i in range(0,len(data),4):
            # timestamp value
            timestamp = data[i+2] * 1E12 + data[i+1] * 8E3 + data[i] * 81.03
            timestamp_noutc = timestamp%1e12
            # timestamp metadata
            channel = self.META_CHANNEL_MASK & data[i+3]
            slope = ((self.META_SLOPE_MASK & data[i+3]) >> 4)
            fifo_lf = ((self.META_FIFO_LF_MASK & data[i+3]) >> 8)
            fifo_ef = ((self.META_FIFO_EF_MASK & data[i+3]) >> 12)
            # putting everything together
            timestamps.append([timestamp_noutc, channel, slope, fifo_lf, fifo_ef])

        #if(verbose):
            #print "Number of timestamps = %d" % (len(timestamps))
            #for i in range(len(timestamps)):
            #    print timestamps[i]

        return timestamps, data


if __name__ == '__main__' :
    main()
