Exemple #1
0
class TRACE_ALLCHAN_WINDOW(Tk.Frame):
    """
  This window displays a live ADC redout
  """
    def __init__(self, master=None, packedHighSpeed=False):
        self.maxtraces = 5
        self.selChan = 0

        Tk.Frame.__init__(self, master)  # hack to make work in python2

        self.pack()
        self.figure = Figure(figsize=(15, 7), dpi=100, facecolor='white')

        self.canvas = FigureCanvas(self.figure, master=self)
        self.canvas.show()
        self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
        self.toolbar = NaviationToolbar(self.canvas, self)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

        self.pauseButton = Tk.Button(self, text="Pause", command=self.pause)
        self.pauseButton.pack(side=Tk.LEFT)

        self.playButton = Tk.Button(self,
                                    text="Play",
                                    command=self.play,
                                    state=Tk.DISABLED)
        self.playButton.pack(side=Tk.LEFT)

        self.prevButton = Tk.Button(self,
                                    text="Previous Trace",
                                    command=self.prevTrace,
                                    state=Tk.DISABLED)
        self.prevButton.pack(side=Tk.LEFT)

        self.nextButton = Tk.Button(self,
                                    text="Next Trace",
                                    command=self.nextTrace,
                                    state=Tk.DISABLED)
        self.nextButton.pack(side=Tk.LEFT)

        self.packedHighSpeed = packedHighSpeed
        self.femb = None
        self.iTrace = -1
        self.traces = []
        self.timestamps = []

        self.reset()

    def reset(self, iTrace=None):
        self.femb = FEMB_UDP()
        self.figure.clf()
        self.subgs = [None] * 16
        self.ax = [None] * 16
        self.plot = [None] * 16

        # 4x4 grid, one cell per channel
        self.gs = gridspec.GridSpec(4, 4)
        self.gs.update(wspace=0.2, hspace=0.2)
        # 1 plots per channel
        for row in range(4):
            for col in range(4):
                self.subgs[col + 4 * row] = gridspec.GridSpecFromSubplotSpec(
                    1, 1, subplot_spec=self.gs[col + 4 * row], hspace=0.0)
                self.ax[col + 4 * row] = self.figure.add_subplot(
                    self.subgs[col + 4 * row][0])
                self.ax[col + 4 * row].tick_params(axis='x',
                                                   colors='black',
                                                   labelsize='medium')
                self.ax[col + 4 * row].tick_params(axis='y',
                                                   colors='black',
                                                   labelsize='smaller')

        if iTrace is None:
            self.ani = animation.FuncAnimation(self.figure,
                                               self.plotData,
                                               interval=1000,
                                               blit=True)
        else:
            self.plotData(0, iTrace)
        self.canvas.draw()

    def pause(self):
        self.ani.event_source.stop()
        self.reset(self.iTrace)
        self.pauseButton['state'] = Tk.DISABLED
        self.playButton['state'] = Tk.NORMAL
        self.prevButton['state'] = Tk.NORMAL
        self.nextButton['state'] = Tk.DISABLED

    def play(self):
        self.ani.event_source.start()
        self.pauseButton['state'] = Tk.NORMAL
        self.playButton['state'] = Tk.DISABLED
        self.prevButton['state'] = Tk.DISABLED
        self.nextButton['state'] = Tk.DISABLED

    def prevTrace(self):
        self.iTrace -= 1
        self.reset(self.iTrace)
        if self.iTrace < 1:
            self.prevButton['state'] = Tk.DISABLED
        else:
            self.prevButton['state'] = Tk.NORMAL
        if self.iTrace >= len(self.traces) - 1:
            self.nextButton['state'] = Tk.DISABLED
        else:
            self.nextButton['state'] = Tk.NORMAL

    def nextTrace(self):
        self.iTrace += 1
        self.reset(self.iTrace)
        if self.iTrace < 1:
            self.prevButton['state'] = Tk.DISABLED
        else:
            self.prevButton['state'] = Tk.NORMAL
        if self.iTrace >= len(self.traces) - 1:
            self.nextButton['state'] = Tk.DISABLED
        else:
            self.nextButton['state'] = Tk.NORMAL

    def plotData(self, iFrame, iTrace=None):
        for a in self.ax:
            a.cla()
            a.locator_params(tight=True, nbins=3)

        # In case no data, return an empty plot
        self.plot[0] = self.ax[0].plot()

        for r in range(4):
            for c in range(4):
                t, adc, thistimestamp = self.getTraceAndFFT(iTrace=iTrace,
                                                            chan=c + 4 * r)
                if not (t is None) and not (adc is None):
                    self.plot[c + 4 * r] = self.ax[c + 4 * r].plot(t, adc)
                    if c + 4 * r < 12: self.ax[c + 4 * r].set_xticklabels([])
        self.figure.text(0.5,
                         0.02,
                         'Time [us]',
                         ha='center',
                         color='black',
                         fontsize='25.0',
                         weight='bold')
        self.figure.text(0.08,
                         0.5,
                         'ADC',
                         ha='center',
                         rotation=90,
                         color='black',
                         fontsize='25.0',
                         weight='bold')

        if not (thistimestamp is None):
            self.figure.suptitle(
                thistimestamp.replace(microsecond=0).isoformat(" "))
        self.canvas.draw()
        return self.plot[0]

    def getTraceAndFFT(self, iTrace=None, chan=0):
        """
    Gets trace from FEMB and returns 4 1D arrays:
        times, ADC counts
    """
        data = None
        timestamp = None
        if iTrace is None:
            data = self.femb.get_data(100)
            timestamp = datetime.datetime.now()
            self.traces.append(data)
            self.timestamps.append(timestamp)
            if len(self.traces) > self.maxtraces:
                self.traces.pop(0)
                self.timestamps.pop(0)
            self.iTrace = len(self.traces) - 1
        else:
            data = self.traces[iTrace]
            timestamp = self.timestamps[iTrace]
        if data == None:
            return None, None, None, None, None
        if len(data) == 0:
            return None, None, None, None, None

        chSamples = None
        if self.packedHighSpeed:
            chSamples = WRITE_ROOT_TREE.convertHighSpeedPacked(None, data)
        else:
            chSamples = WRITE_ROOT_TREE.convertHighSpeedSimple(None, data)

        xpoint = []
        ypoint = []
        num = 0
        for samp in chSamples[chan]:
            xpoint.append(num * 0.5)
            ypoint.append(samp)
            num = num + 1

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

        return xarr, yarr, timestamp
class TRACE_ALLCHAN_WINDOW(Tk.Frame):
    """
  This window displays a live ADC redout
  """
    def __init__(self, master=None):
        self.maxtraces = 5
        self.selChan = 0

        Tk.Frame.__init__(self, master)  # hack to make work in python2

        self.pack()
        self.figure = Figure(figsize=(20, 8), dpi=100, facecolor='white')

        self.canvas = FigureCanvas(self.figure, master=self)
        self.canvas.show()
        self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
        self.toolbar = NaviationToolbar(self.canvas, self)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

        self.pauseButton = Tk.Button(self, text="Pause", command=self.pause)
        self.pauseButton.pack(side=Tk.LEFT)

        self.playButton = Tk.Button(self,
                                    text="Play",
                                    command=self.play,
                                    state=Tk.DISABLED)
        self.playButton.pack(side=Tk.LEFT)

        self.prevButton = Tk.Button(self,
                                    text="Previous Trace",
                                    command=self.prevTrace,
                                    state=Tk.DISABLED)
        self.prevButton.pack(side=Tk.LEFT)

        self.nextButton = Tk.Button(self,
                                    text="Next Trace",
                                    command=self.nextTrace,
                                    state=Tk.DISABLED)
        self.nextButton.pack(side=Tk.LEFT)

        self.femb = None
        self.iTrace = -1
        self.traces = []
        self.timestamps = []

        self.reset()

    def reset(self, iTrace=None):
        self.femb = FEMB_UDP()
        self.femb_config = CONFIG()
        self.figure.clf()
        self.subgs = [None] * 16 * 4
        self.ax = [None] * 16 * 4
        self.plot = [None] * 16 * 4

        # 4x4x4 grid, one cell per channel
        self.gs = gridspec.GridSpec(4, 16)
        self.gs.update(wspace=0.2, hspace=0.2)
        # 1 plots per channel
        for row in range(4):
            for col in range(16):
                self.subgs[col + 16 * row] = gridspec.GridSpecFromSubplotSpec(
                    1, 1, subplot_spec=self.gs[col + 16 * row], hspace=0.0)
                self.ax[col + 16 * row] = self.figure.add_subplot(
                    self.subgs[col + 16 * row][0])
                self.ax[col + 16 * row].tick_params(axis='x',
                                                    colors='black',
                                                    labelsize='medium')
                self.ax[col + 16 * row].tick_params(axis='y',
                                                    colors='black',
                                                    labelsize='smaller')

        if iTrace is None:
            self.ani = animation.FuncAnimation(self.figure,
                                               self.plotData,
                                               interval=100,
                                               blit=True)
        else:
            self.plotData(0, iTrace)
        self.canvas.draw()

    def pause(self):
        self.ani.event_source.stop()
        self.reset(self.iTrace)
        self.pauseButton['state'] = Tk.DISABLED
        self.playButton['state'] = Tk.NORMAL
        self.prevButton['state'] = Tk.NORMAL
        self.nextButton['state'] = Tk.DISABLED

    def play(self):
        self.ani.event_source.start()
        self.pauseButton['state'] = Tk.NORMAL
        self.playButton['state'] = Tk.DISABLED
        self.prevButton['state'] = Tk.DISABLED
        self.nextButton['state'] = Tk.DISABLED

    def prevTrace(self):
        self.iTrace -= 1
        self.reset(self.iTrace)
        if self.iTrace < 1:
            self.prevButton['state'] = Tk.DISABLED
        else:
            self.prevButton['state'] = Tk.NORMAL
        if self.iTrace >= len(self.traces) - 1:
            self.nextButton['state'] = Tk.DISABLED
        else:
            self.nextButton['state'] = Tk.NORMAL

    def nextTrace(self):
        self.iTrace += 1
        self.reset(self.iTrace)
        if self.iTrace < 1:
            self.prevButton['state'] = Tk.DISABLED
        else:
            self.prevButton['state'] = Tk.NORMAL
        if self.iTrace >= len(self.traces) - 1:
            self.nextButton['state'] = Tk.DISABLED
        else:
            self.nextButton['state'] = Tk.NORMAL

    def plotData(self, iFrame, iTrace=None):
        for a in self.ax:
            a.cla()
            a.locator_params(tight=True, nbins=3)

        # In case no data, return an empty plot
        self.plot[0] = self.ax[0].plot()

        for a in range(4):
            #for a in [2]:
            #if a != 0:
            #    continue
            asicNum = a
            #asicNum = 2
            self.femb_config.setExtClockRegs(asicNum)
            self.femb_config.selectAsic(asicNum)
            #self.femb_config.doAdcAsicConfig(a)
            #self.femb_config.initAsic(a)
            chPlots, thistimestamp = self.getTraceAndFFT(iTrace=iTrace)
            if chPlots == None:
                continue
            if thistimestamp == None:
                continue
            if len(chPlots) != 16:
                continue
            for chan in range(0, 16, 1):
                t = chPlots[chan][0]
                adc = chPlots[chan][1]
                if not (t is None) and not (adc is None):
                    self.plot[chan + 16 * a] = self.ax[chan + 16 * a].plot(
                        t, adc)
                    #if c+4*r < 12: self.ax[c+4*r].set_xticklabels([])
        self.figure.text(0.5,
                         0.02,
                         'Time [us]',
                         ha='center',
                         color='black',
                         fontsize='25.0',
                         weight='bold')
        self.figure.text(0.08,
                         0.5,
                         'ADC',
                         ha='center',
                         rotation=90,
                         color='black',
                         fontsize='25.0',
                         weight='bold')

        if not (thistimestamp is None):
            self.figure.suptitle(
                thistimestamp.replace(microsecond=0).isoformat(" "))
        self.canvas.draw()
        return self.plot[0]

    def getTraceAndFFT(self, iTrace=None):
        """
    Gets trace from FEMB and returns 4 1D arrays:
        times, ADC counts
    """
        data = None
        timestamp = None
        if iTrace is None:
            data = self.femb.get_data(5)
            timestamp = datetime.datetime.now()
            self.traces.append(data)
            self.timestamps.append(timestamp)
            if len(self.traces) > self.maxtraces:
                self.traces.pop(0)
                self.timestamps.pop(0)
            self.iTrace = len(self.traces) - 1
        else:
            data = self.traces[iTrace]
            timestamp = self.timestamps[iTrace]
        if data == None:
            return None, None
        if len(data) == 0:
            return None, None

        chSamples = self.convertHighSpeedPacked(data)

        if len(chSamples) != 16:
            return None, None

        chPlots = []
        for chan in range(0, 16, 1):
            xpoint = []
            ypoint = []
            num = 0
            for samp in chSamples[chan]:
                xpoint.append(num * 0.5)
                ypoint.append(samp)
                num = num + 1

            xarr = np.array(xpoint)
            yarr = np.array(ypoint)
            chPlots.append([xarr, yarr])

        return chPlots, timestamp

    #taken from write_root_tree
    def convertHighSpeedPacked(self, data):
        packetNum = 0
        wordArray = []
        result = [[] for chan in range(16)]
        for word in data:
            if str(hex(word)) == "0xface":
                packetNum = 0
                wordArray = []
            if packetNum > 0 and packetNum < 13:
                wordArray.append(word)
            if packetNum == 12:
                result[0].append(((wordArray[5] & 0xFFF0) >> 4))
                result[1].append(((wordArray[4] & 0xFF00) >> 8)
                                 | ((wordArray[5] & 0x000F) << 8))
                result[2].append(((wordArray[4] & 0x00FF) << 4)
                                 | ((wordArray[3] & 0xF000) >> 12))
                result[3].append(((wordArray[3] & 0x0FFF) >> 0))
                result[4].append(((wordArray[2] & 0xFFF0) >> 4))
                result[5].append(((wordArray[2] & 0x000F) << 8)
                                 | ((wordArray[1] & 0xFF00) >> 8))
                result[6].append(((wordArray[1] & 0x00FF) << 4)
                                 | ((wordArray[0] & 0xF000) >> 12))
                result[7].append(((wordArray[0] & 0x0FFF) >> 0))
                result[8].append(((wordArray[11] & 0xFFF0) >> 4))
                result[9].append(((wordArray[11] & 0x000F) << 8)
                                 | ((wordArray[10] & 0xFF00) >> 8))
                result[10].append(((wordArray[10] & 0x00FF) << 4)
                                  | ((wordArray[9] & 0xF000) >> 12))
                result[11].append(((wordArray[9] & 0x0FFF)))
                result[12].append(((wordArray[8] & 0xFFF0) >> 4))
                result[13].append(((wordArray[8] & 0x000F) << 8)
                                  | ((wordArray[7] & 0xFF00) >> 8))
                result[14].append(((wordArray[7] & 0x00FF) << 4)
                                  | ((wordArray[6] & 0xF000) >> 12))
                result[15].append(((wordArray[6] & 0x0FFF)))
            packetNum = packetNum + 1
        return result
