class TRACE_FFT_WINDOW_WIB(Gtk.Window):
    """
  This window displays a live ADC redout and its FFT
  """
    def __init__(self):
        Gtk.Window.__init__(self, title="ADC View Window")

        self.set_default_size(800, 800)

        self.figure = Figure(figsize=(8, 8), dpi=100)

        sw = Gtk.ScrolledWindow()
        self.add(sw)
        # A scrolled window border goes outside the scrollbars and viewport
        sw.set_border_width(10)

        canvas = FigureCanvas(self.figure)  # a Gtk.DrawingArea
        canvas.set_size_request(750, 750)
        sw.add_with_viewport(canvas)

        self.show_all()

        self.sw = sw
        self.canvas = canvas

        self.femb = None
        self.reset()

    def reset(self):
        self.femb = FEMB_UDP()
        self.figure.clf()
        self.ax1 = self.figure.add_subplot(211)
        self.ax2 = self.figure.add_subplot(212)
        self.plot1 = self.ax1.plot([], [])
        self.plot2 = self.ax2.plot([], [])
        self.ani = animation.FuncAnimation(self.figure,
                                           self.plotData,
                                           interval=1000)  #, blit=True)
        self.canvas.draw()

    def plotData(self, iFrame):
        self.ax1.cla()
        self.ax2.cla()
        self.ax1.set_xlabel("Time [us]")
        self.ax1.set_ylabel("Sample Value [ADC Counts]")
        self.ax2.set_xlabel("Frequency [MHz]")
        self.ax2.set_ylabel("|Y(freq)|")
        t, adc, frq, ampl = self.getTraceAndFFT()
        if t == None:
            return None
        self.plot1 = self.ax1.plot(t, adc)
        self.plot2 = self.ax2.plot(frq, ampl, 'r')
        self.canvas.draw()
        return self.plot1

    def getTraceAndFFT(self):
        """
    Gets trace from FEMB and returns 4 1D arrays:
        times, ADC counts, frequencies, Amplitude
    """
        Yfft_total = []
        first = 1
        #data = self.femb.get_data(10)
        data = self.femb.get_data_packets(1)
        if data == None:
            #time.sleep(1.)
            return None, None, None, None
        if len(data) == 0:
            #time.sleep(1.)
            return None, None, None, None
        xpoint = []
        ypoint = []
        num = 0

        print("HERE")
        for samp in data:
            print(samp)

        return None, None, None, None
        for samp in data:
            chNum = ((samp >> 12) & 0xF)
            sampVal = (samp & 0xFFF)
            #print str(chNum) + "\t" + str(sampVal) + "\t" + str( hex(sampVal) )
            #if chNum == 0:
            xpoint.append(num * 0.5)
            ypoint.append(sampVal)
            num = num + 1

        xarr = np.array(xpoint)
        yarr = np.array(ypoint)

        Fs = 2.0
        # sampling rate
        Ts = 1.0 / Fs
        # sampling interval
        t = np.arange(0, 1, Ts)  # time vector

        n = len(yarr)  # length of the signal
        k = np.arange(n)
        T = n / Fs
        frq = k / T  # two sides frequency range
        frq = frq[:n // 2]  # one side frequency range

        Yfft = np.fft.fft(yarr) / n  # fft computing and normalization
        Yfft = Yfft[:n // 2]
        frq = frq[1:]
        Yfft = Yfft[1:]

        #do averaging and normalization, very messy
        pos = 0
        total = 0
        for x in np.nditer(Yfft):
            #print abs(x)
            total = total + abs(x)
            if first == 1:
                Yfft_total.append(abs(x))
            else:
                Yfft_total[pos] = Yfft_total[pos] + abs(x)
            pos = pos + 1

        first = 0
        if total < 0:
            #time.sleep(0.1)
            return None, None, None, None

        pos = 0
        Yfft_norm = []
        for bin in Yfft_total:
            Yfft_norm.append(bin / total)

        return xarr, yarr, frq, Yfft_norm
class FEMB_CONFIG(FEMB_CONFIG_BASE):

    def __init__(self,exitOnError=True):
        super().__init__(exitOnError=exitOnError)
        #declare board specific registers
        self.FEMB_VER = "adctestP1single"
        self.REG_RESET = 0
        self.REG_ASIC_RESET = 1
        self.REG_ASIC_SPIPROG = 2
        self.REG_SEL_CH = 7
        self.REG_HS = 17
        self.REG_FESPI_BASE = 0x250 # 592 in decimal
        self.REG_ADCSPI_BASE = 0x200 # 512 in decimal
        self.REG_FESPI_RDBACK_BASE = 0x278 # 632 in decimal
        self.REG_ADCSPI_RDBACK_BASE = 0x228 # 552 in decimal
        self.REG_LATCHLOC1_4 = 4
        self.REG_LATCHLOC5_8 = 14
        self.REG_CLKPHASE = 6

        self.REG_LATCHLOC1_4_data = 0x6
        self.REG_LATCHLOC5_8_data = 0x0
        self.REG_CLKPHASE_data = 0xfffc0000

        self.REG_LATCHLOC1_4_data_1MHz = 0x5
        self.REG_LATCHLOC5_8_data_1MHz = 0x0
        self.REG_CLKPHASE_data_1MHz = 0xffff0000

        self.REG_LATCHLOC1_4_data_cold = 0x6
        self.REG_LATCHLOC5_8_data_cold = 0x0
        self.REG_CLKPHASE_data_cold = 0xfffc0000

        self.REG_LATCHLOC1_4_data_1MHz_cold = 0x4
        self.REG_LATCHLOC5_8_data_1MHz_cold = 0x0
        self.REG_CLKPHASE_data_1MHz_cold = 0xfffc0001

        self.ADC_TESTPATTERN = [0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca, 0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef]

        ##################################
        # external clock control registers
        ##################################
        self.FPGA_FREQ_MHZ = 200 # frequency of FPGA clock in MHz
        self.REG_EXTCLK_RD_EN_OFF = 23
        self.REG_EXTCLK_ADC_OFF = 21
        self.REG_EXTCLK_ADC_WID = 22
        self.REG_EXTCLK_MSB_OFF = 25
        self.REG_EXTCLK_MSB_WID = 26
        self.REG_EXTCLK_PERIOD = 20
        self.REG_EXTCLK_LSB_FC_WID2 = 32
        self.REG_EXTCLK_LSB_FC_OFF1 = 29
        self.REG_EXTCLK_RD_EN_WID = 24
        self.REG_EXTCLK_LSB_FC_WID1 = 30
        self.REG_EXTCLK_LSB_FC_OFF2 = 31
        self.REG_EXTCLK_LSB_S_WID = 28
        self.REG_EXTCLK_LSB_S_OFF = 27
        self.REG_EXTCLK_INV = 33
        ##################################
        ##################################

        self.NASICS = 1
        self.FUNCGENINTER = Keysight_33600A("/dev/usbtmc1",1)
        self.POWERSUPPLYINTER = RigolDP800("/dev/usbtmc0",["CH2","CH3","CH1"]) # turn on CH2 first
        self.F2DEFAULT = 0
        self.CLKDEFAULT = "fifo"

        ## Firmware update related variables
        self.FIRMWAREPATH2MHZ = "/home/oper/Documents/CarlosForkedRepo/femb_python/femb_python/test_measurements/adc_clock_test/code/S_SKT_ADC_CHP_TST.sof"
        #self.FIRMWAREPATH1MHZ = "/opt/sw/releases/femb_firmware-0.1.0/adc_tester/S7_1M_SBND_FPGA.sof"
        self.FIRMWAREPROGEXE = "/opt/sw/intelFPGA/17.0/qprogrammer/bin/quartus_pgm"
        #self.FIRMWAREPROGCABLE = "USB-Blaster"
        self.FIRMWAREPROGCABLE = "USB-BlasterII"
        self.SAMPLERATE = 2e6

        #initialize FEMB UDP object
        self.femb = FEMB_UDP()
        self.adc_reg = ADC_ASIC_REG_MAPPING()

    def resetFEMBBoard(self): #cp 1/17/18
        #
        #   resetFEMBBoard()
        #       sends a 1 to register 1 for "instantaneous" ASIC reset.
        #       sends a 0 to register 1 to ensure reset is not locked in.
        #
        #       procedure:
        #           line 29: FPGA to ASIC reset
        #           line 30: wait 5 ms
        #           line 31: FPGA to ASIC disable reset
        #
        
        print (" FEMB_CONFIG--> Reset FEMB (10 seconds) --")
        #Reset FEMB system
        self.femb.write_reg ( self.REG_RESET, 1)
        time.sleep(5.)
        self.femb.write_reg ( self.REG_RESET, 0)
        time.sleep(2.)
        print (" FEMB_CONFIG--> Reset FEMB is DONE\n")
        

    def initBoard(self):
        """
        % initBoard()
        % 	set up default registers. 
        % 	first wave in setting clock settings.
        """
        
        print ("FEMB_CONFIG--> initBoard() -> Initialize FEMB --")
        
        # Frame size is multiple of 13, so 0xFACE is consistently the first 2 bytes.
        frame_size = settings.frame_size
        if (frame_size%13 != 0):
            frame_size = 13 * (frame_size//13)
            
        self.femb.write_reg(10, frame_size)
        time.sleep(0.1)
    
        if (self.femb.read_reg(10) != frame_size):
            sys.exit("FEMB_CONFIG--> initBoard() -> Frame Size not set correctly, something wrong with FPGA communication")
        
        print ("FEMB_CONFIG--> initBoard() -> Chip tester version {}".format(hex(self.femb.read_reg(0x101))))

        # Set to WIB Mode and start by reading out chip 1
        # Channel Setting is irrelevant in WIB mode
        self.femb.write_reg(8, 0x80000001)                  # WIB_MODE   <= reg8_p(0)
        self.femb.write_reg(7, 0x80000000)                  # CHN_select <= reg7_p(7 downto 0)

        """ SHIFT DATA BUS """
        # LATCH_LOC_0 <= reg4_p(7 downto 0)
        self.femb.write_reg(settings.LATCHLOC_reg, settings.LATCHLOC_data)
        
        """ SHIFT DATA BUS """
        # CLK_selectx <= reg6_p(7 downto 0)
        self.femb.write_reg(settings.CLKPHASE_reg, settings.CLKPHASE_data)
        
#        self.femb.write_reg( 9, 0)

        # Write Coarse Clock Control
        self.femb.write_reg(21, settings.reg21_value[0])
        self.femb.write_reg(21, settings.reg21_value[1])
        self.femb.write_reg(21, settings.reg21_value[2])
        self.femb.write_reg(21, settings.reg21_value[3])
        self.femb.write_reg(21, settings.reg21_value[4])
        self.femb.write_reg(21, settings.reg21_value[5])

        self.femb.write_reg(22, settings.reg22_value[0])    # RESET Offset      
        self.femb.write_reg(23, settings.reg23_value[0])    # RESET Width
        
        self.femb.write_reg(24, settings.reg24_value[0])    # READ Offset
        self.femb.write_reg(25, settings.reg25_value[0])    # READ Width
        
        self.femb.write_reg(26, settings.reg26_value[0])    # IDXM Offset
        self.femb.write_reg(27, settings.reg27_value[0])    # IDXM Width
        
        self.femb.write_reg(28, settings.reg28_value[0])    # IDXL Offset
        self.femb.write_reg(29, settings.reg29_value[0])    # IDXL Width
        
        self.femb.write_reg(30, settings.reg30_value[0])    # IDL1 Offset
        self.femb.write_reg(31, settings.reg31_value[0])    # IDL1 Width
                                                            
        self.femb.write_reg(32, settings.reg32_value[0])    # IDL2 Offset
        self.femb.write_reg(33, settings.reg33_value[0])    # IDL2 Width

        #Fine Control
        self.femb.write_reg(34, settings.reg34_value[0])    # C0 & C1 fine clock settings   
        self.femb.write_reg(35, settings.reg35_value[0])    # C2 & C3 fine clock settings
        self.femb.write_reg(36, settings.reg36_value[0])    # C2 & C3 fine clock settings

        #set default value to FEMB ADCs
        #clk = 2 is external
        #clk = 0 is internal
        self.adc_reg.set_adc_board( d=0, pcsr=0, pdsr=0, slp=0, tstin=1,
                 clk = 0, frqc = 1, en_gr = 0, f0 = 0, f1 = 0, 
                 f2 = 0, f3 = 0, f4 = 0, f5 = 1, slsb = 0) # set to internal 1/31/18 cp
                 
        self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0x30)
        self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0)
        self.configAdcAsic()
        
        print (" FEMB_CONFIG--> initBOARD() -> Initialize FEMB is DONE\n")
    """    
    def syncADC(self):
        #   syncADC()
        #
        #       procedures:
        #           1.  set channel/global registers ensure F5=1, so
        #               test data is selected and pipelined. Just as 
        #               in labview. 
        #           2.  configure ADC ASIC 
        #           3.

        
        print ("\n FEMB_CONFIG--> Start sync ADC--")


        self.select_chn(1) # channel 0 & write clocks
        self.select_chn(3) # channel 0 & write clocks
        self.select_chn(1) # channel 0 & write clocks
        self.adc_reg.set_adc_global(chip = settings.chip_num, f5 = 1) # Test DATA
        self.configAdcAsic()
            
        print (" FEMB_CONFIG --> syncADC() -> Test ADC {}".format(settings.chip_num))
        print (" FEMB_CONFIG --> syncADC() -> self.adc_reg.set_adc_global() \n")
#        for i in range(10,20,1):
#        print ("Register {} {}".format(i, hex(self.femb.read_reg(i))))
            
        unsync = self.testUnsyncNew(settings.chip_num)
        if unsync != True:
            print (" FEMB_CONFIG --> ADC {} not synced, try to fix".format(settings.chip_num))
            response = self.fixUnsyncNew(a)
            if (response != True):
                sys.exit (" FEMB_CONFIG --> ADC {} could not sync".format(settings.chip_num))
        elif (unsync == True):
            print ("FEMB_CONFIG--> ADC {} synced!".format(settings.chip_num))
                
            self.adc_reg.set_adc_global(chip = settings.chip_num, f5 = 1)
            self.configAdcAsic()
            
        self.REG_LATCHLOC1_4_data = self.femb.read_reg( settings.LATCHLOC_reg) 
        self.REG_CLKPHASE_data    = self.femb.read_reg( settings.CLKPHASE_reg)
        print ("FEMB_CONFIG--> Final Latch latency " + str(hex(self.REG_LATCHLOC1_4_data)))
        print ("FEMB_CONFIG--> Final Phase Shift " + str(hex(self.REG_CLKPHASE_data)))
        self.FinalSyncCheck()
        print ("FEMB_CONFIG--> ADC passed Sync Test!")
    """
    def syncADC(self,iASIC=None):
        #turn on ADC test mode
        print("FEMB_CONFIG--> Start sync ADC")
        reg3 = self.femb.read_reg (3)
        newReg3 = ( reg3 | 0x80000000 )

        self.femb.write_reg ( 3, newReg3 ) #31 - enable ADC test pattern
        time.sleep(0.1)                

        alreadySynced = True
        for a in range(0,self.NASICS,1):
            print("FEMB_CONFIG--> Test ADC " + str(a))
            unsync, syncDicts = self.testUnsync(a)
            if unsync != 0:
                alreadySynced = False
                print("FEMB_CONFIG--> ADC not synced, try to fix")
                self.fixUnsync(a)
        latchloc1_4 = self.femb.read_reg ( self.REG_LATCHLOC1_4 ) 
        latchloc5_8 = self.femb.read_reg ( self.REG_LATCHLOC5_8 )
        clkphase    = self.femb.read_reg ( self.REG_CLKPHASE )
        if self.SAMPLERATE == 1e6:
            if self.COLD:
                self.REG_LATCHLOC1_4_data_1MHz_cold = latchloc1_4
                self.REG_LATCHLOC5_8_data_1MHz_cold = latchloc5_8
                self.REG_CLKPHASE_data_1MHz_cold    = clkphase
            else:
                self.REG_LATCHLOC1_4_data_1MHz = latchloc1_4
                self.REG_LATCHLOC5_8_data_1MHz = latchloc5_8
                self.REG_CLKPHASE_data_1MHz    = clkphase
        else: # 2 MHz
            if self.COLD:
                self.REG_LATCHLOC1_4_data_cold = latchloc1_4
                self.REG_LATCHLOC5_8_data_cold = latchloc5_8
                self.REG_CLKPHASE_data_cold    = clkphase
            else:
                self.REG_LATCHLOC1_4_data = latchloc1_4
                self.REG_LATCHLOC5_8_data = latchloc5_8
                self.REG_CLKPHASE_data    = clkphase
        print("FEMB_CONFIG--> Latch latency {:#010x} {:#010x} Phase: {:#010x}".format(latchloc1_4,
                        latchloc5_8, clkphase))
        self.femb.write_reg ( 3, (reg3&0x7fffffff) )
        self.femb.write_reg ( 3, (reg3&0x7fffffff) )
        print("FEMB_CONFIG--> End sync ADC")
        return not alreadySynced,latchloc1_4,latchloc5_8 ,clkphase

    def testUnsync(self, adc, npackets=10):
        print("Starting testUnsync adc: ",adc)
        adcNum = int(adc)
        if (adcNum < 0 ) or (adcNum > 7 ):
                print("FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number")
                return

        #loop through channels, check test pattern against data
        syncDataCounts = [{} for i in range(16)] #dict for each channel
        for ch in range(0,16,1):
                self.selectChannel(adcNum,ch, 1)
                time.sleep(0.05)                
                data = self.femb.get_data(npackets)
                if data == None:
                    continue
                for samp in data:
                        if samp == None:
                                continue
                        #chNum = ((samp >> 12 ) & 0xF)
                        sampVal = (samp & 0xFFF)
                        if sampVal in syncDataCounts[ch]:
                            syncDataCounts[ch][sampVal] += 1
                        else:
                            syncDataCounts[ch][sampVal] = 1
        # check jitter
        badSync = 0
        maxCodes = [None]*16
        syncDicts = [{}]*16
        for ch in range(0,16,1):
            sampSum = 0
            maxCode = None
            nMaxCode = 0
            for code in syncDataCounts[ch]:
                nThisCode = syncDataCounts[ch][code]
                sampSum += nThisCode
                if nThisCode > nMaxCode:
                    nMaxCode = nThisCode
                    maxCode = code
            maxCodes[ch] = maxCode
            syncDicts[ch]["maxCode"] = maxCode
            syncDicts[ch]["nSamplesMaxCode"] = nMaxCode
            syncDicts[ch]["nSamples"] = sampSum
            syncDicts[ch]["zeroJitter"] = True
            if len(syncDataCounts[ch]) > 1:
                syncDicts[ch]["zeroJitter"] = False
                badSync = 1
                diff = sampSum-nMaxCode
                frac = diff / float(sampSum)
                print("Sync Error: Jitter for Ch {:2}: {:8.4%} ({:5}/{:5})".format(ch,frac,diff,sampSum))
        for ch in range(0,16,1):
            maxCode = maxCodes[ch]
            correctCode = self.ADC_TESTPATTERN[ch]
            syncDicts[ch]["data"] = True
            syncDicts[ch]["maxCodeMatchesExpected"] = True
            if maxCode is None:
                syncDicts[ch]["data"] = False
                badSync = 1
                print("Sync Error: no data for ch {:2}".format(ch))
            elif maxCode != correctCode:
                syncDicts[ch]["maxCodeMatchesExpected"] = True
                badSync = 1
                print("Sync Error: mismatch for ch {:2}: expected {:#03x} observed {:#03x}".format(ch,correctCode,maxCode))
        return badSync, syncDicts

    def selectChannel(self,asic,chan,hsmode=1,singlechannelmode=None):
        """
        asic is chip number 0 to 7
        chan is channel within asic from 0 to 15
        hsmode: if 0 then streams all channels of a chip, if 1 only te selected channel. defaults to 1
        singlechannelmode: not implemented
        """
        hsmodeVal = int(hsmode) & 1;
        asicVal = int(asic)
        if (asicVal < 0 ) or (asicVal >= self.NASICS ) :
                print( "femb_config_femb : selectChan - invalid ASIC number, only 0 to {} allowed".format(self.NASICS-1))
                return
        chVal = int(chan)
        if (chVal < 0 ) or (chVal > 15 ) :
                print("femb_config_femb : selectChan - invalid channel number, only 0 to 15 allowed")
                return

        #print( "Selecting ASIC " + str(asicVal) + ", channel " + str(chVal))

        self.femb.write_reg ( self.REG_HS, hsmodeVal)
        regVal = (chVal << 8 ) + asicVal
        self.femb.write_reg( self.REG_SEL_CH, regVal)

    """
    def testUnsyncNew(self, chip):

        print("\n FEMB_CONFIG --> testUnsyncNew() -> chip = {} --".format(chip))        
        
        adcNum = int(chip)
        if (adcNum < 0 ) or (adcNum > 3 ):
            print (" FEMB_CONFIG --> testUnsyncNew() -> Invalid asic number, must be between 0 and 3")
            return
            
        for j in range(100):    #reset sync error
            self.femb.write_reg(11, 1) # ERROR_RESET <= reg11_p(0)
            time.sleep(0.01)
            self.femb.write_reg(11, 0) # ERROR_RESET <= reg11_p(0)
            time.sleep(0.01)
            
            if (chip == 0):
                conv_error = self.femb.read_reg(12)     # reg12_i => x"" & CONV_ERROR 
                header_error = self.femb.read_reg(13)   # reg13_i => HDR2_ERROR & HDR1_ERROR 
                
#            elif (chip == 1):
#                conv_error = self.femb.read_reg(50)    # reg50_i => x"0000" & CONV_ERROR_1
#                header_error = self.femb.read_reg(51)  # reg51_i => HDR2_ERROR_2 & HDR1_ERROR_2
#            elif (chip == 2):
#                conv_error = self.femb.read_reg(52)
#                header_error = self.femb.read_reg(53)
#            elif (chip == 3):
#                conv_error = self.femb.read_reg(54)
#                header_error = self.femb.read_reg(55)
            
            error = False
            
            if (conv_error != 0): # CONV_ERROR exists
                print (" FEMB_CONFIG --> testUnsyncNew() -> Convert error({})!  Trial {}".format(hex(conv_error),j))
                error = True
            else:
                print (" FEMB_CONFIG --> testUnsyncNew() -> No Convert Error ({})  Trial {}!".format(hex(conv_error),j)) #convert = 0
                
            if (header_error != 0): # HEADER_ERROR exists
                print (" FEMB_CONFIG --> testUnsyncNew() -> Header error ({})!".format(hex(header_error)))
                error = True
            else:
                print (" FEMB_CONFIG --> testUnsyncNew() -> No Header Error({})!  Trial {}".format(hex(header_error),j)) #not finding header
                
            if (error == False): #break loop if no error found
                print (" FEMB_CONFIG --> testUnsyncNew() -> Correct on Loop {}  Trial {}".format(j,j))
                break
                #return True
            elif (j > 30):
                print (" FEMB_CONFIG --> testUnsyncNew() -> Convert error({})!  Trial {}".format(hex(conv_error),j))
                print (" FEMB_CONFIG --> testUnsyncNew() -> Header error ({})!  Trial {}".format(hex(header_error),j))
                #sync_status = self.femb.read_reg(self.REG_ASIC_SPIPROG) >> 24
                #print ("FEMB_CONFIG--> Register 2 Sync status is {}".format(hex(sync_status)))
                return False
            else:
                self.configAdcAsic(False)
                #print ("Loop {}".format(j))
           
        for ch in range(0,16,1):
            for test in range(0,200,1):
                data = self.get_data_chipXchnX(chip = adcNum, chn = ch, packets = 1)#issue here?
                #print("unsyncNew data -> {}".format(data))
                if (len(data) == 0):
                    print (" FEMB_CONFIG--> testUnsyncNew() -> Sync response didn't come in")
                    return False
                for samp in data[0:len(data)]:
                    if samp != self.ADC_TESTPATTERN[ch]:
                        print (" FEMB_CONFIG --> testUnsyncNew() -> Chip {} chn {} looking for {} but found {}".format(
                                adcNum, ch, hex(self.ADC_TESTPATTERN[ch]), hex(samp)))
                        return False
                        
        return True
    """

    def initFunctionGenerator(self):
        """
        rm = visa.ResourceManager()
        try:
            #keysight = rm.open_resource('USB0::0x0957::0x5707::MY53802435::0::INSTR')
            keysight = rm.open_resource(u'USB0::2391::22279::MY53802422::0::INSTR')
            print ("Keysight Initialize--> Instrument Connected")
        except VisaIOError:
            print ("Keysight Initialize--> Exact system name not found")
            keysight = rm.open_resource(rm.list_resources()[0])
        
        #Sets the self.instrument object in "GPIB_FUNCTIONS" to the 
        #connected instrument, this makes it very easy to reference later
        time.sleep(0.1)
        keysight.write("Source1:Apply:Triangle {},{},{}".format(settings.frequency,settings.amplitude,settings.offset))
        keysight.write("Output1:Load 50")
        #keysight.write("Output1:Load INFINITY")
        keysight.write("Source1:Burst:Mode Triggered")
        keysight.write("Source1:Burst:Ncycles 1")
        keysight.write("Source1:Burst:Phase {}".format(settings.phase_start))
        keysight.write("Source1:Burst:State ON")
        keysight.write("Initiate1:Continuous OFF")
        
        return keysight
        """
    def configAdcAsic(self): #cp 1/29/18 #helper
        """
        config()
        
        """   
        print("FEMB_CONFIG -> configAdcAsic() --")    
    
        Adcasic_regs = self.adc_reg.REGS
        #ADC ASIC SPI registers
        self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0x40)
        self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0)
        time.sleep(0.01)
        self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0x20)
        self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0)
        time.sleep(0.01)
        self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0x40)
        self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0)
        time.sleep(0.01)

        self.select_chn(1) # channel 1 & write clocks
        self.select_chn(3) # channel 3 & write clocks
        self.select_chn(1) # channel 1 & write clocks

        for k in range(10):            
            i = 0
            for regNum in range(self.REG_ADCSPI_BASE,self.REG_ADCSPI_BASE+len(Adcasic_regs),1):
                    self.femb.write_reg( regNum, Adcasic_regs[i])
                    i = i + 1
                    
            # Program ADC ASIC SPI
            self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0)
            time.sleep(.05)
            self.femb.write_reg ( self.REG_ASIC_SPIPROG, 1)
            time.sleep(.05)
            self.femb.write_reg ( self.REG_ASIC_SPIPROG, 1)
            time.sleep(.05)
            #self.femb.write_reg ( self.REG_ASIC_SPIPROG, 0)

            # Check ADC ASIC SPI
            readback_regs = []
            i = 0
            for regNum in range(self.REG_ADCSPI_RDBACK_BASE,self.REG_ADCSPI_RDBACK_BASE+len(Adcasic_regs),1):
                readback_regs.append(self.femb.read_reg(regNum))
                #print ( "femb_config_sbnd.py -> configAdcAsic() -> readback reg: " + str(hex(regNum)) + " from base: " + str(hex(Adcasic_regs[i])))
                i = i + 1
            
            i=0
            for i in range (0,len(readback_regs),1): #Why is this reading out extra adc asic registers?
                if (Adcasic_regs[i] != readback_regs[i]):
                    print ("\t FEMB_CONFIG --> CONFIG() ERROR -> configAdcAsic() -> Sent Adcasic_reg not correct = " + str(hex(Adcasic_regs[i])) + " , rb_reg = " + str(hex(readback_regs[i])) )
                else:
                    continue
                    #print ("femb_config_sbnd.py -> configAdcAsic() -> Adcasic_reg correct = " + str(hex(Adcasic_regs[i])) + " , rb_reg = " + str(hex(readback_regs[i])) )
            
