from tkinter import * import serial import serial.tools.list_ports import codecs import math import time from math import floor root = Tk() csr_acquire = IntVar() csr_trigger = IntVar() st_trig = IntVar() st_ff = IntVar() st_fe = IntVar() st_rxfe = IntVar() g_s = IntVar() deb_var = IntVar() class Application(Frame): """ Create the window and populate with widgets """ def __init__(self,parent): """ initializes the frame """ Frame.__init__(self,parent,background="white") # # frame 1 holds the QUIT and status line # self.frame1 = Frame(parent) self.frame1.grid(row=0,column=0,sticky=W) self.frame1.config(highlightthickness=1,highlightbackground="black") # # frame 2 holds the fetching of 16 bit words # self.frame2 = Frame(parent) self.frame2.grid(row=1,column=0,sticky=W) self.frame2.config(highlightthickness=1,highlightbackground="black") # # frame 3 holds the setting and verifying of 8-bit parameters # self.frame3 = Frame(parent) self.frame3.grid(row=2,column=0,sticky=W) self.frame3.config(highlightthickness=1,highlightbackground="black") # # frame 4 is for reading data from the data fifo # self.frame4 = Frame(parent) self.frame4.grid(row=3,column=0,sticky=W) self.frame4.config(highlightthickness=1,highlightbackground="black") # # frame 5 holds the voltmeter # self.frame5 = Frame(parent) self.frame5.grid(row=4,column=0,sticky=W) self.frame5.config(highlightthickness=1,highlightbackground="black") self.parent = parent self.debugit = False self.canvas_width = 500 self.canvas_height = 500 self.grid() self.create_widgets() self.isopen = 0 self.openPort() self.voltages = [] self.adcs = [] def create_widgets(self): self.buttonQ = Button(self.frame1, text="Quit") self.buttonQ["command"] = self.quitit self.buttonQ.grid(row=0,column=0, sticky=W) self.cdebug = Checkbutton(self.frame1,text="Debug?",variable=deb_var) self.cdebug.grid(row=0,column=1,sticky=W) self.slabel = Label(self.frame1, text="Status:") self.slabel.grid(row=1, column=0, sticky=W) self.status = Text(self.frame1,height=1,width=40) self.status.grid(row=1, column=1, sticky=W) self.status.delete("1.0",END) self.rlabel = Label(self.frame1, text="Result:") self.rlabel.grid(row=2, column=0, sticky=W) self.answer = Text(self.frame1,height=1, width=40) self.answer.grid(row=2,column=1,sticky=W) self.answer.delete("1.0",END) # # set up the fetch buttons to get 16 bit words # firmware version, test vector from switches, # and the ADC value present # self.fetchlabel = Label(self.frame2, text="Fetch:") self.fetchlabel.grid(row=0, column=1, sticky=W) self.buttonV = Button(self.frame2,text="Version") self.buttonV.grid(row=0,column=2, sticky=W) self.buttonV["command"] = lambda: self.getdata16(0xa) self.buttonS = Button(self.frame2,text="Test") self.buttonS.grid(row=0,column=3, sticky=W) self.buttonS["command"] = lambda: self.getdata16(0xc) self.buttonD = Button(self.frame2,text="ADC Data") self.buttonD.grid(row=0,column=4, sticky=W) self.buttonD["command"] = lambda: self.getdata16(8) self.text16 = Text(self.frame2, height=1, width=10) self.text16.grid(row=0, column=5) # # next, set 8-bit parameters # # status register: # row = 0 self.setlabel = Label(self.frame3, text="Status Register:") self.setlabel.grid(row=row, column=0, sticky=W) self.buttonRS = Button(self.frame3, text="Read", command=self.readStatus) self.buttonRS.grid(row=row, column=1, sticky=W) self.RStext = Text(self.frame3, height=1, width=10) self.RStext.grid(row=row, column=2, sticky=W) row = row + 1 self.sglobal = Checkbutton(self.frame3,text="Start",variable=g_s) self.sglobal.grid(row=row,column=1,sticky=W) self.strigger = Checkbutton(self.frame3,text="Trigger Ena",variable=st_trig) self.strigger.grid(row=row,column=2,sticky=W) self.sfifofull = Checkbutton(self.frame3,text="ADC Fifo Full",variable=st_ff) self.sfifofull.grid(row=row,column=3,sticky=W) self.sfifoempty = Checkbutton(self.frame3,text="ADC Fifo Empty",variable=st_fe) self.sfifoempty.grid(row=row,column=4,sticky=W) row = row + 1 self.rxfifoempty = Checkbutton(self.frame3,text="RX Fifo Empty",variable=st_rxfe) self.rxfifoempty.grid(row=row,column=4,sticky=W) # # control register: # row = row + 1 self.csrlabel = Label(self.frame3, text="Control Register:") self.csrlabel.grid(row=row, column=0, sticky=W) self.csrread = Button(self.frame3, text="Read",command=self.readCSR) self.csrread.grid(row=row, column=1, sticky=W) self.csrtext = Text(self.frame3, height=1, width=6) self.csrtext.grid(row=row, column=2, sticky=W) row = row + 1 self.buttonSC = Button(self.frame3, text="Set", command=self.setCSR) self.buttonSC.grid(row=row, column=1, sticky=W) self.radacq = Checkbutton(self.frame3, text="Acquire", variable=csr_acquire) self.radacq.grid(row=row,column=2,sticky=W) self.radtrig = Checkbutton(self.frame3, text="Trigger", variable=csr_trigger) self.radtrig.grid(row=row,column=3,sticky=W) # # threshold register # row = row + 1 self.thlabel = Label(self.frame3, text="Threshold Register:") self.thlabel.grid(row=row, column=0, sticky=W) self.buttonST = Button(self.frame3, text="Set", command=self.setThreshold) self.buttonST.grid(row=row, column=1, sticky=W) self.STtext = Text(self.frame3, height=1, width=10) self.STtext.grid(row=row,column=2, sticky=W) self.STtext.insert("1.0","80") self.buttonRT = Button(self.frame3, text="Read", command=self.readThreshold) self.buttonRT.grid(row=row, column=3, sticky=W) self.RTstext = Text(self.frame3, height=1, width=10) self.RTstext.grid(row=row, column=4, sticky=W) # # prefill register - how many data points to save before trigger # row = row + 1 self.blabel = Label(self.frame3, text="Prefill Register:") self.blabel.grid(row=row, column=0, sticky=W) self.buttonSB = Button(self.frame3, text="Set", command=self.setPrefill) self.buttonSB.grid(row=row, column=1, sticky=W) self.SBtext = Text(self.frame3, height=1, width=10) self.SBtext.grid(row=row,column=2, sticky=W) self.SBtext.insert("1.0","60") self.buttonRB = Button(self.frame3, text="Read", command=self.readPrefill) self.buttonRB.grid(row=row, column=3, sticky=W) self.RBstext = Text(self.frame3, height=1, width=10) self.RBstext.grid(row=row, column=4, sticky=W) # # read data from the fifo # self.dlabel = Label(self.frame4, text="Fifo Data:") self.dlabel.grid(row=0, column=0, sticky=W) self.buttonD = Button(self.frame4, text="Read 1", command=self.read1Data) self.buttonD.grid(row=0, column=1, sticky=W) self.dtext = Text(self.frame4, height=1, width=8) self.dtext.grid(row=0, column=2, sticky=W) self.buttonAll = Button(self.frame4, text="Read till Empty", command=self.readAllData) self.buttonAll.grid(row=0,column=3, sticky=W) self.buttonPlot = Button(self.frame4, text="Plot", command=self.plotAll) self.buttonPlot.grid(row=0, column=4, sticky=W) self.buttonreplot = Button(self.frame4, text="Replot", command=self.rePlot) self.buttonreplot.grid(row=1, column=4, sticky=W) self.textLow = Text(self.frame4,height=1,width=6) self.textLow.grid(row=1,column=5,sticky=W) self.textLow.insert("1.0",0) self.textHi = Text(self.frame4,height=1,width=6) self.textHi.grid(row=1,column=6,sticky=W) self.textHi.insert("1.0",65535) self.C = Canvas(self.frame5,bg="white", height=self.canvas_height,width=self.canvas_width) self.C.grid(row=0,column=0,columnspan=5) def plotAll(self): self.debugit = deb_var.get() == 1 self.plot() def readAllData(self): self.debugit = deb_var.get() == 1 if self.debugit: print("readAllData:") # # read until fifo empty but not more than 1024 # n = 1 self.voltages.clear() self.adcs.clear() for i in range(0,65535): idata = self.fiforead() if idata == 0: print(" timeout reading n="+str(n)) break adc = idata >> 4 self.adcs.append(adc) volt = 0.244e-3 * adc self.voltages.append(volt) last = idata & 1 empty = (idata >> 1) & 1 start = (idata >> 2) & 1 triggered = (idata >> 3) & 1 if triggered == 1: if self.debugit: print(" "+str(n)+" data="+hex(idata)+" ADC="+hex(adc)+" empty="+str(empty)+" TRIGGERED!") else: if self.debugit: print(" "+str(n)+" data="+hex(idata)+" ADC="+hex(adc)+" empty="+str(empty)) if last == 1: if self.debugit: print("last word! "+hex(idata)) break n += 1 # if n%1000 == 0: # print(".",end="") if self.debugit: print("") print(" read "+str(n)+" times") self.plot() def read1Data(self): self.debugit = deb_var.get() == 1 if self.debugit: print("read1Data:") # # read 1 data point (16 bits, 2 bytes) from the fifo # idata = self.fiforead() if self.debugit: print(" data read back: "+hex(idata)) last = idata & 1 empty = (idata >> 1) & 1 start = (idata >> 2) & 1 triggered = (idata >> 3) & 1 if self.debugit: print("triggered="+str(triggered)+" start="+str(start)+" empty="+str(empty)+" last="+str(last)) self.dtext.delete(1.0,END) self.dtext.insert(1.0,hex(idata)) def fiforead(self): # # 1st write 0x8 indicating read fifo # haddr = 0x10 if self.debugit: print(" writing "+hex(haddr)) sendb = haddr.to_bytes(1,"little") self.ser.write(sendb) # # read 2 bytes # rdata = self.ser.read(2) idata = int.from_bytes(rdata,byteorder="little") if len(rdata) == 0: return 0 else: return idata def write_to_address(self,addr,value): if self.debugit: print("write_to_address:") # # this function does 3 writes to the FPGA: # the first is a byte of instructions # the 2nd is the lower byte of the data word # the 3rd is the upper byte of the data word # if self.isopen == 0: self.status.insert(END,"You MUST open a port first!\n Doing it for you...\n") self.openPort() # # write addr first, tells the FPGA to get ready for value, # which comes 2nd and 3rd. addr and value are integers # haddr = addr if self.debugit: print(" writing "+hex(value)+" to address "+hex(addr)) self.status.insert(END," sending write command to address "+hex(addr)) sendb = haddr.to_bytes(1,"little") self.ser.write(sendb) # # send the data you want to write # value_low = value & 0xFF if self.debugit: print(" sending "+hex(value_low)) sendb = value_low.to_bytes(1,"little") if self.debugit: print(" in bytes is "+str(sendb)) self.ser.write(sendb) value_high = value >> 8 if self.debugit: print(" sending "+hex(value_high)) sendb = value_high.to_bytes(1,"little") if self.debugit: print(" in bytes is "+str(sendb)) self.ser.write(sendb) def read_from_address(self,addr): if self.isopen == 0: self.status.insert(END,"You MUST open a port first!\n Doing it for you...\n") self.openPort() if self.debugit: print("read_from_address:") if self.debugit: print(" write to address "+hex(addr)) self.status.delete(1.0,END) self.status.insert(END,"write command to address 0x"+hex(addr)) sendb = addr.to_bytes(1,"little") # # write the instruction # self.ser.write(sendb) # # now read the result # tdata = self.ser.read(2) if self.debugit: print(" value read back in bytes: "+str(tdata)) idata = int.from_bytes(tdata,byteorder="little") if self.debugit: print(" value read back in hex: "+hex(idata)) if len(tdata) == 0: return 0 else: return idata def readCSR(self): self.debugit = deb_var.get() == 1 if self.debugit: print("readCSR") haddr = 0x0 idata = self.read_from_address(haddr) self.csrtext.delete(1.0,END) self.csrtext.insert(1.0,hex(idata)) if idata & 1 > 0: csr_acquire.set(1) else: csr_acquire.set(0) if idata & 2 > 0: csr_trigger.set(1) else: csr_trigger.set(0) def setCSR(self): self.debugit = deb_var.get() == 1 # # this function will take the bits from the checkboxes and # overwrite CSR # if self.debugit: print("setCSR:") if self.isopen == 0: self.status.insert(END,"You MUST open a port first!\n Doing it for you...\n") self.openPort() # # so far we only have 2 bits, but we could easily have more # bit0 = csr_acquire.get() bit1 = csr_trigger.get() if self.debugit: print(" bit 0 "+str(bit0)) if self.debugit: print(" bit 1 "+str(bit1)) # # write the data # value = bit0 + 2*bit1 if self.debugit: print(" value = "+hex(value)) haddr = 1 self.write_to_address(haddr,value) def write_csr(self,which_bit,bit_val): if self.debugit: print("write_csr:") # # first read CSR # addr = 0x0 if self.debugit: print(" bit="+str(which_bit)+" and bit value = "+str(bit_val)) value = self.read_from_address(addr) if value == 0: print("TIMEOUT!!!") if self.debugit: print(" reading from address 0x22 returns "+hex(value)) self.status.insert(END," CSR value read is "+str(value)+"\n") vor = 2**which_bit if bit_val == 1: value_new = value | vor else: value_new = value & ~vor self.status.insert(END," sending "+hex(value_new)+"\n") # # now write to csr, address 3 # addr = 3 self.write_to_address(addr,value_new) def readStatus(self): self.debugit = deb_var.get() == 1 # # write to 0x2, then read back 2 byte status register # if self.debugit: print("readStatus:") haddr = 0x2 idata = self.read_from_address(haddr) if idata == 0: print("TIMEOUT!!!") if self.debugit: print(" status value read back is "+hex(idata)) self.RStext.delete(1.0,END) self.RStext.insert(1.0,hex(idata)) # # check the bits. here is the latest: # bit 0 global_start enabled # 1 trigger enabled # 2 rx_fifo_empty # 3 data_fifo_empty # 4 data_fifo_full # 5 triggered if idata & 1 > 0: g_s.set(1) else: g_s.set(0) if idata & 2 > 0: st_trig.set(1) else: st_trig.set(0) if idata & 8 > 0: st_fe.set(1) else: st_fe.set(0) if idata & 16 > 0: st_ff.set(1) else: st_ff.set(0) if idata & 4 > 1: st_rxfe.set(1) else: st_rxfe.set(0) def setThreshold(self): self.debugit = deb_var.get() == 1 if self.debugit: print("setThreshold:") haddr = 3 thresh = self.STtext.get("1.0",END).strip('\n') thresh_int = int(thresh,16) if self.debugit: print(" sending threshold "+thresh) self.write_to_address(haddr,thresh_int) def readThreshold(self): self.debugit = deb_var.get() == 1 if self.debugit: print("readThreshold:") haddr = 0x4 idata = self.read_from_address(haddr) if idata == 0: print("TIMEOUT!!!") if self.debugit: print(" threshold value read back from address "+hex(haddr)+" is "+hex(idata)) self.RTstext.delete(1.0,END) self.RTstext.insert(1.0,hex(idata)) def setPrefill(self): self.debugit = deb_var.get() == 1 if self.debugit: print("setPrefill:") haddr = 5 prefill = self.SBtext.get("1.0",END).strip('\n') prefill_int = int(prefill,16) self.write_to_address(haddr,prefill_int) def readPrefill(self): self.debugit = deb_var.get() == 1 if self.debugit: print("readPrefill:") haddr = 0x6 idata = self.read_from_address(haddr) if idata == 0: print("TIMEOUT!!!") if self.debugit: print(" prefill value read back from address "+hex(haddr)+" is "+hex(idata)) self.RBstext.delete(1.0,END) self.RBstext.insert(1.0,hex(idata)) def quitit(self): print("That's all folks!") quit() def openPort(self): if self.isopen == 1: self.status.insert(END,"Port is already open!\n") self.ser.close() #return # # defaults # port = "/dev/ttyS0" sbaud = "1000000" baud = int(sbaud) timeout = 5 if self.debugit: print("port="+port+" baud="+sbaud) self.ser = serial.Serial(port,sbaud,timeout=timeout) if self.ser.isOpen(): self.status.insert(END,self.ser.name + " is now open\n") print(self.ser.name + " is now open...") self.isopen = 1 else: self.status.insert(END,self.ser.name + " is NOT open!!!\n") print("sorry, problem trying to open port "+port+"\n") def getdata16(self,which): self.debugit = deb_var.get() == 1 # # fetches 1 of the 16 bit words # # # first check to see if any port has been opened or not # if self.isopen == 0: self.status.insert(END,"Sorry but you MUST open a port first!") return # # fetch what? # addr = which; if which == 0: self.status.insert(END,"??? invalid address!!!") return # # send the command # if self.debugit: print("sending "+str(addr)) self.status.delete(1.0,END) self.status.insert(1.0,"Sending...") sendb = addr.to_bytes(1,"little") self.ser.write(sendb) self.status.insert(END,"done!") # # now wait a short time and then look for input # nbytes = 2 self.status.insert(END," Waiting...") #time.sleep(0.1) tdata = self.ser.read(nbytes) ld = len(tdata) if self.debugit: print(ld) if ld > 0: # # flag input has arrived and print out in hex # noinput = 0 idata = int.from_bytes(tdata,byteorder="little") self.text16.delete(1.0,END) self.text16.insert(1.0,hex(idata)) if self.debugit: print("idata1: "+str(idata)) self.status.insert(END," done!") self.answer.delete(1.0,END) # # check to see if this is the ADC data, then make the display of voltage # if addr == 8: val = idata/16 if self.debugit: print("idata: ",str(val)) # # now calculate the votage read # voltage = val * 0.244E-3 self.answer.delete(1.0,END) svolt = "{:.2f}".format(voltage) #svolt = str(round("{:.2f}".format(voltage) self.answer.insert(1.0,hex(int(val)) + " = " +svolt+" volts") self.display(voltage) else: self.answer.insert(1.0,hex(idata)) else: self.status.insert(END," timeout!") def rePlot(self): # # get low and high fifo bins to plot # self.C.delete("all") xlow = int(self.textLow.get("1.0",END).strip('\n')) xhi = int(self.textHi.get("1.0",END).strip('\n')) self.plotPoints(xlow,xhi,False) def plot(self): print("drawing plot...") self.C.delete("all") nmax =len(self.voltages) self.plotPoints(0,65535,False) print(" done!") def plotPoints(self,xlow,xhigh,connect): # # xoff and yoff are the offsets for the plot in the canvas # xoff = 50 yoff = 50 voltmax = 1.0 if len(self.voltages) == 0: print(" no data to plot!") return width = self.canvas_width height = self.canvas_height pw = width - 2*xoff ph = height - 2*yoff self.C.create_rectangle(xoff,yoff,width-xoff,height-yoff) n = 0 radius = 1 xold = 0 yold = 0 # # display the y axis, voltage # self.C.create_text(xoff-20,20,text="Voltage") self.C.create_text(xoff-15,height-yoff,text="0.0") self.C.create_text(xoff-15,height-yoff-0.25*ph,text="0.25") self.C.create_text(xoff-15,height-yoff-0.5*ph,text="0.5") self.C.create_text(xoff-15,height-yoff-0.75*ph,text="0.75") self.C.create_text(xoff-15,height-yoff-ph,text="1.0") # # display x axis, time. note that delta-t is 1us # # make 10 intervals, so 11 ticks starting at 0 # nvolts = xhigh-xlow #len(self.voltages) ticky = 10 ninterval = 10 deltax = (self.canvas_width-2*xoff)/ninterval xtick = xoff timeScale = "ms" if nvolts < 1001: dscale = 1.0*nvolts/ninterval timeScale = "us" else: dscale = 1.0*nvolts/(1000*ninterval) scale = 0.0 for i in range(0,ninterval): self.C.create_line(xtick,height-yoff-ticky/2,xtick,height-yoff+ticky/2) sscale = str( floor(scale*10)/10 ) self.C.create_text(xtick-5,height-yoff/2,text=sscale) scale += dscale xtick += deltax self.C.create_text(self.canvas_width-20,height-yoff/2,text=timeScale) for i in range(xlow,xhigh): volt = self.voltages[i] y = height - yoff - volt*ph/voltmax x = xoff + n*pw/nvolts x0 = x - radius x1 = x + radius y0 = y - radius y1 = y + radius self.C.create_oval(x0,y0,x1,y1) if n == 0: xold = x yold = y else: if connect: self.C.create_line(x,y,xold,yold) xold = x yold = y n += 1 def display(self,volts): self.C.delete("all") # # draw a circle centered at half the canvas width and height # with radius circle_radius # circle_radius = 100 circle_center_x = self.canvas_width/2 circle_center_y = circle_radius + 50 print(str(circle_radius)) print(str(circle_center_x)) print(str(circle_center_y)) left_x = circle_center_x - 100 right_x = circle_center_x + 100 left_y = circle_center_y - 100 right_y = circle_center_y + 100 self.C.create_oval(left_x,left_y,right_x,right_y) # # voltage goes from 0 to 1, so scale the angle of # the meter line # angle = math.pi * volts linex = circle_radius * math.cos(angle) liney = circle_radius * math.sin(angle) x0 = circle_center_x y0 = circle_center_y self.C.create_line(x0,y0,x0-linex,y0-liney) for i in range(0,11): val = float(i)/10 sval = str(val) ang = math.pi * val x1 = x0 - (circle_radius+10) * math.cos(ang) y1 = y0 - (circle_radius+10) * math.sin(ang) self.C.create_text(x1,y1,text=sval) def main(): # modify the window root.title("Python/BASYS3 DAQ") root.wm_title("Python/BASYS3 DAQ") root.geometry("600x900+500+100") root.update() #create the frame that holds other widgets app = Application(root) #kick off event loop root.mainloop() if __name__ == '__main__': main()