class FEMB_CONFIG(FEMB_CONFIG_BASE):
    def __init__(self):
        super().__init__()
        #declare board specific registers
        self.FEMB_VER = "adctest"
        self.REG_RESET = 0
        self.REG_ASIC_RESET = 1
        self.REG_ASIC_SPIPROG = 2
        self.REG_SEL_ASIC = 7
        self.REG_SEL_CH = 7
        self.REG_FESPI_BASE = 592
        self.REG_ADCSPI_BASE = 512
        self.REG_FESPI_RDBACK_BASE = 632
        self.REG_ADCSPI_RDBACK_BASE = 552
        self.REG_HS = 17
        self.REG_LATCHLOC = 4
        self.REG_CLKPHASE = 6
        self.ADC_TESTPATTERN = [
            0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca,
            0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef
        ]
        self.NASICS = 1

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

    def resetBoard(self):
        #Reset system
        self.femb.write_reg(self.REG_RESET, 1)
        time.sleep(5.)

        #Reset registers
        self.femb.write_reg(self.REG_RESET, 2)
        time.sleep(1.)

        #Time stamp reset
        #femb.write_reg( 0, 4)
        #time.sleep(0.5)

        #Reset ADC ASICs
        self.femb.write_reg(self.REG_ASIC_RESET, 1)
        time.sleep(0.5)

    def initBoard(self):
        nRetries = 5
        for iRetry in range(nRetries):
            #set up default registers

            #Reset ADC ASICs
            self.femb.write_reg(self.REG_ASIC_RESET, 1)
            time.sleep(0.5)

            #Set ADC test pattern register
            self.femb.write_reg(3, 0x01230000)  # test pattern off
            #self.femb.write_reg( 3, 0x81230000) # test pattern on

            #Set ADC latch_loc
            self.femb.write_reg(self.REG_LATCHLOC, 0x66666667)
            #Set ADC clock phase
            self.femb.write_reg(self.REG_CLKPHASE, 0xfffc0054)

            #internal test pulser control
            self.femb.write_reg(5, 0x00000000)
            self.femb.write_reg(13, 0x0)  #enable

            #Set test and readout mode register
            self.femb.write_reg(
                7, 0x0000)  #11-8 = channel select, 3-0 = ASIC select

            #Set number events per header
            self.femb.write_reg(8, 0x0)

            #ADC ASIC SPI registers
            print("Config ADC ASIC SPI")
            print("ADCADC")
            self.femb.write_reg(self.REG_ADCSPI_BASE + 0, 0xC0C0C0C)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 1, 0xC0C0C0C)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 2, 0xC0C0C0C)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 3, 0xC0C0C0C)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 4, 0xC0C0C0C)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 5, 0xC0C0C0C)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 6, 0xC0C0C0C)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 7, 0xC0C0C0C)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 8, 0x18321832)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 9, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 10, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 11, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 12, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 13, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 14, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 15, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 16, 0x64186418)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 17, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 18, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 19, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 20, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 21, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 22, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 23, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 24, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 25, 0x60c868c8)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 26, 0x60606868)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 27, 0x60606868)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 28, 0x60606868)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 29, 0x60606868)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 30, 0x60606868)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 31, 0x60606868)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 32, 0x60606868)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 33, 0x9060A868)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 34, 0x10001)

            #ADC ASIC sync
            self.femb.write_reg(17,
                                0x1)  # controls HS link, 0 for on, 1 for off
            self.femb.write_reg(17,
                                0x0)  # controls HS link, 0 for on, 1 for off

            #Write ADC ASIC SPI
            print("Program ADC ASIC SPI")
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)

            print("Check ADC ASIC SPI")
            for regNum in range(self.REG_ADCSPI_RDBACK_BASE,
                                self.REG_ADCSPI_RDBACK_BASE + 34, 1):
                val = self.femb.read_reg(regNum)
                print(hex(val))

            #enable streaming
            #self.femb.write_reg( 9, 0x8)

            #LBNE_ADC_MODE
            self.femb.write_reg(16, 0x1)

            # Check that board streams data
            data = self.femb.get_data(1)
            if data == None:
                print("Board not streaming data, retrying initialization...")
                continue  # try initializing again
            print("FEMB_CONFIG--> Reset FEMB is DONE")
            return
        print(
            "Error: Board not streaming data after trying to initialize {} times. Exiting."
            .format(nRetries))
        sys.exit(1)

    def selectChannel(self, asic, chan, hsmode=None):
        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))

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

    def syncADC(self):
        #turn on ADC test mode
        print("Start sync ADC")
        reg3 = self.femb.read_reg(3)
        newReg3 = (reg3 | 0x80000000)
        self.femb.write_reg(3, newReg3)  #31 - enable ADC test pattern
        alreadySynced = True
        for a in range(0, self.NASICS, 1):
            print("Test ADC " + str(a))
            unsync = self.testUnsync(a)
            if unsync != 0:
                alreadySynced = False
                print("ADC not synced, try to fix")
                self.fixUnsync(a)
        LATCH = self.femb.read_reg(self.REG_LATCHLOC)
        PHASE = self.femb.read_reg(self.REG_CLKPHASE)
        print("Latch latency " + str(hex(LATCH)) + "\tPhase " +
              str(hex(PHASE)))
        print("End sync ADC")
        return not alreadySynced, LATCH, None, PHASE

    def testUnsync(self, adc):
        adcNum = int(adc)
        if (adcNum < 0) or (adcNum >= self.NASICS):
            print("femb_config_femb : testLink - invalid asic number")
            return

        #loop through channels, check test pattern against data
        badSync = 0
        for ch in range(0, 16, 1):
            self.selectChannel(adcNum, ch)
            time.sleep(0.1)
            for test in range(0, 1000, 1):
                data = self.femb.get_data(1)
                for samp in data:
                    chNum = ((samp >> 12) & 0xF)
                    sampVal = (samp & 0xFFF)
                    if sampVal != self.ADC_TESTPATTERN[ch]:
                        badSync = 1
                    if badSync == 1:
                        break
                if badSync == 1:
                    break
            if badSync == 1:
                break
        return badSync

    def fixUnsync(self, adc):
        adcNum = int(adc)
        if (adcNum < 0) or (adcNum >= self.NASICS):
            print("femb_config_femb : testLink - invalid asic number")
            return

        initLATCH = self.femb.read_reg(self.REG_LATCHLOC)
        initPHASE = self.femb.read_reg(self.REG_CLKPHASE)

        #loop through sync parameters
        for phase in range(0, 2, 1):
            clkMask = (0x1 << adcNum)
            testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum))
            self.femb.write_reg(self.REG_CLKPHASE, testPhase)
            for shift in range(0, 16, 1):
                shiftMask = (0xF << 4 * adcNum)
                testShift = ((initLATCH & ~(shiftMask)) |
                             (shift << 4 * adcNum))
                self.femb.write_reg(self.REG_LATCHLOC, testShift)
                #reset ADC ASIC
                self.femb.write_reg(self.REG_ASIC_RESET, 1)
                time.sleep(0.1)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.1)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.1)
                #test link
                unsync = self.testUnsync(adcNum)
                if unsync == 0:
                    print("ADC synchronized")
                    return
        #if program reaches here, sync has failed
        print("ADC SYNC process failed for ADC # " + str(adc))
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
class TRACE_FFT_ALLCHAN_WINDOW(Tk.Frame):
    """
  This window displays a live ADC redout and its FFT
  """
    def __init__(self, master=None):
        self.maxtraces = 5
        self.selChan = 0

        Tk.Frame.__init__(self, master)  # hack to make work in python2

        self.pack()

        #self.figure = Figure(figsize=(14,9), dpi=100, facecolor='gray')
        self.figure = Figure(figsize=(14, 8), dpi=100, facecolor='gray')

        self.canvas = FigureCanvas(self.figure, master=self)
        self.canvas.show()
        self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
        self.toolbar = NaviationToolbar(self.canvas, self)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

        self.pauseButton = Tk.Button(self, text="Pause", command=self.pause)
        self.pauseButton.pack(side=Tk.LEFT)

        self.playButton = Tk.Button(self,
                                    text="Play",
                                    command=self.play,
                                    state=Tk.DISABLED)
        self.playButton.pack(side=Tk.LEFT)

        self.prevButton = Tk.Button(self,
                                    text="Previous Trace",
                                    command=self.prevTrace,
                                    state=Tk.DISABLED)
        self.prevButton.pack(side=Tk.LEFT)

        self.nextButton = Tk.Button(self,
                                    text="Next Trace",
                                    command=self.nextTrace,
                                    state=Tk.DISABLED)
        self.nextButton.pack(side=Tk.LEFT)

        self.femb = None
        self.iTrace = -1
        self.traces = []
        self.timestamps = []

        self.reset()

    def reset(self, iTrace=None):
        self.femb = FEMB_UDP()
        self.figure.clf()
        self.subgs = [None] * 16
        self.ax = [None] * 32
        self.plot = [None] * 32

        # 4x4 grid, one cell per channel
        self.gs = gridspec.GridSpec(4, 4)
        self.gs.update(wspace=0.2, hspace=0.2)
        # 2 plots per channel
        for row in range(4):
            for col in range(4):
                self.subgs[col + 4 * row] = gridspec.GridSpecFromSubplotSpec(
                    2, 1, subplot_spec=self.gs[col + 4 * row], hspace=0.0)
                self.ax[col + 8 * row] = self.figure.add_subplot(
                    self.subgs[col + 4 * row][0])
                self.ax[col + 8 * row].tick_params(axis='x', colors='blue')
                self.ax[col + 8 * row].tick_params(axis='y', colors='blue')
                self.ax[col + 8 * row].xaxis.tick_top()
                self.ax[col + 8 * row].yaxis.tick_right()
                self.ax[4 + col + 8 * row] = self.figure.add_subplot(
                    self.subgs[col + 4 * row][1])
                self.ax[4 + col + 8 * row].tick_params(axis='x', colors='red')
                self.ax[4 + col + 8 * row].tick_params(axis='y', colors='red')

        if iTrace is None:
            self.ani = animation.FuncAnimation(self.figure,
                                               self.plotData,
                                               interval=1000,
                                               blit=True)
        else:
            self.plotData(0, iTrace)
        self.canvas.draw()

    def pause(self):
        self.ani.event_source.stop()
        self.reset(self.iTrace)
        self.pauseButton['state'] = Tk.DISABLED
        self.playButton['state'] = Tk.NORMAL
        self.prevButton['state'] = Tk.NORMAL
        self.nextButton['state'] = Tk.DISABLED

    def play(self):
        self.ani.event_source.start()
        self.pauseButton['state'] = Tk.NORMAL
        self.playButton['state'] = Tk.DISABLED
        self.prevButton['state'] = Tk.DISABLED
        self.nextButton['state'] = Tk.DISABLED

    def prevTrace(self):
        self.iTrace -= 1
        self.reset(self.iTrace)
        if self.iTrace < 1:
            self.prevButton['state'] = Tk.DISABLED
        else:
            self.prevButton['state'] = Tk.NORMAL
        if self.iTrace >= len(self.traces) - 1:
            self.nextButton['state'] = Tk.DISABLED
        else:
            self.nextButton['state'] = Tk.NORMAL

    def nextTrace(self):
        self.iTrace += 1
        self.reset(self.iTrace)
        if self.iTrace < 1:
            self.prevButton['state'] = Tk.DISABLED
        else:
            self.prevButton['state'] = Tk.NORMAL
        if self.iTrace >= len(self.traces) - 1:
            self.nextButton['state'] = Tk.DISABLED
        else:
            self.nextButton['state'] = Tk.NORMAL

    def plotData(self, iFrame, iTrace=None):
        for a in self.ax:
            a.cla()
            a.locator_params(tight=True, nbins=3)

        # in case no data, return an empty plot
        self.plot[0] = self.ax[0].plot()

        for r in range(4):
            for c in range(4):
                t, adc, frq, amp, thistimestamp = self.getTraceAndFFT(
                    iTrace=iTrace, chan=c + 4 * r)
                if not (t is None) and not (adc is None):
                    self.plot[c + 8 * r] = self.ax[c + 8 * r].plot(t, adc)
                    if c + 8 * r > 3: self.ax[c + 8 * r].set_xticklabels([])
                if not (frq is None) and not (amp is None):
                    self.plot[4 + c + 8 * r] = self.ax[4 + c + 8 * r].plot(
                        frq, amp, 'r')
                    if 4 + c + 8 * r < 28:
                        self.ax[4 + c + 8 * r].set_xticklabels([])

        self.figure.text(0.45, 0.04, 'Time [us]', ha='center', color='blue')
        self.figure.text(0.55,
                         0.04,
                         'Frequency [MHz]',
                         ha='center',
                         color='red')
        self.figure.text(0.042,
                         0.45,
                         'ADC',
                         ha='center',
                         rotation=90,
                         color='blue')
        self.figure.text(0.04,
                         0.55,
                         '|Y(freq)|',
                         ha='center',
                         rotation=90,
                         color='red')

        if not (thistimestamp is None):
            self.figure.suptitle(
                thistimestamp.replace(microsecond=0).isoformat(" "))
        self.canvas.draw()
        return self.plot[0]

    def getTraceAndFFT(self, iTrace=None, chan=0):
        """
    Gets trace from FEMB and returns 4 1D arrays:
        times, ADC counts, frequencies, Amplitude
    """
        Yfft_total = []
        first = 1
        data = None
        timestamp = None
        if iTrace is None:
            data = self.femb.get_data(100)
            timestamp = datetime.datetime.now()
            self.traces.append(data)
            self.timestamps.append(timestamp)
            if len(self.traces) > self.maxtraces:
                self.traces.pop(0)
                self.timestamps.pop(0)
            self.iTrace = len(self.traces) - 1
        else:
            data = self.traces[iTrace]
            timestamp = self.timestamps[iTrace]
        if data == None:
            #time.sleep(1.)
            return None, None, None, None, None
        if len(data) == 0:
            #time.sleep(1.)
            return None, None, None, None, None
        xpoint = []
        ypoint = []
        num = 0

        packetNum = 0
        wordArray = []
        for word in data:
            #print(str(packetNum) + "\t" + str(hex(word)) )
            if str(hex(word)) == "0xface":
                packetNum = 0
                wordArray = []
            if packetNum > 0 and packetNum < 13:
                wordArray.append(word)
            if packetNum == 12:
                chSamp = []
                for i in range(0, 16, 1):
                    chSamp.append(0)
                chSamp[0] = ((wordArray[5] & 0xFFF0) >> 4)
                chSamp[1] = ((wordArray[4] & 0xFF00) >> 8) | (
                    (wordArray[5] & 0x000F) << 8)
                chSamp[2] = ((wordArray[4] & 0x00FF) << 4) | (
                    (wordArray[3] & 0xF000) >> 12)
                chSamp[3] = ((wordArray[3] & 0x0FFF) >> 0)
                chSamp[4] = ((wordArray[2] & 0xFFF0) >> 4)
                chSamp[5] = ((wordArray[2] & 0x000F) << 8) | (
                    (wordArray[1] & 0xFF00) >> 8)
                chSamp[6] = ((wordArray[1] & 0x00FF) << 4) | (
                    (wordArray[0] & 0xF000) >> 12)
                chSamp[7] = ((wordArray[0] & 0x0FFF) >> 0)
                chSamp[8] = ((wordArray[11] & 0xFFF0) >> 4)
                chSamp[9] = ((wordArray[11] & 0x000F) << 8) | (
                    (wordArray[10] & 0xFF00) >> 8)
                chSamp[10] = ((wordArray[10] & 0x00FF) << 4) | (
                    (wordArray[9] & 0xF000) >> 12)
                chSamp[11] = ((wordArray[9] & 0x0FFF))
                chSamp[12] = ((wordArray[8] & 0xFFF0) >> 4)
                chSamp[13] = ((wordArray[8] & 0x000F) << 8) | (
                    (wordArray[7] & 0xFF00) >> 8)
                chSamp[14] = ((wordArray[7] & 0x00FF) << 4) | (
                    (wordArray[6] & 0xF000) >> 12)
                chSamp[15] = ((wordArray[6] & 0x0FFF))

                xpoint.append(num * 0.5)
                ypoint.append(chSamp[int(chan)])
                num = num + 1

            packetNum = packetNum + 1

        #return None, 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, timestamp