#            val = self.femb.read_reg ( self.REG_ASIC_SPIPROG ) 
            wrong = False
#
#            if (((val & 0x10000) >> 16) != 1):
#                #print ("FEMB_CONFIG--> Something went wrong when programming ADC 1")
#                wrong = True
                
#            if (((val & 0x40000) >> 18) != 1):
#                #print ("FEMB_CONFIG--> Something went wrong when programming ADC 2")
#                wrong = True
                
#            if (((val & 0x100000) >> 20) != 1):
#                #print ("FEMB_CONFIG--> Something went wrong when programming ADC 3")
#                wrong = True
                
#            if (((val & 0x400000) >> 22) != 1):
#                #print ("FEMB_CONFIG--> Something went wrong when programming ADC 4")
#                wrong = True

            if (wrong == True and k == 9):
                print ("\tFEMB_CONFIG--> CONFIG() -> SPI_Status")
                print (hex(val))
                sys.exit("\tFEMB_CONFIG--> CONFIG() -> femb_config_femb : Wrong readback. ADC SPI failed")
                return
                
            elif (wrong == 0): 
                print ("\tFEMB_CONFIG--> CONFIG() -> ADC ASIC SPI is OK")
                break
            #else:
                #print ("FEMB_CONFIG--> Try {}, since SPI response was {}".format(k + 2, hex(val)))

    def FinalSyncCheck(self):
        #
        #   FinalSyncCheck()
        #
        #       procedures:   
        #           line 337: set chip [determine which chip is being sync'd]
        #           line 339: set global register [send test data from PC to FPGA (where is this data going?)  F5=1  
        #           line 340: write SPI (wtf is SPI?)
        
        print ("FEMB_CONFIG--> Final sync check to make sure")
        for a in settings.chips_to_use:
            
            self.adc_reg.set_adc_global(chip = a, f5 = 1)
            self.configAdcAsic()
            self.select_chn(1) # channel 0 & write clocks
            self.select_chn(3) # channel 0 & write clocks
            self.select_chn(1) # channel 0 & write clocks
            # quad board settings:
            #self.select_chip(chip = a)
            
            # single board settings:
            #select_chip is not necessary

            badSync = 0
            for ch in range(0,16,1):
                for test in range(0,100,1):
                    data = self.get_data_chipXchnX(chip = a, chn = ch, packets = 1)
                    if (len(data) == 0):
                        print ("FEMB_CONFIG--> Sync response bad.  Exiting...")
                        return 1
                    for samp in data[0:len(data)]:
                        if samp != self.ADC_TESTPATTERN[ch]:
                            badSync = 1 
                            print ("FEMB_CONFIG--> Chip {} chn {} looking for {} but found {}".format(
                                    a, ch, hex(self.ADC_TESTPATTERN[ch]), hex(samp)))
                        if badSync == 1:
                                break
                    #print("time after checking the sample {}".format(time.time()))
                    if badSync == 1:
                        break
                #print("time after checking 100 samples {}".format(time.time()))
                if badSync == 1:
                    self.femb.write_reg( 9, 1)
                    sys.exit("FEMB_CONFIG--> Failed final check looking at channel test values")

            self.configAdcAsic()
            print ("FEMB_CONFIG--> Chip {} recieved the correct test values!".format(a))
        
            resp = self.testUnsyncNew(a)
            if (resp == False):
                self.femb.write_reg(9, 1)
                sys.exit("FEMB_CONFIG--> Sync failed in the final check")                
                
        self.adc_reg.set_adc_global(chip = a, f5 = 0)