class FEMB_CONFIG(FEMB_CONFIG_BASE):
    def __init__(self):
        super().__init__()
        #declare board specific registers
        self.FEMB_VER = "adctest"
        self.REG_RESET = 0
        self.REG_ASIC_RESET = 1
        self.REG_ASIC_SPIPROG = 2
        self.REG_SEL_ASIC = 7
        self.REG_SEL_CH = 7
        self.REG_FESPI_BASE = 592
        self.REG_ADCSPI_BASE = 512
        self.REG_FESPI_RDBACK_BASE = 632
        self.REG_ADCSPI_RDBACK_BASE = 552
        self.REG_HS = 17
        self.REG_LATCHLOC = 4
        self.REG_CLKPHASE = 6
        #Latch latency 0x6666666f    Phase 0xffff0055
        self.ADC_TESTPATTERN = [
            0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca,
            0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef
        ]
        self.NASICS = 1
        self.FUNCGENINTER = RigolDG4000("/dev/usbtmc1", 1)
        self.POWERSUPPLYINTER = RigolDP800("/dev/usbtmc0", ["CH1"])
        self.F2DEFAULT = 0
        self.CLKDEFAULT = "fifo"

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

    def resetBoard(self):
        #Reset system
        self.femb.write_reg(self.REG_RESET, 1)
        time.sleep(5.)

        #Reset registers
        self.femb.write_reg(self.REG_RESET, 2)
        time.sleep(1.)

        #Time stamp reset
        #femb.write_reg( 0, 4)
        #time.sleep(0.5)

        #Reset ADC ASICs
        self.femb.write_reg(self.REG_ASIC_RESET, 1)
        time.sleep(0.5)

    def initBoard(self):
        nRetries = 5
        for iRetry in range(nRetries):
            #set up default registers

            #Reset ADC ASICs
            self.femb.write_reg(self.REG_ASIC_RESET, 1)
            time.sleep(0.5)

            #Set ADC test pattern register
            self.femb.write_reg(3, 0x01230000)  # test pattern off
            #self.femb.write_reg( 3, 0x81230000) # test pattern on

            #Set ADC latch_loc
            self.femb.write_reg(self.REG_LATCHLOC, 0x66666667)
            #Set ADC clock phase
            self.femb.write_reg(self.REG_CLKPHASE, 0xfffc0054)

            #internal test pulser control
            self.femb.write_reg(5, 0x00000000)
            self.femb.write_reg(13, 0x0)  #enable

            #Set test and readout mode register
            self.femb.write_reg(
                7, 0x0000)  #11-8 = channel select, 3-0 = ASIC select

            #Set number events per header
            self.femb.write_reg(8, 0x0)

            #ADC ASIC SPI registers
            print("Config ADC ASIC SPI")
            print("ADCADC")
            ## Corresponds to f0=f1=0, clk=0,clk1=1, pcsr=pdsr=frqc=1, tstin=1
            ## en_gr=0, slp=0
            ## Clocks from digital generator of FIFO
            regs = [
                0xC0C0C0C,
                0xC0C0C0C,
                0xC0C0C0C,
                0xC0C0C0C,
                0xC0C0C0C,
                0xC0C0C0C,
                0xC0C0C0C,
                0xC0C0C0C,
                0x18321832,
                0x18181819,
                0x18181818,
                0x18181818,
                0x18181818,
                0x18181818,
                0x18181818,
                0x18181818,
                0x64186418,
                0x30303030,
                0x30303030,
                0x30303030,
                0x30303030,
                0x30303030,
                0x30303030,
                0x30303030,
                0x30303030,
                0x60c868c8,
                0x60606868,
                0x60606868,
                0x60606868,
                0x60606868,
                0x60606868,
                0x60606868,
                0x60606868,
                0x9060A868,
                0x10001,
            ]

            self.adc_reg.set_sbnd_board(frqc=1,
                                        pdsr=1,
                                        pcsr=1,
                                        clk0=0,
                                        clk1=1,
                                        f1=0,
                                        f2=0,
                                        tstin=1)
            regs = self.adc_reg.REGS
            for iReg, val in enumerate(regs):
                #print("{:032b}".format(val))
                print("{:08x}".format(val))
                self.femb.write_reg(self.REG_ADCSPI_BASE + iReg, val)

            #ADC ASIC sync
            self.femb.write_reg(17,
                                0x1)  # controls HS link, 0 for on, 1 for off
            self.femb.write_reg(17,
                                0x0)  # controls HS link, 0 for on, 1 for off

            #Write ADC ASIC SPI
            print("Program ADC ASIC SPI")
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)

            print("Check ADC ASIC SPI")
            for regNum in range(self.REG_ADCSPI_RDBACK_BASE,
                                self.REG_ADCSPI_RDBACK_BASE + 34, 1):
                val = self.femb.read_reg(regNum)
                #print("{:08x}".format(val))

            #enable streaming
            #self.femb.write_reg( 9, 0x8)

            #LBNE_ADC_MODE
            self.femb.write_reg(16, 0x1)

            # Check that board streams data
            data = self.femb.get_data(1)
            if data == None:
                print("Board not streaming data, retrying initialization...")
                continue  # try initializing again
            print("FEMB_CONFIG--> Reset FEMB is DONE")
            return
        print(
            "Error: Board not streaming data after trying to initialize {} times. Exiting."
            .format(nRetries))
        sys.exit(1)

    def configAdcAsic_regs(self, Adcasic_regs):
        #ADC ASIC SPI registers
        print("FEMB_CONFIG--> Config ADC ASIC SPI")
        for k in range(10):
            i = 0
            for regNum in range(self.REG_ADCSPI_BASE,
                                self.REG_ADCSPI_BASE + len(Adcasic_regs), 1):
                #print("{:032b}".format(Adcasic_regs[i]))
                print("{:08x}".format(Adcasic_regs[i]))
                self.femb.write_reg(regNum, Adcasic_regs[i])
                time.sleep(0.05)
                i = i + 1

            #print("  ADC ASIC write : ",Adcasic_regs)
            #ADC ASIC sync
            self.femb.write_reg(17,
                                0x1)  # controls HS link, 0 for on, 1 for off
            self.femb.write_reg(17,
                                0x0)  # controls HS link, 0 for on, 1 for off

            #Write ADC ASIC SPI
            print("FEMB_CONFIG--> Program ADC ASIC SPI")
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)

            #self.femb.write_reg ( 18, 0x0)
            #time.sleep(0.1)

            #LBNE_ADC_MODE
            self.femb.write_reg(16, 0x1)

            print("FEMB_CONFIG--> Check ADC ASIC SPI")
            adcasic_rb_regs = []
            for regNum in range(
                    self.REG_ADCSPI_RDBACK_BASE,
                    self.REG_ADCSPI_RDBACK_BASE + len(Adcasic_regs), 1):
                val = self.femb.read_reg(regNum)
                #print("{:08x}".format(val))
                adcasic_rb_regs.append(val)

            #print("  ADC ASIC read back: ",adcasic_rb_regs)
            #if (adcasic_rb_regs !=Adcasic_regs  ) :
            #    #if ( k == 1 ):
            #    #    sys.exit("femb_config : Wrong readback. ADC SPI failed")
            #    #    return
            #    print("FEMB_CONFIG--> ADC ASIC Readback didn't match, retrying...")
            #else:
            if True:
                print("FEMB_CONFIG--> ADC ASIC SPI is OK")
                break
        #enable streaming
        #self.femb.write_reg ( 9, 0x8)
        #LBNE_ADC_MODE

    def configAdcAsic(self,
                      enableOffsetCurrent=None,
                      offsetCurrent=None,
                      testInput=None,
                      freqInternal=None,
                      sleep=None,
                      pdsr=None,
                      pcsr=None,
                      clockMonostable=None,
                      clockExternal=None,
                      clockFromFIFO=None,
                      sLSB=None,
                      f0=0,
                      f1=0,
                      f2=0,
                      f3=None,
                      f4=None,
                      f5=None):
        """
        Configure ADCs
          enableOffsetCurrent: 0 disable offset current, 1 enable offset current
          offsetCurrent: 0-15, amount of current to draw from sample and hold
          testInput: 0 digitize normal input, 1 digitize test input
          freqInternal: internal clock frequency: 0 1MHz, 1 2MHz
          sleep: 0 disable sleep mode, 1 enable sleep mode
          pdsr: if pcsr=0: 0 PD is low, 1 PD is high
          pcsr: 0 power down controlled by pdsr, 1 power down controlled externally
          Only one of these can be enabled:
            clockMonostable: True ADC uses monostable clock
            clockExternal: True ADC uses external clock
            clockFromFIFO: True ADC uses digital generator FIFO clock
          sLSB: LSB current steering mode. 0 for full, 1 for partial (ADC7 P1)
          f0, f1, f2, f3, f4, f5: version specific
        """
        FEMB_CONFIG_BASE.configAdcAsic(self,
                                       clockMonostable=clockMonostable,
                                       clockExternal=clockExternal,
                                       clockFromFIFO=clockFromFIFO)
        if enableOffsetCurrent is None:
            enableOffsetCurrent = 0
        if offsetCurrent is None:
            offsetCurrent = 0
        else:
            offsetCurrent = int(
                "{:04b}".format(offsetCurrent)[::-1],
                2)  # need to reverse bits, use string/list tricks
        if testInput is None:
            testInput = 1
        if freqInternal is None:
            freqInternal = 1
        if sleep is None:
            sleep = 0
        if pdsr is None:
            pdsr = 1
        if pcsr is None:
            pcsr = 1
        if not (clockMonostable or clockExternal or clockFromFIFO):
            clockFromFIFO = True
        clk0 = 0
        clk1 = 0
        if clockExternal:
            clk0 = 1
            clk1 = 0
        elif clockFromFIFO:
            clk0 = 0
            clk1 = 1
        self.adc_reg.set_sbnd_board(en_gr=enableOffsetCurrent,
                                    d=offsetCurrent,
                                    tstin=testInput,
                                    frqc=freqInternal,
                                    slp=sleep,
                                    pdsr=pdsr,
                                    pcsr=pcsr,
                                    clk0=clk0,
                                    clk1=clk1,
                                    f1=f1,
                                    f2=f2,
                                    res2=0,
                                    res1=1,
                                    res0=1)
        self.configAdcAsic_regs(self.adc_reg.REGS)

        #regs = [
        # 0xC0C0C0C,
        # 0xC0C0C0C,
        # 0xC0C0C0C,
        # 0xC0C0C0C,
        # 0xC0C0C0C,
        # 0xC0C0C0C,
        # 0xC0C0C0C,
        # 0xC0C0C0C,
        # 0x18321832,
        # 0x18181818,
        # 0x18181818,
        # 0x18181818,
        # 0x18181818,
        # 0x18181818,
        # 0x18181818,
        # 0x18181818,
        # 0x64186418,
        # 0x30303030,
        # 0x30303030,
        # 0x30303030,
        # 0x30303030,
        # 0x30303030,
        # 0x30303030,
        # 0x30303030,
        # 0x30303030,
        # 0x60c868c8,
        # 0x60606868,
        # 0x60606868,
        # 0x60606868,
        # 0x60606868,
        # 0x60606868,
        # 0x60606868,
        # 0x60606868,
        # 0x9060A868,
        # 0x10001,
        #]
        #self.configAdcAsic_regs(regs)

    def selectChannel(self, asic, chan, hsmode=None):
        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))

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

    def syncADC(self):
        #turn on ADC test mode
        print("Start sync ADC")
        reg3 = self.femb.read_reg(3)
        newReg3 = (reg3 | 0x80000000)
        self.femb.write_reg(3, newReg3)  #31 - enable ADC test pattern
        alreadySynced = True
        for a in range(0, self.NASICS, 1):
            print("Test ADC " + str(a))
            unsync = self.testUnsync(a)
            if unsync != 0:
                alreadySynced = False
                print("ADC not synced, try to fix")
                self.fixUnsync(a)
        LATCH = self.femb.read_reg(self.REG_LATCHLOC)
        PHASE = self.femb.read_reg(self.REG_CLKPHASE)
        self.femb.write_reg(3, reg3)  # turn off adc test pattern
        self.femb.write_reg(3, reg3)  # turn off adc test pattern
        print("Latch latency {:#010x} Phase: {:#010x}".format(LATCH, PHASE))
        print("End sync ADC")
        return not alreadySynced, LATCH, None, PHASE

    def testUnsync(self, adc):
        adcNum = int(adc)
        if (adcNum < 0) or (adcNum >= self.NASICS):
            print("femb_config_femb : testLink - invalid asic number")
            return

        #loop through channels, check test pattern against data
        badSync = 0
        for ch in range(0, 16, 1):
            self.selectChannel(adcNum, ch)
            time.sleep(0.1)
            for test in range(0, 1000, 1):
                data = self.femb.get_data(1)
                for samp in data:
                    chNum = ((samp >> 12) & 0xF)
                    sampVal = (samp & 0xFFF)
                    if sampVal != self.ADC_TESTPATTERN[ch]:
                        badSync = 1
                    if badSync == 1:
                        break
                if badSync == 1:
                    break
            if badSync == 1:
                break
        return badSync

    def fixUnsync(self, adc):
        adcNum = int(adc)
        if (adcNum < 0) or (adcNum >= self.NASICS):
            print("femb_config_femb : testLink - invalid asic number")
            return

        initLATCH = self.femb.read_reg(self.REG_LATCHLOC)
        initPHASE = self.femb.read_reg(self.REG_CLKPHASE)

        #loop through sync parameters
        for phase in range(0, 2, 1):
            clkMask = (0x1 << adcNum)
            testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum))
            self.femb.write_reg(self.REG_CLKPHASE, testPhase)
            for shift in range(0, 16, 1):
                shiftMask = (0xF << 4 * adcNum)
                testShift = ((initLATCH & ~(shiftMask)) |
                             (shift << 4 * adcNum))
                self.femb.write_reg(self.REG_LATCHLOC, testShift)
                #reset ADC ASIC
                self.femb.write_reg(self.REG_ASIC_RESET, 1)
                time.sleep(0.1)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.1)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.1)
                #test link
                unsync = self.testUnsync(adcNum)
                if unsync == 0:
                    print("ADC synchronized")
                    return
        #if program reaches here, sync has failed
        print("ADC SYNC process failed for ADC # " + str(adc))
class FEMB_CONFIG(FEMB_CONFIG_BASE):
    def __init__(self, exitOnError=True):
        super().__init__(exitOnError=exitOnError)
        #declare board specific registers
        self.FEMB_VER = "adctestP1quad"

        self.REG_RESET = 0  # bit 0 system, 1 reg, 2 alg, 3 udp
        self.REG_PWR_CTRL = 1  # bit 0-3 pwr, 8-15 blue LEDs near buttons
        self.REG_ASIC_SPIPROG_RESET = 2  # bit 0 FE SPI, 1 ADC SPI, 4 FE ASIC RESET, 5 ADC ASIC RESET, 6 SOFT ADC RESET & SPI readback check
        # I zero out REG_ASIC_SPIPROG_RESET a lot because only transitions from 0 to 1 do anything
        self.REG_SEL_CH = 3  # bit 0-7 chip, 8-15 channel, 31 WIB mode

        self.REG_DAC1 = 4  # bit 0-15 DAC val, 16-19 tp mode select, 31 set dac
        self.REG_DAC2 = 5  # bit 0-15 tp period, 16-31 tp shift

        self.REG_FPGA_TST_PATT = 6  # bit 0-11 tst patt, 16 enable

        self.REG_ADC_CLK = 7  # bit 0-3 clk phase, 8 clk speed sel
        self.REG_LATCHLOC = 8  # bit 0-7 ADC1, 8-15 ADC2, 16-23 ADC3, 24-31 ADC4

        self.REG_STOP_ADC = 9  # bit 0 stops sending convert, read ADC HEADER redundant with reg 2

        self.REG_UDP_FRAME_SIZE = 63  # bits 0-11
        self.REG_FIRMWARE_VERSION = 0xFF  # 255 in decimal
        self.CONFIG_FIRMWARE_VERSION = 259  # this file is written for this

        self.REG_LATCHLOC_data_2MHz = 0x02020202
        self.REG_LATCHLOC_data_1MHz = 0x0
        self.REG_LATCHLOC_data_2MHz_cold = 0x02020202
        self.REG_LATCHLOC_data_1MHz_cold = 0x0

        self.REG_CLKPHASE_data_2MHz = 0x4
        self.REG_CLKPHASE_data_1MHz = 0x0
        self.REG_CLKPHASE_data_2MHz_cold = 0x4
        self.REG_CLKPHASE_data_1MHz_cold = 0x0

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

        # registers 64-88 are SPI to ASICs
        # 88 is last register besides 255 which is firmware version
        self.REG_FESPI_BASE = 84  # this configures all FE ASICs
        self.REG_ADCSPI_BASES = [64, 69, 74, 79]  # for each chip

        self.REG_EXTCLK_INV = 10
        self.REG_EXTCLK_BASES = [11, 20, 29, 38]  # for each chip
        self.FPGA_FREQ_MHZ = 200  # frequency of FPGA clock in MHz

        self.REG_PLL_BASES = [17, 26, 35, 44]  # for each chip

        self.NASICS = 4
        #self.FUNCGENINTER = DummyFuncGen("","")
        self.FUNCGENINTER = Keysight_33600A("/dev/usbtmc0", 1)
        self.POWERSUPPLYINTER = DummyPowerSupply("", "")
        self.F2DEFAULT = 0
        self.CLKDEFAULT = "fifo"

        self.SAMPLERATE = 2e6

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

        self.adc_regs = []
        for i in range(self.NASICS):
            self.adc_regs.append(ADC_ASIC_REG_MAPPING())

        #self.defaultConfigFunc = lambda: self.configAdcAsic()
        self.defaultConfigFunc = lambda: self.configAdcAsic(clockMonostable=
                                                            True)
        #self.defaultConfigFunc = lambda: self.configAdcAsic(clockMonostable=True,freqInternal=0) # 1 MHz

    def resetBoard(self):
        """
        Reset registers and state machines NOT udp
        Make sure to set reg 0 back to zero
            or there will be much sadness!
        """
        #Reset registers
        self.femb.write_reg(self.REG_RESET, 2)
        time.sleep(1.)

        #Reset state machines
        self.femb.write_reg(self.REG_RESET, 4)
        time.sleep(1.)

        #Reset reset register to 0
        self.femb.write_reg(self.REG_RESET, 0)
        time.sleep(0.2)

    def initBoard(self):
        #set up default registers

        # test readback
        readback = self.femb.read_reg(1)
        if readback is None:
            if self.exitOnError:
                print("FEMB_CONFIG: Error reading register 0, Exiting.")
                sys.exit(1)
            else:
                raise ReadRegError("Couldn't read register 0")

        ##### Start Top-level Labview stacked sequence struct 0
        firmwareVersion = self.femb.read_reg(
            self.REG_FIRMWARE_VERSION) & 0xFFFF
        if firmwareVersion != self.CONFIG_FIRMWARE_VERSION:
            raise FEMBConfigError(
                "Board firmware version {} doesn't match configuration firmware version {}"
                .format(firmwareVersion, self.CONFIG_FIRMWARE_VERSION))
        print("Firmware Version: ", firmwareVersion)

        self.femb.write_reg(self.REG_UDP_FRAME_SIZE, 0x1FB)
        time.sleep(0.05)
        self.setFPGADac(0, 0, 0, 0)  # write regs 4 and 5
        self.femb.write_reg(1, 0)  # pwr ctrl
        self.femb.write_reg(3, (5 << 8))  # chn sel
        self.femb.write_reg(6, self.DEFAULT_FPGA_TST_PATTERN)  #tst pattern
        self.femb.write_reg(7, 13)  #adc clk
        self.femb.write_reg(8, 0)  #latchloc
        ##### End Top-level Labview stacked sequence struct 0

        self.turnOnAsics()

        nRetries = 1
        for iRetry in range(nRetries):

            #Reset ASICs
            self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET,
                                0x0)  # zero out reg
            self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET,
                                0x30)  # reset FE and ADC
            self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET,
                                0x0)  # zero out reg
            time.sleep(0.1)

            #Set FPGA test pattern register
            self.femb.write_reg(
                self.REG_FPGA_TST_PATT,
                self.DEFAULT_FPGA_TST_PATTERN)  # test pattern off
            #self.femb.write_reg(self.REG_FPGA_TST_PATT, self.DEFAULT_FPGA_TST_PATTERN+(1 << 16)) # test pattern on
            #Set ADC latch_loc and clock phase and sample rate
            if self.SAMPLERATE == 1e6:
                if self.COLD:
                    self.femb.write_reg(self.REG_LATCHLOC,
                                        self.REG_LATCHLOC_data_1MHz_cold)
                    self.femb.write_reg(
                        self.REG_ADC_CLK,
                        (self.REG_CLKPHASE_data_1MHz_cold & 0xF) | (1 << 8))
                else:
                    self.femb.write_reg(self.REG_LATCHLOC,
                                        self.REG_LATCHLOC_data_1MHz)
                    self.femb.write_reg(self.REG_ADC_CLK,
                                        (self.REG_CLKPHASE_data_1MHz & 0xF) |
                                        (1 << 8))
            else:  # use 2 MHz values
                if self.COLD:
                    self.femb.write_reg(self.REG_LATCHLOC,
                                        self.REG_LATCHLOC_data_2MHz_cold)
                    self.femb.write_reg(
                        self.REG_ADC_CLK,
                        (self.REG_CLKPHASE_data_2MHz_cold & 0xF))
                else:
                    self.femb.write_reg(self.REG_LATCHLOC,
                                        self.REG_LATCHLOC_data_2MHz)
                    self.femb.write_reg(self.REG_ADC_CLK,
                                        (self.REG_CLKPHASE_data_2MHz & 0xF))
            self.writePLLs(0, 0x20001, 0)

            self.setFPGADac(0, 1, 0, 0)

            #Configure ADC (and external clock inside)
            try:
                #self.femb.write_reg(self.REG_FESPI_BASE,1)
                ##self.adc_regs[0].set_chip(frqc=1)
                #regsListOfLists = []
                #for chipRegConfig in self.adc_regs:
                #    chipRegConfig.set_chip(frqc=1)
                #    regsListOfLists.append(chipRegConfig.REGS)
                #self.configAdcAsic_regs(regsListOfLists)

                self.defaultConfigFunc()
            except ReadRegError:
                continue

            print("ADC Soft Reset...")
            self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET,
                                1 << 6)  # ADC soft reset
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET,
                                0x0)  # zero out reg
            time.sleep(0.1)

            #            self.printSyncRegister()
            #            self.syncADC()

            self.printSyncRegister()

            self.selectChannel(0, 0)  # not packed many channels

            #print("Stop ADC...")
            #self.femb.write_reg(self.REG_STOP_ADC,1)
            #time.sleep(0.1)
            #print("Start ADC...")
            #self.femb.write_reg(self.REG_STOP_ADC,0)
            #time.sleep(0.1)
            #self.printSyncRegister()

            # Check that board streams data
            data = self.femb.get_data(1)
            if data == None:
                print("Board not streaming data, retrying initialization...")
                continue  # try initializing again
            print("FEMB_CONFIG--> Reset FEMB is DONE")
            return
        print(
            "Error: Board not streaming data after trying to initialize {} times."
            .format(nRetries))
        if self.exitOnError:
            print("Exiting.")
            sys.exit(1)
        else:
            raise InitBoardError

    def configAdcAsic_regs(self, Adcasic_regs):
        """
        Takes a list NASICS long, each a list of 5 32 bit registers.
        """
        #ADC ASIC SPI registers
        assert (type(Adcasic_regs) == list)
        assert (len(Adcasic_regs) == self.NASICS)
        print("FEMB_CONFIG--> Config ADC ASIC SPI")
        for iTry in range(2):
            #print("  Try at writing SPI: ",iTry+1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0)
            for iChip, chipRegs in enumerate(Adcasic_regs):
                assert (len(chipRegs) == 5)
                for iReg in range(5):
                    self.femb.write_reg(self.REG_ADCSPI_BASES[iChip] + iReg,
                                        chipRegs[iReg])
                    #print("{:3}  {:#010x}".format(self.REG_ADCSPI_BASES[iChip]+iReg, chipRegs[iReg]))
                    time.sleep(0.05)

            self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 3)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 2)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 0)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_RESET, 0)
            time.sleep(0.1)

        self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET, 1 << 6)  # soft reset

        self.printSyncRegister()

    def getSyncStatus(self):
        syncBits = None
        adc0 = None
        fe0 = None
        adc1 = None
        fe1 = None
        adc2 = None
        fe2 = None
        adc3 = None
        fe3 = None
        reg = self.femb.read_reg(self.REG_ASIC_SPIPROG_RESET)
        if reg is None:
            print("Error: can't read back sync register")
            if self.exitOnError:
                return
            else:
                raise ReadRegError
        else:
            print("Register 2: {:#010x}".format(reg))
            syncBits = reg >> 24
            reg = reg >> 16
            adc0 = ((reg >> 0) & 1) == 1
            fe0 = ((reg >> 1) & 1) == 1
            adc1 = ((reg >> 2) & 1) == 1
            fe1 = ((reg >> 3) & 1) == 1
            adc2 = ((reg >> 4) & 1) == 1
            fe2 = ((reg >> 5) & 1) == 1
            adc3 = ((reg >> 6) & 1) == 1
            fe3 = ((reg >> 7) & 1) == 1
        return (fe0, fe1, fe2, fe3), (adc0, adc1, adc2, adc3), syncBits

    def printSyncRegister(self):
        (fe0, fe1, fe2, fe3), (adc0, adc1, adc2,
                               adc3), syncBits = self.getSyncStatus()
        reg = self.femb.read_reg(self.REG_ASIC_SPIPROG_RESET)
        print("ASIC Readback Status:")
        print("  ADC 0:", adc0, "FE 0:", fe0)
        print("  ADC 1:", adc1, "FE 1:", fe1)
        print("  ADC 2:", adc2, "FE 2:", fe2)
        print("  ADC 3:", adc3, "FE 3:", fe3)
        print("ADC Sync Bits: {:#010b} (0 is good)".format(syncBits))

    def configAdcAsic(self,
                      enableOffsetCurrent=None,
                      offsetCurrent=None,
                      testInput=None,
                      freqInternal=None,
                      sleep=None,
                      pdsr=None,
                      pcsr=None,
                      clockMonostable=None,
                      clockExternal=None,
                      clockFromFIFO=None,
                      sLSB=None,
                      f0=None,
                      f1=None,
                      f2=None,
                      f3=None,
                      f4=None,
                      f5=None):
        """
        Configure ADCs
          enableOffsetCurrent: 0 disable offset current, 1 enable offset current
          offsetCurrent: 0-15, amount of current to draw from sample and hold
          testInput: 0 digitize normal input, 1 digitize test input
          freqInternal: internal clock frequency: 0 1MHz, 1 2MHz
          sleep: 0 disable sleep mode, 1 enable sleep mode
          pdsr: if pcsr=0: 0 PD is low, 1 PD is high
          pcsr: 0 power down controlled by pdsr, 1 power down controlled externally
          Only one of these can be enabled:
            clockMonostable: True ADC uses monostable clock
            clockExternal: True ADC uses external clock
            clockFromFIFO: True ADC uses digital generator FIFO clock
          sLSB: LSB current steering mode. 0 for full, 1 for partial (ADC7 P1)
          f0, f1, f2, f3, f4, f5: version specific
        """
        FEMB_CONFIG_BASE.configAdcAsic(self,
                                       clockMonostable=clockMonostable,
                                       clockExternal=clockExternal,
                                       clockFromFIFO=clockFromFIFO)
        if enableOffsetCurrent is None:
            enableOffsetCurrent = 0
        if offsetCurrent is None:
            offsetCurrent = 0
        else:
            offsetCurrent = int(
                "{:04b}".format(offsetCurrent)[::-1],
                2)  # need to reverse bits, use string/list tricks
        if testInput is None:
            testInput = 1
        if freqInternal is None:
            freqInternal = 1
        if sleep is None:
            sleep = 0
        if pdsr is None:
            pdsr = 0
        if pcsr is None:
            pcsr = 0
        if sLSB is None:
            sLSB = 0
        if f1 is None:
            f1 = 0
        if f2 is None:
            f2 = 0
        if f3 is None:
            f3 = 0
        if f4 is None:
            f4 = 1
        if f5 is None:
            f5 = 0
        if not (clockMonostable or clockExternal or clockFromFIFO):
            clockExternal = True
        # a bunch of things depend on the clock choice
        clk0 = 0
        clk1 = 0
        if clockExternal:
            clk0 = 1
            clk1 = 0
        elif clockFromFIFO:
            clk0 = 0
            clk1 = 1
        if f0 is None:
            if clockExternal:
                f0 = 1
            else:
                f0 = 0
        if clockExternal:
            self.extClock(enable=True)
        else:
            self.extClock(enable=False)

        regsListOfLists = []
        for chipRegConfig in self.adc_regs:
            chipRegConfig.set_chip(en_gr=enableOffsetCurrent,
                                   d=offsetCurrent,
                                   tstin=testInput,
                                   frqc=freqInternal,
                                   slp=sleep,
                                   pdsr=pdsr,
                                   pcsr=pcsr,
                                   clk0=clk0,
                                   clk1=clk1,
                                   f0=f0,
                                   f1=f1,
                                   f2=f2,
                                   f3=f3,
                                   f4=f4,
                                   f5=f5,
                                   slsb=sLSB)
            regsListOfLists.append(chipRegConfig.REGS)
        self.configAdcAsic_regs(regsListOfLists)

    def selectChannel(self, asic, chan, hsmode=1, singlechannelmode=0):
        """
        asic is chip number 0 to 7
        chan is channel within asic from 0 to 15
        hsmode: if 0 then WIB streaming mode, 
            if 1 then sends ch then adc, defaults to 1
        singlechannelmode: if 1 and hsmode = 0, then only 
            send a single channel of data instead of 16 in a row
        
        """
        hsmodeVal = int(hsmode) & 1  # only 1 bit
        hsmodeVal = (~hsmodeVal) & 1  # flip bit
        singlechannelmode = int(singlechannelmode) & 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_STOP_ADC, 1)
        time.sleep(0.05)

        # bit 4 of chVal is the single channel mode bit
        chVal += (singlechannelmode << 4)

        # in this firmware asic = 0 disables readout, so asics are 1,2,3,4

        regVal = (asicVal + 1) + (chVal << 8) + (hsmodeVal << 31)
        self.femb.write_reg(self.REG_SEL_CH, regVal)
        time.sleep(0.05)

        self.femb.write_reg(self.REG_STOP_ADC, 0)

    def syncADC(self, iASIC=None):
        #return True, 0, 0
        #turn on ADC test mode
        print("FEMB_CONFIG--> Start sync ADC")

        self.configAdcAsic(clockMonostable=True, f4=0, f5=1)
        time.sleep(0.1)

        alreadySynced = True
        asicsToSync = [iASIC]
        if iASIC is None:
            # not actually getting for sync just for properly configured ADC chips
            feSPI, adcSPI, syncBits = self.getSyncStatus()
            asicsToSync = [i for i in range(self.NASICS) if adcSPI[i]]
        for a in asicsToSync:
            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)
        latchloc = None
        phase = None
        latchloc = self.femb.read_reg(self.REG_LATCHLOC)
        clkphase = self.femb.read_reg(self.REG_ADC_CLK) & 0b1111
        if self.SAMPLERATE == 1e6:
            if self.COLD:
                self.REG_LATCHLOC_data_1MHz_cold = latchloc
                self.REG_CLKPHASE_data_1MHz_cold = clkphase
            else:
                self.REG_LATCHLOC_data_1MHz = latchloc
                self.REG_CLKPHASE_data_1MHz = clkphase
        else:  # 2 MHz
            if self.COLD:
                self.REG_LATCHLOC_data_2MHZ_cold = latchloc
                self.REG_CLKPHASE_data_2MHZ_cold = clkphase
            else:
                self.REG_LATCHLOC_data_2MHZ = latchloc
                self.REG_CLKPHASE_data_2MHZ = clkphase
        print("FEMB_CONFIG--> Latch latency {:#010x} Phase: {:#010x}".format(
            latchloc, clkphase))
        self.defaultConfigFunc()
        print("FEMB_CONFIG--> End sync ADC")
        return not alreadySynced, latchloc, None, clkphase

    def testUnsync(self, adc, npackets=10):
        #return 0, []
        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

#        syncBits = self.femb.read_reg(2) >> 24
#        theseSyncBits = (syncBits >> (2*adc)) & 0b11
#        if theseSyncBits == 0:
#            return 0, []
#        else:
#            return 1, []