#        for i in range (100):
#            sync_status = self.femb.read_reg(self.REG_ASIC_SPIPROG) >> 24
#            if ((sync_status & 0x3F) != 0):
#
#                if (i == 99):
#                    print ("FEMB_CONFIG--> Register 2 giving back a sync error")
#                    print ("Sync status is {}".format(hex(sync_status)))
#                    sys.exit("Done with trying")
#
#                self.configAdcAsic(False)
#                
#            else:
#                print ("FEMB_CONFIG--> No Sync error through Register 2 check: ({})!".format(hex(sync_status)))
#                break

            
    def fixUnsyncNew(self, adc):

        print("\n femb_config_sbnd.py -> fixUnsyncNew() -> adc = " + str(adc) + "\n")        
        
        adcNum = int(adc)
        if (adcNum < 0) or (adcNum > 3):
                print ("FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number")
                return

        initLATCH1_4 = self.femb.read_reg( settings.LATCHLOC_reg)
        initPHASE = self.femb.read_reg( settings.CLKPHASE_reg)
        
        #loop through sync parameters
        shiftMask = (0xFF << 8*adcNum)
        initSetting = (initLATCH1_4 & shiftMask) >> (8*adcNum)
        print ("FEMB_CONFIG--> First testing around default value of {}".format(initSetting))
        for phase in range(0,4,1):
            clkMask = (0x3 << (adcNum * 2))
            testPhase = ( (initPHASE & ~(clkMask)) | (phase << (adcNum * 2)) ) 
            self.femb.write_reg( settings.CLKPHASE_reg, testPhase)
            #print ("Init Setting is {}".format(hex(initSetting)))
            #print ("Will test {}, {}, and {}".format(initSetting - 1, initSetting, initSetting + 1))
            for shift in range(initSetting - 1,initSetting + 2,1):
                print ("\n\tfemb_config_sbnd.py -> fixUnsyncNew -> This time, we're testing {}\n".format(shift))
                testShift = ( (initLATCH1_4 & ~(shiftMask)) | (shift << 8*adcNum) )
                self.femb.write_reg( settings.LATCHLOC_reg, testShift)
                print ("FEMB_CONFIG--> Trying to sync Chip {} with Latch Lock:{} and Phase:{}".format(adcNum, 
                       hex(testShift), hex(testPhase)))
                       
                #test link
                unsync = self.testUnsyncNew(adcNum)
                if unsync == True :
                    print ("FEMB_CONFIG--> ADC {} synchronized".format(adc))
                    self.REG_LATCHLOC1_4_data = testShift
                    self.REG_CLKPHASE_data = testPhase
                    return True
            #Then try all settings
        print ("FEMB_CONFIG--> Now testing the rest of them")
        for phase in range(0,4,1):
            clkMask = (0x3 << (adcNum * 2))
            testPhase = ( (initPHASE & ~(clkMask)) | (phase << (adcNum * 2)) ) 
            self.femb.write_reg( settings.CLKPHASE_reg, testPhase)
            #First test latch lock settings close to default values
            shiftMask = (0xFF << 8*adcNum)
            initSetting = initLATCH1_4 & shiftMask
            for shift in range(0,16,1):
                testShift = ( (initLATCH1_4 & ~(shiftMask)) | (shift << 8*adcNum) )
                self.femb.write_reg( settings.LATCHLOC_reg, testShift)
                print ("FEMB_CONFIG--> Trying to sync Chip {} with Latch Lock:{} and Phase:{}".format(adcNum, 
                       hex(testShift), hex(testPhase)))
                       
                #test link
                unsync = self.testUnsyncNew(adcNum)
                if unsync == True :
                    print ("FEMB_CONFIG--> ADC {} synchronized".format(adc))
                    self.REG_LATCHLOC1_4_data = testShift
                    self.REG_CLKPHASE_data = testPhase
                    return True
        #if program reaches here, sync has failed
        print ("FEMB_CONFIG--> ADC SYNC process failed for ADC # " + str(adc))
        return False
    
    def select_chn(self, chn): 
        """
        % select_chn()
        %       This function is used in sending instructions to fpga to select chip.
        %       There is not an option to select a chip for single socket boards. 
        %       This function is mostly relevent for using on quad board.
        %       This function is used to output the desired clock settings correlated to the    
        %       'selected chip'
        %       Assume 16 channels
        %
        %       [quad board:]
        %           clock reg values [10-43]   
        % 
        %       [single board:]
        %           clock reg values [21-33]
        """
        print("\t FEMB_CONFIG//select_chn()")
        if (chn < 0 ) or (chn > settings.chn_num):
            print ("\t FEMB_CONFIG//select_chn()//Error: Chn must be between 0 and {}".format(self.chn_num))
            return
        """ quad board remains...
        self.femb.write_reg(9, 1)		  # STOP_ADC <= reg9_p (quad board)
        time.sleep(0.01)                          # WAIT
        self.femb.write_reg(3, 0x80000001 + chip) # CHP_SELECT <= reg3_p(7 downto 0) (quad board) 
        time.sleep(0.01)                          # WAIT
        self.femb.write_reg(9, 0)		  # STOP_ADC <= reg9_p (quad board)
        time.sleep(0.01)                          # WAIT
        self.femb.write_reg(47, 1)                # ERROR_RESET <= reg47_p (quad board)
        time.sleep(0.01)                          # WAIT
        self.femb.write_reg(47, 0)                # ERROR_RESET <= reg47_p (quad board)
        """
        # STOP ADC: TRUE ???
        time.sleep(0.01)                         # WAIT
        self.femb.write_reg(7, 0x00000001 + chn) # CHN_SELECT <= reg7(7 downto 0)
        time.sleep(0.01)                         # WAIT
	# STOP ADC: FALSE ???
	# WAIT
        self.femb.write_reg(11, 1)               # CHN_SELECT <= reg11(0)
        time.sleep(0.01)                         # WAIT
        self.femb.write_reg(11, 0)               # CHN_SELECT <= reg11(0)

        self.selected_chn = chn # originally self.selected_chip?? what is it used for?
        if (self.femb.read_reg(7) != 0x00000001 + chn):
            print ("\t FEMB CONFIG --> select_chn() -> Error - chip not chosen correctly!")
            print ("\t Should be ".format(hex(0x00000001 + chn)))
            print ("\t It is {}".format(hex(self.femb.read_reg(7))))
            
        to_add = 0
        """ quad board remains...
        if (settings.extended == True):
            to_add = 4

        self.femb.write_reg(10, settings.reg10_value[chip + to_add]) #INV_RST_ADC1 <= reg10_p(0)
							             #INV_READ_ADC1<= reg10_p(1)
        #Course Control Quad Board
        self.femb.write_reg(11, settings.reg11_value[chip + to_add])
        self.femb.write_reg(12, settings.reg12_value[chip + to_add])
        self.femb.write_reg(13, settings.reg13_value[chip + to_add])
        self.femb.write_reg(14, settings.reg14_value[chip + to_add])
        self.femb.write_reg(15, settings.reg15_value[chip + to_add])
        self.femb.write_reg(16, settings.reg16_value[chip + to_add])
        
        #Fine Control Quad Board
        self.femb.write_reg(17, settings.reg17_value[chip + to_add])
        self.femb.write_reg(18, settings.reg18_value[chip + to_add])
        self.femb.write_reg(19, settings.reg19_value[chip + to_add])
        self.femb.write_reg(19, settings.reg19_value[chip + to_add])
        self.femb.write_reg(19, 0x80000000 + settings.reg19_value[chip + to_add])
        """
        self.femb.write_reg( settings.CLKPHASE_reg, 0xFF)
        self.femb.write_reg( settings.CLKPHASE_reg, self.REG_CLKPHASE_data)
        
        time.sleep(0.01)


    def get_data_chipXchnX(self, chip, chn, packets = 1):
        
        if (chn < -1 ) or (chn > settings.chn_num ):
            print ("FEMB CONFIG --> get_data_chipXchnX() -> Error: Channel must be between 0 and 15, or -1 for all channels")
            return
        
        if (chip < 0 ) or (chip > settings.chip_num ):
            print ("FEMB CONFIG --> get_data_chipXchnX() -> Error: Chip must be between 0 and {}".format(self.chip_num))
            return

        k = 0
        for i in range(10):
            
            data = self.femb.get_data_packets(data_type = "int", num = packets, header = False)
            
            try:
                if (k > 0):
                    print ("FEMB CONFIG --> Now doing another test")
                    print (hex(data[0]))
                    print (data[0] == 0xFACE)
                    print (data[0] != 0xFACE)
                if (data[0] != 0xFACE):
                #If FACE isn't the first 2 bytes, turn WIB mode off and then on and try again
                    self.femb.write_reg(8,0) # Turn WIB Mode Off
                    time.sleep(0.01)
                    self.femb.write_reg(8,1) # Turn WIB Mode On
                    time.sleep(0.01)
                    
                # quad board settings:
#                    self.select_chip(chip) #tells fpga which chip information to provide
#                    self.femb.write_reg(3, chip+1)  # CHP_Select <= reg_3p(7-0)
#                                                    # CHN_Select <= reg_3p(15-0)
#                                                    # WIB_Mode <= reg_3p(31)
                # single board settings:
                    self.femb.write_reg(7, chn)      # CHN_select <= reg7_p(7-0)       
                    time.sleep(0.001)

                    if (k > 8):
                        print ("FEMB CONFIG --> Error in get_data_chipXchnX: Packet format error")
                        #print (hex(data[0]))
                        #print (data)
                        return None
                    else:
                        print ("FEMB CONFIG --> Error in get_data_chipXchnX: Packet format error, trying again...")
                        print ("k = {}".format(k))
                        print (data[0:13])
                        print (hex(data[0]))
                        print ("FEMB CONFIG --> Hey: {}".format(data[0] == 0xFACE))
                        k += 1
                else:
                    break
            except IndexError:
                print ("FEMB CONFIG --> Something was wrong with the incoming data")
                print (data)
            
        test_length = len(data)
        
#        if ((test_length % self.BPS) != 0):
#            print ("FEMB CONFIG -> Error in get_data_chipXchnX: Irregular packet size")
#            print (data)
#            return None
        
        full_samples = test_length // self.BPS
        
        chn_data = []
        
        for i in range (full_samples):
            if (chn == 7):
                chn_data.append(data[(self.BPS*i)+1] & 0x0FFF)
            if (chn == 6):
                chn_data.append(((data[(self.BPS*i)+2] & 0x00FF) << 4) + ((data[(self.BPS*i)+1] & 0xF000) >> 12))
            if (chn == 5):
                chn_data.append(((data[(self.BPS*i)+3] & 0x000F) << 8) + ((data[(self.BPS*i)+2] & 0xFF00) >> 8))
            if (chn == 4):
                chn_data.append(((data[(self.BPS*i)+3] & 0xFFF0) >> 4))
            if (chn == 3):
                chn_data.append(data[(self.BPS*i)+4] & 0x0FFF)
            if (chn == 2):
                chn_data.append(((data[(self.BPS*i)+5] & 0x00FF) << 4) + ((data[(self.BPS*i)+4] & 0xF000) >> 12))
            if (chn == 1):
                chn_data.append(((data[(self.BPS*i)+6] & 0x000F) << 8) + ((data[(self.BPS*i)+5] & 0xFF00) >> 8))
            if (chn == 0):
                chn_data.append(((data[(self.BPS*i)+6] & 0xFFF0) >> 4))
            if (chn == 15):
                chn_data.append(data[(self.BPS*i)+7] & 0x0FFF)
            if (chn == 14):
                chn_data.append(((data[(self.BPS*i)+8] & 0x00FF) << 4) + ((data[(self.BPS*i)+7] & 0xF000) >> 12))
            if (chn == 13):
                chn_data.append(((data[(self.BPS*i)+9] & 0x000F) << 8) + ((data[(self.BPS*i)+8] & 0xFF00) >> 8))
            if (chn == 12):
                chn_data.append(((data[(self.BPS*i)+9] & 0xFFF0) >> 4))
            if (chn == 11):
                chn_data.append(data[(self.BPS*i)+10] & 0x0FFF)
            if (chn == 10):
                chn_data.append(((data[(self.BPS*i)+11] & 0x00FF) << 4) + ((data[(self.BPS*i)+10] & 0xF000) >> 12))
            if (chn == 9):
                chn_data.append(((data[(self.BPS*i)+12] & 0x000F) << 8) + ((data[(self.BPS*i)+11] & 0xFF00) >> 8))
            if (chn == 8):
                chn_data.append(((data[(self.BPS*i)+12] & 0xFFF0) >> 4))
            if (chn == -1):
                return (data)
            
        return chn_data