#loop through channels, check test pattern against data
        syncDataCounts = [{} for i in range(16)]  #dict for each channel
        self.selectChannel(adcNum, 0, singlechannelmode=0)
        time.sleep(0.05)
        data = self.femb.get_data(npackets)
        if data == None:
            print("Error: Couldn't read data in testUnsync")
            if self.exitOnError:
                print("Exiting.")
                sys.exit(1)
            else:
                raise SyncADCError
        for samp in data:
            if samp == None:
                continue
            ch = ((samp >> 12) & 0xF)
            sampVal = (samp & 0xFFF)
            if sampVal in syncDataCounts[ch]:
                syncDataCounts[ch][sampVal] += 1
            else:
                syncDataCounts[ch][sampVal] = 1
        # check jitter
        print("Channel 0:")
        for key in sorted(syncDataCounts[0]):
            print(" {0:#06x} = {0:#018b} count: {1}".format(
                key, syncDataCounts[0][key]))
        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 fixUnsync(self, adc):
        adcNum = int(adc)
        if (adcNum < 0) or (adcNum > 7):
            print(
                "FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number"
            )
            return

        initLATCH = self.femb.read_reg(self.REG_LATCHLOC)
        initPHASE = self.femb.read_reg(
            self.REG_ADC_CLK)  # remember bit 16 sample rate

        phases = [0, 1]
        if self.COLD:
            phases = [0, 1, 0, 1, 0]

        #loop through sync parameters
        for shift in range(0, 16, 1):
            shiftMask = (0xFF << 8 * adcNum)
            testShift = ((initLATCH & ~(shiftMask)) | (shift << 8 * adcNum))
            self.femb.write_reg(self.REG_LATCHLOC, testShift)
            time.sleep(0.01)
            for phase in phases:
                clkMask = (0x1 << adcNum)
                testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum))
                self.femb.write_reg(self.REG_ADC_CLK, testPhase)
                time.sleep(0.01)
                print("try shift: {} phase: {} testingUnsync...".format(
                    shift, phase))
                #reset ADC ASIC
                self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET,
                                    1 << 6)  # ADC soft reset
                time.sleep(0.1)
                self.femb.write_reg(self.REG_ASIC_SPIPROG_RESET,
                                    0x0)  # zero out reg
                time.sleep(0.1)
                #test link
                unsync, syncDicts = self.testUnsync(adcNum)
                if unsync == 0:
                    print("FEMB_CONFIG--> ADC synchronized")
                    return
        #if program reaches here, sync has failed
        print("Error: FEMB_CONFIG--> ADC SYNC process failed for ADC # " +
              str(adc))
        print(
            "Setting back to original values: LATCHLOC: {:#010x}, PHASE: {:#010x}"
            .format(initLATCH, initPHASE & 0xF))
        self.femb.write_reg(self.REG_LATCHLOC, initLATCH)
        self.femb.write_reg(self.REG_ADC_CLK, initPHASE)
        if self.exitOnError:
            sys.exit(1)
        else:
            raise SyncADCError

    def extClock(self,
                 enable=False,
                 period=500,
                 mult=1,
                 offset_rst=0,
                 offset_read=480,
                 offset_msb=230,
                 offset_lsb=480,
                 width_rst=50,
                 width_read=20,
                 width_msb=270,
                 width_lsb=20,
                 offset_lsb_1st_1=50,
                 width_lsb_1st_1=190,
                 offset_lsb_1st_2=480,
                 width_lsb_1st_2=20,
                 inv_rst=True,
                 inv_read=True,
                 inv_msb=False,
                 inv_lsb=False,
                 inv_lsb_1st=False):
        """
        Programs external clock. All non-boolean arguments except mult are in nanoseconds
        IDXM = msb
        IDXL = lsb
        IDL = lsb_1st
        """

        rd_off = 0
        rst_off = 0
        rst_wid = 0
        msb_off = 0
        msb_wid = 0
        lsb_fc_wid2 = 0
        lsb_fc_off1 = 0
        rd_wid = 0
        lsb_fc_wid1 = 0
        lsb_fc_off2 = 0
        lsb_wid = 0
        lsb_off = 0
        inv = 0

        if enable:
            clock = 1. / self.FPGA_FREQ_MHZ * 1000.  # clock now in ns
            denominator = clock / mult
            period_val = period // denominator
            #print("FPGA Clock freq: {} MHz period: {} ns".format(self.FPGA_FREQ_MHZ,clock))
            #print("ExtClock option mult: {}".format(mult))
            #print("ExtClock option period: {} ns".format(period))
            #print("ExtClock option offset_read: {} ns".format(offset_read))
            #print("ExtClock option offset_rst: {} ns".format(offset_rst))
            #print("ExtClock option offset_msb: {} ns".format(offset_msb))
            #print("ExtClock option offset_lsb: {} ns".format(offset_lsb))
            #print("ExtClock option offset_lsb_1st_1: {} ns".format(offset_lsb_1st_1))
            #print("ExtClock option offset_lsb_1st_2: {} ns".format(offset_lsb_1st_2))
            #print("ExtClock option width_read: {} ns".format(width_read))
            #print("ExtClock option width_rst: {} ns".format(width_rst))
            #print("ExtClock option width_msb: {} ns".format(width_msb))
            #print("ExtClock option width_lsb: {} ns".format(width_lsb))
            #print("ExtClock option width_lsb_1st_1: {} ns".format(width_lsb_1st_1))
            #print("ExtClock option width_lsb_1st_2: {} ns".format(width_lsb_1st_2))
            #print("ExtClock option inv_rst: {}".format(inv_rst))
            #print("ExtClock option inv_read: {}".format(inv_read))
            #print("ExtClock option inv_msb: {}".format(inv_msb))
            #print("ExtClock option inv_lsb: {}".format(inv_lsb))
            #print("ExtClock option inv_lsb_1st: {}".format(inv_lsb_1st))
            #print("ExtClock denominator: {} ns".format(denominator))
            #print("ExtClock period: {} ns".format(period_val))

            rd_off = int(offset_read // denominator) & 0xFFFF
            rst_off = int(offset_rst // denominator) & 0xFFFF
            rst_wid = int(width_rst // denominator) & 0xFFFF
            msb_off = int(offset_msb // denominator) & 0xFFFF
            msb_wid = int(width_msb // denominator) & 0xFFFF
            lsb_fc_wid2 = int(width_lsb_1st_2 // denominator) & 0xFFFF
            lsb_fc_off1 = int(offset_lsb_1st_1 // denominator) & 0xFFFF
            rd_wid = int(width_read // denominator) & 0xFFFF
            lsb_fc_wid1 = int(width_lsb_1st_1 // denominator) & 0xFFFF
            lsb_fc_off2 = int(offset_lsb_1st_2 // denominator) & 0xFFFF
            lsb_wid = int(width_lsb // denominator) & 0xFFFF
            lsb_off = int(offset_lsb // denominator) & 0xFFFF

            if inv_rst:
                inv += 1 << 0
            if inv_read:
                inv += 1 << 1
            if inv_msb:
                inv += 1 << 2
            if inv_lsb:
                inv += 1 << 3
            if inv_lsb_1st:
                inv += 1 << 4

        def writeRegAndPrint(name, reg, val):
            #print("ExtClock Register {0:15} number {1:3} set to {2:10} = {2:#010x}".format(name,reg,val))
            #print("ExtClock Register {0:15} number {1:3} set to {2:#034b}".format(name,reg,val))
            self.femb.write_reg(reg, val)

        writeRegAndPrint("inv", self.REG_EXTCLK_INV, inv),
        for iChip, regBase in enumerate(self.REG_EXTCLK_BASES):
            iStr = str(iChip)
            asicRegs = [
                ("RST_ADC" + iStr, (rst_wid << 16) | rst_off),
                ("READ_ADC" + iStr, (rd_wid << 16) | rd_off),
                ("IDXM_ADC" + iStr, (msb_wid << 16) | msb_off),  # msb
                ("IDXL_ADC" + iStr, (lsb_wid << 16) | lsb_off),  # lsb
                ("IDL1_ADC" + iStr,
                 (lsb_fc_wid1 << 16) | lsb_fc_off1),  # lsb_fc_1
                ("IDL2_ADC" + iStr,
                 (lsb_fc_wid2 << 16) | lsb_fc_off2),  # lsb_fc_1
            ]
            for iReg, tup in enumerate(asicRegs):
                name = tup[0]
                val = tup[1]
                writeRegAndPrint(name, regBase + iReg, val)

    def turnOffAsics(self):
        oldReg = self.femb.read_reg(self.REG_PWR_CTRL)
        newReg = oldReg & 0xFFFFFFF0
        self.femb.write_reg(self.REG_PWR_CTRL, newReg)
        #pause after turning off ASICs
        time.sleep(2)
        #self.femb.write_reg(self.REG_RESET, 4) # bit 2 is ASIC reset as far as I can see

    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))
        oldReg = self.femb.read_reg(self.REG_PWR_CTRL)
        newReg = oldReg | (1 << asic)
        self.femb.write_reg(self.REG_PWR_CTRL, newReg)

        time.sleep(2)  #pause after turn on
        #self.femb.write_reg(self.REG_RESET, 4) # bit 2 is ASIC reset as far as I can see

    def turnOnAsics(self):
        print("turnOnAsics 0-{}".format(int(self.NASICS - 1)))

        reg = self.femb.read_reg(self.REG_PWR_CTRL)
        for iAsic in reversed(range(self.NASICS)):
            print("iAsic", iAsic)
            reg = reg | (1 << iAsic)
            self.femb.write_reg(self.REG_PWR_CTRL, reg)
            if iAsic > 0:
                print("sleeping...")
                time.sleep(5.)

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

    def setFPGADac(self, amp, mode, freq, delay):
        """
        mode: 0 DAC only, 1 ext tp, 2 gnd, 3 1.8V, 4 test pulse, 5 1.8V FE, 6 ASIC TP DAC
        """
        ampRegVal = ((mode & 0xFFFF) << 16) | (amp & 0xFFFF)
        freqRegVal = ((delay & 0xFFFF) << 16) | (freq & 0xFFFF)

        self.femb.write_reg(self.REG_DAC2, freqRegVal)
        time.sleep(0.05)

        self.femb.write_reg(self.REG_DAC1, ampRegVal)
        time.sleep(0.05)
        self.femb.write_reg(self.REG_DAC1, ampRegVal & 0x80000000)
        time.sleep(0.05)
        self.femb.write_reg(self.REG_DAC1, ampRegVal)

    def writePLLs(self, step0, step1, step2):
        for iChip in range(3):
            self.writePLL(iChip, step0, step1, step2)

    def writePLL(self, iChip, step0, step1, step2):
        def writeRegAndPrint(name, reg, val):
            self.femb.write_reg(reg, val)
            time.sleep(0.05)
            readback = self.femb.read_reg(reg)
            #print("PLL Register {0:15} number {1:3} set to {2:10} = {2:#010x}".format(name,reg,val))
            #print("PLL Register {0:15} number {1:3} set to {2:#034b}".format(name,reg,val))
            if readback == val:
                pass
                #print("  Readback match")
            else:
                print(
                    "PLL Register {0:15} number {1:3} set to {2:10} = {2:#010x}"
                    .format(name, reg, val))
                print(
                    "  READBACK DOESN'T MATCH! write: {:#010x} read: {:#010x}".
                    format(val, readback))

        regBase = self.REG_PLL_BASES[iChip]
        iStr = str(iChip)
        asicRegs = [
            ("pll_STEP0_ADC" + iStr, step0),
            ("pll_STEP1_ADC" + iStr, step1),
            ("pll_STEP2_ADC" + iStr, step2),
        ]
        for iReg, tup in enumerate(asicRegs):
            name = tup[0]
            val = tup[1]
            writeRegAndPrint(name, regBase + iReg, val)

    def syncPLLs(self):
        for iChip in range(1):
            syncd, detail = self.testUnsync(iChip)

    def programFirmware(self, firmware):
        """
        Programs the FPGA using the firmware file given.
        """
        pass

    def checkFirmwareProgrammerStatus(self):
        """
        Prints a debug message for the firmware programmer
        """
        pass

    def programFirmware1Mhz(self):
        pass

    def programFirmware2Mhz(self):
        pass

    def getClockStr(self):
        latchloc = self.femb.read_reg(self.REG_LATCHLOC)
        clkphase = self.femb.read_reg(self.REG_ADC_CLK)
        if latchloc is None:
            return "Register Read Error"
        if clkphase is None:
            return "Register Read Error"
        return "Latch Loc: {:#010x} Clock Phase: {:#010x}".format(
            latchloc, clkphase & 0xF)
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 = "/opt/sw/releases/femb_firmware-0.1.0/adc_tester/S7_2M_SBND_FPGA.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 resetBoard(self):
        #Reset system
        self.femb.write_reg(self.REG_RESET, 1)
        time.sleep(5.)

        #Reset registers
        self.femb.write_reg(self.REG_RESET, 2)
        time.sleep(1.)

        #Time stamp reset
        #femb.write_reg( 0, 4)
        #time.sleep(0.5)

        #Reset ADC ASICs
        self.femb.write_reg(self.REG_ASIC_RESET, 1)
        time.sleep(0.5)

    def initBoard(self):
        nRetries = 5
        for iRetry in range(nRetries):
            #set up default registers

            #Reset ADC ASICs
            self.femb.write_reg(self.REG_ASIC_RESET, 1)
            time.sleep(0.5)

            readback = self.femb.read_reg(0)
            if readback is None:
                if self.exitOnError:
                    print("FEMB_CONFIG: Error reading register 0, Exiting.")
                    sys.exit(1)
                else:
                    raise ReadRegError("Couldn't read register 0")

            #Set ADC test pattern register
            self.femb.write_reg(3, 0x01170000)  # test pattern off
            #self.femb.write_reg( 3, 0x81170000) # test pattern on

            #Set ADC latch_loc and clock phase
            latchloc1 = None
            latchloc5 = None
            clockphase = None
            if self.SAMPLERATE == 1e6:
                if self.COLD:
                    print("Using 1 MHz cold latchloc/clockphase")
                    latchloc1 = self.REG_LATCHLOC1_4_data_1MHz_cold
                    latchloc5 = self.REG_LATCHLOC5_8_data_1MHz_cold
                    clockphase = self.REG_CLKPHASE_data_1MHz_cold
                else:
                    print("Using 1 MHz warm latchloc/clockphase")
                    latchloc1 = self.REG_LATCHLOC1_4_data_1MHz
                    latchloc5 = self.REG_LATCHLOC5_8_data_1MHz
                    clockphase = self.REG_CLKPHASE_data_1MHz
            else:  # use 2 MHz values
                if self.COLD:
                    print("Using 2 MHz cold latchloc/clockphase")
                    latchloc1 = self.REG_LATCHLOC1_4_data_cold
                    latchloc5 = self.REG_LATCHLOC5_8_data_cold
                    clockphase = self.REG_CLKPHASE_data_cold
                else:
                    print("Using 2 MHz warm latchloc/clockphase")
                    latchloc1 = self.REG_LATCHLOC1_4_data
                    latchloc5 = self.REG_LATCHLOC5_8_data
                    clockphase = self.REG_CLKPHASE_data

            print(
                "Initializing with Latch Loc: {:#010x} {:#010x} Clock Phase: {:#010x}"
                .format(latchloc1, latchloc5, clockphase))
            self.femb.write_reg(self.REG_LATCHLOC1_4, latchloc1)
            self.femb.write_reg(self.REG_LATCHLOC5_8, latchloc5)
            for iTry in range(5):
                self.femb.write_reg(self.REG_CLKPHASE, ~clockphase)
                time.sleep(0.05)
                self.femb.write_reg(self.REG_CLKPHASE, ~clockphase)
                time.sleep(0.05)
                self.femb.write_reg(self.REG_CLKPHASE, clockphase)
                time.sleep(0.05)
                self.femb.write_reg(self.REG_CLKPHASE, clockphase)
                time.sleep(0.05)

            print("Readback: ", self.getClockStr())

            #internal test pulser control
            self.femb.write_reg(5, 0x00000000)
            self.femb.write_reg(13, 0x0)  #enable

            #Set test and readout mode register
            self.femb.write_reg(
                self.REG_HS,
                0x0)  # 0 readout all 15 channels, 1 readout only selected one
            self.femb.write_reg(
                self.REG_SEL_CH,
                0x0000)  #11-8 = channel select, 3-0 = ASIC select

            #Set number events per header
            self.femb.write_reg(8, 0x0)

            #Configure ADC (and external clock inside)
            try:
                self.configAdcAsic()
                #self.configAdcAsic(clockMonostable=True)
            except ReadRegError:
                continue
            # Check that board streams data
            data = self.femb.get_data(1)
            if data == None:
                print("Board not streaming data, retrying initialization...")
                continue  # try initializing again
            print("FEMB_CONFIG--> Reset FEMB is DONE")
            return
        print(
            "Error: Board not streaming data after trying to initialize {} times."
            .format(nRetries))
        if self.exitOnError:
            print("Exiting.")
            sys.exit(1)
        else:
            raise InitBoardError

    def configAdcAsic_regs(self, Adcasic_regs):
        #ADC ASIC SPI registers
        assert (len(Adcasic_regs) == 36)
        print("FEMB_CONFIG--> Config ADC ASIC SPI")
        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])
                time.sleep(0.05)
                i = i + 1

            #print("  ADC ASIC write : ",Adcasic_regs)
            #ADC ASIC sync -- Justin: I don't think this exists anymore
            #self.femb.write_reg ( 17, 0x1) # controls HS link, 0 for on, 1 for off
            #self.femb.write_reg ( 17, 0x0) # controls HS link, 0 for on, 1 for off

            #Write ADC ASIC SPI
            print("FEMB_CONFIG--> Program ADC ASIC SPI")
            self.femb.write_reg(self.REG_ASIC_RESET, 1)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)

            #enable streaming
            #self.femb.write_reg( 9, 0x1)

            #LBNE_ADC_MODE
            self.femb.write_reg(18, 0x1)

            print("FEMB_CONFIG--> Check ADC ASIC SPI")
            adcasic_rb_regs = []
            for regNum in range(
                    self.REG_ADCSPI_RDBACK_BASE,
                    self.REG_ADCSPI_RDBACK_BASE + len(Adcasic_regs), 1):
                val = self.femb.read_reg(regNum)
                if val is None:
                    message = "Error in FEMB_CONFIG.configAdcAsic_regs: read from board failed"
                    print(message)
                    if self.exitOnError:
                        return
                    else:
                        raise ReadRegError
                adcasic_rb_regs.append(val)

            #print("{:32}  {:32}".format("Write","Readback"))
            #print("{:8}  {:8}".format("Write","Readback"))
            # we only get 15 LSBs back so miss D0 for a channel and CLK0
            readbackMatch = True
            for regNum in range(36):
                write_val = Adcasic_regs[regNum]  #& 0x7FFF
                readback_val = adcasic_rb_regs[(regNum + 9) % 36] >> 1
                # we only get the 15 LSBs back
                if readback_val != (Adcasic_regs[regNum] & 0x7FFF):
                    readbackMatch = False
                #print("{:032b}  {:032b}".format(write_val,readback_val))
                #print("{:08X}  {:08X}".format(write_val,readback_val))

            if readbackMatch:
                print("FEMB_CONFIG--> ADC ASIC SPI is OK")
                return
            else:
                print(
                    "FEMB_CONFIG--> ADC ASIC Readback didn't match, retrying..."
                )
        print("Error: Wrong ADC SPI readback.")
        if self.exitOnError:
            print("Exiting.")
            sys.exit(1)
        else:
            raise ConfigADCError

    def configAdcAsic(self,
                      enableOffsetCurrent=None,
                      offsetCurrent=None,
                      testInput=None,
                      freqInternal=None,
                      sleep=None,
                      pdsr=None,
                      pcsr=None,
                      clockMonostable=None,
                      clockExternal=None,
                      clockFromFIFO=None,
                      sLSB=None,
                      f0=None,
                      f1=None,
                      f2=None,
                      f3=None,
                      f4=None,
                      f5=None):
        """
        Configure ADCs
          enableOffsetCurrent: 0 disable offset current, 1 enable offset current
          offsetCurrent: 0-15, amount of current to draw from sample and hold
          testInput: 0 digitize normal input, 1 digitize test input
          freqInternal: internal clock frequency: 0 1MHz, 1 2MHz
          sleep: 0 disable sleep mode, 1 enable sleep mode
          pdsr: if pcsr=0: 0 PD is low, 1 PD is high
          pcsr: 0 power down controlled by pdsr, 1 power down controlled externally
          Only one of these can be enabled:
            clockMonostable: True ADC uses monostable clock
            clockExternal: True ADC uses external clock
            clockFromFIFO: True ADC uses digital generator FIFO clock
          sLSB: LSB current steering mode. 0 for full, 1 for partial (ADC7 P1)
          f0, f1, f2, f3, f4, f5: version specific
        """
        FEMB_CONFIG_BASE.configAdcAsic(self,
                                       clockMonostable=clockMonostable,
                                       clockExternal=clockExternal,
                                       clockFromFIFO=clockFromFIFO)
        if enableOffsetCurrent is None:
            enableOffsetCurrent = 0
        if offsetCurrent is None:
            offsetCurrent = 0
        else:
            offsetCurrent = int(
                "{:04b}".format(offsetCurrent)[::-1],
                2)  # need to reverse bits, use string/list tricks
        if testInput is None:
            testInput = 1
        if freqInternal is None:
            freqInternal = 1
        if sleep is None:
            sleep = 0
        if pdsr is None:
            pdsr = 0
        if pcsr is None:
            pcsr = 0
        if sLSB is None:
            sLSB = 0
        if f1 is None:
            f1 = 0
        if f2 is None:
            f2 = 0
        if f3 is None:
            f3 = 0
        if f4 is None:
            f4 = 1
        if f5 is None:
            f5 = 0
        if not (clockMonostable or clockExternal or clockFromFIFO):
            clockExternal = True
        # a bunch of things depend on the clock choice
        clk0 = 0
        clk1 = 0
        if clockExternal:
            clk0 = 1
            clk1 = 0
        elif clockFromFIFO:
            clk0 = 0
            clk1 = 1
        if f0 is None:
            if clockExternal:
                f0 = 1
            else:
                f0 = 0
        if clockExternal:
            self.extClock(enable=True)
        else:
            self.extClock(enable=False)

        self.adc_reg.set_sbnd_board(en_gr=enableOffsetCurrent,
                                    d=offsetCurrent,
                                    tstin=testInput,
                                    frqc=freqInternal,
                                    slp=sleep,
                                    pdsr=pdsr,
                                    pcsr=pcsr,
                                    clk0=clk0,
                                    clk1=clk1,
                                    f0=f0,
                                    f1=f1,
                                    f2=f2,
                                    f3=f3,
                                    f4=f4,
                                    f5=f5,
                                    slsb=sLSB)
        self.configAdcAsic_regs(self.adc_reg.REGS)

    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 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 fixUnsync(self, adc):
        adcNum = int(adc)
        if (adcNum < 0) or (adcNum > 7):
            print(
                "FEMB_CONFIG--> femb_config_femb : testLink - invalid asic number"
            )
            return

        initLATCH1_4 = self.femb.read_reg(self.REG_LATCHLOC1_4)
        initLATCH5_8 = self.femb.read_reg(self.REG_LATCHLOC5_8)
        initPHASE = self.femb.read_reg(self.REG_CLKPHASE)

        phases = [0, 1]
        if self.COLD:
            phases = [0, 1, 0, 1, 0]

        #loop through sync parameters
        for shift in range(0, 16, 1):
            shiftMask = (0x3F << 8 * adcNum)
            if (adcNum < 4):
                testShift = ((initLATCH1_4 & ~(shiftMask)) |
                             (shift << 8 * adcNum))
                self.femb.write_reg(self.REG_LATCHLOC1_4, testShift)
                time.sleep(0.01)
            else:
                testShift = ((initLATCH5_8 & ~(shiftMask)) |
                             (shift << 8 * adcNum))
                self.femb.write_reg(self.REG_LATCHLOC5_8, testShift)
                time.sleep(0.01)
            for phase in phases:
                clkMask = (0x1 << adcNum)
                testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum))
                self.femb.write_reg(self.REG_CLKPHASE, testPhase)
                time.sleep(0.01)
                print("try shift: {} phase: {} testingUnsync...".format(
                    shift, phase))
                print(
                    "     initPHASE: {:#010x}, phase: {:#010x}, testPhase: {:#010x}"
                    .format(initPHASE, phase, testPhase))
                #reset ADC ASIC
                self.femb.write_reg(self.REG_ASIC_RESET, 1)
                time.sleep(0.01)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.01)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.01)
                #test link
                unsync, syncDicts = self.testUnsync(adcNum)
                if unsync == 0:
                    print("FEMB_CONFIG--> ADC synchronized")
                    return
        #if program reaches here, sync has failed
        print("Error: FEMB_CONFIG--> ADC SYNC process failed for ADC # " +
              str(adc))
        print(
            "Setting back to original values: LATCHLOC1_4: {:#010x}, LATCHLOC5_8: {:#010x}, PHASE: {:#010x}"
            .format, initLATCH1_4, initLATCH5_8, initPHASE)
        self.femb.write_reg(self.REG_LATCHLOC1_4, initLATCH1_4)
        self.femb.write_reg(self.REG_LATCHLOC5_8, initLATCH5_8)
        self.femb.write_reg(self.REG_CLKPHASE, initPHASE)
        if self.exitOnError:
            sys.exit(1)
        else:
            raise SyncADCError

    def extClock(self,
                 enable=False,
                 period=500,
                 mult=1,
                 offset_rst=0,
                 offset_read=480,
                 offset_msb=230,
                 offset_lsb=480,
                 width_rst=50,
                 width_read=20,
                 width_msb=270,
                 width_lsb=20,
                 offset_lsb_1st_1=50,
                 width_lsb_1st_1=190,
                 offset_lsb_1st_2=480,
                 width_lsb_1st_2=20,
                 inv_rst=True,
                 inv_read=True,
                 inv_msb=False,
                 inv_lsb=False,
                 inv_lsb_1st=False):
        """
        Programs external clock. All non-boolean arguments except mult are in nanoseconds
        """

        rd_en_off = 0
        adc_off = 0
        adc_wid = 0
        msb_off = 0
        msb_wid = 0
        period_val = 0
        lsb_fc_wid2 = 0
        lsb_fc_off1 = 0
        rd_en_wid = 0
        lsb_fc_wid1 = 0
        lsb_fc_off2 = 0
        lsb_s_wid = 0
        lsb_s_off = 0
        inv = 0

        if enable:
            clock = 1. / self.FPGA_FREQ_MHZ * 1000.  # clock now in ns
            #print("FPGA Clock freq: {} MHz period: {} ns".format(self.FPGA_FREQ_MHZ,clock))
            #print("ExtClock option mult: {}".format(mult))
            #print("ExtClock option period: {} ns".format(period))
            #print("ExtClock option offset_read: {} ns".format(offset_read))
            #print("ExtClock option offset_rst: {} ns".format(offset_rst))
            #print("ExtClock option offset_msb: {} ns".format(offset_msb))
            #print("ExtClock option offset_lsb: {} ns".format(offset_lsb))
            #print("ExtClock option offset_lsb_1st_1: {} ns".format(offset_lsb_1st_1))
            #print("ExtClock option offset_lsb_1st_2: {} ns".format(offset_lsb_1st_2))
            #print("ExtClock option width_read: {} ns".format(width_read))
            #print("ExtClock option width_rst: {} ns".format(width_rst))
            #print("ExtClock option width_msb: {} ns".format(width_msb))
            #print("ExtClock option width_lsb: {} ns".format(width_lsb))
            #print("ExtClock option width_lsb_1st_1: {} ns".format(width_lsb_1st_1))
            #print("ExtClock option width_lsb_1st_2: {} ns".format(width_lsb_1st_2))
            #print("ExtClock option inv_rst: {}".format(inv_rst))
            #print("ExtClock option inv_read: {}".format(inv_read))
            #print("ExtClock option inv_msb: {}".format(inv_msb))
            #print("ExtClock option inv_lsb: {}".format(inv_lsb))
            #print("ExtClock option inv_lsb_1st: {}".format(inv_lsb_1st))
            denominator = clock / mult
            #print("ExtClock denominator: {} ns".format(denominator))
            period_val = period // denominator
            rd_en_off = offset_read // denominator
            adc_off = offset_rst // denominator
            adc_wid = width_rst // denominator
            msb_off = offset_msb // denominator
            msb_wid = width_msb // denominator
            lsb_fc_wid2 = width_lsb_1st_2 // denominator
            lsb_fc_off1 = offset_lsb_1st_1 // denominator
            rd_en_wid = width_read // denominator
            lsb_fc_wid1 = width_lsb_1st_1 // denominator
            lsb_fc_off2 = offset_lsb_1st_2 // denominator
            lsb_s_wid = width_lsb // denominator
            lsb_s_off = offset_lsb // denominator
            if inv_rst:
                inv += 1 << 0
            if inv_read:
                inv += 1 << 1
            if inv_msb:
                inv += 1 << 2
            if inv_lsb:
                inv += 1 << 3
            if inv_lsb_1st:
                inv += 1 << 4

        regsValsToWrite = [
            ("rd_en_off", self.REG_EXTCLK_RD_EN_OFF, rd_en_off),
            ("adc_off", self.REG_EXTCLK_ADC_OFF, adc_off),
            ("adc_wid", self.REG_EXTCLK_ADC_WID, adc_wid),
            ("msb_off", self.REG_EXTCLK_MSB_OFF, msb_off),
            ("msb_wid", self.REG_EXTCLK_MSB_WID, msb_wid),
            ("period", self.REG_EXTCLK_PERIOD, period_val),
            ("lsb_fc_wid2", self.REG_EXTCLK_LSB_FC_WID2, lsb_fc_wid2),
            ("lsb_fc_off1", self.REG_EXTCLK_LSB_FC_OFF1, lsb_fc_off1),
            ("rd_en_wid", self.REG_EXTCLK_RD_EN_WID, rd_en_wid),
            ("lsb_fc_wid1", self.REG_EXTCLK_LSB_FC_WID1, lsb_fc_wid1),
            ("lsb_fc_off2", self.REG_EXTCLK_LSB_FC_OFF2, lsb_fc_off2),
            ("lsb_s_wid", self.REG_EXTCLK_LSB_S_WID, lsb_s_wid),
            ("lsb_s_off", self.REG_EXTCLK_LSB_S_OFF, lsb_s_off),
            ("inv", self.REG_EXTCLK_INV, inv),
        ]
        for name, reg, val in regsValsToWrite:
            val = int(val) & 0xFFFF  # only 16 bits for some reason
            #print("ExtClock Register {0:12} number {1:3} set to {2:5} = {2:#06x}".format(name,reg,val))
            self.femb.write_reg(reg, val)

    def programFirmware(self, firmware):
        """
        Programs the FPGA using the firmware file given.
        """
        if self.FIRMWAREPROGCABLE == "USB-BlasterII":
            # this programmer is too fast for our board
            # (or linux or something) so we have to slow it down
            jtagconfig_commandline = os.path.dirname(self.FIRMWAREPROGEXE)
            jtagconfig_commandline = os.path.join(jtagconfig_commandline,
                                                  "jtagconfig")
            jtagconfig_commandline += " --setparam 1 JtagClock 6M"
            print(jtagconfig_commandline)
            subprocess.run(jtagconfig_commandline.split(), check=True)
        commandline = "{} -c {} -m jtag -o p;{}".format(
            self.FIRMWAREPROGEXE, self.FIRMWAREPROGCABLE, firmware)
        commandlinelist = commandline.split()
        print(commandline)
        print(commandlinelist)
        subprocess.run(commandlinelist, check=True)

    def checkFirmwareProgrammerStatus(self):
        """
        Prints a debug message for the firmware programmer
        """
        jtagconfig_commandline = os.path.dirname(self.FIRMWAREPROGEXE)
        jtagconfig_commandline = os.path.join(jtagconfig_commandline,
                                              "jtagconfig")
        if self.FIRMWAREPROGCABLE == "USB-BlasterII":
            # this programmer is too fast for our board
            # (or linux or something) so we have to slow it down
            jtagconfig_commandline_speed = jtagconfig_commandline + " --setparam 1 JtagClock 6M"
            print(jtagconfig_commandline_speed)
            subprocess.run(jtagconfig_commandline_speed.split())
        subprocess.run(jtagconfig_commandline.split())

    def programFirmware1Mhz(self):
        self.programFirmware(self.FIRMWAREPATH1MHZ)
        self.SAMPLERATE = 1e6

    def programFirmware2Mhz(self):
        self.programFirmware(self.FIRMWAREPATH2MHZ)
        self.SAMPLERATE = 2e6

    def getClockStr(self):
        latchloc1 = self.femb.read_reg(self.REG_LATCHLOC1_4)
        latchloc5 = self.femb.read_reg(self.REG_LATCHLOC5_8)
        clkphase = self.femb.read_reg(self.REG_CLKPHASE)
        if latchloc1 is None:
            return "Register Read Error"
        if latchloc5 is None:
            return "Register Read Error"
        if clkphase is None:
            return "Register Read Error"
        return "Latch Loc: {:#010x} {:#010x} Clock Phase: {:#010x}".format(
            latchloc1, latchloc5, clkphase)

    def getSyncStatus(self):
        return [None], [True], None
Exemple #9
0
class FEMB_CONFIG(FEMB_CONFIG_BASE):
    def __init__(self):
        super().__init__()
        #declare board specific registers
        self.FEMB_VER = "35t"
        self.REG_RESET = 0
        self.REG_ASIC_RESET = 1
        self.REG_ASIC_SPIPROG = 2
        self.REG_SEL_ASIC = 7
        self.REG_SEL_CH = 7
        self.REG_FESPI_BASE = 592
        self.REG_ADCSPI_BASE = 512
        self.REG_FESPI_RDBACK_BASE = 632
        self.REG_ADCSPI_RDBACK_BASE = 552
        self.REG_HS = 17
        self.REG_LATCHLOC = 4
        self.REG_CLKPHASE = 6
        self.ADC_TESTPATTERN = [
            0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca,
            0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef
        ]
        self.NASICS = 8

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

        #initialiuze ASIC ch objects, specify SPI register number (firmware specific!!!)
        self.feasic_ch_list = []
        for ch in range(0, 128, 1):
            chVal = int(ch)
            if (chVal < 0) or (chVal > 127):
                continue

            #seriously messy mapping between ch # and register bits
            regGrp = int((chVal % 64) / 16)
            regGrpLine = 7 - int((chVal % 16) / 2)
            regGrpBase = [27, 18, 9, 0]

            regNum = self.REG_FESPI_BASE + regGrpBase[regGrp] + regGrpLine
            regPos = (1 - chVal % 2) * 8 + int(chVal / 64) * 16

            feasic_ch = FEASIC_CH_CONFIG(ch, regNum, regPos)
            self.feasic_ch_list.append(feasic_ch)

    def resetBoard(self):
        #Reset system
        self.femb.write_reg(self.REG_RESET, 1)
        time.sleep(5.)

        #Reset registers
        self.femb.write_reg(self.REG_RESET, 2)
        time.sleep(1.)

        #Time stamp reset
        #femb.write_reg( 0, 4)
        #time.sleep(0.5)

        #Reset ADC ASICs
        self.femb.write_reg(self.REG_ASIC_RESET, 1)
        time.sleep(0.5)

        #Reset FE ASICs
        self.femb.write_reg(self.REG_ASIC_RESET, 2)
        time.sleep(0.5)

    def initBoard(self):
        nRetries = 5
        for iRetry in range(nRetries):
            #set up default registers

            #Reset ADC ASICs
            self.femb.write_reg(self.REG_ASIC_RESET, 1)
            time.sleep(0.5)

            #Reset FE ASICs
            self.femb.write_reg(self.REG_ASIC_RESET, 2)
            time.sleep(0.5)

            #Set ADC test pattern register
            self.femb.write_reg(3, 0x01230000)  #31 - enable ADC test pattern,

            #Set ADC latch_loc
            self.femb.write_reg(self.REG_LATCHLOC, 0x77777677)
            #Set ADC clock phase
            self.femb.write_reg(self.REG_CLKPHASE, 0x1e)

            #internal test pulser control
            self.femb.write_reg(5, 0x02000001)
            self.femb.write_reg(13, 0x0)  #enable

            #Set test and readout mode register
            self.femb.write_reg(
                7, 0x0000)  #11-8 = channel select, 3-0 = ASIC select

            #Set number events per header
            self.femb.write_reg(8, 0x0)

            #FE ASIC SPI registers
            print("Config FE ASIC SPI")
            for regNum in range(self.REG_FESPI_BASE, self.REG_FESPI_BASE + 34,
                                1):
                self.femb.write_reg(regNum, 0xC4C4C4C4)
            self.femb.write_reg(self.REG_FESPI_BASE + 8, 0xC400C400)
            self.femb.write_reg(self.REG_FESPI_BASE + 16, 0x00C400C4)
            self.femb.write_reg(self.REG_FESPI_BASE + 25, 0xC400C400)
            self.femb.write_reg(self.REG_FESPI_BASE + 33, 0x00C400C4)

            #ADC ASIC SPI registers
            print("Config ADC ASIC SPI")
            self.femb.write_reg(self.REG_ADCSPI_BASE + 0, 0xc0c0c0c)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 1, 0xc0c0c0c)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 2, 0xc0c0c0c)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 3, 0xc0c0c0c)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 4, 0xc0c0c0c)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 5, 0xc0c0c0c)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 6, 0xc0c0c0c)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 7, 0xc0c0c0c)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 8, 0x18321832)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 9, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 10, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 11, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 12, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 13, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 14, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 15, 0x18181818)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 16, 0x64186418)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 17, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 18, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 19, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 20, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 21, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 22, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 23, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 24, 0x30303030)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 25, 0x60c860c8)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 26, 0x60606060)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 27, 0x60606060)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 28, 0x60606060)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 29, 0x60606060)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 30, 0x60606060)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 31, 0x60606060)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 32, 0x60606060)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 33, 0x90609060)
            self.femb.write_reg(self.REG_ADCSPI_BASE + 34, 0x10001)

            #ADC ASIC sync
            self.femb.write_reg(17,
                                0x1)  # controls HS link, 0 for on, 1 for off
            self.femb.write_reg(17,
                                0x0)  # controls HS link, 0 for on, 1 for off

            #Write FE ASIC SPI
            print("Program FE ASIC SPI")
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 2)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 2)
            time.sleep(0.1)

            #Write ADC ASIC SPI
            print("Program ADC ASIC SPI")
            self.femb.write_reg(self.REG_ASIC_RESET, 1)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)

            #35t ONLY, check if sync is ok, try redoing ADC reprogramming if not
            for test in range(0, 5, 1):
                regVal = self.femb.read_reg(6)
                isSync = ((regVal & 0xFFFF0000) >> 16)
                if isSync == 0:
                    print("Synced ADCs")
                    break
                self.femb.write_reg(self.REG_ASIC_RESET, 1)
                time.sleep(0.1)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.1)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.1)
            """
            print("Check ADC ASIC SPI")
            for regNum in range(self.REG_ADCSPI_RDBACK_BASE,self.REG_ADCSPI_RDBACK_BASE+34,1):
                    val = self.femb.read_reg( regNum ) 
                    print(hex(val))

            print("Check FE ASIC SPI")
            for regNum in range(self.REG_FESPI_RDBACK_BASE,self.REG_FESPI_RDBACK_BASE+34,1):
                    val = self.femb.read_reg( regNum)            
                    print(hex(val))
            """

            # Check that board streams data
            data = self.femb.get_data(1)
            if data == None:
                print("Board not streaming data, retrying initialization...")
                continue  # try initializing again
            print("FEMB_CONFIG--> Reset FEMB is DONE")
            return
        print(
            "Error: Board not streaming data after trying to initialize {} times. Exiting."
            .format(nRetries))
        sys.exit(1)

    def configFeAsic(self, gain, shape, base):
        gainVal = int(gain)
        if (gainVal < 0) or (gainVal > 3):
            return
        shapeVal = int(shape)
        if (shapeVal < 0) or (shapeVal > 3):
            return
        baseVal = int(base)
        if (baseVal < 0) or (baseVal > 1):
            return

        #get ASIC channel config register SPI values
        chReg = 0x0
        gainArray = [0, 2, 1, 3]
        shapeArray = [2, 0, 3, 1]  #I don't know why
        chReg = (gainArray[gainVal] << 4) + (shapeArray[shapeVal] << 2)

        if (baseVal == 0):
            chReg = chReg + 0x40

        #enable test capacitor here
        chReg = chReg + 0x80  #enabled
        #chReg = chReg + 0x0 #disabled

        #need better organization of SPI, just store in words for now
        word1 = chReg + (chReg << 8) + (chReg << 16) + (chReg << 24)
        word2 = (chReg << 8) + (chReg << 24)
        word3 = chReg + (chReg << 16)

        #turn off HS data before register writes
        self.femb.write_reg_bits(9, 0, 0x1, 0)
        print("HS link turned off")
        time.sleep(1)

        print("Config FE ASIC SPI")
        for regNum in range(self.REG_FESPI_BASE, self.REG_FESPI_BASE + 34, 1):
            self.femb.write_reg(regNum, word1)
        self.femb.write_reg(self.REG_FESPI_BASE + 8, word2)
        self.femb.write_reg(self.REG_FESPI_BASE + 16, word3)
        self.femb.write_reg(self.REG_FESPI_BASE + 25, word2)
        self.femb.write_reg(self.REG_FESPI_BASE + 33, word3)

        #Write FE ASIC SPI
        print("Program FE ASIC SPI")
        self.femb.write_reg(self.REG_ASIC_SPIPROG, 2)
        time.sleep(0.1)
        self.femb.write_reg(self.REG_ASIC_SPIPROG, 2)
        time.sleep(0.1)

        #print "Check FE ASIC SPI"
        #for regNum in range(self.REG_FESPI_RDBACK_BASE,self.REG_FESPI_RDBACK_BASE+34,1):
        #        val = self.femb.read_reg( regNum)
        #        print hex(val)

        #turn HS link back on
        print("HS link turned back on")
        time.sleep(1)
        self.femb.write_reg_bits(9, 0, 0x1, 1)

    def selectChannel(self, asic, chan, hsmode=None):
        asicVal = int(asic)
        if (asicVal < 0) or (asicVal > 7):
            print("femb_config_femb : selectChan - invalid ASIC number")
            return
        chVal = int(chan)
        if (chVal < 0) or (chVal > 15):
            print("femb_config_femb : selectChan - invalid channel number")
            return

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

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

    def setInternalPulser(self, pulserEnable, pulseHeight):
        pulserEnable = int(pulserEnable)
        if (pulserEnable < 0) or (pulserEnable > 1):
            return
        pulserEnableVal = int(pulserEnable)
        if (pulseHeight < 0) or (pulseHeight > 32):
            return
        pulseHeightVal = int(pulseHeight)
        self.femb.write_reg_bits(5, 0, 0x1F, pulseHeightVal)
        #self.femb.write_reg_bits( 16, 8,0x1,0)
        self.femb.write_reg_bits(13, 1, 0x1, pulserEnableVal)

    def syncADC(self):
        #turn on ADC test mode
        print("Start sync ADC")
        reg3 = self.femb.read_reg(3)
        newReg3 = (reg3 | 0x80000000)
        self.femb.write_reg(3, newReg3)  #31 - enable ADC test pattern
        alreadySynced = True
        for a in range(0, 8, 1):
            print("Test ADC " + str(a))
            unsync = self.testUnsync(a)
            if unsync != 0:
                print("ADC not synced, try to fix")
                alreadySynced = False
                self.fixUnsync(a)
        LATCH = self.femb.read_reg(self.REG_LATCHLOC)
        PHASE = self.femb.read_reg(self.REG_CLKPHASE)
        print("Latch latency " + str(hex(LATCH)) + "\tPhase " +
              str(hex(PHASE)))
        print("End sync ADC")
        return not alreadySynced, LATCH, None, PHASE

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

        #loop through channels, check test pattern against data
        badSync = 0
        for ch in range(0, 16, 1):
            self.selectChannel(adcNum, ch)
            time.sleep(0.1)
            for test in range(0, 10, 1):
                data = self.femb.get_data(1)
                if data == None:
                    continue
                for samp in data:
                    if samp == None:
                        continue
                    chNum = ((samp >> 12) & 0xF)
                    sampVal = (samp & 0xFFF)
                    if sampVal != self.ADC_TESTPATTERN[ch]:
                        badSync = 1
                    if badSync == 1:
                        break
                if badSync == 1:
                    break
            if badSync == 1:
                break
        return badSync

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

        initLATCH = self.femb.read_reg(self.REG_LATCHLOC)
        initPHASE = self.femb.read_reg(self.REG_CLKPHASE)

        #loop through sync parameters
        for phase in range(0, 2, 1):
            clkMask = (0x1 << adcNum)
            testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum))
            self.femb.write_reg(self.REG_CLKPHASE, testPhase)
            for shift in range(0, 16, 1):
                shiftMask = (0xF << 4 * adcNum)
                testShift = ((initLATCH & ~(shiftMask)) |
                             (shift << 4 * adcNum))
                self.femb.write_reg(self.REG_LATCHLOC, testShift)
                #reset ADC ASIC
                self.femb.write_reg(self.REG_ASIC_RESET, 1)
                time.sleep(0.1)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.1)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.1)
                #test link
                unsync = self.testUnsync(adcNum)
                if unsync == 0:
                    print("ADC synchronized")
                    return
        #if program reaches here, sync has failed
        print("ADC SYNC process failed for ADC # " + str(adc))
Exemple #10
0
class FEMB_CONFIG(FEMB_CONFIG_BASE):
    def __init__(self):
        super().__init__()
        #declare board specific registers
        self.FEMB_VER = "SBND(FE-ASIC with internal DAC)"
        self.REG_RESET = 0
        self.REG_ASIC_RESET = 1
        self.REG_ASIC_SPIPROG = 2
        self.REG_SEL_ASIC = 7
        self.REG_SEL_CH = 7
        self.REG_FESPI_BASE = 0x250
        self.REG_ADCSPI_BASE = 0x200
        self.REG_FESPI_RDBACK_BASE = 0x278
        self.REG_ADCSPI_RDBACK_BASE = 0x228
        self.REG_HS = 17
        self.REG_LATCHLOC1_4 = 4
        self.REG_LATCHLOC1_4_data = 0x07060707
        self.REG_LATCHLOC5_8 = 14
        self.REG_LATCHLOC5_8_data = 0x06060606
        self.REG_CLKPHASE = 6
        self.REG_CLKPHASE_data = 0xe1
        self.REG_EN_CALI = 16
        self.ADC_TESTPATTERN = [
            0x12, 0x345, 0x678, 0xf1f, 0xad, 0xc01, 0x234, 0x567, 0x89d, 0xeca,
            0xff0, 0x123, 0x456, 0x789, 0xabc, 0xdef
        ]
        self.NASICS = 8

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

    def resetBoard(self):
        #Reset system
        self.femb.write_reg(self.REG_RESET, 1)

        #Reset registers
        self.femb.write_reg(self.REG_RESET, 2)

        #Time stamp reset
        #femb.write_reg ( 0, 4)

        #Reset ADC ASICs
        self.femb.write_reg(self.REG_ASIC_RESET, 1)

    def initBoard(self):
        nRetries = 5
        for iRetry in range(nRetries):
            print("FEMB_CONFIG--> Reset FEMB")
            #set up default registers

            #Reset ADC ASICs
            self.femb.write_reg(self.REG_ASIC_RESET, 1)

            #Set ADC test pattern register
            self.femb.write_reg(3, 0x01170000)  #31 - enable ADC test pattern,

            #Set ADC latch_loc
            self.femb.write_reg(self.REG_LATCHLOC1_4,
                                self.REG_LATCHLOC1_4_data)
            self.femb.write_reg(self.REG_LATCHLOC5_8,
                                self.REG_LATCHLOC5_8_data)
            #Set ADC clock phase
            self.femb.write_reg(self.REG_CLKPHASE, self.REG_CLKPHASE_data)

            #internal test pulser control
            freq = 500
            dly = 80
            ampl = 0 % 32
            int_dac = 0  # or 0xA1
            dac_meas = int_dac  # or 60
            reg_5_value = ((freq << 16) & 0xFFFF0000) + (
                (dly << 8) & 0xFF00) + ((dac_meas | ampl) & 0xFF)
            self.femb.write_reg(5, reg_5_value)
            self.femb.write_reg(16, 0x0)

            self.femb.write_reg(13, 0x0)  #enable

            #Set test and readout mode register
            self.femb.write_reg(
                7, 0x0000)  #11-8 = channel select, 3-0 = ASIC select
            self.femb.write_reg(17,
                                1)  #11-8 = channel select, 3-0 = ASIC select

            #for iReg in range(len(self.fe_reg.REGS)):
            #  self.fe_reg.REGS[iReg] = 0xFFFFFFFF
            #set default value to FEMB ADCs and FEs
            #self.configAdcAsic(pdsr=1,pcsr=1,clockFromFIFO=True,freqInternal=1,f2=1)
            self.configAdcAsic_regs(self.adc_reg.REGS)
            self.configFeAsic_regs(self.fe_reg.REGS)

            #Set number events per header -- no use
            #self.femb.write_reg ( 8, 0x0)

            # Check that board streams data
            data = self.femb.get_data(1)
            if data == None:
                print("Board not streaming data, retrying initialization...")
                continue  # try initializing again
            print("FEMB_CONFIG--> Reset FEMB is DONE")
            return
        print(
            "Error: Board not streaming data after trying to initialize {} times. Exiting."
            .format(nRetries))
        sys.exit(1)

    def configAdcAsic_regs(self, Adcasic_regs):
        #ADC ASIC SPI registers
        print("FEMB_CONFIG--> Config ADC ASIC SPI")
        for k in range(10):
            i = 0
            for regNum in range(self.REG_ADCSPI_BASE,
                                self.REG_ADCSPI_BASE + len(Adcasic_regs), 1):
                #print("{:032b}".format(Adcasic_regs[i]))
                #print("{:08x}".format(Adcasic_regs[i]))
                self.femb.write_reg(regNum, Adcasic_regs[i])
                time.sleep(0.05)
                i = i + 1

            #print("  ADC ASIC write : ",Adcasic_regs)
            #ADC ASIC sync
            #self.femb.write_reg ( 17, 0x1) # controls HS link, 0 for on, 1 for off
            #self.femb.write_reg ( 17, 0x0) # controls HS link, 0 for on, 1 for off

            #Write ADC ASIC SPI
            print("FEMB_CONFIG--> Program ADC ASIC SPI")
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
            time.sleep(0.1)

            self.femb.write_reg(18, 0x0)
            time.sleep(0.1)

            print("FEMB_CONFIG--> Check ADC ASIC SPI")
            adcasic_rb_regs = []
            for regNum in range(
                    self.REG_ADCSPI_RDBACK_BASE,
                    self.REG_ADCSPI_RDBACK_BASE + len(Adcasic_regs), 1):
                val = self.femb.read_reg(regNum)
                adcasic_rb_regs.append(val)

            #print("  ADC ASIC read back: ",adcasic_rb_regs)
            if (adcasic_rb_regs != Adcasic_regs):
                if (k == 1):
                    sys.exit("femb_config : Wrong readback. ADC SPI failed")
                    return
                print(
                    "FEMB_CONFIG--> ADC ASIC Readback didn't match, retrying..."
                )
            else:
                print("FEMB_CONFIG--> ADC ASIC SPI is OK")
                break
        #enable streaming
        #self.femb.write_reg ( 9, 0x8)
        #LBNE_ADC_MODE

    def configFeAsic_regs(self, feasic_regs):
        print("FEMB_CONFIG--> Config FE ASIC SPI")
        assert (len(feasic_regs) == 34)

        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])
                i = i + 1
            #Write FE ASIC SPI
            print("FEMB_CONFIG--> Program FE ASIC SPI")
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 2)
            self.femb.write_reg(self.REG_ASIC_SPIPROG, 2)

            print("FEMB_CONFIG--> Check FE ASIC SPI")
            feasic_rb_regs = []
            for regNum in range(self.REG_FESPI_RDBACK_BASE,
                                self.REG_FESPI_RDBACK_BASE + len(feasic_regs),
                                1):
                val = self.femb.read_reg(regNum)
                feasic_rb_regs.append(val)

            if (feasic_rb_regs != feasic_regs):
                if (k == 9):
                    sys.exit(
                        "femb_config_femb : Wrong readback. FE SPI failed")
                    return
                print(
                    "FEMB_CONFIG--> FE ASIC Readback didn't match, retrying..."
                )
                if len(feasic_rb_regs) == len(feasic_regs):
                    print("{:15} {:15}".format("feasic_rb_regs",
                                               "feasic_regs"))
                    for iReg in range(len(feasic_rb_regs)):
                        print("{:#010x}      {:#010x}".format(
                            feasic_rb_regs[iReg], feasic_regs[iReg]))
                else:
                    print("lens don't match: {} != {}".format(
                        len(feasic_rb_regs), len(feasic_regs)))
            else:
                print("FEMB_CONFIG--> FE ASIC SPI is OK")
                #print("{:15} {:15}".format("feasic_rb_regs","feasic_regs"))
                #for iReg in range(len(feasic_rb_regs)):
                #    print("{:#010x}      {:#010x}".format(feasic_rb_regs[iReg],feasic_regs[iReg]))
                break

    def configFeAsic(self,
                     gain,
                     shape,
                     base,
                     slk=None,
                     slkh=None,
                     monitorBandgap=None,
                     monitorTemp=None):
        """
        Configure FEs with given gain/shape/base values.
        Also, configure leakage current slk = 0 for 500 pA, 1 for 100 pA
            and slkh = 0 for 1x leakage current, 1 for 10x leakage current
        if monitorBandgap is True: monitor bandgap instead of signal
        if monitorTemp is True: monitor temperature instead of signal
        """
        gain = int("{:02b}".format(gain)[::-1],
                   2)  # need to reverse bits, use string/list tricks
        shape = int("{:02b}".format(shape)[::-1],
                    2)  # need to reverse bits, use string/list tricks
        if slk is None:
            slk = 0
        if slkh is None:
            slkh = 0
        if monitorBandgap and monitorTemp:
            raise Exception(
                "You can't monitor bandgap and temperature at the same time. Set either monitorBandgap or monitorTemp False"
            )
        stb = 0
        if monitorBandgap:
            stb = 0b11
        if monitorTemp:
            stb = 0b10
        self.fe_reg.set_fe_sbnd_board(snc=base,
                                      sg=gain,
                                      st=shape,
                                      slk0=slk,
                                      stb=stb)
        self.configFeAsic_regs(self.fe_reg.REGS)

    def configAdcAsic(self,
                      enableOffsetCurrent=None,
                      offsetCurrent=None,
                      testInput=None,
                      freqInternal=None,
                      sleep=None,
                      pdsr=None,
                      pcsr=None,
                      clockMonostable=None,
                      clockExternal=None,
                      clockFromFIFO=None,
                      sLSB=None,
                      f0=None,
                      f1=None,
                      f2=None,
                      f3=None,
                      f4=None,
                      f5=None):
        """
        Configure ADCs
          enableOffsetCurrent: 0 disable offset current, 1 enable offset current
          offsetCurrent: 0-15, amount of current to draw from sample and hold
          testInput: 0 digitize normal input, 1 digitize test input
          freqInternal: internal clock frequency: 0 1MHz, 1 2MHz
          sleep: 0 disable sleep mode, 1 enable sleep mode
          pdsr: if pcsr=0: 0 PD is low, 1 PD is high
          pcsr: 0 power down controlled by pdsr, 1 power down controlled externally
          Only one of these can be enabled:
            clockMonostable: True ADC uses monostable clock
            clockExternal: True ADC uses external clock
            clockFromFIFO: True ADC uses digital generator FIFO clock
          sLSB: LSB current steering mode. 0 for full, 1 for partial (ADC7 P1)
          f0, f1, f2, f3, f4, f5: version specific
        """
        FEMB_CONFIG_BASE.configAdcAsic(self,
                                       clockMonostable=clockMonostable,
                                       clockExternal=clockExternal,
                                       clockFromFIFO=clockFromFIFO)
        if enableOffsetCurrent is None:
            enableOffsetCurrent = 0
        if offsetCurrent is None:
            offsetCurrent = 0
        else:
            offsetCurrent = int(
                "{:04b}".format(offsetCurrent)[::-1],
                2)  # need to reverse bits, use string/list tricks
        if testInput is None:
            testInput = 0
        if freqInternal is None:
            freqInternal = 0
        if sleep is None:
            sleep = 0
        if pdsr is None:
            pdsr = 0
        if pcsr is None:
            pcsr = 0
        clk0 = 0
        clk1 = 0
        if clockExternal:
            clk0 = 1
            clk1 = 0
        elif clockFromFIFO:
            clk0 = 0
            clk1 = 1
        self.adc_reg.set_sbnd_board(en_gr=enableOffsetCurrent,
                                    d=offsetCurrent,
                                    tstin=testInput,
                                    frqc=freqInternal,
                                    slp=sleep,
                                    pdsr=pdsr,
                                    pcsr=pcsr,
                                    clk0=clk0,
                                    clk1=clk1,
                                    f1=f1,
                                    f2=f2)
        self.configAdcAsic_regs(self.adc_reg.REGS)

    def selectChannel(self, asic, chan, 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
        hsmodeVal = int(hsmode)
        if (hsmodeVal != 0) and (hsmodeVal != 1):
            print(
                "FEMB_CONFIG--> femb_config_femb : selectChan - invalid HS mode"
            )
            return

        print("FEMB_CONFIG--> Selecting ASIC " + str(asicVal) + ", channel " +
              str(chVal))

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

    def setInternalPulser(self, pulserEnable, pulseHeight):
        if pulserEnable:
            print("Enabling internal FPGA DAC")

            # turn on test capacitor on all FE ASIC channels
            fe_reg = copy.deepcopy(self.fe_reg.REGS)

            self.fe_reg.set_fe_sbnd_board(sts=1)
            for i in range(len(fe_reg)):
                self.fe_reg.REGS[i] = fe_reg[i] | self.fe_reg.REGS[i]
                print(hex(self.fe_reg.REGS[i]))

            self.configFeAsic_regs(self.fe_reg.REGS)

            # internal FPGA DAC settings
            freq = 20  # number of samples between pulses
            dly = 80  # dly*5ns sets inteval between where FPGA starts pulse and ADC samples
            ampl = pulseHeight % 32  # mV injected
            int_dac = 0  # or 0xA1
            dac_meas = int_dac  # or 60
            reg_5_value = ((freq << 16) & 0xFFFF0000) + (
                (dly << 8) & 0xFF00) + ((dac_meas | ampl) & 0xFF)
            self.femb.write_reg(5, reg_5_value)

            # set to pulser mode (0x01) and enable FPGA DAC (0x01xx)
            self.femb.write_reg(16, 0x0101)
            print(self.femb.read_reg(16))
        else:
            print("Disabling pulser (still testing may not work)")

            # disable test capacitor
            fe_reg = copy.deepcopy(self.fe_reg.REGS)

            self.fe_reg.set_fe_sbnd_board(sts=0)
            for i in range(len(fe_reg)):
                self.fe_reg.REGS[i] = fe_reg[i] | self.fe_reg.REGS[i]
                print(hex(self.fe_reg.REGS[i]))

            self.configFeAsic_regs(self.fe_reg.REGS)

            # disable pulser mode
            self.femb.write_reg(16, 0x0)
            print(self.femb.read_reg(16))

    def syncADC(self):
        #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 = self.testUnsync(a)
            if unsync != 0:
                alreadySynced = False
                print("FEMB_CONFIG--> ADC not synced, try to fix")
                self.fixUnsync(a)
        self.REG_LATCHLOC1_4_data = self.femb.read_reg(self.REG_LATCHLOC1_4)
        self.REG_LATCHLOC5_8_data = self.femb.read_reg(self.REG_LATCHLOC5_8)
        self.REG_CLKPHASE_data = self.femb.read_reg(self.REG_CLKPHASE)
        print("FEMB_CONFIG--> Latch latency " + str(hex(self.REG_LATCHLOC1_4_data)) \
                        + str(hex(self.REG_LATCHLOC5_8_data )) + \
                        "\tPhase " + str(hex(self.REG_CLKPHASE_data)))
        self.femb.write_reg(3, (reg3 & 0x7fffffff))
        self.femb.write_reg(3, (reg3 & 0x7fffffff))
        print("FEMB_CONFIG--> End sync ADC")
        return not alreadySynced, self.REG_LATCHLOC1_4_data, self.REG_LATCHLOC5_8_data, self.REG_CLKPHASE_data

    def testUnsync(self, adc):
        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
        badSync = 0
        for ch in range(0, 16, 1):
            self.selectChannel(adcNum, ch, 1)
            time.sleep(0.05)
            for test in range(0, 10, 1):
                data = self.femb.get_data(1)
                #print("test: ",test," data: ",data)
                if data == None:
                    continue
                for samp in data[0:(16 * 1024 + 1023)]:
                    if samp == None:
                        continue
                    chNum = ((samp >> 12) & 0xF)
                    sampVal = (samp & 0xFFF)
                    if sampVal != self.ADC_TESTPATTERN[ch]:
                        badSync = 1
                    if badSync == 1:
                        break
                if badSync == 1:
                    break
            if badSync == 1:
                break
        return badSync

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

        initLATCH1_4 = self.femb.read_reg(self.REG_LATCHLOC1_4)
        initLATCH5_8 = self.femb.read_reg(self.REG_LATCHLOC5_8)
        initPHASE = self.femb.read_reg(self.REG_CLKPHASE)

        #loop through sync parameters
        for phase in range(0, 2, 1):
            clkMask = (0x1 << adcNum)
            testPhase = ((initPHASE & ~(clkMask)) | (phase << adcNum))
            self.femb.write_reg(self.REG_CLKPHASE, testPhase)
            time.sleep(0.01)
            for shift in range(0, 16, 1):
                shiftMask = (0x3F << 8 * adcNum)
                if (adcNum < 4):
                    testShift = ((initLATCH1_4 & ~(shiftMask)) |
                                 (shift << 8 * adcNum))
                    self.femb.write_reg(self.REG_LATCHLOC1_4, testShift)
                    time.sleep(0.01)
                else:
                    testShift = ((initLATCH5_8 & ~(shiftMask)) |
                                 (shift << 8 * adcNum))
                    self.femb.write_reg(self.REG_LATCHLOC5_8, testShift)
                    time.sleep(0.01)
                print("trying phase: ", phase, " shift: ", shift,
                      " testingUnsync...")
                #reset ADC ASIC
                self.femb.write_reg(self.REG_ASIC_RESET, 1)
                time.sleep(0.01)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.01)
                self.femb.write_reg(self.REG_ASIC_SPIPROG, 1)
                time.sleep(0.01)
                #test link
                unsync = self.testUnsync(adcNum)
                if unsync == 0:
                    print("FEMB_CONFIG--> ADC synchronized")
                    return
        #if program reaches here, sync has failed
        print("FEMB_CONFIG--> ADC SYNC process failed for ADC # " + str(adc))

    def get_rawdata_chipXchnX(self, chip=0, chn=0):
        i = 0
        while (1):
            i = i + 1
            self.selectChannel(chip, chn, 1)
            data = self.femb.get_rawdata()
            #make sure the data belong to chipXchnX
            data0 = struct.unpack_from(">1H", data[0:2])
            if (len(data) > 2):
                if ((data0[0] >> 12) == chn):
                    if (i > 1):
                        print(
                            "FEMB_CONFIG--> get_rawdata_chipXchnX--> cycle%d to get right data"
                            % i)
                    break
        return data

    def get_rawdata_packets_chipXchnX(self, chip=0, chn=0, val=10):
        i = 0
        while (1):
            self.selectChannel(chip, chn, 1)
            data = self.femb.get_rawdata_packets(val)
            #make sure the data belong to chnX
            if (len(data) > 2):
                data0 = struct.unpack_from(">1H", data[0:2])
                if ((data0[0] >> 12) == chn):
                    if (i > 1):
                        print(
                            "FEMB_CONFIG--> get_rawdata_chipXchnX--> cycle%d to get right data"
                            % i)
                    break
        return data

    def enablePulseMode(self, srcflag):
        #Configures board in test pulse mode
        #srcflag = 0 means external input is enabled
        #srcflag = 1 means internal FPGA DAC is enabled with default settings
        #srcflag = 99 means turn it off
        #ETW just playing around with the internal DAC settings not sure this works
        srcflag = int(srcflag)
        if (srcflag == 1):
            print("Enabling internal FPGA DAC")

            # turn on test capacitor on all FE ASIC channels
            fe_reg = copy.deepcopy(self.fe_reg.REGS)

            self.fe_reg.set_fe_sbnd_board(sts=1)
            for i in range(len(fe_reg)):
                self.fe_reg.REGS[i] = fe_reg[i] | self.fe_reg.REGS[i]
                print(hex(self.fe_reg.REGS[i]))

            self.configFeAsic_regs(self.fe_reg.REGS)

            # internal FPGA DAC settings
            freq = 20  # number of samples between pulses
            dly = 80  # dly*5ns sets inteval between where FPGA starts pulse and ADC samples
            ampl = 20 % 32  # mV injected
            int_dac = 0  # or 0xA1
            dac_meas = int_dac  # or 60
            reg_5_value = ((freq << 16) & 0xFFFF0000) + (
                (dly << 8) & 0xFF00) + ((dac_meas | ampl) & 0xFF)
            self.femb.write_reg(5, reg_5_value)

            # set to pulser mode (0x01) and enable FPGA DAC (0x01xx)
            self.femb.write_reg(16, 0x0101)
            print(self.femb.read_reg(16))

        elif (srcflag == 0):
            print("Enabling external pulse (still testing may not work)")

            # turn on test capacitor on all FE ASIC channels
            fe_reg = copy.deepcopy(self.fe_reg.REGS)

            self.fe_reg.set_fe_sbnd_board(sts=1)
            for i in range(len(fe_reg)):
                self.fe_reg.REGS[i] = fe_reg[i] | self.fe_reg.REGS[i]
                print(hex(self.fe_reg.REGS[i]))

            self.configFeAsic_regs(self.fe_reg.REGS)

            # set to pulser mode (0x01) and enable external input (0x00xx)
            self.femb.write_reg(16, 0x0001)
            print(self.femb.read_reg(16))

        elif (srcflag == 99):
            print("Disabling pulser (still testing may not work)")

            # disable test capacitor
            fe_reg = copy.deepcopy(self.fe_reg.REGS)

            self.fe_reg.set_fe_sbnd_board(sts=0)
            for i in range(len(fe_reg)):
                self.fe_reg.REGS[i] = fe_reg[i] | self.fe_reg.REGS[i]
                print(hex(self.fe_reg.REGS[i]))

            self.configFeAsic_regs(self.fe_reg.REGS)

            # disable pulser mode
            self.femb.write_reg(16, 0x0)
            print(self.femb.read_reg(16))

        else:
            print("Source flag must be 0 (ext), 1 (dac), or 99 (disable)")