Beispiel #3
0
class FEMB_CONFIG:
    def __init__(self):
        self.NASICS = 4

        #declare board specific registers
        self.REG_RESET = 0
        self.REG_FEASIC_SPI = 5
        self.REG_FESPI_BASE = 20
        self.REG_FESPI_RDBACK_BASE = None
        self.REG_ADCSPI_RDBACK_BASE = None
        self.REG_HS = 17
        self.REG_TEST_PULSE = 99
        self.REG_TEST_PULSE_FREQ = 500
        self.REG_TEST_PULSE_DLY = 80
        self.REG_TEST_PULSE_AMPL = 0 % 32
        self.REG_EN_CALI = 16

        self.REG_RESET = 0
        self.REG_DAC_VALUE = 1
        self.REG_SET_DAC = 2
        self.REG_START = 3
        self.REG_SEL_ASIC = 4
        self.REG_SEL_CH = 4
        self.REG_ASIC_RESET = 5
        self.REG_ASIC_SPIPROG = 5
        self.REG_SAMPLE_STOP = 6
        self.REG_TP_PERIOD_P = 7
        self.REG_TP_PERIOD_N = 7
        self.REG_TP_MODE = 9
        self.REG_TST_SW = 12
        self.REG_LED_CNTL = 13
        self.REG_FESPI_BASE = 20
        self.REG_FRAME_SIZE = 40
        self.REG_DAC_ADC_EN = 60
        self.REG_TST_SW = 12

        self.plot = plot_functions()
        self.comm_settings = None

        #initialize FEMB UDP object
        self.femb = FEMB_UDP()
        self.fe_reg = FE_ASIC_REG_MAPPING()

        self.WIB_RESET = 1

        self.BPS = 13  #Bytes per sample
        self.selected_chip = None
        self.selected_chn = None

    def resetFEMBBoard(self):
        print("FEMB_CONFIG--> Reset FEMB (4 seconds)")
        sys.stdout.flush()
        #Reset FEMB system
        self.femb.write_reg(self.REG_RESET, 1)
        time.sleep(4)
        print("FEMB_CONFIG--> Reset FEMB is DONE")

    def initBoard(self):
        print("FEMB_CONFIG--> Initialize FEMB")
        #set up default registers

        #Tells the FPGA to turn on the ASICs
        self.femb.write_reg(12, 0x0)
        #self.turnOnAsics() #added

        #Tells the FPGA to turn off each DAC
        self.femb.write_reg(61, 0xF)

        #Set to Regular Mode (as opposed to Sampling Scope mode) and pick a chip/channel output
        self.femb.write_reg(10, 0)
        self.select_chip_chn(chip=2, chn=7)

        #Select TP FE Mode
        self.femb.write_reg(9, 8)

        #Give a default DAC value
        self.femb.write_reg(1, settings.default_DAC)
        self.femb.write_reg(2, 1)
        self.femb.write_reg(2, 0)

        #Give a default pulse timing
        self.femb.write_reg(7, (settings.default_TP_Shift << 16) +
                            settings.default_TP_Period)

        #Write the default ADC settings
        i = 0
        for reg in range(65, 69, 1):
            self.femb.write_reg(reg, settings.Latch_Settings[i])
            i = i + 1

        i = 0
        for reg in range(69, 73, 1):
            self.femb.write_reg(reg, settings.Phase_Settings[i])
            i = i + 1

        self.femb.write_reg(73, settings.test_ADC_Settings)

        self.femb.write_reg(74, settings.pre_buffer)

        #Write the frame size as a multiple of 16
        frame_size = settings.frame_size
        if (frame_size % 16 != 0):
            frame_size = 16 * (frame_size // 16)

        #Write the defaul ASIC settings
        self.fe_reg.set_fe_board(sts=1,
                                 snc=1,
                                 sg=1,
                                 st=1,
                                 smn=0,
                                 sbf=1,
                                 slk=0,
                                 stb=0,
                                 s16=0,
                                 slkh=0,
                                 sdc=0,
                                 sdacsw2=1,
                                 sdacsw1=0,
                                 sdac=settings.sync_peak_height)
        print("FEMB_CONFIG --> FE ASIC SPI")
        self.configFeAsic()

        print("FEMB_CONFIG--> Initialize FEMB is DONE")

    def turnOffAsics(self):
        self.femb.write_reg(self.REG_TST_SW, 0xF)
        #pause after turning off ASICs
        time.sleep(2)

    def turnOnAsic(self, asic):
        asicVal = int(asic)
        if (asicVal < 0) or (asicVal >= self.NASICS):
            print(
                "femb_config_femb : turnOnAsics - invalid ASIC number, only 0 to {} allowed"
                .format(self.NASICS - 1))
            return
        print("turnOnAsic " + str(asicVal))
        #self.femb.write_reg( self.REG_TST_SW, 0xF) #turn off all
        self.femb.write_reg_bits(self.REG_TST_SW, asicVal, 0x1, 0x0)
        time.sleep(2)  #pause after turn on

        #start ASICs
        self.femb.write_reg(self.REG_START, 1)
        self.configFeAsic()

    def turnOnAsics(self):
        #print( "Turn On Asics" )
        #self.femb.write_reg( self.REG_TST_SW, 0x0)
        #time.sleep(1) #pause after turn on
        #start ASICs
        #self.femb.write_reg( self.REG_START, 1)
        #self.configFeAsic()

        self.turnOnAsic(0)
        self.turnOnAsic(1)
        self.turnOnAsic(2)
        self.turnOnAsic(3)

        #pause after turning on ASICs
        time.sleep(2)

    def configFeAsic(self, to_print=False):
        #Grab ASIC settings from linked class
        Feasic_regs = self.fe_reg.REGS
        #Choose to output status updates or not
        if (to_print == True):
            print("FEMB_CONFIG--> Config FE ASIC SPI")
        #Try 10 times (ocassionally it wont work the first time)
        for k in range(10):
            i = 0
            for regNum in range(self.REG_FESPI_BASE,
                                self.REG_FESPI_BASE + len(Feasic_regs), 1):
                self.femb.write_reg(regNum, Feasic_regs[i])
                #                    print (hex(Feasic_regs[i]))
                i = i + 1

            #Write ADC ASIC SPI
            if (to_print == True):
                print("FEMB_CONFIG--> Program FE ASIC SPI")
            #Reset, then write twice
            self.femb.write_reg(self.REG_FEASIC_SPI, 2)
            self.femb.write_reg(self.REG_FEASIC_SPI, 0)
            time.sleep(.2)
            self.femb.write_reg(self.REG_FEASIC_SPI, 1)
            self.femb.write_reg(self.REG_FEASIC_SPI, 0)
            time.sleep(.2)
            self.femb.write_reg(self.REG_FEASIC_SPI, 1)
            self.femb.write_reg(self.REG_FEASIC_SPI, 0)
            time.sleep(.2)

            if (to_print == True):
                print("FEMB_CONFIG--> Check FE ASIC SPI")

            #The FPGA automatically compares the readback to check if it matches what was written.  That result is read back
            #A bit that's zero means the corresponding ASIC didn't write properly
            val = self.femb.read_reg(self.REG_FEASIC_SPI)
            wrong = False

            if (((val & 0x10000) >> 16) != 1 and (0 in settings.chips_to_use)):
                print(
                    "FEMB_CONFIG--> Something went wrong when programming FE 1"
                )
                wrong = True

            if (((val & 0x20000) >> 17) != 1 and (1 in settings.chips_to_use)):
                print(
                    "FEMB_CONFIG--> Something went wrong when programming FE 2"
                )
                wrong = True

            if (((val & 0x40000) >> 18) != 1 and (2 in settings.chips_to_use)):
                print(
                    "FEMB_CONFIG--> Something went wrong when programming FE 3"
                )
                wrong = True

            if (((val & 0x80000) >> 19) != 1 and (3 in settings.chips_to_use)):
                print(
                    "FEMB_CONFIG--> Something went wrong when programming FE 4"
                )
                wrong = True

            if (wrong == True and k == 9):
                print("FEMB_CONFIG--> SPI_Status is {}").format(hex(val))
                #sys.exit("FEMB_CONFIG--> femb_config_femb : Wrong readback. FE SPI failed")
                return

            elif (wrong == False):
                self.fe_reg.info.fe_regs_sent = Feasic_regs
                if (to_print == True):
                    print("FEMB_CONFIG--> FE ASIC SPI is OK")
                break

    #ASSUMES ASICS HAVE BEEN SET FOR THE INTERNAL PULSER
    def syncADC(self, chips):
        print("FEMB_CONFIG--> Start sync ADC")

        #Don't ask me why, but you need to set the channel at this point for it to output the right data
        self.select_chip_chn(chip=0, chn=1)
        for chip in chips:

            #Tells the FPGA to turn on each DAC
            self.femb.write_reg(61, 0x0)

            #Read from DATA output ADCs
            self.femb.write_reg(60, 0)

            #Set to Regular Mode (not sampling scope mode)
            self.femb.write_reg(10, 0)

            #Select the internal DAC readout
            self.femb.write_reg(9, 3)

            #Get the ASIC to send out pulses.  Bit 6 needs to be high for ASIC DAC
            self.reg_17_value = (settings.default_TP_Period << 16) + (
                settings.default_TP_Shift << 8) + (0b01000000)
            self.femb.write_reg(17, self.reg_17_value)

            print("FEMB_CONFIG--> Test ADC {}".format(chip))

            for chn in range(settings.channels):
                #Tests if it's synchronized, returns True if it is
                unsync = self.testUnsync(chip=chip, chn=chn)
                if unsync != True:
                    print(
                        "FEMB_CONFIG--> Chip {}, Chn {} not synced, try to fix"
                        .format(chip, chn))
                    response = self.fixUnsync_outputADC(chip=chip, chn=chn)
                    if (response != True):
                        print(
                            "FEMB_CONFIG--> Something is wrong with Chip {}, Chn {}"
                            .format(chip, chn))
#                        sys.exit ("FEMB_CONFIG--> ADC {} could not sync".format(chip))

            print("FEMB_CONFIG--> ADC {} synced!".format(chip))

            print("FEMB_CONFIG--> Trying to sync test ADC".format(chip))

            #Have one of the channels output its pulse to the test monitor pin
            self.fe_reg.set_fe_chn(chip=chip, chn=0, smn=1)
            self.configFeAsic()

            #Read from TEST output ADCs
            self.femb.write_reg(60, 1)

            #Select the monitor readout
            self.femb.write_reg(9, 3)

            unsync = self.testUnsync(chip=chip, chn=chn)
            if unsync != True:
                print(
                    "FEMB_CONFIG--> Chip {} (test ADC) not synced, try to fix".
                    format(chip))
                response = self.fixUnsync_testADC(chip=chip)
                if (response != True):
                    print(
                        "FEMB_CONFIG--> Something is wrong with Chip {} (test ADC)"
                        .format(chip))
            else:
                print("FEMB_CONFIG--> Chip {} (test ADC) synced!".format(chip))

        self.comm_settings = []
        print("FEMB_CONFIG--> Final Shift Settings: ")
        for reg in range(65, 69, 1):
            value = self.femb.read_reg(reg)
            print("Register {}: {}".format(reg, hex(value)))
            self.comm_settings.append(value)

        print("FEMB_CONFIG--> Final Phase Settings: ")
        for reg in range(69, 73, 1):
            value = self.femb.read_reg(reg)
            print("Register {}: {}".format(reg, hex(value)))
            self.comm_settings.append(value)

        value = self.femb.read_reg(73)
        print("Register {}: {}".format(73, hex(value)))
        self.comm_settings.append(value)

        self.femb.write_reg(17, 0)

        print("FEMB_CONFIG--> ADC passed Sync Test!")

    def testUnsync(self, chip, chn):
        #Get some packets of data
        self.select_chip_chn(chip=chip, chn=chn)
        data = self.get_data_chipXchnX(chip=chip,
                                       chn=chn,
                                       packets=25,
                                       data_format="counts")

        #Find some peaks
        peaks_index = detect_peaks(x=data, mph=settings.sync_peak_min, mpd=100)
        #Make sure you have more than 0 peaks (so it's not flat) and less than the maximum
        #(if there's no peak, the baseline will give hundreds of peaks)
        #If it's bad, print it, so we see (must enable inline printing for iPython)
        if (len(peaks_index)
                == 0) or (len(peaks_index) > settings.sync_peaks_max):
            print("Chip {}, Channel {} has {} peaks!".format(
                chip, chn, len(peaks_index)))
            #            print (peaks_index)
            figure_data = self.plot.quickPlot(data)
            ax = figure_data[0]
            for j in peaks_index:
                y_value = data[j]
                ax.scatter(j / 2, y_value, marker='x')

            ax.set_ylabel('mV')
            ax.set_title("Error")
            ax.title.set_fontsize(30)
            for item in ([ax.xaxis.label, ax.yaxis.label] +
                         ax.get_xticklabels() + ax.get_yticklabels()):
                item.set_fontsize(20)
            plt.show()
            plt.close()
            return False

        #So that function before only gives you the X locations of where the peaks are.  Let's get the Y values from that
        peaks_value = []
        for i in peaks_index:
            peaks_value.append(data[i])
#        print ("Chip {}, Channel {} has peak values {}".format(chip, chn, peaks_value))
#Check if the peak is at the wrong height (happens when it's not synced, the peak will be havled or doubled)
        for peak in peaks_value:
            if ((peak < settings.sync_peak_min)
                    or (peak > settings.sync_peak_max)):
                print("FEMB CONFIG--> Chip {}, Chn {} has a peak that's {}".
                      format(chip, chn, peak))
                figure_data = self.plot.quickPlot(data)
                ax = figure_data[0]
                for j in peaks_index:
                    y_value = data[j]
                    ax.scatter(j / 2, y_value, marker='x')

                ax.set_ylabel('mV')
                ax.set_title("Error")
                ax.title.set_fontsize(30)
                for item in ([ax.xaxis.label, ax.yaxis.label] +
                             ax.get_xticklabels() + ax.get_yticklabels()):
                    item.set_fontsize(20)
                plt.show()
                plt.close()
                return False
        #Check if the baseline is right (this also gets halved and doubled with unsynced ADCs) (avoid the peak to grab a middle section)
        try:
            baseline_area_start = peaks_index[0] + 200
            baseline_area_end = peaks_index[1] - 200
        except IndexError:
            baseline_area_start = 100
            baseline_area_end = 500
        baseline_data = data[baseline_area_start:baseline_area_end]
        baseline = np.mean(baseline_data)
        if ((baseline < settings.sync_baseline_min)
                or (baseline > settings.sync_baseline_max)):
            print("FEMB CONFIG--> Chip {}, Chn {} has a baseline that's {}".
                  format(chip, chn, baseline))
            figure_data = self.plot.quickPlot(data)
            ax = figure_data[0]
            for j in peaks_index:
                y_value = data[j]
                ax.scatter(j / 2, y_value, marker='x')

            ax.set_ylabel('mV')
            ax.set_title("Error")
            ax.title.set_fontsize(30)
            for item in ([ax.xaxis.label, ax.yaxis.label] +
                         ax.get_xticklabels() + ax.get_yticklabels()):
                item.set_fontsize(20)
            plt.show()
            plt.close()
            return False
        return True

    #Shifts through all possible delay and phase options, checking to see if each one fixed the issue
    def fixUnsync_outputADC(self, chip, chn):
        self.select_chip_chn(chip=chip, chn=chn)

        shift_reg = chip + 65
        phase_reg = chip + 69

        #Get the initial setting you don't disturb the other channels
        init_shift = self.femb.read_reg(shift_reg)
        init_phase = self.femb.read_reg(phase_reg)

        #Because Python can't have a friggin NAND or XOR function that works right at the bitwise level, this is how we get the bitmask
        #This will find the 2 bits in the register that correspond to the channel you want to change.  Say it's channel 2
        #In binary, it makes 0b00000000000000000000000000110000
        #Then inverts it to  0b11111111111111111111111111001111
        #Now you AND that with the initial result to get the initial values WITHOUT the channel you want to change
        #Now you can bitshift your desired setting to that empty space with zeroes, like say you wanted to write a 0b10,
        #It would be 0b100000.  Then add that to whatever the result of the initial values AND mask was.  Boom, you've done it.
        init_mask = (0x3 << (2 * chn))
        neg_mask = 0
        for i in range(32):
            FF_bit = (0xFFFFFFFF >> i) & 0x1
            test_bit = (init_mask >> i) & 0x1
            if (FF_bit != test_bit):
                result_bit = 1
            else:
                result_bit = 0
            neg_mask = neg_mask + (result_bit << i)

        #There are 16 possible sync permutations for every ADC
        for shift in range(4):
            for phase in range(4):

                shift_setting = shift << (2 * chn)
                init_shift_with_mask = init_shift & neg_mask
                final_shift = shift_setting + init_shift_with_mask

                #                print ("Shift is {}".format(shift))
                #                print ("phase is {}".format(phase))
                #                print ("Negative mask is {}".format(bin(neg_mask)))
                #                print ("Initial reading is {}".format(bin(init_shift)))
                #                print ("The new setting is {}".format(bin(shift_setting)))
                #                print ("Making space for the new setting is {}".format(bin(init_shift_with_mask)))
                #                print ("Adding together is {}".format(bin(final_shift)))

                self.femb.write_reg(shift_reg, final_shift)

                phase_setting = phase << (2 * chn)
                init_phase_with_mask = init_phase & neg_mask
                final_phase = phase_setting + init_phase_with_mask

                self.femb.write_reg(phase_reg, final_phase)

                #See if this new setting fixed it
                unsync = self.testUnsync(chip=chip, chn=chn)
                if unsync == True:
                    print("FEMB_CONFIG--> Chip {}, Chn {} fixed!".format(
                        chip, chn))
                    return True

        print("FEMB_CONFIG--> ADC SYNC process failed for Chip {}, Channel {}".
              format(chip, chn))
        self.femb.write_reg(shift_reg, init_shift)
        self.femb.write_reg(phase_reg, init_phase)
        return False

    #Same thing as above, except the timing register is different, so the bitmath has to be changed.
    def fixUnsync_testADC(self, chip):
        self.select_chip_chn(chip=chip, chn=2)
        init_mask = (0xF << (2 * chip))

        neg_mask = 0
        for i in range(32):
            FF_bit = (0xFFFFFFFF >> i) & 0x1
            test_bit = (init_mask >> i) & 0x1
            if (FF_bit != test_bit):
                result_bit = 1
            else:
                result_bit = 0
            neg_mask = neg_mask + (result_bit << i)

        init_shift = self.femb.read_reg(73)
        print("Init shift is {}".format(hex(init_shift)))
        print("Init mask is {}".format(bin(init_mask)))
        print("Negative mask is {}".format(bin(neg_mask)))
        for shift in range(4):
            for phase in range(4):
                setting = (phase << 2) + shift
                print("Setting is {}".format(bin(setting)))

                final_setting = setting << (chip * 4)
                print("Final Setting is {}".format(bin(setting)))

                init_shift_with_mask = init_shift & neg_mask
                print("Initshift with mask is {}".format(
                    hex(init_shift_with_mask)))

                really_final = init_shift_with_mask + final_setting
                print("Final setting to write is {}".format(bin(really_final)))

                #                init_shift_with_mask = init_shift & neg_mask
                #                final_shift = shift_setting + init_shift_with_mask

                #                print ("Shift is {}".format(shift))
                #                print ("phase is {}".format(phase))
                #                print ("Negative mask is {}".format(bin(neg_mask)))
                #                print ("Initial reading is {}".format(bin(init_shift)))
                #                print ("The new setting is {}".format(bin(shift_setting)))
                #                print ("Making space for the new setting is {}".format(bin(init_shift_with_mask)))
                #                print ("Adding together is {}".format(bin(final_shift)))

                unsync = self.testUnsync(chip=chip, chn=1)
                if unsync == True:
                    print(
                        "FEMB_CONFIG--> Chip {} test ADC fixed!".format(chip))
                    return True

        print("FEMB_CONFIG--> ADC SYNC process failed for Chip {} ADC".format(
            chip))
        return False

    #Select the chip and channel and read it out.  And check that it was actually set.  It's weirdly a problem
    def select_chip_chn(self, chip, chn):
        if (chip < 0) or (chip > settings.chip_num):
            print(
                "FEMB CONFIG -> Error in get_data_chipXchnX: Chip must be between 0 and {}"
                .format(settings.chip_num))
            return

        if (chn < 0) or (chn > 15):
            print(
                "FEMB CONFIG -> Error in get_data_chipXchnX: Channel must be between 0 and 15"
            )
            return

        chip_int = int(chip + 1)
        chn_int = int(chn)

        reg4_value = chn_int + (chip_int << 8)

        for i in range(10):
            self.femb.write_reg(4, reg4_value)
            time.sleep(0.1)
            reg4_read = self.femb.read_reg(4)
            try:
                if ((reg4_read & 0xF) != chn) or ((
                    (reg4_read >> 8) & 0xF) != chip + 1):
                    if (i == 9):
                        sys.exit(
                            "FEMB CONFIG--> Register response was {}, should have been {}, trying again..."
                            .format(hex(reg4_read), hex(reg4_value)))
                    else:
                        print(
                            "FEMB CONFIG--> Register response was {}, should have been {}, trying again..."
                            .format(hex(reg4_read), hex(reg4_value)))
                else:
                    self.selected_chip = chip
                    self.selected_chn = chn
                    break
            except TypeError:
                print("FEMB CONFIG--> No readback value, trying again...")

    #Get data in a variety of ways.  You can even pre-convert it to mV!
    def get_data_chipXchnX(self, chip, chn, packets=1, data_format="counts"):

        if (chn < -1) or (chn > 15):
            print(
                "FEMB CONFIG -> Error in get_data_chipXchnX: Channel must be between 0 and 15, or -1 for all channels"
            )
            return

        if (chip < 0) or (chip > settings.chip_num):
            print(
                "FEMB CONFIG -> Error in get_data_chipXchnX: Chip must be between 0 and {}, but it's {}"
                .format(settings.chip_num, chip))
            return

        if (self.selected_chip != chip) or (self.selected_chn != chn):
            self.select_chip_chn(chip=chip, chn=chn)

        if (data_format == "bin"):
            data = self.femb.get_data_packets(data_type="bin",
                                              num=packets,
                                              header=True)

        data = self.femb.get_data_packets(data_type="int",
                                          num=packets,
                                          header=False)

        if (data_format == "mV"):
            for i in range(len(data)):
                data[i] = data[i] * (0.0018 / 16384)

        elif (data_format == "V"):
            for i in range(len(data)):
                data[i] = data[i] * (1.8 / 16384)
        return data

    #Get a whole chip's worth of data
    def get_data_chipX(self, chip, packets=1, data_format="counts"):

        chip_data = [
            chip, [], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
            []
        ]
        for chn in range(16):
            for i in range(packets):
                chip_data[chn + 1].extend(
                    list(
                        self.get_data_chipXchnX(chip,
                                                chn,
                                                packets=1,
                                                data_format=data_format)[1:]))
        return chip_data

    #Placeholder for the full chip readout
    def get_data_chipXchnX_SS(self, chip, chn, packets=1):

        if (chn < -1) or (chn > 15):
            print(
                "FEMB CONFIG -> Error in get_data_chipXchnX: Channel must be between 0 and 15, or -1 for all channels"
            )
            return

        if (chip < 0) or (chip > settings.chip_num):
            print(
                "FEMB CONFIG -> Error in get_data_chipXchnX: Chip must be between 0 and {}, but it's {}"
                .format(settings.chip_num, chip))
            return

        if (self.selected_chip != chip) or (self.selected_chn != chn):
            self.select_chip(chip=chip, chn=chn)

        k = 0
        for i in range(10):

            data = self.femb.get_data_packets(data_type="int",
                                              num=packets,
                                              header=False)

            try:
                if (k > 0):
                    print("FEMB CONFIG --> Now doing another test")
                    print(hex(data[0]))
                    print(data[0] == 0xFACE)
                    print(data[0] != 0xFACE)
                if (data[0] != 0xFACE):
                    #If FACE isn't the first 2 bytes, do the equivalent of turning WIB mode off and then on and try again
                    self.femb.write_reg(3, chip + 1)
                    self.select_chip(chip)

                    if (k > 8):
                        print(
                            "FEMB CONFIG --> Error in get_data_chipXchnX: Packet format error"
                        )
                        print(hex(data[0]))
                        print(data)
                        return None
                    else:
                        print(
                            "FEMB CONFIG --> Error in get_data_chipXchnX: Packet format error, trying again..."
                        )
                        print("k = {}".format(k))
                        print(data[0:13])
                        print(hex(data[0]))
                        print(data[0] == 0xFACE)
                        k += 1
                else:
                    break
            except IndexError:
                print(
                    "FEMB CONFIG --> Something was wrong with the incoming data"
                )
                print(data)

        test_length = len(data)

        #        if ((test_length % self.BPS) != 0):
        #            print ("FEMB CONFIG -> Error in get_data_chipXchnX: Irregular packet size")
        #            print (data)
        #            return None

        full_samples = test_length // self.BPS

        chn_data = []

        for i in range(full_samples):
            if (chn == 7):
                chn_data.append(data[(self.BPS * i) + 1] & 0x0FFF)
            if (chn == 6):
                chn_data.append(((data[(self.BPS * i) + 2] & 0x00FF) << 4) +
                                ((data[(self.BPS * i) + 1] & 0xF000) >> 12))
            if (chn == 5):
                chn_data.append(((data[(self.BPS * i) + 3] & 0x000F) << 8) +
                                ((data[(self.BPS * i) + 2] & 0xFF00) >> 8))
            if (chn == 4):
                chn_data.append(((data[(self.BPS * i) + 3] & 0xFFF0) >> 4))
            if (chn == 3):
                chn_data.append(data[(self.BPS * i) + 4] & 0x0FFF)
            if (chn == 2):
                chn_data.append(((data[(self.BPS * i) + 5] & 0x00FF) << 4) +
                                ((data[(self.BPS * i) + 4] & 0xF000) >> 12))
            if (chn == 1):
                chn_data.append(((data[(self.BPS * i) + 6] & 0x000F) << 8) +
                                ((data[(self.BPS * i) + 5] & 0xFF00) >> 8))
            if (chn == 0):
                chn_data.append(((data[(self.BPS * i) + 6] & 0xFFF0) >> 4))
            if (chn == 15):
                chn_data.append(data[(self.BPS * i) + 7] & 0x0FFF)
            if (chn == 14):
                chn_data.append(((data[(self.BPS * i) + 8] & 0x00FF) << 4) +
                                ((data[(self.BPS * i) + 7] & 0xF000) >> 12))
            if (chn == 13):
                chn_data.append(((data[(self.BPS * i) + 9] & 0x000F) << 8) +
                                ((data[(self.BPS * i) + 8] & 0xFF00) >> 8))
            if (chn == 12):
                chn_data.append(((data[(self.BPS * i) + 9] & 0xFFF0) >> 4))
            if (chn == 11):
                chn_data.append(data[(self.BPS * i) + 10] & 0x0FFF)
            if (chn == 10):
                chn_data.append(((data[(self.BPS * i) + 11] & 0x00FF) << 4) +
                                ((data[(self.BPS * i) + 10] & 0xF000) >> 12))
            if (chn == 9):
                chn_data.append(((data[(self.BPS * i) + 12] & 0x000F) << 8) +
                                ((data[(self.BPS * i) + 11] & 0xFF00) >> 8))
            if (chn == 8):
                chn_data.append(((data[(self.BPS * i) + 12] & 0xFFF0) >> 4))
            if (chn == -1):
                return (data)

        return chn_data
Beispiel #4
0
class WRITE_DATA(object):
    def __init__(self, filedir="data"):
        self.femb = FEMB_UDP()
        self.filename = "output_write_data.bin"
        self.numpacketsrecord = 100
        self.run = 0
        self.runtype = 0
        self.runversion = 0
        self.date = int(datetime.datetime.today().strftime('%Y%m%d%H%M%S'))
        self.filedir = filedir

    @property
    def data_file_path(self):
        return os.path.join(self.filedir, self.filename)

    def assure_filedir(self):
        #check local directory structure
        if os.path.isdir(str(self.filedir)) == False:
            print("write_data: Data directory not found, making now.")
            os.makedirs(str(self.filedir))
        #check if directory actually created
        if os.path.isdir(str(self.filedir)) == False:
            print(
                "write_data: Error creating data directory, check filesystem.")
            return None
        return 1

    def open_file(self):
        print("write_data: Open file: %s" % self.data_file_path)

        self.assure_filedir()

        self.data_file = open(self.data_file_path, 'wb')
        return 1

    def record_data(self, subrun, asic, asicCh):
        subrunVal = int(subrun)
        if subrunVal < 0:
            return
        asicVal = int(asic)
        if asicVal < 0:
            return
        asicChVal = int(asicCh)
        if asicChVal < 0:
            return
        #print("write_data: Record data")
        data = self.femb.get_data_packets(self.numpacketsrecord)
        if data == None:
            print(
                "write_data: Did not get any data, streaming might have failed!!!"
            )
            return
        for packet in data:
            #UDP packet header
            self.data_file.write(struct.pack('!H', 0x0))
            self.data_file.write(struct.pack('!H', 0xDEAD))
            self.data_file.write(struct.pack('!H', 0xBEEF))
            self.data_file.write(struct.pack('!H', 0x0))
            self.data_file.write(struct.pack('!H', 0xBA5E))
            self.data_file.write(struct.pack('!H', subrunVal))
            self.data_file.write(struct.pack('!H', asicVal))
            self.data_file.write(struct.pack('!H', asicChVal))
            #write data
            self.data_file.write(packet)

    def close_file(self):
        print("write_data: Close file")
        self.data_file.close()